diff options
author | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
---|---|---|
committer | Stephen D. Huston <shuston@apache.org> | 2011-10-21 01:19:00 +0000 |
commit | ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5 (patch) | |
tree | dcfb94e75656c6c239fc3dcb754cd2015126424d /cpp | |
parent | 5eb354b338bb8d8fcd35b6ac3fb33f8103e757c3 (diff) | |
download | qpid-python-ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5.tar.gz |
Undo bad merge from trunk - merged at wrong level.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1187150 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp')
635 files changed, 8823 insertions, 22446 deletions
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 17411e90a4..5c37ecfc97 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -80,7 +80,6 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "qpidc-${qpidc_version}") add_subdirectory(managementgen) add_subdirectory(etc) add_subdirectory(src) -add_subdirectory(bindings/qpid) add_subdirectory(docs/api) # add_subdirectory(docs/man) add_subdirectory(examples) diff --git a/cpp/INSTALL b/cpp/INSTALL index dbd41c7cc1..6483d7de4e 100644 --- a/cpp/INSTALL +++ b/cpp/INSTALL @@ -47,9 +47,9 @@ Redhat Linux 3, will almost certainly require some packages to be upgraded. ==================== The following libraries and header files must be installed to build a source distribution: - * boost <http://www.boost.org> (1.35)(*) - * libuuid <http://kernel.org/~kzak/util-linux/> (2.19) - * pkgconfig <http://pkgconfig.freedesktop.org/wiki/> (0.21) + * boost <http://www.boost.org> (1.35)(*) + * e2fsprogs <http://e2fsprogs.sourceforge.net/> (1.39) + * pkgconfig <http://pkgconfig.freedesktop.org/wiki/> (0.21) (*) earlier versions of boost e.g. 1.33 also work and there is a patch to get 1.32 working in the svn tree though that is only recommended as @@ -96,12 +96,12 @@ the following must also be installed: * python-devel * swig <http://www.swig.org> (1.3.35) -UUID problems: -In some earlier Linux releases (such as Fedora 11), the uuid/uuid.h -file is located in the e2fsprogs-devel package instead of -libuuid-devel. If you are using an older Linux release and run into a -problem during configure in which uuid.h cannot be found, install the -e2fsprogs-devel package. +UUID problems: +In some later Linux releases (such as Fedora 12), the uuid/uuid.h file has been +moved from e2fsprogs-devel into libuuid-devel. If you are using a newer Linux +release and run into a problem during configure in which uuid.h cannot be found, +look for and install the libuuid-devel package. + 2.2. How to Install =================== @@ -112,7 +112,7 @@ e2fsprogs-devel package. On linux most packages can be installed using your distribution's package management tool. For example on Fedora: - # yum install boost-devel libuuid-devel pkgconfig gcc-c++ make autoconf automake ruby libtool help2man doxygen graphviz + # yum install boost-devel e2fsprogs-devel pkgconfig gcc-c++ make autoconf automake ruby libtool help2man doxygen graphviz The optional clustering packages changed name in Fedora 10. On Fedora 9 or earlier: # yum install openais-devel cman-devel diff --git a/cpp/INSTALL-WINDOWS b/cpp/INSTALL-WINDOWS index 75fa69079e..964d644a7a 100644 --- a/cpp/INSTALL-WINDOWS +++ b/cpp/INSTALL-WINDOWS @@ -64,7 +64,7 @@ manually installed to non-standard locations. For example: It is also necessary to set BOOST_ROOT to refer to the base of your Boost
installation. The Visual Studio projects refer to it. For example:
- # set BOOST_ROOT="C:\Program Files\boost\boost_1_35_0"
+ # set BOOST_ROOT=C:\Program Files\boost\boost_1_35_0
3. Building from a Source Distribution
@@ -75,7 +75,7 @@ Visual Studio solution file which is generated by CMake. From a command prompt:
# cd qpid\cpp
- # cmake -i -G "Visual Studio 9 2008" .
+ # cmake -i
Output from CMake includes .h files in the include directory, .vcproj
files for executables and dlls, and the qpid-cpp.sln solution file.
@@ -120,12 +120,7 @@ files that are part of the build. Configure again. Repeat until all the Cache Values are gray.
- Click the OK button to generate the project/make files.
-Open the qpid-cpp.sln solution located in the build directory, select Debug
-or Release, and build. You can build both Release and Debug from the same
-project.
-
-If you build all the projects you can then "Build" the RUN_TESTS project.
-This will run the test suite against the Qpid version just built.
+Now follow instruction for building from a source distribution in step (3).
5. Tests
diff --git a/cpp/Makefile.am b/cpp/Makefile.am index 9f4b8e2082..01b8507454 100644 --- a/cpp/Makefile.am +++ b/cpp/Makefile.am @@ -33,7 +33,3 @@ SUBDIRS = managementgen etc src docs/api docs/man examples bindings/qmf bindings # Update libtool, if needed. libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck - -check-long: all - $(MAKE) -C src/tests check-long -
\ No newline at end of file diff --git a/cpp/bindings/qmf/python/Makefile.am b/cpp/bindings/qmf/python/Makefile.am index 8abad32959..421590f189 100644 --- a/cpp/bindings/qmf/python/Makefile.am +++ b/cpp/bindings/qmf/python/Makefile.am @@ -30,13 +30,11 @@ BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmfengine.i - $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qmfengine.cpp $(srcdir)/python.i + swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qmfengine.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _qmfengine.la -qenginedir = $(pyexecdir) -qengine_PYTHON = qmfengine.py qmf.py #_qmfengine_la_LDFLAGS = -avoid-version -module -shrext "$(PYTHON_SO)" #_qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".so" diff --git a/cpp/bindings/qmf/ruby/Makefile.am b/cpp/bindings/qmf/ruby/Makefile.am index de8c4d10d5..cfb3a33870 100644 --- a/cpp/bindings/qmf/ruby/Makefile.am +++ b/cpp/bindings/qmf/ruby/Makefile.am @@ -35,9 +35,9 @@ qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = qmfengine.la -qmfengine_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" +qmfengine_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" qmfengine_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidclient $(top_builddir)/src/libqmfengine.la -qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing +qmfengine_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) nodist_qmfengine_la_SOURCES = qmfengine.cpp CLEANFILES = qmfengine.cpp diff --git a/cpp/bindings/qmf/tests/test_base.rb b/cpp/bindings/qmf/tests/test_base.rb index 7d4609097c..3e4337a9c0 100644 --- a/cpp/bindings/qmf/tests/test_base.rb +++ b/cpp/bindings/qmf/tests/test_base.rb @@ -24,7 +24,6 @@ require 'socket' class ConsoleTestBase < Qmf::ConsoleHandler def initialize - sleep(2) @settings = Qmf::ConnectionSettings.new @settings.host = ARGV[0] if ARGV.size > 0 @settings.port = ARGV[1].to_i if ARGV.size > 1 @@ -68,7 +67,7 @@ class ConsoleTestBase < Qmf::ConsoleHandler def assert(condition, in_text=nil) text = " (#{in_text})" if in_text - raise "Assertion failed: #{condition} #{text}" unless condition + raise "Assertion failed: #{left} != #{right}#{text}" unless condition end def fail(text) diff --git a/cpp/bindings/qmf2/examples/cpp/Makefile.am b/cpp/bindings/qmf2/examples/cpp/Makefile.am index 062fbd0a85..84207d43c4 100644 --- a/cpp/bindings/qmf2/examples/cpp/Makefile.am +++ b/cpp/bindings/qmf2/examples/cpp/Makefile.am @@ -21,7 +21,7 @@ INCLUDE = -I$(top_srcdir)/include AM_CPPFLAGS = $(INCLUDE) -noinst_PROGRAMS=agent event_driven_list_agents list_agents print_events +noinst_PROGRAMS=agent list_agents print_events agent_SOURCES=agent.cpp agent_LDADD=$(top_builddir)/src/libqmf2.la @@ -29,8 +29,5 @@ agent_LDADD=$(top_builddir)/src/libqmf2.la list_agents_SOURCES=list_agents.cpp list_agents_LDADD=$(top_builddir)/src/libqmf2.la -event_driven_list_agents_SOURCES=event_driven_list_agents.cpp -event_driven_list_agents_LDADD=$(top_builddir)/src/libqmf2.la - print_events_SOURCES=print_events.cpp print_events_LDADD=$(top_builddir)/src/libqmf2.la diff --git a/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp b/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp deleted file mode 100644 index c288aa6bdd..0000000000 --- a/cpp/bindings/qmf2/examples/cpp/event_driven_list_agents.cpp +++ /dev/null @@ -1,107 +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 <sys/select.h> -#include <time.h> - -#include <qpid/messaging/Connection.h> -#include <qpid/messaging/Duration.h> -#include <qmf/Agent.h> -#include <qmf/ConsoleEvent.h> -#include <qmf/ConsoleSession.h> -#include <qpid/types/Variant.h> -#include "qmf/posix/EventNotifier.h" - -#include <string> -#include <iostream> - -using namespace std; -using namespace qmf; -using qpid::types::Variant; -using qpid::messaging::Duration; - -int main(int argc, char** argv) -{ - string url("localhost"); - string connectionOptions; - string sessionOptions; - - if (argc > 1) - url = argv[1]; - if (argc > 2) - connectionOptions = argv[2]; - if (argc > 3) - sessionOptions = argv[3]; - - qpid::messaging::Connection connection(url, connectionOptions); - connection.open(); - - ConsoleSession session(connection, sessionOptions); - session.open(); - session.setAgentFilter(""); - - posix::EventNotifier notifier(session); - - int fd(notifier.getHandle()); - time_t lastUpdate; - bool ftl = false; - - time(&lastUpdate); - - while (true) { - fd_set rfds; - struct timeval tv; - int nfds, retval; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - nfds = fd + 1; - tv.tv_sec = 10; - tv.tv_usec = 0; - - retval = select(nfds, &rfds, NULL, NULL, &tv); - - if (retval > 0 && FD_ISSET(fd, &rfds)) { - ConsoleEvent event; - while (session.nextEvent(event, Duration::IMMEDIATE)) { - string eventType = ""; - switch(event.getType()) { - case CONSOLE_AGENT_ADD: eventType = "Added"; break; - case CONSOLE_AGENT_DEL: eventType = "Deleted"; break; - case CONSOLE_AGENT_RESTART: eventType = "Restarted"; break; - case CONSOLE_AGENT_SCHEMA_UPDATE: eventType = "Schema Updated"; break; - case CONSOLE_AGENT_SCHEMA_RESPONSE: eventType = "Schema Response"; break; - case CONSOLE_EVENT: eventType = "Event"; break; - case CONSOLE_QUERY_RESPONSE: eventType = "Query Response"; break; - case CONSOLE_METHOD_RESPONSE: eventType = "Method Response"; break; - case CONSOLE_EXCEPTION: eventType = "Exception"; break; - case CONSOLE_SUBSCRIBE_ADD: eventType = "Subscription Added"; break; - case CONSOLE_SUBSCRIBE_UPDATE: eventType = "Subscription Updated"; break; - case CONSOLE_SUBSCRIBE_DEL: eventType = "Subscription Deleted" ; break; - case CONSOLE_THREAD_FAILED: eventType = "Thread Failure"; break; - default: eventType = "[UNDEFINED]"; - } - cout << "Agent " << eventType << ": " << event.getAgent().getName() << endl; - } - } else { - cout << "No message received within waiting period." << endl; - } - } -} - diff --git a/cpp/bindings/qmf2/python/Makefile.am b/cpp/bindings/qmf2/python/Makefile.am index 3dc04e832f..7adc62eddb 100644 --- a/cpp/bindings/qmf2/python/Makefile.am +++ b/cpp/bindings/qmf2/python/Makefile.am @@ -30,12 +30,12 @@ BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_python_typemaps.i - $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i + swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _cqmf2.la -cqpiddir = $(pyexecdir) +cqpiddir = $(pythondir) cqpid_PYTHON = qmf2.py cqmf2.py _cqmf2_la_LDFLAGS = -avoid-version -module -shared diff --git a/cpp/bindings/qmf2/qmf2.i b/cpp/bindings/qmf2/qmf2.i index 0f573fe3e6..a09a95168f 100644 --- a/cpp/bindings/qmf2/qmf2.i +++ b/cpp/bindings/qmf2/qmf2.i @@ -37,7 +37,6 @@ %} -%include <qpid/ImportExport.h> %include <qpid/messaging/ImportExport.h> %include <qpid/messaging/Duration.h> diff --git a/cpp/bindings/qmf2/ruby/Makefile.am b/cpp/bindings/qmf2/ruby/Makefile.am index 97bbc6f385..ae840f87c6 100644 --- a/cpp/bindings/qmf2/ruby/Makefile.am +++ b/cpp/bindings/qmf2/ruby/Makefile.am @@ -34,9 +34,9 @@ rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = cqmf2.la dist_rubylib_DATA = qmf2.rb -cqmf2_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" +cqmf2_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" cqmf2_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqmf2 $(top_builddir)/src/libqmf2.la -cqmf2_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing +cqmf2_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) nodist_cqmf2_la_SOURCES = cqmf2.cpp CLEANFILES = cqmf2.cpp diff --git a/cpp/bindings/qpid/CMakeLists.txt b/cpp/bindings/qpid/CMakeLists.txt deleted file mode 100644 index 7c9f76f991..0000000000 --- a/cpp/bindings/qpid/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -include(FindSWIG) -include(UseSWIG) -include(FindRuby) -include(FindPythonLibs) -include(FindPerlLibs) - -if (SWIG_FOUND) - set(CMAKE_SWIG_FLAGS "-w361,362,401,467,503") - - if (PYTHONLIBS_FOUND) - add_subdirectory(python) - endif (PYTHONLIBS_FOUND) - - if (RUBY_FOUND) - add_subdirectory(ruby) - endif (RUBY_FOUND) - - if (PERLLIBS_FOUND) - add_subdirectory(perl) - endif (PERLLIBS_FOUND) -endif (SWIG_FOUND) diff --git a/cpp/bindings/qpid/Makefile.am b/cpp/bindings/qpid/Makefile.am index 31bce5d1d5..ca9eda0c73 100644 --- a/cpp/bindings/qpid/Makefile.am +++ b/cpp/bindings/qpid/Makefile.am @@ -21,7 +21,7 @@ SUBDIRS = dotnet if HAVE_SWIG -EXTRA_DIST = CMakeLists.txt qpid.i +EXTRA_DIST = qpid.i if HAVE_RUBY_DEVEL SUBDIRS += ruby diff --git a/cpp/bindings/qpid/dotnet/configure-windows.ps1 b/cpp/bindings/qpid/dotnet/configure-windows.ps1 index 23fc742e07..34395911b9 100644 --- a/cpp/bindings/qpid/dotnet/configure-windows.ps1 +++ b/cpp/bindings/qpid/dotnet/configure-windows.ps1 @@ -24,32 +24,29 @@ # This script configures a qpid\cpp developer build environment under Windows
# to enable working with cpp\bindings\qpid\dotnet binding source code.
#
-# * Supports multiple versions of Visual Studio (VS2008, VS2010) as CMake
-# generator.
-#
# * Supports 32-bit and/or 64-bit development platforms.
#
# * User chooses in-source or out-of-source build directories.
#
# - 'In-source' builds happen when CMake is run from directory qpid\cpp.
-# Hundreds of CMake-generated output files are placed in qpid\cpp\src.
+# Hundreds of CMake-generated output files are placed in qpid\cpp\src.
# These files go right on top of files that are part of the source tree
# in qpid\cpp\src.
-# In-source builds support only one platform.
+# In-source builds support only one platform.
# Choose only a 32-bit or a 64-bit platform but not both.
#
# - Out-of-source builds happen when the user chooses another directory
# under qpid in which to run CMake. Out-of-source builds are required
-# in order to build both x86 and x64 targets using the same source tree.
+# in order to build both x86 and x64 targets using the same source tree.
# For each build platform (32-bit x86 or Win32, or 64-bit x64) the user
-# specifies a build directory and a specific version of Boost.
+# specifies a build directory and a specific version of Boost.
# Many platform/Boost-version directories may reside side by side.
#
# * User chooses to run CMake or not.
#
# - When a new build directory is created then the user is given the
-# option of running CMake in that directory. Running CMake is a
-# necessary step as CMake creates important source, solution, and
+# option of running CMake in that directory. Running CMake is a
+# necessary step as CMake creates important source, solution, and
# project files.
#
# - If a directory "looks like" is has already had CMake run in it
@@ -66,7 +63,7 @@ # 3. CMake 2.8 (or later) must be installed. The cmake\bin directory
# must be in the user's path.
# 4. Boost library specifications may or may not be in the user's path.
-# The script author recommeds not to have Boost in the path and only
+# The script author recommeds not to have Boost in the path and only
# allow the Boost path to be specified by generated command procedures.
# 5. Visual Studio build environment must be installed.
#
@@ -93,7 +90,7 @@ # In this example the build dirs are new. The script will prompt
# asking if CMake is to run in the build directories. User chooses Yes.
#
-# Now this script runs CMake twice, once each with the 32-bit and 64-bit
+# Now this script runs CMake twice, once each with the 32-bit and 64-bit
# generators.
# * This step creates qpid-cpp.sln and related project files.
# C:\svn\qpid\build32\qpid-cpp.sln
@@ -110,7 +107,7 @@ # C:\svn\qpid\build64\setenv-messaging-x64-64bit.bat
#
# Next the user compiles solution qpid\build32\qpid-cpp.sln.
-#
+#
# Using the generated scripts:
#
# Case 1. Run an executable in 32-bit mode.
@@ -145,11 +142,6 @@ $global:txtPath = '$env:PATH' $global:txtQR = '$env:QPID_BUILD_ROOT'
$global:txtWH = 'Write-Host'
-#############################
-# Visual Studio version selection dialog items and choice
-#
-[array]$global:VsVersionCmakeChoiceList = "Visual Studio 10", "Visual Studio 9 2008"
-$global:cmakeGenerator = ''
#############################
# Select-Folder
@@ -176,7 +168,7 @@ function AskYesOrNo ($Question="No question?", $Title="No Title?") [Windows.Forms.MessageBoxIcon]::Question)
$result = $dlg -eq [Windows.Forms.DialogResult]::Yes
-
+
$result
}
@@ -196,7 +188,7 @@ function SanityCheckBoostPath ($path=0) $toTest = ('include', 'lib')
foreach ($pattern in $toTest) {
- $target = Join-Path $path $pattern
+ $target = Join-Path $path $pattern
if (!(Test-Path -path $target)) {
$result = $false
}
@@ -204,7 +196,7 @@ function SanityCheckBoostPath ($path=0) } else {
$result = $false
}
-
+
if (! $result) {
Write-Host "The path ""$displayPath"" does not appear to be a Boost root path."
}
@@ -227,7 +219,7 @@ function SanityCheckBuildPath ($path=0) $toTest = ('CMakeFiles', 'docs', 'etc', 'examples', 'include',
'managementgen', 'src')
foreach ($pattern in $toTest) {
- $target = Join-Path $path $pattern
+ $target = Join-Path $path $pattern
if (!(Test-Path -path $target)) {
$result = $false
}
@@ -321,7 +313,7 @@ function WriteDotnetBindingEnvSetupBat $out = @("@ECHO OFF
REM
-REM Call this command procedure from a command prompt to set up a $vsPlatform ($nBits-bit)
+REM Call this command procedure from a command prompt to set up a $vsPlatform ($nBits-bit)
REM $slnName environment
REM
REM > call $outfileName
@@ -337,56 +329,6 @@ ECHO Environment set for $slnName $vsPlatform $nBits-bit development. $out | Out-File "$buildRoot\$outfileName" -encoding ASCII
}
-#############################
-# Return the SelectedItem from the dropdown list and close the form.
-#
-function Return-DropDown {
- if ($DropDown.SelectedItem -ne $null) {
- $global:cmakeGenerator = $DropDown.SelectedItem.ToString()
- $Form.Close()
- Write-Host "Selected generator: $global:cmakeGenerator"
- }
-}
-
-#############################
-# Create the CMake generator form and launch it
-#
-function SelectCMakeGenerator {
-
- $Form = New-Object System.Windows.Forms.Form
-
- $Form.width = 350
- $Form.height = 150
- $Form.Text = ”Select CMake Generator”
-
- $DropDown = new-object System.Windows.Forms.ComboBox
- $DropDown.Location = new-object System.Drawing.Size(120,10)
- $DropDown.Size = new-object System.Drawing.Size(150,30)
-
- ForEach ($Item in $global:VsVersionCmakeChoiceList) {
- $DropDown.Items.Add($Item)
- }
- $DropDown.SelectedIndex = 0
-
- $Form.Controls.Add($DropDown)
-
- $DropDownLabel = new-object System.Windows.Forms.Label
- $DropDownLabel.Location = new-object System.Drawing.Size(10,10)
- $DropDownLabel.size = new-object System.Drawing.Size(100,20)
- $DropDownLabel.Text = "CMake generators"
- $Form.Controls.Add($DropDownLabel)
-
- $Button = new-object System.Windows.Forms.Button
- $Button.Location = new-object System.Drawing.Size(120,50)
- $Button.Size = new-object System.Drawing.Size(120,20)
- $Button.Text = "Select a generator"
- $Button.Add_Click({Return-DropDown})
- $form.Controls.Add($Button)
-
- $Form.Add_Shown({$Form.Activate()})
- $Form.ShowDialog()
-}
-
#############################
# Main
@@ -399,12 +341,6 @@ function SelectCMakeGenerator { [string] $cppDir = Resolve-Path (Join-Path $curDir "..\..\..")
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
-[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
-
-#############################
-# User dialog to select a version of Visual Studio as CMake generator
-#
-SelectCMakeGenerator
#############################
# User dialog to get optional 32-bit boost and build paths
@@ -476,7 +412,7 @@ if ($make32) { $env:BOOST_ROOT = "$boost32"
cd "$build32"
Write-Host "Running 32-bit CMake in $build32 ..."
- CMake -G "$global:cmakeGenerator" "-DCMAKE_INSTALL_PREFIX=install_x86" $cppDir
+ CMake -G "Visual Studio 9 2008" "-DCMAKE_INSTALL_PREFIX=install_x86" $cppDir
} else {
Write-Host "Skipped 32-bit CMake."
}
@@ -488,7 +424,7 @@ if ($make64) { $env:BOOST_ROOT = "$boost64"
cd "$build64"
Write-Host "Running 64-bit CMake in $build64"
- CMake -G "$global:cmakeGenerator Win64" "-DCMAKE_INSTALL_PREFIX=install_x64" $cppDir
+ CMake -G "Visual Studio 9 2008 Win64" "-DCMAKE_INSTALL_PREFIX=install_x64" $cppDir
} else {
Write-Host "Skipped 64-bit CMake."
}
@@ -501,7 +437,7 @@ if ($make64) { if ($defined32) {
Write-Host "Writing 32-bit scripts..."
-
+
###########
# Powershell script to launch org.apache.qpid.messaging.sln
#
@@ -512,8 +448,8 @@ if ($defined32) { -vsPlatform "x86" `
-nBits "32" `
-outfileName "start-devenv-messaging-x86-32bit.ps1"
-
-
+
+
###########
# Batch script (that you doubleclick) to launch powershell script
# that launches org.apache.qpid.messaging.sln.
@@ -546,7 +482,7 @@ if ($defined32) { if ($defined64) {
Write-Host "Writing 64-bit scripts..."
-
+
###########
# Powershell script to launch org.apache.qpid.messaging.sln
#
@@ -557,8 +493,8 @@ if ($defined64) { -vsPlatform "x64" `
-nBits "64" `
-outfileName "start-devenv-messaging-x64-64bit.ps1"
-
-
+
+
###########
# Batch script (that you doubleclick) to launch powershell script
# that launches org.apache.qpid.messaging.sln.
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs index 6976be5d02..abe35cf053 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.direct.receiver/Properties/AssemblyInfo.cs @@ -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,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("csharp.direct.receiver")]
@@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.direct.receiver")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs index 12368def8e..18502a0666 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.direct.sender/Properties/AssemblyInfo.cs @@ -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,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("csharp.direct.sender")]
@@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.direct.sender")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs index 459130ec6c..a87f92ccdf 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/Properties/AssemblyInfo.cs @@ -20,7 +20,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("csharp.map.callback.receiver")]
@@ -28,12 +28,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.map.callback.receiver")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -43,11 +43,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs index 2be4011f19..e633f76673 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.sender/Properties/AssemblyInfo.cs @@ -28,7 +28,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.map.callback.sender")]
-[assembly: AssemblyCopyright("Copyright 2010")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs index f11ce8c220..694d6b9ce1 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.receiver/Properties/AssemblyInfo.cs @@ -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,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("csharp.map.receiver")]
@@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.map.receiver")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs index ee09057f18..ea29ac2417 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.sender/Properties/AssemblyInfo.cs @@ -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,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("csharp.map.sender")]
@@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp.map.sender")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb b/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb index 469d6ed5cf..d0727fe9fa 100644 --- a/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb +++ b/cpp/bindings/qpid/dotnet/examples/visualbasic.example.client/MyProject/AssemblyInfo.vb @@ -6,9 +6,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,34 +21,34 @@ Imports System Imports System.Reflection
Imports System.Runtime.InteropServices
-' General Information about an assembly is controlled through the following
+' General Information about an assembly is controlled through the following
' set of attributes. Change these attribute values to modify the information
' associated with an assembly.
' Review the values of the assembly attributes
-<Assembly: AssemblyTitle("visualbasic.example.client")>
-<Assembly: AssemblyDescription("")>
-<Assembly: AssemblyCompany("")>
-<Assembly: AssemblyProduct("visualbasic.example.client")>
-<Assembly: AssemblyCopyright("Copyright 2011")>
-<Assembly: AssemblyTrademark("")>
+<Assembly: AssemblyTitle("visualbasic.example.client")>
+<Assembly: AssemblyDescription("")>
+<Assembly: AssemblyCompany("Microsoft")>
+<Assembly: AssemblyProduct("visualbasic.example.client")>
+<Assembly: AssemblyCopyright("Copyright © Microsoft 2010")>
+<Assembly: AssemblyTrademark("")>
<Assembly: ComVisible(False)>
'The following GUID is for the ID of the typelib if this project is exposed to COM
-<Assembly: Guid("ec9df8cf-c1d4-4938-9e72-93fb81d55700")>
+<Assembly: Guid("ec9df8cf-c1d4-4938-9e72-93fb81d55700")>
' Version information for an assembly consists of the following four values:
'
' Major Version
-' Minor Version
+' Minor Version
' Build Number
' Revision
'
-' You can specify all the values or you can default the Build and Revision Numbers
+' You can specify all the values or you can default the Build and Revision Numbers
' by using the '*' as shown below:
-' <Assembly: AssemblyVersion("1.0.*")>
+' <Assembly: AssemblyVersion("1.0.*")>
-<Assembly: AssemblyVersion("1.0.0.0")>
-<Assembly: AssemblyFileVersion("1.0.0.0")>
+<Assembly: AssemblyVersion("1.0.0.0")>
+<Assembly: AssemblyFileVersion("1.0.0.0")>
diff --git a/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln b/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln index edf8af4808..90e98a4bbe 100644 --- a/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln +++ b/cpp/bindings/qpid/dotnet/org.apache.qpid.messaging.sessionreceiver.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
-#
+#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -8,9 +8,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/cpp/bindings/qpid/dotnet/src/Address.cpp b/cpp/bindings/qpid/dotnet/src/Address.cpp index 79a8021d9a..b688d973ed 100644 --- a/cpp/bindings/qpid/dotnet/src/Address.cpp +++ b/cpp/bindings/qpid/dotnet/src/Address.cpp @@ -141,7 +141,7 @@ namespace Messaging { }
}
- // Copy constructor look-alike (C#)
+ // copy constructor
Address::Address(const Address ^ address)
{
System::Exception ^ newException = nullptr;
@@ -163,28 +163,6 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Address::Address(const Address % address)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- addressp = new ::qpid::messaging::Address(
- *(const_cast<Address %>(address).NativeAddress));
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
// unmanaged clone
Address::Address(const ::qpid::messaging::Address & addrp)
{
diff --git a/cpp/bindings/qpid/dotnet/src/Address.h b/cpp/bindings/qpid/dotnet/src/Address.h index 8bbc207d4e..e5a00d8f11 100644 --- a/cpp/bindings/qpid/dotnet/src/Address.h +++ b/cpp/bindings/qpid/dotnet/src/Address.h @@ -64,7 +64,6 @@ namespace Messaging { // copy constructor
Address(const Address ^ address);
- Address(const Address % address);
// unmanaged clone
Address(const ::qpid::messaging::Address & addrp);
diff --git a/cpp/bindings/qpid/dotnet/src/Connection.cpp b/cpp/bindings/qpid/dotnet/src/Connection.cpp index 12c0e29f74..69ace7db52 100644 --- a/cpp/bindings/qpid/dotnet/src/Connection.cpp +++ b/cpp/bindings/qpid/dotnet/src/Connection.cpp @@ -114,7 +114,7 @@ namespace Messaging { }
- // Copy constructor look-alike (C#)
+ // Copy constructor
Connection::Connection(const Connection ^ connection)
{
System::Exception ^ newException = nullptr;
@@ -136,28 +136,6 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Connection::Connection(const Connection % connection)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- connectionp = new ::qpid::messaging::Connection(
- *(const_cast<Connection %>(connection).NativeConnection));
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
// Destructor
Connection::~Connection()
diff --git a/cpp/bindings/qpid/dotnet/src/Connection.h b/cpp/bindings/qpid/dotnet/src/Connection.h index 0788f5d225..f9b62d4a08 100644 --- a/cpp/bindings/qpid/dotnet/src/Connection.h +++ b/cpp/bindings/qpid/dotnet/src/Connection.h @@ -56,7 +56,6 @@ namespace Messaging { // copy constructor
Connection(const Connection ^ connection);
- Connection(const Connection % connection);
// unmanaged clone
// not defined
diff --git a/cpp/bindings/qpid/dotnet/src/Duration.h b/cpp/bindings/qpid/dotnet/src/Duration.h index d4239fae88..213c338a59 100644 --- a/cpp/bindings/qpid/dotnet/src/Duration.h +++ b/cpp/bindings/qpid/dotnet/src/Duration.h @@ -81,17 +81,7 @@ namespace Messaging { Duration ^ result = gcnew Duration(multiplier * dur->Milliseconds);
return result;
}
-
- static bool operator == (Duration ^ a, Duration ^ b)
- {
- return a->Milliseconds == b->Milliseconds;
- }
-
- static bool operator != (Duration ^ a, Duration ^ b)
- {
- return a->Milliseconds != b->Milliseconds;
- }
-};
+ };
public ref class DurationConstants sealed
{
diff --git a/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h b/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h index d82e276fc8..1dd92b8688 100644 --- a/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h +++ b/cpp/bindings/qpid/dotnet/src/FailoverUpdates.h @@ -54,7 +54,6 @@ namespace Messaging { // copy constructor
FailoverUpdates(const FailoverUpdates ^ failoverUpdates) {}
- FailoverUpdates(const FailoverUpdates % failoverUpdates) {}
// assignment operator
FailoverUpdates % operator=(const FailoverUpdates % rhs)
diff --git a/cpp/bindings/qpid/dotnet/src/Message.cpp b/cpp/bindings/qpid/dotnet/src/Message.cpp index e5dbf845b3..fe7825134d 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.cpp +++ b/cpp/bindings/qpid/dotnet/src/Message.cpp @@ -235,7 +235,7 @@ namespace Messaging { }
}
- // Copy constructor look-alike (C#)
+ // Copy constructor
Message::Message(const Message ^ message)
{
System::Exception ^ newException = nullptr;
@@ -257,29 +257,7 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Message::Message(const Message % message)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- messagep = new ::qpid::messaging::Message(
- *(const_cast<Message %>(message).NativeMessage));
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
- // Property
+ // Property
void Message::SetProperty(System::String ^ name, System::Object ^ value)
{
System::Exception ^ newException = nullptr;
diff --git a/cpp/bindings/qpid/dotnet/src/Message.h b/cpp/bindings/qpid/dotnet/src/Message.h index ac7f285fe5..b92cc4200b 100644 --- a/cpp/bindings/qpid/dotnet/src/Message.h +++ b/cpp/bindings/qpid/dotnet/src/Message.h @@ -71,7 +71,6 @@ namespace Messaging { // Copy constructor
Message(const Message ^ message);
- Message(const Message % message);
// unmanaged clone
Message(const ::qpid::messaging::Message & msgp);
diff --git a/cpp/bindings/qpid/dotnet/src/Receiver.cpp b/cpp/bindings/qpid/dotnet/src/Receiver.cpp index 8aa77effbd..3c0d79b393 100644 --- a/cpp/bindings/qpid/dotnet/src/Receiver.cpp +++ b/cpp/bindings/qpid/dotnet/src/Receiver.cpp @@ -89,7 +89,7 @@ namespace Messaging { }
- // Copy constructor look-alike (C#)
+ // Copy constructor
Receiver::Receiver(const Receiver ^ receiver) :
parentSession(receiver->parentSession)
{
@@ -112,29 +112,6 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Receiver::Receiver(const Receiver % receiver) :
- parentSession(receiver.parentSession)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- receiverp = new ::qpid::messaging::Receiver(
- *(const_cast<Receiver %>(receiver).NativeReceiver));
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
//
// Get(message)
diff --git a/cpp/bindings/qpid/dotnet/src/Receiver.h b/cpp/bindings/qpid/dotnet/src/Receiver.h index 8ddcc9ac01..e9912a61dd 100644 --- a/cpp/bindings/qpid/dotnet/src/Receiver.h +++ b/cpp/bindings/qpid/dotnet/src/Receiver.h @@ -65,7 +65,6 @@ namespace Messaging { // copy constructor
Receiver(const Receiver ^ receiver);
- Receiver(const Receiver % receiver);
// unmanaged clone
// undefined
diff --git a/cpp/bindings/qpid/dotnet/src/Sender.cpp b/cpp/bindings/qpid/dotnet/src/Sender.cpp index 3225f1a6e1..584075ef5f 100644 --- a/cpp/bindings/qpid/dotnet/src/Sender.cpp +++ b/cpp/bindings/qpid/dotnet/src/Sender.cpp @@ -84,7 +84,7 @@ namespace Messaging { }
- // Copy constructor look-alike (C#)
+ // Copy constructor
Sender::Sender(const Sender ^ sender)
: parentSession(sender->parentSession)
{
@@ -107,29 +107,6 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Sender::Sender(const Sender % sender)
- : parentSession(sender.parentSession)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- senderp = new ::qpid::messaging::Sender(
- *(const_cast<Sender %>(sender).NativeSender));
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
//
// Send(msg)
diff --git a/cpp/bindings/qpid/dotnet/src/Sender.h b/cpp/bindings/qpid/dotnet/src/Sender.h index 4054e87316..0e90a9f4a4 100644 --- a/cpp/bindings/qpid/dotnet/src/Sender.h +++ b/cpp/bindings/qpid/dotnet/src/Sender.h @@ -62,7 +62,6 @@ namespace Messaging { // copy constructor
Sender(const Sender ^ sender);
- Sender(const Sender % sender);
~Sender();
!Sender();
diff --git a/cpp/bindings/qpid/dotnet/src/Session.cpp b/cpp/bindings/qpid/dotnet/src/Session.cpp index 0e918769a3..880331c588 100644 --- a/cpp/bindings/qpid/dotnet/src/Session.cpp +++ b/cpp/bindings/qpid/dotnet/src/Session.cpp @@ -89,7 +89,7 @@ namespace Messaging { }
- // Copy constructor look-alike (C#)
+ // Copy constructor
Session::Session(const Session ^ session)
: parentConnectionp(session->parentConnectionp)
{
@@ -113,30 +113,6 @@ namespace Messaging { }
}
- // Copy constructor implicitly dereferenced (C++)
- Session::Session(const Session % session)
- : parentConnectionp(session.parentConnectionp)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- sessionp = new ::qpid::messaging::Session(
- *(const_cast<Session %>(session).NativeSession));
-
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
void Session::Close()
{
@@ -248,31 +224,6 @@ namespace Messaging { }
}
- void Session::AcknowledgeUpTo(Message ^ message)
- {
- AcknowledgeUpTo(message, false);
- }
-
- void Session::AcknowledgeUpTo(Message ^ message, bool sync)
- {
- System::Exception ^ newException = nullptr;
-
- try
- {
- sessionp->acknowledgeUpTo(*(message->NativeMessage), sync);
- }
- catch (const ::qpid::types::Exception & error)
- {
- String ^ errmsg = gcnew String(error.what());
- newException = gcnew QpidException(errmsg);
- }
-
- if (newException != nullptr)
- {
- throw newException;
- }
- }
-
void Session::Reject(Message ^ message)
{
System::Exception ^ newException = nullptr;
diff --git a/cpp/bindings/qpid/dotnet/src/Session.h b/cpp/bindings/qpid/dotnet/src/Session.h index 4b98a37f18..7eaad8a0a5 100644 --- a/cpp/bindings/qpid/dotnet/src/Session.h +++ b/cpp/bindings/qpid/dotnet/src/Session.h @@ -69,7 +69,6 @@ namespace Messaging { // copy constructor
Session(const Session ^ session);
- Session(const Session % session);
~Session();
!Session();
@@ -104,8 +103,6 @@ namespace Messaging { void Acknowledge(bool sync);
void Acknowledge(Message ^ message);
void Acknowledge(Message ^ message, bool sync);
- void AcknowledgeUpTo(Message ^ message);
- void AcknowledgeUpTo(Message ^ message, bool sync);
void Reject(Message ^);
void Release(Message ^);
void Sync();
diff --git a/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs b/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs index 81a89ce393..cf50e88200 100644 --- a/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs +++ b/cpp/bindings/qpid/dotnet/test/messaging.test/Properties/AssemblyInfo.cs @@ -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,7 @@ using System.Reflection; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-// General Information about an assembly is controlled through the following
+// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("messaging.test")]
@@ -31,12 +31,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("messaging.test")]
-[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
@@ -46,11 +46,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values:
//
// Major Version
-// Minor Version
+// Minor Version
// Build Number
// Revision
//
-// You can specify all the values or you can default the Build and Revision Numbers
+// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
diff --git a/cpp/bindings/qpid/examples/perl/client.pl b/cpp/bindings/qpid/examples/perl/client.pl index 19d9d3f14f..93eec88e07 100644 --- a/cpp/bindings/qpid/examples/perl/client.pl +++ b/cpp/bindings/qpid/examples/perl/client.pl @@ -20,13 +20,13 @@ use strict; use warnings; -use cqpid_perl; +use cqpid; my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); @@ -35,7 +35,7 @@ my $session = $connection->createSession(); my $sender = $session->createSender("service_queue"); #create temp queue & receiver... -my $responseQueue = new cqpid_perl::Address("#response-queue; {create:always, delete:always}"); +my $responseQueue = new cqpid::Address("#response-queue; {create:always, delete:always}"); my $receiver = $session->createReceiver($responseQueue); #Now send some messages... @@ -47,7 +47,7 @@ my @s = ( "And the mome raths outgrabe." ); -my $request = new cqpid_perl::Message(); +my $request = new cqpid::Message(); $request->setReplyTo($responseQueue); for (my $i=0; $i<4; $i++) { $request->setContent($s[$i]); diff --git a/cpp/bindings/qpid/examples/perl/drain.pl b/cpp/bindings/qpid/examples/perl/drain.pl index 60ac0c50ed..8010b7c95b 100644 --- a/cpp/bindings/qpid/examples/perl/drain.pl +++ b/cpp/bindings/qpid/examples/perl/drain.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid_perl; +use cqpid; use Getopt::Long; my $url = "127.0.0.1"; @@ -47,11 +47,11 @@ if ($#ARGV ge 0) { } sub getTimeout { - return ($forever) ? $cqpid_perl::Duration::FOREVER : new cqpid_perl::Duration($timeout*1000); + return ($forever) ? $cqpid::Duration::FOREVER : new cqpid::Duration($timeout*1000); } -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); @@ -59,13 +59,13 @@ eval { my $receiver = $session->createReceiver($address); my $timeout = getTimeout(); - my $message = new cqpid_perl::Message(); + my $message = new cqpid::Message(); my $i = 0; while($receiver->fetch($message, $timeout)) { print "Message(properties=" . $message->getProperties() . ",content='"; if ($message->getContentType() eq "amqp/map") { - my $content = cqpid_perl::decodeMap($message); + my $content = cqpid::decodeMap($message); map{ print "\n$_ => $content->{$_}"; } keys %{$content}; } else { @@ -77,7 +77,7 @@ eval { if ($replyto->getName()) { print "Replying to " . $message->getReplyTo()->str() . "...\n"; my $sender = $session->createSender($replyto); - my $response = new cqpid_perl::Message("received by the server."); + my $response = new cqpid::Message("received by the server."); $sender->send($response); } $session->acknowledge(); diff --git a/cpp/bindings/qpid/examples/perl/hello_world.pl b/cpp/bindings/qpid/examples/perl/hello_world.pl index a96b98a002..cf2f05f8b7 100644 --- a/cpp/bindings/qpid/examples/perl/hello_world.pl +++ b/cpp/bindings/qpid/examples/perl/hello_world.pl @@ -21,13 +21,13 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use cqpid; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[0] : "amq.topic"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($broker, $connectionOptions); +my $connection = new cqpid::Connection($broker, $connectionOptions); eval { $connection->open(); @@ -36,12 +36,12 @@ eval { my $receiver = $session->createReceiver($address); my $sender = $session->createSender($address); - $sender->send(new cqpid_perl::Message("Hello world!")); + $sender->send(new cqpid::Message("Hello world!")); - #my $duration = new cqpid_perl::Duration(1000); + #my $duration = new cqpid::Duration(1000); #print ">>>" . $duration->getMilliseconds() . "\n"; - my $message = $receiver->fetch($cqpid_perl::Duration::SECOND); + my $message = $receiver->fetch($cqpid::Duration::SECOND); #$message->setDurable(1); #print "Durable: " . $message->getDurable() . "\n"; diff --git a/cpp/bindings/qpid/examples/perl/hello_xml.pl b/cpp/bindings/qpid/examples/perl/hello_xml.pl index cebf2ceee6..c48a5225c2 100644 --- a/cpp/bindings/qpid/examples/perl/hello_xml.pl +++ b/cpp/bindings/qpid/examples/perl/hello_xml.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid_perl; +use cqpid; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; @@ -44,7 +44,7 @@ x-bindings: [{ exchange: xml-exchange, key: weather, arguments: { xquery:" $quer END -my $connection = new cqpid_perl::Connection($broker, $connectionOptions); +my $connection = new cqpid::Connection($broker, $connectionOptions); eval { $connection->open(); @@ -52,7 +52,7 @@ eval { my $receiver = $session->createReceiver($address); - my $message = new cqpid_perl::Message(); + my $message = new cqpid::Message(); my $content = <<END; <weather> diff --git a/cpp/bindings/qpid/examples/perl/map_receiver.pl b/cpp/bindings/qpid/examples/perl/map_receiver.pl index 2e2611e38f..e3e8a201dd 100644 --- a/cpp/bindings/qpid/examples/perl/map_receiver.pl +++ b/cpp/bindings/qpid/examples/perl/map_receiver.pl @@ -21,21 +21,21 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use cqpid; my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[0] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); my $session = $connection->createSession(); my $receiver = $session->createReceiver($address); - my $content = cqpid_perl::decodeMap($receiver->fetch()); - #my $content = cqpid_perl::decodeList($receiver->fetch()); + my $content = cqpid::decodeMap($receiver->fetch()); + #my $content = cqpid::decodeList($receiver->fetch()); print Dumper($content); diff --git a/cpp/bindings/qpid/examples/perl/map_sender.pl b/cpp/bindings/qpid/examples/perl/map_sender.pl index 4107cd48b9..095acce0ab 100644 --- a/cpp/bindings/qpid/examples/perl/map_sender.pl +++ b/cpp/bindings/qpid/examples/perl/map_sender.pl @@ -21,13 +21,13 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use cqpid; my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[1] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[2] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); @@ -35,13 +35,13 @@ eval { my $session = $connection->createSession(); my $sender = $session->createSender($address); - my $message = new cqpid_perl::Message(); + my $message = new cqpid::Message(); my $content = { id => 987654321, name => "Widget", percent => sprintf("%.2f", 0.99), colours => [ qw (red green white) ], }; - cqpid_perl::encode($content, $message); + cqpid::encode($content, $message); $sender->send($message, 1); $connection->close(); diff --git a/cpp/bindings/qpid/examples/perl/server.pl b/cpp/bindings/qpid/examples/perl/server.pl index b14da565b9..0c64f15c66 100644 --- a/cpp/bindings/qpid/examples/perl/server.pl +++ b/cpp/bindings/qpid/examples/perl/server.pl @@ -20,13 +20,13 @@ use strict; use warnings; -use cqpid_perl; +use cqpid; my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); @@ -41,7 +41,7 @@ eval { my $sender = $session->createSender($address); my $s = $request->getContent(); $s = uc($s); - my $response = new cqpid_perl::Message($s); + my $response = new cqpid::Message($s); $sender->send($response); print "Processed request: " . $request->getContent() . " -> " . $response->getContent() . "\n"; $session->acknowledge(); diff --git a/cpp/bindings/qpid/examples/perl/spout.pl b/cpp/bindings/qpid/examples/perl/spout.pl index 7365e732bf..50773a4fe2 100644 --- a/cpp/bindings/qpid/examples/perl/spout.pl +++ b/cpp/bindings/qpid/examples/perl/spout.pl @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid_perl; +use cqpid; use Getopt::Long; use Time::Local; @@ -77,19 +77,19 @@ sub setProperties { } } -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +my $connection = new cqpid::Connection($url, $connectionOptions); eval { $connection->open(); my $session = $connection->createSession(); my $sender = $session->createSender($address); - my $message = new cqpid_perl::Message(); + my $message = new cqpid::Message(); setProperties($message) if (@properties); if (@entries) { my $content = {}; setEntries($content); - cqpid_perl::encode($content, $message); + cqpid::encode($content, $message); } elsif ($content) { $message->setContent($content); @@ -98,7 +98,7 @@ eval { my $receiver; if ($replyto) { - my $responseQueue = new cqpid_perl::Address($replyto); + my $responseQueue = new cqpid::Address($replyto); $receiver = $session->createReceiver($responseQueue); $message->setReplyTo($responseQueue); } diff --git a/cpp/bindings/qpid/perl/CMakeLists.txt b/cpp/bindings/qpid/perl/CMakeLists.txt deleted file mode 100644 index 6edaf284b1..0000000000 --- a/cpp/bindings/qpid/perl/CMakeLists.txt +++ /dev/null @@ -1,38 +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. -# - -##------------------------------------------------------ -## Use Swig to generate a literal binding to the C++ API -##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") - -swig_add_module(cqpid_perl perl ${CMAKE_CURRENT_SOURCE_DIR}/perl.i) -swig_link_libraries(cqpid_perl qpidmessaging qpidtypes qmf2 ${PERL_LIBRARY}) - -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PERL_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") - -##---------------------------------- -## Install the complete Perl binding -##---------------------------------- -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid_perl.so - ${CMAKE_CURRENT_BINARY_DIR}/cqpid_perl.pm - DESTINATION ${PERL_VENDORARCH} - COMPONENT ${QPID_COMPONENT_CLIENT} - ) diff --git a/cpp/bindings/qpid/perl/Makefile.am b/cpp/bindings/qpid/perl/Makefile.am index da082896e8..982d493ba0 100644 --- a/cpp/bindings/qpid/perl/Makefile.am +++ b/cpp/bindings/qpid/perl/Makefile.am @@ -21,22 +21,22 @@ if HAVE_PERL_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC) -EXTRA_DIST = CMakeLists.txt perl.i -BUILT_SOURCES = cqpid_perl.cpp +EXTRA_DIST = perl.i +BUILT_SOURCES = cqpid.cpp SWIG_FLAGS = -w362,401 -cqpid_perl.cpp: $(srcdir)/perl.i $(srcdir)/../qpid.i $(srcdir)/../../swig_perl_typemaps.i - $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid_perl.cpp $(srcdir)/perl.i +cqpid.cpp: $(srcdir)/perl.i $(srcdir)/../qpid.i $(srcdir)/../../swig_perl_typemaps.i + $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid.cpp $(srcdir)/perl.i -lib_LTLIBRARIES = libcqpid_perl.la -cqpid_perl_PERL = cqpid_perl.pm +lib_LTLIBRARIES = cqpid.la +cqpid_PERL = cqpid.pm -libcqpid_perl_la_LDFLAGS = -avoid-version -shared -libcqpid_perl_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ +cqpid_la_LDFLAGS = -avoid-version -module -shared +cqpid_la_LIBADD = -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -libcqpid_perl_la_CXXFLAGS = $(INCLUDES) -fno-strict-aliasing -nodist_libcqpid_perl_la_SOURCES = cqpid_perl.cpp +cqpid_la_CXXFLAGS = $(INCLUDES) +nodist_cqpid_la_SOURCES = cqpid.cpp -CLEANFILES = cqpid_perl.cpp cqpid_perl.pm +CLEANFILES = cqpid.cpp cqpid.pm endif # HAVE_PERL_DEVEL diff --git a/cpp/bindings/qpid/perl/perl.i b/cpp/bindings/qpid/perl/perl.i index 38ac91761f..b7ae0568b6 100644 --- a/cpp/bindings/qpid/perl/perl.i +++ b/cpp/bindings/qpid/perl/perl.i @@ -17,7 +17,7 @@ * under the License. */ -%module cqpid_perl +%module cqpid %include "std_string.i" %include "../../swig_perl_typemaps.i" diff --git a/cpp/bindings/qpid/python/CMakeLists.txt b/cpp/bindings/qpid/python/CMakeLists.txt deleted file mode 100644 index 5e4649cd7c..0000000000 --- a/cpp/bindings/qpid/python/CMakeLists.txt +++ /dev/null @@ -1,45 +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. -# - -##------------------------------------------------------ -## Use Swig to generate a literal binding to the C++ API -##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") - -swig_add_module(cqpid python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) -swig_link_libraries(cqpid qpidmessaging qpidtypes qmf2 ${PYTHON_LIBRARIES}) - -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PYTHON_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") - -##------------------------------------ -## Install the complete Python binding -##------------------------------------ -execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cqpid.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqpid.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cqpid.py - ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyc - ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyo - ${CMAKE_CURRENT_BINARY_DIR}/_cqpid.so - DESTINATION ${PYTHON_SITE_PACKAGES} - COMPONENT ${QPID_COMPONENT_CLIENT} - ) diff --git a/cpp/bindings/qpid/python/Makefile.am b/cpp/bindings/qpid/python/Makefile.am index dd25f34829..7fa4106be0 100644 --- a/cpp/bindings/qpid/python/Makefile.am +++ b/cpp/bindings/qpid/python/Makefile.am @@ -25,17 +25,17 @@ generated_file_list = \ cqpid.cpp \ cqpid.py -EXTRA_DIST = CMakeLists.txt python.i +EXTRA_DIST = python.i BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 $(generated_file_list): $(srcdir)/python.i $(srcdir)/../qpid.i $(srcdir)/../../swig_python_typemaps.i - $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i + swig -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i pylibdir = $(PYTHON_LIB) lib_LTLIBRARIES = _cqpid.la -cqpiddir = $(pyexecdir) +cqpiddir = $(pythondir) cqpid_PYTHON = cqpid.py _cqpid_la_LDFLAGS = -avoid-version -module -shared diff --git a/cpp/bindings/qpid/python/python.i b/cpp/bindings/qpid/python/python.i index 9d45bf54ee..bf61cb10b7 100644 --- a/cpp/bindings/qpid/python/python.i +++ b/cpp/bindings/qpid/python/python.i @@ -21,357 +21,21 @@ %include "std_string.i" %include "../../swig_python_typemaps.i" -/* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't - * convert uint8_t by default. */ -%apply unsigned char { uint8_t }; - - -/* - * Exceptions - * - * The convention below is that exceptions in _cqpid.so have the same - * names as in the C++ library. They get renamed to their Python - * equivalents when brought into the Python wrapping - */ -%{ -static PyObject* pNoMessageAvailable; -static PyObject* pTargetCapacityExceeded; -static PyObject* pNotFound; -static PyObject* pTransportFailure; -%} - -%init %{ - pNoMessageAvailable = PyErr_NewException( - "_cqpid.NoMessageAvailable", NULL, NULL); - Py_INCREF(pNoMessageAvailable); - PyModule_AddObject(m, "NoMessageAvailable", pNoMessageAvailable); - - pTargetCapacityExceeded = PyErr_NewException( - "_cqpid.TargetCapacityExceeded", NULL, NULL); - Py_INCREF(pTargetCapacityExceeded); - PyModule_AddObject(m, "TargetCapacityExceeded", pTargetCapacityExceeded); - - pNotFound = PyErr_NewException( - "_cqpid.NotFound", NULL, NULL); - Py_INCREF(pNotFound); - PyModule_AddObject(m, "NotFound", pNotFound); - - pTransportFailure = PyErr_NewException( - "_cqpid.TransportFailure", NULL, NULL); - Py_INCREF(pTransportFailure); - PyModule_AddObject(m, "TransportFailure", pTransportFailure); -%} - -%pythoncode %{ - Empty = _cqpid.NoMessageAvailable - TargetCapacityExceeded = _cqpid.TargetCapacityExceeded - NotFound = _cqpid.NotFound - ConnectError = _cqpid.TransportFailure -%} - /* Define the general-purpose exception handling */ %exception { - PyObject * pExceptionType = NULL; std::string error; Py_BEGIN_ALLOW_THREADS; try { $action - } catch (qpid::messaging::NoMessageAvailable & ex) { - pExceptionType = pNoMessageAvailable; - error = ex.what(); - } catch (qpid::messaging::TargetCapacityExceeded & ex) { - pExceptionType = pTargetCapacityExceeded; - error = ex.what(); - } catch (qpid::messaging::NotFound & ex) { - pExceptionType = pNotFound; - error = ex.what(); - } catch (qpid::messaging::TransportFailure & ex) { - pExceptionType = pTransportFailure; - error = ex.what(); } catch (qpid::types::Exception& ex) { - pExceptionType = PyExc_RuntimeError; error = ex.what(); } Py_END_ALLOW_THREADS; if (!error.empty()) { - PyErr_SetString(pExceptionType, error.c_str()); + PyErr_SetString(PyExc_RuntimeError, error.c_str()); return NULL; } } - -/* This only renames the non-const version (I believe). Then again, I - * don't even know why there is a non-const version of the method. */ -%rename(opened) qpid::messaging::Connection::isOpen(); -%rename(receiver) qpid::messaging::Session::createReceiver; -%rename(sender) qpid::messaging::Session::createSender; -%rename(_acknowledge_all) qpid::messaging::Session::acknowledge(bool); -%rename(_acknowledge_msg) qpid::messaging::Session::acknowledge( - Message &, bool); - -%rename(_fetch) qpid::messaging::Receiver::fetch; -%rename(unsettled) qpid::messaging::Receiver::getUnsettled; -%rename(available) qpid::messaging::Receiver::getAvailable; - -%rename(unsettled) qpid::messaging::Sender::getUnsettled; -%rename(available) qpid::messaging::Sender::getAvailable; -%rename(_send) qpid::messaging::Sender::send; - -%rename(_getReplyTo) qpid::messaging::Message::getReplyTo; -%rename(_setReplyTo) qpid::messaging::Message::setReplyTo; -%rename(_getTtl) qpid::messaging::Message::getTtl; -%rename(_setTtl) qpid::messaging::Message::setTtl; - - %include "../qpid.i" -%extend qpid::messaging::Connection { - %pythoncode %{ - # Handle the different options by converting underscores to hyphens. - # Also, the sasl_mechanisms option in Python has no direct - # equivalent in C++, so we will translate them to sasl_mechanism - # when possible. - def __init__(self, url=None, **options): - args = [url] if url else [] - if options : - if "sasl_mechanisms" in options : - if ' ' in options.get("sasl_mechanisms",'') : - raise Exception( - "C++ Connection objects are unable to handle " - "multiple sasl-mechanisms") - options["sasl_mechanism"] = options.pop("sasl_mechanisms") - args.append(options) - this = _cqpid.new_Connection(*args) - try: self.this.append(this) - except: self.this = this - %} - - /* Return a pre-existing session with the given name, if one - * exists, otherwise return a new one. (Note that if a - * pre-existing session exists, the transactional argument is - * ignored, and the returned session might not satisfy the desired - * setting. */ - qpid::messaging::Session _session(const std::string & name, - bool transactional) { - if (!name.empty()) { - try { - return self->getSession(name); - } - catch (const qpid::messaging::KeyError &) { - } - } - if (transactional) { - return self->createTransactionalSession(name); - } - else { - return self->createSession(name); - } - } - - %pythoncode %{ - def session(self, name=None, transactional=False) : - if name is None : - name = '' - return self._session(name, transactional) - %} - - %pythoncode %{ - @staticmethod - def establish(url=None, **options) : - conn = Connection(url, **options) - conn.open() - return conn - %} -} - -%extend qpid::messaging::Session { - %pythoncode %{ - def acknowledge(self, message=None, disposition=None, sync=True) : - if disposition : - raise Exception("SWIG does not support dispositions yet. Use " - "Session.reject and Session.release instead") - if message : - self._acknowledge_msg(message, sync) - else : - self._acknowledge_all(sync) - - __swig_getmethods__["connection"] = getConnection - if _newclass: connection = _swig_property(getConnection) - %} -} - - -%extend qpid::messaging::Receiver { - %pythoncode %{ - __swig_getmethods__["capacity"] = getCapacity - __swig_setmethods__["capacity"] = setCapacity - if _newclass: capacity = _swig_property(getCapacity, setCapacity) - - __swig_getmethods__["session"] = getSession - if _newclass: session = _swig_property(getSession) - %} - - %pythoncode %{ - def fetch(self, timeout=None) : - if timeout is None : - return self._fetch() - else : - # Python API uses timeouts in seconds, - # but C++ API uses milliseconds - return self._fetch(Duration(int(1000*timeout))) - %} -} - -%extend qpid::messaging::Sender { - %pythoncode %{ - def send(self, object, sync=True) : - if isinstance(object, Message): - message = object - else: - message = Message(object) - return self._send(message, sync) - - __swig_getmethods__["capacity"] = getCapacity - __swig_setmethods__["capacity"] = setCapacity - if _newclass: capacity = _swig_property(getCapacity, setCapacity) - - __swig_getmethods__["session"] = getSession - if _newclass: session = _swig_property(getSession) - %} -} - - -%extend qpid::messaging::Message { - %pythoncode %{ - # UNSPECIFIED was module level before, but I do not - # know how to insert python code at the top of the module. - # (A bare "%pythoncode" inserts at the end. - UNSPECIFIED=object() - def __init__(self, content=None, content_type=UNSPECIFIED, id=None, - subject=None, user_id=None, reply_to=None, - correlation_id=None, durable=None, priority=None, - ttl=None, properties=None): - this = _cqpid.new_Message('') - try: self.this.append(this) - except: self.this = this - if content : - self.content = content - if content_type != UNSPECIFIED : - self.content_type = content_type - if id is not None : - self.id = id - if subject is not None : - self.subject = subject - if user_id is not None : - self.user_id = user_id - if reply_to is not None : - self.reply_to = reply_to - if correlation_id is not None : - self.correlation_id = correlation_id - if durable is not None : - self.durable = durable - if priority is not None : - self.priority = priority - if ttl is not None : - self.ttl = ttl - if properties is not None : - # Can't set properties via (inst).getProperties, because - # the typemaps make a copy of the underlying properties. - # Instead, set via setProperty for the time-being - for k, v in properties.iteritems() : - self.setProperty(k, v) - - def _get_content(self) : - if self.content_type == "amqp/list" : - return decodeList(self) - if self.content_type == "amqp/map" : - return decodeMap(self) - return self.getContent() - def _set_content(self, content) : - if isinstance(content, basestring) : - self.setContent(content) - elif isinstance(content, list) or isinstance(content, dict) : - encode(content, self) - else : - # Not a type we can handle. Try setting it anyway, - # although this will probably lead to a swig error - self.setContent(content) - __swig_getmethods__["content"] = _get_content - __swig_setmethods__["content"] = _set_content - if _newclass: content = _swig_property(_get_content, _set_content) - - __swig_getmethods__["content_type"] = getContentType - __swig_setmethods__["content_type"] = setContentType - if _newclass: content_type = _swig_property(getContentType, - setContentType) - - __swig_getmethods__["id"] = getMessageId - __swig_setmethods__["id"] = setMessageId - if _newclass: id = _swig_property(getMessageId, setMessageId) - - __swig_getmethods__["subject"] = getSubject - __swig_setmethods__["subject"] = setSubject - if _newclass: subject = _swig_property(getSubject, setSubject) - - __swig_getmethods__["priority"] = getPriority - __swig_setmethods__["priority"] = setPriority - if _newclass: priority = _swig_property(getPriority, setPriority) - - def getTtl(self) : - return self._getTtl().getMilliseconds()/1000.0 - def setTtl(self, duration) : - self._setTtl(Duration(int(1000*duration))) - __swig_getmethods__["ttl"] = getTtl - __swig_setmethods__["ttl"] = setTtl - if _newclass: ttl = _swig_property(getTtl, setTtl) - - __swig_getmethods__["user_id"] = getUserId - __swig_setmethods__["user_id"] = setUserId - if _newclass: user_id = _swig_property(getUserId, setUserId) - - __swig_getmethods__["correlation_id"] = getCorrelationId - __swig_setmethods__["correlation_id"] = setCorrelationId - if _newclass: correlation_id = _swig_property(getCorrelationId, - setCorrelationId) - - __swig_getmethods__["redelivered"] = getRedelivered - __swig_setmethods__["redelivered"] = setRedelivered - if _newclass: redelivered = _swig_property(getRedelivered, - setRedelivered) - - __swig_getmethods__["durable"] = getDurable - __swig_setmethods__["durable"] = setDurable - if _newclass: durable = _swig_property(getDurable, setDurable) - - __swig_getmethods__["properties"] = getProperties - if _newclass: properties = _swig_property(getProperties) - - def getReplyTo(self) : - return self._getReplyTo().str() - def setReplyTo(self, address_str) : - self._setReplyTo(Address(address_str)) - __swig_getmethods__["reply_to"] = getReplyTo - __swig_setmethods__["reply_to"] = setReplyTo - if _newclass: reply_to = _swig_property(getReplyTo, setReplyTo) - - def __repr__(self): - args = [] - for name in ["id", "subject", "user_id", "reply_to", - "correlation_id", "priority", "ttl", - "durable", "redelivered", "properties", - "content_type"] : - value = getattr(self, name) - if value : args.append("%s=%r" % (name, value)) - if self.content is not None: - if args: - args.append("content=%r" % self.content) - else: - args.append(repr(self.content)) - return "Message(%s)" % ", ".join(args) - %} -} - -%pythoncode %{ -# Bring into module scope -UNSPECIFIED = Message.UNSPECIFIED -%} diff --git a/cpp/bindings/qpid/qpid.i b/cpp/bindings/qpid/qpid.i index 352bafa3c8..e60ce1ce7c 100644 --- a/cpp/bindings/qpid/qpid.i +++ b/cpp/bindings/qpid/qpid.i @@ -27,7 +27,6 @@ #include <qpid/messaging/Sender.h> #include <qpid/messaging/Message.h> #include <qpid/messaging/Duration.h> -#include <qpid/messaging/FailoverUpdates.h> // // Wrapper functions for map-decode and list-decode. This allows us to avoid @@ -49,7 +48,6 @@ qpid::types::Variant::List& decodeList(const qpid::messaging::Message& msg) { %} -%include <qpid/ImportExport.h> %include <qpid/messaging/ImportExport.h> %include <qpid/messaging/Address.h> %include <qpid/messaging/Duration.h> @@ -58,7 +56,6 @@ qpid::types::Variant::List& decodeList(const qpid::messaging::Message& msg) { %include <qpid/messaging/Sender.h> %include <qpid/messaging/Session.h> %include <qpid/messaging/Connection.h> -%include <qpid/messaging/FailoverUpdates.h> qpid::types::Variant::Map& decodeMap(const qpid::messaging::Message&); qpid::types::Variant::List& decodeList(const qpid::messaging::Message&); diff --git a/cpp/bindings/qpid/ruby/.gitignore b/cpp/bindings/qpid/ruby/.gitignore deleted file mode 100644 index ab78513491..0000000000 --- a/cpp/bindings/qpid/ruby/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -pkg -html diff --git a/cpp/bindings/qpid/ruby/CMakeLists.txt b/cpp/bindings/qpid/ruby/CMakeLists.txt deleted file mode 100644 index 25258cfc6a..0000000000 --- a/cpp/bindings/qpid/ruby/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -##-------------------------------------------------- -## Properties used for generating the Ruby bindings. -##-------------------------------------------------- -set(GEM_BINDINGS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ext/cqpid) -set(GEM_BINDINGS_SOURCE_FILE ${GEM_BINDINGS_SOURCE_DIR}/cqpid.cpp) -set(GEM_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) -set(GEM_OUTPUT_FILE ${GEM_OUTPUT_PATH}/pkg/qpid-${qpidc_version}.0.gem) - - -##------------------------------------------------------ -## Use Swig to generate a literal binding to the C++ API -##------------------------------------------------------ -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") - -swig_add_module(cqpid ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) -swig_link_libraries(cqpid qpidmessaging qpidtypes qmf2 ${RUBY_LIBRARY}) - -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${RUBY_INCLUDE_DIR} -I${qpid-cpp_SOURCE_DIR}/include") - -##---------------------------------- -## Install the complete Ruby binding -##---------------------------------- -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid.so - RENAME cqpid.so - DESTINATION ${RUBY_SITEARCH_DIR} - COMPONENT ${QPID_COMPONENT_CLIENT} - ) - -add_custom_command(OUTPUT ${GEM_BINDINGS_SOURCE_FILE} - COMMAND cp ${swig_generated_file_fullname} ${GEM_BINDINGS_SOURCE_FILE} - DEPENDS ${swig_generated_file_fullname} - ) - -add_custom_command(OUTPUT ${GEM_OUTPUT_FILE} - COMMAND OUTPUT_DIR=${GEM_OUTPUT_PATH} rake clean clobber package - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${swig_generated_file_fullname} ${GEM_BINDINGS_SOURCE_FILE} - ) - -add_custom_target(gemfile - DEPENDS ${GEM_OUTPUT_FILE} - ) - diff --git a/cpp/bindings/qpid/ruby/LICENSE b/cpp/bindings/qpid/ruby/LICENSE deleted file mode 100644 index cff2a5e25d..0000000000 --- a/cpp/bindings/qpid/ruby/LICENSE +++ /dev/null @@ -1,234 +0,0 @@ -========================================================================= -== Apache License == -========================================================================= - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -========================================================================= -== Boost License == -========================================================================= - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - diff --git a/cpp/bindings/qpid/ruby/Makefile.am b/cpp/bindings/qpid/ruby/Makefile.am index a2a5dd76bd..67a3615362 100644 --- a/cpp/bindings/qpid/ruby/Makefile.am +++ b/cpp/bindings/qpid/ruby/Makefile.am @@ -21,7 +21,7 @@ if HAVE_RUBY_DEVEL INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -EXTRA_DIST = CMakeLists.txt ruby.i +EXTRA_DIST = ruby.i BUILT_SOURCES = cqpid.cpp SWIG_FLAGS = -w362,401 @@ -33,10 +33,10 @@ cqpid.cpp: $(srcdir)/ruby.i $(srcdir)/../qpid.i $(srcdir)/../../swig_ruby_typema rubylibarchdir = $(RUBY_LIB_ARCH) rubylibarch_LTLIBRARIES = cqpid.la -cqpid_la_LDFLAGS = -avoid-version -module -shared -shrext ".$(RUBY_DLEXT)" +cqpid_la_LDFLAGS = -avoid-version -module -shrext ".$(RUBY_DLEXT)" cqpid_la_LIBADD = $(RUBY_LIBS) -L$(top_builddir)/src/.libs -lqpidmessaging -lqpidtypes \ $(top_builddir)/src/libqpidmessaging.la $(top_builddir)/src/libqpidtypes.la -cqpid_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) -fno-strict-aliasing +cqpid_la_CXXFLAGS = $(INCLUDES) -I$(RUBY_INC) -I$(RUBY_INC_ARCH) nodist_cqpid_la_SOURCES = cqpid.cpp CLEANFILES = cqpid.cpp diff --git a/cpp/bindings/qpid/ruby/README.rdoc b/cpp/bindings/qpid/ruby/README.rdoc deleted file mode 100644 index 0ae7e5cbed..0000000000 --- a/cpp/bindings/qpid/ruby/README.rdoc +++ /dev/null @@ -1,45 +0,0 @@ -= Qpid - Open Source AMQP Messaging - -Qpid is an cross-platform enterprise messaging system. - -Version :: 0.10.0.alpha.0 - -= Links - -Documents :: http://qpid.apache.org/ - -= Installation - -You can install Qpid with the following command. - - $ gem install qpid - -== Building The Native Code - -The Qpid gem requires that you have available the Qpid libraries and -development header files. To install them, please see: - -http://cwiki.apache.org/qpid/developer-pages.html - -If you are building the gem within the Qpid development environment -itself, you can specify the location of the Qpid headers and -libraries with: - -$ ruby extconfig.rb --with-qpid-lib=[path to libqpidclient.so, etc.] -$ make - -== Examples - -Take a look at the integration tests for examples on how to leverage -the messaging capabilities of Qpid in your Ruby applications. - -== License - -Licensed to the Apache Software Foundation (ASF) under one or more -contributor licensing agreements. - -Author:: Darryl L. Pierce (mailto:dpierce@redhat.com) -Copyright:: Copyright (c) 2011, Red Hat, Inc. -Homepage:: http://qpid.apache.org -License:: Apache License 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html - diff --git a/cpp/bindings/qpid/ruby/Rakefile b/cpp/bindings/qpid/ruby/Rakefile deleted file mode 100644 index 07cfff9844..0000000000 --- a/cpp/bindings/qpid/ruby/Rakefile +++ /dev/null @@ -1,130 +0,0 @@ -# Rakefile for Qpid -*- ruby -*- -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -task :noop - -# look for a root directory for out-of-tree builds - -OUTPUT_DIR=ENV["OUTPUT_DIR"] || "." - -require "rubygems" -require "rubygems/package_task" - -require "rake/clean" -require "rake/extensiontask" -require "rake/rdoctask" -require "rake/testtask" - -CLOBBER.include("pkg") - -load "./lib/qpid/version.rb" - -#------------- -# Gem Details. -#------------- - -NAME = "qpid" -# VERSION = Qpid::VERSION -AUTHOR = "Darryl L. Pierce" -EMAIL = "dpierce@redhat.com" -HOMEPAGE = "http://qpid.apache.org" -SUMMARY = "Qpid is an enterprise messaging framework." - -desc "Default: run all tests." -task :default => :"test:all" - -#--------------- -# Testing tasks. -#--------------- - -desc "Run all tests (alias for test:all)." -task :test => :"test:all" - -namespace :test do - desc "Run all tests (default)." - task :all => [:units, :integrations] - - desc "Run unit tests." - Rake::TestTask.new(:units) do |t| - t.libs << "." - t.pattern = "test/test*.rb" - t.verbose = true - end - - desc "Run integration tests." - Rake::TestTask.new(:integrations) do |t| - t.libs << "." - t.pattern = "test/integration/*.rb" - t.verbose = true - end - -end - -#--------------------- -# Documentation tasks. -#--------------------- - -Rake::RDocTask.new(:rdoc => "rdoc", - :clobber_rdoc => "rdoc:clean", - :rerdoc => "rdoc:force") do |rd| - rd.main = "README.rdoc" - rd.options << "--all" - rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") -end - -#----------------- -# Package the gem. -#----------------- - -spec = Gem::Specification.new do |s| - s.name = NAME - s.version = Qpid::VERSION - s.platform = Gem::Platform::RUBY - s.extra_rdoc_files = ["README.rdoc"] - s.summary = SUMMARY - s.description = s.summary - s.author = AUTHOR - s.email = EMAIL - s.homepage = HOMEPAGE - - s.extensions = FileList["ext/**/extconf.rb"] - - s.require_path = "lib" - # DEPRECATED s.autorequire = NAME - s.files = FileList["LICENSE", - "README.rdoc", - "Rakefile", - "TODO", - "lib/**/*.rb", - "test/**/*.rb", - "examples/**/*.rb", - "ext/**/*"] -end - -Gem::PackageTask.new(spec) do |pkg| - pkg.package_dir = "#{OUTPUT_DIR}/pkg" -end - -#------------------ -# Build native code -#------------------ - -Rake::ExtensionTask.new("cqpid", spec) - diff --git a/cpp/bindings/qpid/ruby/TODO b/cpp/bindings/qpid/ruby/TODO deleted file mode 100644 index 454aac9200..0000000000 --- a/cpp/bindings/qpid/ruby/TODO +++ /dev/null @@ -1,7 +0,0 @@ -TODO Items ------------------------------------------------------------------------------ - -Version 0.11.0: - * Deliver the Ruby bindings as a gem. - * Rework the blocking tasks to not bring the main thread to a halt. - diff --git a/cpp/bindings/qpid/ruby/examples/client.rb b/cpp/bindings/qpid/ruby/examples/client.rb deleted file mode 100644 index f42f25cfc9..0000000000 --- a/cpp/bindings/qpid/ruby/examples/client.rb +++ /dev/null @@ -1,50 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -if __FILE__ == $0 - broker = ARGV[1] || "amqp:tcp:localhost:5672" - options = ARGV[2] || "" - - connection = Qpid::Messaging::Connection.new broker, options - connection.open - session = connection.create_session - sender = session.create_sender "service_queue" - response_queue = Qpid::Messaging::Address.new("#response-queue", "", - :create => :always, - :delete => :always) - receiver = session.create_receiver response_queue - - ["Twas brillig, and the slithy toves", - "Did gire and gymble in the wabe.", - "All mimsy were the borogroves,", - "And the mome raths outgrabe."].each do |line| - request = Qpid::Messaging::Message.new :content => line - request.reply_to = response_queue - sender.send request - response = receiver.fetch - puts "#{request.content} -> #{response.content}" - end - - connection.close -end - diff --git a/cpp/bindings/qpid/ruby/examples/drain.rb b/cpp/bindings/qpid/ruby/examples/drain.rb deleted file mode 100644 index a6cf35e189..0000000000 --- a/cpp/bindings/qpid/ruby/examples/drain.rb +++ /dev/null @@ -1,111 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' -require 'optparse' - -options = { - :broker => "localhost", - :timeout => Qpid::Messaging::Duration::IMMEDIATE, - :count => 1, - :forever => false, - :connection_options => "" -} - -opts = OptionParser.new do |opts| - opts.banner = "Usage: drain.rb [OPTIONS] ADDRESS" - - opts.separator "" - opts.separator "Drains messages from the specified address" - opts.separator "" - - opts.on("-h", "--help", - "show this message") do - puts opts - exit - end - - opts.on("-b", "--broker VALUE", - "url of broker to connect to") do |broker| - options[:broker] = broker - end - - opts.on("-t", "--timeout VALUE", Integer, - "timeout in seconds to wait before exiting") do |timeout| - options[:timeout] = Qpid::Messaging::Duration.new timeout * 1000 - end - - opts.on("-f", "--forever", - "ignore timeout and wait forever") do - options[:forever] = true - end - - opts.on("--connection-options VALUE", - "connection options string in the form {name1:value,name2:value2}") do |conopts| - options[:connection_options] = conopts - end - - opts.on("-c", "--count VALUE", Integer, - "number of messages to read before exiting") do |count| - options[:count] = count - end -end - -opts.parse!(ARGV) - -options[:address] = ARGV[0] || "" - -connection = Qpid::Messaging::Connection.new options[:broker], options[:connection_options] -connection.open - -def render_map map - print "{" - map.keys.sort.each_with_index {|key,index| print "#{index > 0 ? ', ' : ''}#{key}:#{map[key]}"} - print "}" -end - -begin - session = connection.create_session - receiver = session.create_receiver options[:address] - done = false - count = 0 - options[:timeout] = Qpid::Messaging::Duration::FOREVER if options[:forever] - - while !done && (count < options[:count]) - message = receiver.fetch(options[:timeout]) - print "Message(properties=" - render_map message.properties - print ", content=" - if message.content_type == "amqp/map" - print "'#{render_map message.content}')" - else - print "'#{message.content}'" - end - print ")\n" - session.acknowledge message - count += 1 - end -rescue Exception => error - puts "Exception: #{error.to_s}" -end - -connection.close - diff --git a/cpp/bindings/qpid/ruby/examples/hello_world.rb b/cpp/bindings/qpid/ruby/examples/hello_world.rb deleted file mode 100644 index 703febeba1..0000000000 --- a/cpp/bindings/qpid/ruby/examples/hello_world.rb +++ /dev/null @@ -1,49 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -# This is your classic Hello World application, written in -# Ruby, that uses Qpid. It demonstrates how to send and -# also receive messages. -# -if __FILE__ == $0 - broker = ARGV[0] || "localhost:5672" - address = ARGV[1] || "amq.topic" - options = ARGV[2] || "" - - connection = Qpid::Messaging::Connection.new broker - connection.open - session = connection.create_session - receiver = session.create_receiver address - sender = session.create_sender address - - # Send a simple message - sender.send Qpid::Messaging::Message.new :content => "Hello world!" - - # Now receive the message - message = receiver.fetch Qpid::Messaging::Duration::SECOND - puts "#{message.content}" - session.acknowledge - - connection.close -end - diff --git a/cpp/bindings/qpid/ruby/examples/map_receiver.rb b/cpp/bindings/qpid/ruby/examples/map_receiver.rb deleted file mode 100644 index 805943a0a4..0000000000 --- a/cpp/bindings/qpid/ruby/examples/map_receiver.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" -address = ARGV[1] || "message_queue; {create: always}" -options = ARGV[2] || "" - -connection = Qpid::Messaging::Connection.new broker, options -connection.open - -def display_value value - case value - when Array - result = "" - value.each_with_index {|element, index| result += "#{', ' if index > 0}#{element}"} - return "[#{result}]" - end - - value.to_s -end - -begin - session = connection.create_session - receiver = session.create_receiver address - - message = receiver.fetch - content = message.content - - print "content-type:#{message.content_type}" - print "{" - content.keys.sort.each_with_index do |key, index| - print "#{', ' if index > 0}#{key}:#{display_value content[key]}" - end - print "}\n" - - session.acknowledge - -rescue Exception => error - puts "Exception: #{error.message}" -end - -connection.close - diff --git a/cpp/bindings/qpid/ruby/examples/map_sender.rb b/cpp/bindings/qpid/ruby/examples/map_sender.rb deleted file mode 100644 index fa0c6e4562..0000000000 --- a/cpp/bindings/qpid/ruby/examples/map_sender.rb +++ /dev/null @@ -1,52 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" -address = ARGV[1] || "message_queue; {create: always}" -options = ARGV[2] || [] - -connection = Qpid::Messaging::Connection.new broker, options -connection.open - -begin - session = connection.create_session - sender = session.create_sender address - message = Qpid::Messaging::Message.new - - content = { - :id => 987654321, - :name => "Widget", - :percent => 0.99, - :colors => ["red", "green", "blue"] - } - - message.content = content - - sender.send message - -rescue Exception => error - puts "Exception: #{error.message}" -end - -connection.close - diff --git a/cpp/bindings/qpid/ruby/examples/server.rb b/cpp/bindings/qpid/ruby/examples/server.rb deleted file mode 100644 index ead9d58472..0000000000 --- a/cpp/bindings/qpid/ruby/examples/server.rb +++ /dev/null @@ -1,51 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -if __FILE__ == $0 - broker = ARGV[0] || "amqp:tcp:localhost:5672" - options = ARGV[1] || "" - - connection = Qpid::Messaging::Connection.new broker, options - connection.open - session = connection.create_session - receiver = session.create_receiver "service_queue; {create:always}" - - loop do - request = receiver.fetch - address = request.reply_to - - if !address.nil? - sender = session.create_sender address - response = Qpid::Messaging::Message.new :content => request.content.upcase - sender.send response - puts "Processed request: #{request.content} -> #{response.content}" - session.acknowledge - else - puts "Error: no reply address specified for request: #{request.content}" - session.reject request - end - end - - connection.close -end - diff --git a/cpp/bindings/qpid/ruby/examples/spout.rb b/cpp/bindings/qpid/ruby/examples/spout.rb deleted file mode 100644 index c012e31f9d..0000000000 --- a/cpp/bindings/qpid/ruby/examples/spout.rb +++ /dev/null @@ -1,126 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' -require 'optparse' - -options = { - :broker => "127.0.0.1", - :address => "", - :timeout => 0, - :count => 1, - :properties => {}, - :content => nil, - :mapped => {} -} - -opts = OptionParser.new do |opts| - opts.banner = "Usage: spout.rb [OPTIONS] ADDRESS" - - opts.on("-h", "--help", - "show this message") do |help| - puts opts - exit - end - - opts.on("-b","--broker VALUE", - "url of broker to connect to ") do |broker| - options[:broker] = broker - end - - opts.on("-t", "--timeout VALUE", Integer, - "exit after the specified time") do |timeout| - options[:timeout] = Qpid::Messaging::Duration.new timeout * 1000 - end - - opts.on("-c", "--count VALUE", Integer, - "stop after count messages have been sent, zero disables") do |count| - options[:count] = count - end - - opts.on("-i", "--id VALUE", - "use the supplied id instead of generating one") do |id| - options[:id] = id - end - - opts.on("--reply-to VALUE", - "specify reply-to address") do |replyto| - options[:replyto] = replyto - end - - opts.on("-P", "--property VALUE", - "specify message property") do |property| - name = property.split(/=/)[0] - value = property.split(/=/)[1] - options[:properties][name] = value - end - - opts.on("-M", "--map VALUE", - "specify entry for map content") do |mapped| - name = mapped.split(/=/)[0] - value = mapped.split(/=/)[1] - options[:mapped][name] = value - end - - opts.on("--content VALUE", - "specify textual content") do |content| - options[:content] = content - end - - opts.on(nil, "--connection-options VALUE", - "connection options string in the form {name1:value1, name2:value2}") do |conopts| - options[:connection_options] = conopts - end -end - -begin - opts.parse!(ARGV) -rescue => error - opts.parse(["-h"]) -end - -# now get the non-arg options -options[:address] = ARGV[0] unless ARGV[0].nil? - -connection = Qpid::Messaging::Connection.new options[:broker], options[:connection_options] -connection.open -session = connection.create_session -sender = session.create_sender options[:address] -message = Qpid::Messaging::Message.new - -options[:properties].each_key {|key| message.properties[key] = options[:properties][key]} - -(1..options[:count]).each do |count| - if !options[:mapped].keys.empty? - message.content = options[:mapped] - elsif options[:content] - message.content = options[:content] - end - message.content = options[:content] unless options[:content].nil? - message.properties["spout-id"] = "#{count}" - message.reply_to = options[:replyto] unless options[:replyto].nil? || options[:replyto].empty? - sender.send message -end - -# session.sync - -connection.close - diff --git a/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb b/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb deleted file mode 100644 index 90292d4bec..0000000000 --- a/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb +++ /dev/null @@ -1,73 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# To create the Makefile then you need to specify the location -# of the Qpid shared libraries using the commandline: -# -# $ ruby extconf.rb --with-qpid-lib=[path to libraries] -# - -require 'mkmf' - -# Setup the build environment. -$CFLAGS = "-fPIC -fno-inline -x c++" - -REQUIRED_LIBRARIES = [ - 'qpidclient', - 'qpidcommon', - 'qpidmessaging', - 'qpidtypes' - ] - -REQUIRED_HEADERS = [ - 'qpid/messaging/Address.h', - 'qpid/messaging/Connection.h', - 'qpid/messaging/Duration.h', - 'qpid/messaging/exceptions.h', - 'qpid/messaging/FailoverUpdates.h', - 'qpid/messaging/Handle.h', - 'qpid/messaging/ImportExport.h', - 'qpid/messaging/Message.h', - 'qpid/messaging/Receiver.h', - 'qpid/messaging/Sender.h', - 'qpid/messaging/Session.h' - ] - -dir_config('qpid') - -def abort_build filetype, filename - abort "Missing required #{filetype}: #{filename}" -end - -def require_library lib - abort_build "library", lib unless have_library lib -end - -def require_header header - abort_build "header", header unless have_header header -end - -have_library('stdc++') - -REQUIRED_LIBRARIES.each {|library| require_library library} - -REQUIRED_HEADERS.each {|header| require_header header} - -create_makefile('cqpid') - diff --git a/cpp/bindings/qpid/ruby/lib/qpid.rb b/cpp/bindings/qpid/ruby/lib/qpid.rb deleted file mode 100644 index 1f00c136c1..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid.rb +++ /dev/null @@ -1,29 +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. -# - -require 'qpid/errors' -require 'qpid/duration' -require 'qpid/address' -require 'qpid/encoding' -require 'qpid/message' -require 'qpid/sender' -require 'qpid/receiver' -require 'qpid/session' -require 'qpid/connection' - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/address.rb b/cpp/bindings/qpid/ruby/lib/qpid/address.rb deleted file mode 100644 index 73b61bb1c7..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/address.rb +++ /dev/null @@ -1,125 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # Address represents an address to which messages can be sent or from - # which they can be received. - # - # An Address can be described using the following pattern: - # - # <address> [ / <subject> ] ; [ { <key> : <value> , ... } ] - # - # where *address* is a simple name and *subject* is a subject or subject - # pattern. - # - # The options, enclosed in curly braces, are key:value pairs delimited by - # a comma. The values can be nested maps also enclosed in curly braces. - # Or they can be lists of values, where they are contained within square - # brackets but still comma delimited, such as: - # - # [value1,value2,value3] - # - # The following are the list of supported options: - # - # create:: Indicates if the address should be created; values are *always*, - # *never*, *sender* or *reciever*. - # - # assert:: Indicates whether or not to assert any specified node properties; - # values are *always*, *never*, *sender* or *receiver*. - # - # delete:: Indicates whether or not to delete the addressed node when a - # sender or receiver is cancelled; values are *always*, *never*, - # *sender* or *receiver*. - # - # node:: A nested map describing properties for the addressed node. - # Properties are *type* (*topic* or *queue*), *durable* (a boolean), - # *x-declare* (a nested map of amqp 0.10-specific options) and - # *x-bindings*. (nested list which specifies a queue, exchange or - # a binding key and arguments. - # - # link:: A nested map through which properties of the link can be specified; - # properties are *durable*, *reliability*, *x-declare*, *x-subscribe* - # and *x-bindings*. - # - # mode:: (*For receivers only*) indicates whether the receiver should consume - # or browse messages; values are *consume* (the default) and *browse*. - class Address - - def initialize(name, subject, options = {}, _type = "", address_impl = nil) - @address_impl = address_impl || Cqpid::Address.new(name, subject, convert_options(options), _type) - end - - def address_impl # :nodoc: - @address_impl - end - - # Returns the name. - def name; @address_impl.getName; end - - # Sets the name. - def name=(name); @address_impl.setName name; end - - # Returns the subject. - def subject; @address_impl.getSubject; end - - # Sets the subject. - def subject=(subject); @address_impl.setSubject(subject); end - - # Returns the type. - #--- - # We cannot use "type" since that clashes with the Ruby object.type - # identifier. - def _type; @address_impl.getType; end - - # Sets the type. - # - # The type of the address determines how Sender and Receiver objects - # are constructed for it. If no type is specified then it will be - # determined by querying the broker. - def _type=(_type); @address_impl.setType(_type); end - - # Returns the options. - def options; @address_impl.getOptions; end - - # Sets the options for the address. - # Any symbols are converted to strings. - def options=(options); @address_impl.setOptions(convert_options(options)); end - - def to_s; @address_impl.str; end - - private - - def convert_options(options) - result = {} - options.each_pair {|key, value| result[key.to_s] = value.to_s} - - return result - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/connection.rb b/cpp/bindings/qpid/ruby/lib/qpid/connection.rb deleted file mode 100644 index 5c56c1f5d0..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/connection.rb +++ /dev/null @@ -1,134 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # Connection allows for establishing connections to a remote endpoint. - class Connection - - # The following general options are supported (as strings or symbols): - # - # username:: - # password:: - # heartbeat:: - # tcp_nodelay:: - # sasl_mechanism:: - # sasl_service:: - # sasl_min_ssf:: - # sasl_max_ssf:: - # transport:: - # - # The following options specifically control reconnection behavior: - # - # reconnect:: *true* or *false*; indicates whether to attempt reconnections - # reconnect_timeout:: the number of seconds to attempt reconnecting - # reconnect_limit:: the number of retries before reporting failure - # reconnect_interval_min:: initial delay, in seconds, before attempting a reconnecting - # reconnect_interval_max:: number of seconds to wait before additional reconnect attempts - # reconnect_interval:: shorthand for setting box min and max values - # reconnect_urls:: a list of alternate URLs to use for reconnection attempts - def initialize(url, options = {}, connection_impl = nil) - @url = url - @connection_impl = connection_impl - @options = options - end - - def connection_impl # :nodoc: - @connection_impl - end - - # Opens the connection. - def open - @connection_impl = Cqpid::Connection.new(@url, convert_options) - @connection_impl.open - end - - # Reports whether the connection is open. - def open?; false || (@connection_impl.isOpen if @connection_impl); end - - # Closes the connection. - def close; @connection_impl.close if open?; end - - # Creates a new session. - # - # If :transactional => true then a transactional session is created. - # Otherwise a standard session is created. - def create_session(args = {}) - name = args[:name] || "" - if open? - if args[:transactional] - session = @connection_impl.createTransactionalSession name - else - session = @connection_impl.createSession name - end - return Session.new(session) - else - raise RuntimeError.new "No connection available." - end - end - - # Returns a session for the specified session name. - def session name - session_impl = @connection_impl.getSession name - Qpid::Messaging::Session.new session_impl if session_impl - end - - # Returns the username used to authenticate with the connection. - def authenticated_username; @connection_impl.getAuthenticatedUsername if open?; end - - # inherited from Handle - - # Returns whether the underlying handle is valid; i.e., not null. - def valid? - @connection_impl.isValid - end - - # Returns whether the underlying handle is null. - def null? - @connection_impl.isNull - end - - # Swaps the underlying connection handle. - def swap connection - @connection_impl.swap connection.connection_impl - end - - private - - def convert_options - result = {} - # map only those options defined in the C++ layer - # TODO when new options are added, this needs to be updated. - unless @options.nil? || @options.empty? - @options.each_pair {|key, value| result[key.to_s] = value.to_s} - end - - return result - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/duration.rb b/cpp/bindings/qpid/ruby/lib/qpid/duration.rb deleted file mode 100644 index c1f44e9281..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/duration.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # A Duration represents a period of time in milliseconds - # - # It defines the following named values as symbols: - # - # :FOREVER :: the maximum integer value for the platform - # :IMMEDIATE :: an alias for 0 - # :SECOND :: 1,000ms - # :MINUTE :: 60,000ms - class Duration - - def initialize duration # :nodoc: - @duration_impl = Cqpid::Duration.new duration - end - - def duration_impl # :nodoc: - @duration_impl - end - - def self.add_item(key, value) # :nodoc: - @hash ||= {} - @hash[key] = Duration.new value - end - - def self.const_missing(key) # :nodoc: - @hash[key] - end - - self.add_item :FOREVER, Cqpid::Duration.FOREVER.getMilliseconds - self.add_item :IMMEDIATE, Cqpid::Duration.IMMEDIATE.getMilliseconds - self.add_item :SECOND, Cqpid::Duration.SECOND.getMilliseconds - self.add_item :MINUTE, Cqpid::Duration.MINUTE.getMilliseconds - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb b/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb deleted file mode 100644 index c8b843b597..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb +++ /dev/null @@ -1,56 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # Encodes the supplied content into the given message. - def self.encode content, message, encoding = nil - prepared = content - case content - when Hash - prepared = {} - content.each_pair do |key,value| - prepared[key.to_s] = value.to_s - end - Cqpid::encode prepared, message.message_impl - when Array - prepared = [] - content.each {|value| prepared << value.to_s} - Cqpid::encode prepared, message.message_impl - end - end - - # Decodes and returns the message's content. - def self.decode(message, content_type = nil) - content_type = message.content_type unless content_type - - case content_type - when "amqp/map": Cqpid.decodeMap message.message_impl - when "amqp/list": Cqpid.decodeList message.message_impl - end - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/errors.rb b/cpp/bindings/qpid/ruby/lib/qpid/errors.rb deleted file mode 100644 index 7a16d08d84..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/errors.rb +++ /dev/null @@ -1,30 +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. -# - -module Qpid - - module Messaging - - class KeyError < RuntimeError - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/message.rb b/cpp/bindings/qpid/ruby/lib/qpid/message.rb deleted file mode 100644 index 9b1b68c7c3..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/message.rb +++ /dev/null @@ -1,157 +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. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # Message represents a message. - class Message - - def initialize(args = {}, message_impl = nil) - @message_impl = message_impl - @message_impl = Cqpid::Message.new if @message_impl.nil? - @message_impl.setContent args[:content].to_s if args[:content] - @content = nil - end - - def message_impl # :nodoc: - @message_impl - end - - # Assigns the reply to address. - # The address must be an instance of Address. - def reply_to=(address); @message_impl.setReplyTo address.address_impl; end - - # Returns the reply to address for the message as an instance of +Address+. - def reply_to - address_impl = @message_impl.getReplyTo - # only return an address if a reply to was specified - Qpid::Messaging::Address.new(nil, nil, nil, nil, address_impl) if address_impl - end - - # Sets the subject. - def subject=(subject); @message_impl.setSubject subject; end - - # Returns the subject. - def subject; @message_impl.getSubject; end - - # Sets the content type. - def content_type=(content_type); @message_impl.setContentType content_type; end - - # Returns the content type. - def content_type; @message_impl.getContentType; end - - # Sets the message id. - def message_id=(message_id); @message_impl.setMessageId message_id.to_s; end - - # Returns the message id. - def message_id; @message_impl.getMessageId; end - - # Sets the user id. - def user_id=(user_id); @message_impl.setUserId user_id; end - - # Returns the user id. - def user_id; @message_impl.getUserId; end - - # Sets the correlation id. - def correlation_id=(correlation_id); @message_impl.setCorrelationId correlation_id; end - - # Returns the correlation id. - def correlation_id; @message_impl.getCorrelationId; end - - # Sets the priority. - def priority=(priority); @message_impl.setPriority priority; end - - # Returns the priority. - def priority; @message_impl.getPriority; end - - # Sets the time-to-live in milliseconds. - def ttl=(duration); @message_impl.setTtl duration; end - - # Returns the time-to-live in milliseconds. - def ttl; @message_impl.getTtl; end - - # Sets the durability. - def durable=(durable); @message_impl.setDurable durable; end - - # Returns the durability. - def durable; @message_impl.getDurable; end - - # Allows marking the message as redelivered. - def redelivered=(redelivered); @message_impl.setRedelivered redelivered; end - - # Returns if the message was redelivered. - def redelivered; @message_impl.getRedelivered; end - - # Returns all named properties. - # *NOTE:* It is recommended to use the +foo[key]+ method for - # retrieving properties. - def properties; @message_impl.getProperties; end - - # Returns the value for the named property. - def [](key); self.properties[key.to_s]; end - - # Assigns a value to the named property. - def []=(key, value); @message_impl.setProperty(key.to_s, value.to_s); end - - # Sets the content. - def content=(content) - content_type = nil - @content = content - case @content - when Hash - content_type = "amqp/map" - when Array - content_type = "amqp/list" - end - if content_type.nil? - @message_impl.setContent @content - else - Qpid::Messaging.encode @content, self, content_type - end - end - - # Returns the content. - def content - if @content.nil? - @content = @message_impl.getContent - - # decode the content is necessary if it - # has an encoded content type - if ["amqp/list", "amqp/map"].include? @message_impl.getContentType - @content = Qpid::Messaging.decode(self, - @message_impl.getContentType) - end - - end - @content - end - - # Returns the content's size. - def content_size; @message_impl.getContentSize; end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb b/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb deleted file mode 100644 index d498aa922b..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb +++ /dev/null @@ -1,102 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -require 'qpid/duration' - -module Qpid - - module Messaging - - # Receiver defines a type for receiving messages. - class Receiver - - def initialize(receiver_impl) # :nodoc: - @receiver_impl = receiver_impl - end - - def receiver_impl # :nodoc: - @receiver_impl - end - - # Retrieves a message from the receiver's local queue, or waits - # for up to the duration specified for one to become available. - def get(duration = Qpid::Messaging::Duration::FOREVER) - message_impl = @receiver_impl.get duration.duration_impl - create_message_wrapper message_impl unless message_impl.nil? - end - - # Retrieves a message from the receiver's subscription, or waits - # for up to the duration specified for one to become available. - def fetch(duration = Qpid::Messaging::Duration::FOREVER) - message_impl = @receiver_impl.fetch duration.duration_impl - create_message_wrapper message_impl unless message_impl.nil? - end - - # Sets the capacity. - # - # The capacity for a receiver determines the number of messages that - # can be held in the receiver before being fetched. - def capacity=(capacity); @receiver_impl.setCapacity capacity; end - - # Returns the capacity. - def capacity; @receiver_impl.getCapacity; end - - # Returns the number of available messages waiting to be fetched. - def available; @receiver_impl.getAvailable; end - - # Returns the number of messages that have been received and acknowledged - # but whose acknowledgements have not been confirmed by the sender. - def unsettled; @receiver_impl.getUnsettled; end - - # Cancels the reciever. - def close; @receiver_impl.close; end - - # Returns whether the receiver is closed. - def closed?; @receiver_impl.isClosed; end - - # Returns the name of the receiver - def name; @receiver_impl.getName; end - - # Returns the Session for this receiver. - def session; Qpid::Messaging::Session.new(@receiver_impl.getSession); end - - # Returns whether the underlying handle is valid. - def valid?; @receiver_impl.isValid; end - - # Returns whether the underlying handle is null. - def null?; @receiver_impl.isNull; end - - def swap receiver - @receiver_impl.swap receiver.receiver_impl - end - - private - - def create_message_wrapper message_impl - Qpid::Messaging::Message.new({}, message_impl) - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/sender.rb b/cpp/bindings/qpid/ruby/lib/qpid/sender.rb deleted file mode 100644 index 5d59c20d7e..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/sender.rb +++ /dev/null @@ -1,82 +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. -# - -module Qpid - - module Messaging - - # Sender defines a type for sending messages. - class Sender - - def initialize(sender_impl) # :nodoc: - @sender_impl = sender_impl - end - - def sender_impl # :nodoc: - @sender_impl - end - - # Sends a message. - def send(message, args = {}) - block = args[:block] || false - @sender_impl.send message.message_impl, block - end - - # Closes the sender. - def close; @sender_impl.close; end - - # Returns the name for the sender. - def name; @sender_impl.getName; end - - # Sets the capacity for the sender, which is the number of outgoing - # messages that can be held pending confirmation or receipt by - # the broker. - def capacity=(capacity); @sender_impl.setCapacity capacity; end - - # Returns the capacity. - def capacity; @sender_impl.getCapacity; end - - # Returns the number of messages sent that are pending receipt - # confirmation by the broker. - def unsettled; @sender_impl.getUnsettled; end - - # Returns the available capacity for sending messages. - def available - @sender_impl.getAvailable - end - - # Returns the Session for this sender. - def session; Qpid::Messaging::Session.new @sender_impl.getSession; end - - # Returns if the underlying sender is valid. - def valid?; @sender_impl.isValid; end - - # Returns if the underlying sender is null. - def null?; @sender_impl.isNull; end - - def swap sender - @sender_impl.swap sender.sender_impl - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/session.rb b/cpp/bindings/qpid/ruby/lib/qpid/session.rb deleted file mode 100644 index 543c26cc70..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/session.rb +++ /dev/null @@ -1,186 +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. -# - -require 'cqpid' - -require 'qpid/errors' - -module Qpid - - module Messaging - - # A Session represents a distinct conversation between end points. - class Session - - def initialize(session) # :nodoc: - @session_impl = session - end - - def session_impl # :nodoc: - @session_impl - end - - # Returns the +Connection+ for the +Session+. - def connection - connection_impl = @session_impl.getConnection - Qpid::Messaging::Connection.new "", {}, connection_impl - end - - # Creates a new endpoint for sending messages. - def create_sender(address) - _address = address - - if address.class == Qpid::Messaging::Address - _address = address.address_impl - end - - Qpid::Messaging::Sender.new(@session_impl.createSender(_address)) - end - - # Retrieves the +Sender+ with the specified name. - def sender(name) - result = nil - - begin - sender_impl = @session_impl.getSender name - result = Sender.for_impl sender_impl - rescue - # treat any error as a key error - end - - raise Qpid::Messaging::KeyError, "No such sender: #{name}" if result.nil? - result - end - - # Retrieves the +Receiver+ with the specified name. - def receiver(name) - result = nil - - begin - receiver_impl = @session_impl.getReceiver name - result = Receiver.for_impl receiver_impl - rescue - # treat any error as a key error - end - - raise Qpid::Messaging::KeyError, "No such receiver: #{name}" if result.nil? - result - end - - # Creates a new endpoint for receiving messages. - def create_receiver(address) - result = nil - - if address.class == Qpid::Messaging::Address - address_impl = address.address_impl - result = Qpid::Messaging::Receiver.new(@session_impl.createReceiver(address_impl)) - else - result = Qpid::Messaging::Receiver.new(@session_impl.createReceiver(address)) - end - - return result - end - - # Closes the Session and all associated Senders and Receivers. - # All Sessions are closed when the associated Connection is closed. - def close; @session_impl.close; end - - # Commits any pending transactions for a transactional session. - def commit; @session_impl.commit; end - - # Rolls back any uncommitted transactions on a transactional session. - def rollback; @session_impl.rollback; end - - # Acknowledges one or more outstanding messages that have been received - # on this session. - # - # If a message is submitted (:message => something_message) then only - # that message is acknowledged. Otherwise all messsages are acknowledged. - # - # If :sync => true then the call will block until the server completes - # processing the acknowledgements. - # If :sync => true then the call will block until processed by the server (def. false) - def acknowledge(args = {}) - sync = args[:sync] || false - message = args[:message] if args[:message] - - unless message.nil? - @session_impl.acknowledge message.message_impl, sync - else - @session_impl.acknowledge sync - end - end - - # Rejects the specified message. A rejected message will not be redelivered. - # - # NOTE: A message cannot be rejected once it has been acknowledged. - def reject(message); @session_impl.reject message.message_impl; end - - # Releases the message, which allows the broker to attempt to - # redeliver it. - # - # NOTE: A message connot be released once it has been acknowled. - def release(message); @session_impl.release message.message_impl; end - - # Requests synchronization with the server. - # - # If :block => true then the call will block until the server acknowledges. - # - # If :block => false (default) then the call will complete and the server - # will send notification on completion. - def sync(args = {}) - block = args[:block] || false - @session_impl.sync block - end - - # Returns the total number of receivable messages, and messages already received, - # by Receivers associated with this session. - def receivable; @session_impl.getReceivable; end - - # Returns the number of messages that have been acknowledged by this session - # whose acknowledgements have not been confirmed as processed by the server. - def unsettled_acks; @session_impl.getUnsettledAcks; end - - # Fetches the receiver for the next message. - def next_receiver(timeout = Qpid::Messaging::Duration::FOREVER) - receiver_impl = @session_impl.nextReceiver(timeout.duration_impl) - Qpid::Messaging::Receiver.new receiver_impl - end - - # Returns whether there are errors on this session. - def error?; @session_impl.hasError; end - - def check_error; @session_impl.checkError; end - - # Returns if the underlying session is valid. - def valid?; @session_impl.isValid; end - - # Returns if the underlying session is null. - def null?; @session_impl.isNull; end - - def swap session - @session_impl.swap session.session_impl - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/version.rb b/cpp/bindings/qpid/ruby/lib/qpid/version.rb deleted file mode 100644 index f387ba98dc..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/version.rb +++ /dev/null @@ -1,31 +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. -# - -module Qpid - - module Version - - NUMBERS = [MAJOR = 0, - MINOR = 13, - BUILD = 0] - end - - VERSION = Version::NUMBERS.join('.') - -end diff --git a/cpp/bindings/qpid/ruby/test/lib/setup.rb b/cpp/bindings/qpid/ruby/test/lib/setup.rb deleted file mode 100644 index c4901ed907..0000000000 --- a/cpp/bindings/qpid/ruby/test/lib/setup.rb +++ /dev/null @@ -1,29 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'qpid' - -def create_session url, session_name - conn = Qpid::Messaging::Connection.new url - conn.open - conn.create_session session_name -end - diff --git a/cpp/bindings/qpid/ruby/test/test_address.rb b/cpp/bindings/qpid/ruby/test/test_address.rb deleted file mode 100644 index f54e93aa3d..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_address.rb +++ /dev/null @@ -1,39 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'cqpid' -require 'qpid/address' - -class TestAddress < Test::Unit::TestCase - - def test_constructor - result = Qpid::Messaging::Address.new "name", "subject", {:foo => :bar}, "type" - - assert_equal "name", result.name - assert_equal "subject", result.subject - assert_equal "type", result._type - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_connection.rb b/cpp/bindings/qpid/ruby/test/test_connection.rb deleted file mode 100644 index 648fb0588a..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_connection.rb +++ /dev/null @@ -1,257 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'cqpid' -require 'qpid/connection' - -class TestConnection < Test::Unit::TestCase - - def setup - @connection_impl = flexmock("connection_impl") - @other_connection = flexmock("other_connection") - @other_connection_impl = flexmock("other_connection_impl") - @cqpid_connection = flexmock(Cqpid::Connection) - - @session = flexmock("session") - @session_name = "test-session" - - @url = "localhost" - @options = {} - - @connection = Qpid::Messaging::Connection.new(@url, @options, @connection_impl) - end - - def test_create_with_username_and_password - @cqpid_connection. - should_receive(:new). - once.with("localhost", - {"username" => "username", - "password" => "password"}). - and_return(@connection_impl) - @connection_impl. - should_receive(:open). - once - - result = Qpid::Messaging::Connection.new("localhost", - :username => "username", - :password => "password") - result.open - - assert_same @connection_impl, result.connection_impl - end - - def test_create_with_hostname - result = Qpid::Messaging::Connection.new("localhost") - - assert_not_nil result - end - - def test_open - @cqpid_connection. - should_receive(:new). - once. - with(@url, {}). - and_return(@connection_impl) - @connection_impl. - should_receive(:open). - once - - @connection.open - - assert_same @connection_impl, @connection.connection_impl - end - - def test_check_open_when_open - @connection_impl. - should_receive(:isOpen). - once. - and_return(true) - - assert @connection.open? - end - - def test_check_open_before_connection - result = Qpid::Messaging::Connection.new("hostname") - - assert !result.open? - end - - def test_check_open_when_closed - @connection_impl. - should_receive(:isOpen). - once. - and_return(false) - - assert !@connection.open? - end - - def test_close_an_unopened_session - @connection_impl. - should_receive(:isOpen). - once. - and_return(false) - - @connection.close - end - - def test_close - @connection_impl. - should_receive(:isOpen). - once. - and_return(true). - should_receive(:close). - once - - @connection.close - end - - def test_create_session_without_name - @connection_impl. - should_receive(:isOpen). - once. - and_return(true). - should_receive(:createSession). - once. - with(""). - and_return(@session) - - result = @connection.create_session - - assert_not_nil result - assert_same @session, result.session_impl - end - - def test_create_session - @connection_impl. - should_receive(:isOpen). - once. - and_return(true). - should_receive(:createSession). - once. - with(@session_name). - and_return(@session) - - result = @connection.create_session :name => @session_name - - assert_not_nil result - assert_same @session, result.session_impl - end - - def test_create_session_raises_exception_when_closed - @connection_impl. - should_receive(:isOpen). - once. - and_return(false) - - assert_raise(RuntimeError) {@connection.create_session @session_name} - end - - def test_create_transactional_session - @connection_impl. - should_receive(:isOpen). - once. - and_return(true). - should_receive(:createTransactionalSession). - once. - with(""). - and_return(@session) - - result = @connection.create_session :transactional => true - - assert_not_nil result - assert_same @session, result.session_impl - end - - def test_authenticated_username_when_not_connected - @connection_impl. - should_receive(:isOpen). - once. - and_return(false) - - result = @connection.authenticated_username - - assert_nil result - end - - def test_authenticated_username - @connection_impl. - should_receive(:isOpen). - once. - and_return(true). - should_receive(:getAuthenticatedUsername). - once. - and_return("farkle") - - result = @connection.authenticated_username - - assert_equal "farkle", result - end - - def test_get_session_with_invalid_name - @connection_impl. - should_receive(:getSession). - once. - with(@session_name). - and_return(nil) - - result = @connection.session @session_name - - assert_nil result - end - - # APIs inherited from Handle - - def test_is_valid - @connection_impl. - should_receive(:isValid). - once. - and_return(true) - - assert @connection.valid? - end - - def test_is_null - @connection_impl. - should_receive(:isNull). - once. - and_return(false) - - assert !@connection.null? - end - - def test_swap - @other_connection. - should_receive(:connection_impl). - once. - and_return(@other_connection_impl) - @connection_impl. - should_receive(:swap). - once. - with(@other_connection_impl) - - @connection.swap @other_connection - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_encoding.rb b/cpp/bindings/qpid/ruby/test/test_encoding.rb deleted file mode 100644 index 060975a1d5..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_encoding.rb +++ /dev/null @@ -1,146 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'cqpid' -require 'qpid/encoding' - -class TestEncoding < Test::Unit::TestCase - - def setup - @cqpid = flexmock(Cqpid) - - @message = flexmock("message") - @message_impl = flexmock("message_impl") - - @encoded = {"foo" => "bar"} - end - - def test_encode_map_with_symbols - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:encode). - once. - with({"foo" => "bar"}, @message_impl). - and_return(@encoded) - - result = Qpid::Messaging.encode({:foo => :bar}, @message) - - assert_same @encoded, result - end - - def test_encode_list_with_symbols - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:encode). - once. - with(["foo", "bar"], @message_impl). - and_return(@encoded) - - result = Qpid::Messaging.encode([:foo, :bar], @message) - - assert_same @encoded, result - end - - def test_encode_with_content_type - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:encode). - once. - with({"foo" => "bar"}, @message_impl). - and_return(@encoded) - - result = Qpid::Messaging.encode({:foo => :bar}, @message) - - assert_same @encoded, result - end - - def test_encode - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:encode). - once. - with({"foo" => "bar"}, @message_impl). - and_return(@encoded) - - result = Qpid::Messaging.encode({"foo" => "bar"}, @message) - - assert_same @encoded, result - end - - def test_decode_for_map - decoded = {"foo" => "bar"} - @message. - should_receive(:content_type). - once. - and_return("amqp/map") - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:decodeMap). - once. - with(@message_impl). - and_return(decoded) - - result = Qpid::Messaging.decode(@message) - - assert_same decoded, result - end - - def test_decode_for_list - decoded = ["foo", "bar"] - @message. - should_receive(:content_type). - once. - and_return("amqp/list") - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @cqpid. - should_receive(:decodeList). - once. - with(@message_impl). - and_return(decoded) - - result = Qpid::Messaging.decode(@message) - - assert_same decoded, result - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_message.rb b/cpp/bindings/qpid/ruby/test/test_message.rb deleted file mode 100644 index 3fc705bf7e..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_message.rb +++ /dev/null @@ -1,353 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'qpid' - -class TestMessage < Test::Unit::TestCase - - def setup - @address = flexmock("address") - @address_impl = flexmock("address_impl") - - @messaging = flexmock(Qpid::Messaging) - @message_impl = flexmock("message") - @message = Qpid::Messaging::Message.new({}, @message_impl) - end - - def test_message_impl - assert_same @message_impl, @message.message_impl - end - - def test_set_reply_to - @address. - should_receive(:address_impl). - once. - and_return(@address_impl) - @message_impl. - should_receive(:setReplyTo). - once. - with(@address_impl) - - @message.reply_to = @address - end - - def test_get_reply_to - @message_impl. - should_receive(:getReplyTo). - once. - and_return(@address_impl) - - result = @message.reply_to - - assert_not_nil result - assert_same @address_impl, result.address_impl - end - - def test_set_subject - @message_impl. - should_receive(:setSubject). - once. - with("New Subject") - - @message.subject = "New Subject" - end - - def test_get_subject - @message_impl. - should_receive(:getSubject). - once. - and_return("Old Subject") - - assert_equal "Old Subject", @message.subject - end - - def test_set_content_type - @message_impl. - should_receive(:setContentType). - once. - and_return("amqp/map") - - @message.content_type = "amqp/map" - end - - def test_get_content_type - @message_impl. - should_receive(:getContentType). - once. - and_return("amqp/list") - - assert_equal "amqp/list", @message.content_type - end - - def test_set_message_id - @message_impl. - should_receive(:setMessageId). - once. - with("717") - - @message.message_id = "717" - end - - def test_get_message_id - @message_impl. - should_receive(:getMessageId). - once. - and_return("1965") - - assert_equal "1965", @message.message_id - end - - def test_set_user_id - @message_impl. - should_receive(:setUserId). - once. - with("129") - - @message.user_id = "129" - end - - def test_get_user_id - @message_impl. - should_receive(:getUserId). - once. - and_return("1971") - - assert_equal "1971", @message.user_id - end - - def test_set_correlation_id - @message_impl. - should_receive(:setCorrelationId). - once. - with("320") - - @message.correlation_id = "320" - end - - def test_get_correlation_id - @message_impl. - should_receive(:getCorrelationId). - once. - and_return("1996") - - assert_equal "1996", @message.correlation_id - end - - def test_set_priority - @message_impl. - should_receive(:setPriority). - once. - with(9) - - @message.priority = 9 - end - - def test_get_priority - @message_impl. - should_receive(:getPriority). - once. - and_return(21) - - assert_equal 21, @message.priority - end - - def test_set_ttl - @message_impl. - should_receive(:setTtl). - once. - with(Qpid::Messaging::Duration::FOREVER) - - @message.ttl = Qpid::Messaging::Duration::FOREVER - end - - def test_get_ttl - @message_impl. - should_receive(:getTtl). - once. - and_return(Qpid::Messaging::Duration::SECOND) - - assert_equal Qpid::Messaging::Duration::SECOND, @message.ttl - end - - def test_set_durable - @message_impl. - should_receive(:setDurable). - once. - with(true) - - @message.durable = true - end - - def test_set_not_durable - @message_impl. - should_receive(:setDurable). - once. - with(false) - - @message.durable = false - end - - def test_get_durable - @message_impl. - should_receive(:getDurable). - once. - and_return(true) - - assert @message.durable - end - - def test_set_redelivered - @message_impl. - should_receive(:setRedelivered). - once. - with(true) - - @message.redelivered = true - end - - def test_set_not_redelivered - @message_impl. - should_receive(:setRedelivered). - once. - with(false) - - @message.redelivered = false - end - - def test_get_redelivered - @message_impl. - should_receive(:getRedelivered). - once. - and_return(false) - - assert !@message.redelivered - end - - def test_get_properties - properties = {"foo" => "bar"} - @message_impl. - should_receive(:getProperties). - once. - and_return(properties) - - result = @message.properties - - assert_equal properties, result - end - - def test_get_property - @message_impl. - should_receive(:getProperties). - once. - and_return({"foo" => "bar"}) - - result = @message["foo"] - - assert_equal "bar", result - end - - def test_set_property - @message_impl. - should_receive(:setProperty). - once. - with("foo", "bar") - - @message["foo"] = "bar" - end - - def test_set_content - @message_impl. - should_receive(:setContent). - once. - with("foo") - - @message.content = "foo" - assert_equal "foo", @message.content - end - - def test_set_content_with_array - content = ["one", "two", "three"] - - @messaging. - should_receive(:encode). - once. - with(content, @message, "amqp/list") - - @message.content = content - assert_same content, @message.content - end - - def test_set_content_with_map - content = {:foo => "bar", :dog => "cat"} - - @messaging. - should_receive(:encode). - once. - with(content, @message, "amqp/map") - - @message.content = content - assert_same content, @message.content - end - - def test_get_content - @message_impl. - should_receive(:getContent). - and_return("foo") - @message_impl. - should_receive(:getContentType). - and_return(String) - - assert_equal "foo", @message.content - end - - def test_get_content_with_array - decoded = ["foo", "bar"] - - @message_impl. - should_receive(:getContent). - and_return("[foo,bar]") - @message_impl. - should_receive(:getContentType). - and_return("amqp/list") - @messaging. - should_receive(:decode). - once. - with(@message, "amqp/list"). - and_return(decoded) - - result = @message.content - assert_same decoded, result - end - - def test_get_content_size - @message_impl. - should_receive(:getContentSize). - once. - and_return(68) - - assert_equal 68, @message.content_size - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_receiver.rb b/cpp/bindings/qpid/ruby/test/test_receiver.rb deleted file mode 100644 index 61a4db17f2..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_receiver.rb +++ /dev/null @@ -1,238 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'qpid/receiver' - -class TestReceiver < Test::Unit::TestCase - - def setup - @session_impl = flexmock("session") - - @Message_class = flexmock(Qpid::Messaging::Message) - @Messaging_module = flexmock(Qpid::Messaging) - @message_impl = flexmock("message_impl") - @message = flexmock("message") - - @receiver_impl = flexmock("receiver") - @other_receiver = flexmock("other_receiver") - @other_receiver_impl = flexmock("other_receiver_impl") - @receiver = Qpid::Messaging::Receiver.new @receiver_impl - end - - def test_receiver_impl - assert_same @receiver_impl, @receiver.receiver_impl - end - - def test_get - @receiver_impl. - should_receive(:get). - once. - with_any_args. - and_return(@message_impl) - - result = @receiver.get - - assert_not_nil result - assert_same @message_impl, result.message_impl - end - - def test_get_with_duration - @receiver_impl. - should_receive(:get). - once. - with_any_args. - and_return(@message_impl) - - result = @receiver.get Qpid::Messaging::Duration::MINUTE - - assert_not_nil result - assert_same @message_impl, result.message_impl - end - - def test_get_with_no_message_received - @receiver_impl. - should_receive(:get). - once. - with_any_args. - and_return(nil) - - result = @receiver.get Qpid::Messaging::Duration::SECOND - - assert_nil result - end - - def test_fetch - @receiver_impl. - should_receive(:fetch). - once. - with_any_args. - and_return(@message_impl) - - result = @receiver.fetch - - assert_not_nil result - assert_same @message_impl, result.message_impl - end - - def test_fetch_with_duration - @receiver_impl. - should_receive(:fetch). - once. - with_any_args. - and_return(@message_impl) - - result = @receiver.fetch Qpid::Messaging::Duration::MINUTE - - assert_not_nil result - assert_same @message_impl, result.message_impl - end - - def test_fetch_with_no_message_received - @receiver_impl. - should_receive(:fetch). - once. - with_any_args. - and_return(nil) - - result = @receiver.fetch Qpid::Messaging::Duration::SECOND - - assert_nil result - end - - def test_set_capacity - @receiver_impl. - should_receive(:setCapacity). - once. - with(15) - - @receiver.capacity = 15 - end - - def test_get_capacity - @receiver_impl. - should_receive(:getCapacity). - once. - and_return(17) - - assert_equal 17, @receiver.capacity - end - - def test_get_available - @receiver_impl. - should_receive(:getAvailable). - once. - and_return(2) - - assert_equal 2, @receiver.available - end - - def test_get_unsettled - @receiver_impl. - should_receive(:getUnsettled). - once. - and_return(12) - - assert_equal 12, @receiver.unsettled - end - - def test_close - @receiver_impl. - should_receive(:close). - once - - @receiver.close - end - - def test_closed_when_open - @receiver_impl. - should_receive(:isClosed). - once. - and_return(false) - - assert !@receiver.closed? - end - - def test_closed - @receiver_impl. - should_receive(:isClosed). - once. - and_return(true) - - assert @receiver.closed? - end - - def test_get_name - @receiver_impl. - should_receive(:getName). - once. - and_return("my-queue") - - assert_equal "my-queue", @receiver.name - end - - def test_get_session - @receiver_impl. - should_receive(:getSession). - once. - and_return(@session_impl) - - result = @receiver.session - - assert_not_nil result - assert_same @session_impl, result.session_impl - end - - def test_is_valid - @receiver_impl. - should_receive(:isValid). - once. - and_return(false) - - assert !@receiver.valid? - end - - def test_is_null - @receiver_impl. - should_receive(:isNull). - once. - and_return(true) - - assert @receiver.null? - end - - def test_swap - @other_receiver. - should_receive(:receiver_impl). - once. - and_return(@other_receiver_impl) - @receiver_impl. - should_receive(:swap). - once. - with(@other_receiver_impl) - - @receiver.swap @other_receiver - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_sender.rb b/cpp/bindings/qpid/ruby/test/test_sender.rb deleted file mode 100644 index 64348b9f72..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_sender.rb +++ /dev/null @@ -1,183 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'qpid/sender' - -class TestSender < Test::Unit::TestCase - - def setup - @messaging = flexmock(Qpid::Messaging) - @message = flexmock("message") - - @session_impl = flexmock("session_impl") - - @sender_impl = flexmock("sender_impl") - @other_sender_impl = flexmock("other_sender_impl") - @sender = Qpid::Messaging::Sender.new @sender_impl - @other_sender = flexmock("other_sender") - end - - def test_send - message_impl = "message_impl" - content = {:foo => :bar} - @message. - should_receive(:message_impl). - once. - and_return(message_impl) - @sender_impl. - should_receive(:send). - once. - with(message_impl, false) - - @sender.send @message - end - - def test_send_and_dont_block - message_impl = "message_impl" - content = {:foo => :bar} - @message. - should_receive(:message_impl). - once. - and_return(message_impl) - @sender_impl. - should_receive(:send). - once. - with(message_impl, false) - - @sender.send @message, :block => false - end - - def test_send_and_block - message_impl = "message_impl" - content = {:foo => :bar} - @message. - should_receive(:message_impl). - once. - and_return(message_impl) - @sender_impl. - should_receive(:send). - once. - with(message_impl, true) - - @sender.send @message, :block => true - end - - def test_close - @sender_impl. - should_receive(:close). - once - - @sender.close - end - - def test_set_capacity - @sender_impl. - should_receive(:setCapacity). - once. - with(17) - - @sender.capacity = 17 - end - - def test_get_capacity - @sender_impl. - should_receive(:getCapacity). - once. - and_return(12) - - assert_equal 12, @sender.capacity - end - - def test_unsettled - @sender_impl. - should_receive(:getUnsettled). - once. - and_return(5) - - assert_equal 5, @sender.unsettled - end - - def test_available - @sender_impl. - should_receive(:getAvailable). - once. - and_return(15) - - assert_equal 15, @sender.available - end - - def test_name - @sender_impl. - should_receive(:getName). - once. - and_return("myname") - - assert_equal "myname", @sender.name - end - - def test_session - @sender_impl. - should_receive(:getSession). - once. - and_return(@session_impl) - - result = @sender.session - - assert_not_nil result - assert_same @session_impl, result.session_impl - end - - def test_is_valid - @sender_impl. - should_receive(:isValid). - once. - and_return(true) - - assert @sender.valid? - end - - def test_is_null - @sender_impl. - should_receive(:isNull). - once. - and_return(false) - - assert !@sender.null? - end - - def test_swap - @other_sender. - should_receive(:sender_impl). - once. - and_return(@other_sender_impl) - @sender_impl. - should_receive(:swap). - once. - with(@other_sender_impl) - - @sender.swap @other_sender - end - -end - diff --git a/cpp/bindings/qpid/ruby/test/test_session.rb b/cpp/bindings/qpid/ruby/test/test_session.rb deleted file mode 100644 index 20f055967b..0000000000 --- a/cpp/bindings/qpid/ruby/test/test_session.rb +++ /dev/null @@ -1,445 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'flexmock/test_unit' - -require 'qpid/errors' -require 'qpid/duration' -require 'qpid/session' - -class TestSession < Test::Unit::TestCase - - def setup - @session_impl = flexmock("session_impl") - @other_session = flexmock("other_session") - @other_session_impl = flexmock("other_session_impl") - @sender = flexmock("sender") - - @Connection_class = flexmock(Qpid::Messaging::Connection) - @connection_impl = flexmock("connection_impl") - @connection = flexmock("connection") - - @Receiver_class = flexmock(Qpid::Messaging::Receiver) - @receiver = flexmock("receiver") - @receiver_impl = flexmock("receiver_impl") - - @address = flexmock("address") - @address_impl = flexmock("address_impl") - - @Sender_class = flexmock(Qpid::Messaging::Sender) - @sender = flexmock("sender") - @sender_impl = flexmock("sender_impl") - - @message = flexmock("message") - @message_impl = flexmock("message_impl") - - @duration = flexmock("duration") - @duration_impl = flexmock("duration_impl") - - @session = Qpid::Messaging::Session.new(@session_impl) - end - - def test_create_sender_with_Address - @address. - should_receive(:class). - once. - and_return(Qpid::Messaging::Address). - should_receive(:address_impl). - once. - and_return(@address_impl) - @session_impl. - should_receive(:createSender). - once. - with(@address_impl). - and_return(@sender_impl) - - result = @session.create_sender @address - - assert_not_nil result - end - - def test_create_sender - @session_impl. - should_receive(:createSender). - once. - with_any_args. - and_return(@sender_impl) - - result = @session.create_sender("my-queue") - - assert_not_nil result - end - - def test_create_sender_with_address_string - @session_impl. - should_receive(:createSender). - once. - with("my-queue;{create:always}"). - and_return(@sender_impl) - - result = @session.create_sender "my-queue;{create:always}" - - assert_same @sender_impl, result.sender_impl - end - - def test_create_receiver - @address. - should_receive(:class). - once. - and_return(Qpid::Messaging::Address). - should_receive(:address_impl). - once. - and_return(@address_impl) - @session_impl. - should_receive(:createReceiver). - once. - with(@address_impl). - and_return(@receiver_impl) - - result = @session.create_receiver(@address) - - assert_equal @receiver_impl, result.receiver_impl - end - - def test_create_receiver_with_address_string - @session_impl. - should_receive(:createReceiver). - once. - with("my-queue"). - and_return(@receiver_impl) - - result = @session.create_receiver("my-queue") - - assert_same @receiver_impl, result.receiver_impl - end - - def test_close - @session_impl. - should_receive(:close). - once - - @session.close - end - - def test_commit - @session_impl. - should_receive(:commit). - once - - @session.commit - end - - def test_rollback - @session_impl. - should_receive(:rollback). - once - - @session.rollback - end - - def test_acknowledge_with_no_args - @session_impl. - should_receive(:acknowledge). - once. - with(false) - - @session.acknowledge - end - - def test_acknowledge_and_sync - @session_impl. - should_receive(:acknowledge). - once. - with(true) - - @session.acknowledge :sync => true - end - - def test_acknowledge_and_dont_sync - @session_impl. - should_receive(:acknowledge). - once. - with(false) - - @session.acknowledge :sync => false - end - - def test_acknowledge_message_without_sync - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @session_impl. - should_receive(:acknowledge). - once. - with(@message_impl, false) - - @session.acknowledge :message => @message - end - - def test_acknowledge_message_and_sync - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @session_impl. - should_receive(:acknowledge). - once. - with(@message_impl, true) - - @session.acknowledge :message => @message, :sync => true - end - - def test_acknowledge_message_and_dont_sync - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @session_impl. - should_receive(:acknowledge). - once. - with(@message_impl, false) - - @session.acknowledge :message => @message, :sync => false - end - - def test_reject_message - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @session_impl. - should_receive(:reject). - once. - with(@message_impl) - - @session.reject @message - end - - def test_release_message - @message. - should_receive(:message_impl). - once. - and_return(@message_impl) - @session_impl. - should_receive(:release). - once. - with(@message_impl) - - @session.release @message - end - - def test_sync_without_block - @session_impl. - should_receive(:sync). - once - - @session.sync - end - - def test_sync_and_block - @session_impl. - should_receive(:sync). - once. - with(true) - - @session.sync :block => true - end - - def test_sync_and_dont_block - @session_impl. - should_receive(:sync). - once. - with(false) - - @session.sync :block => false - end - - def test_receivable - @session_impl. - should_receive(:getReceivable). - once. - and_return(5) - - assert_equal 5, @session.receivable - end - - def test_unsettled_acks - @session_impl. - should_receive(:getUnsettledAcks). - once. - and_return(17) - - assert_equal 17, @session.unsettled_acks - end - - def test_next_receiver_with_no_duration - @session_impl. - should_receive(:nextReceiver). - once. - with(Qpid::Messaging::Duration::FOREVER.duration_impl). - and_return(@receiver_impl) - - result = @session.next_receiver - - assert_same @receiver_impl, result.receiver_impl - end - - def test_next_receiver_with_duration - @duration. - should_receive(:duration_impl). - once. - and_return(@duration_impl) - @session_impl. - should_receive(:nextReceiver). - once. - with(@duration_impl). - and_return(@receiver_impl) - - result = @session.next_receiver @duration - - assert_same @receiver_impl, result.receiver_impl - end - - def test_sender - @session_impl. - should_receive(:getSender). - once. - with("farkle"). - and_return(@sender_impl) - @Sender_class. - should_receive(:for_impl). - once. - with(@sender_impl). - and_return(@sender) - - result = @session.sender "farkle" - - assert_same @sender, result - end - - def test_sender_with_invalid_name - @session_impl. - should_receive(:getSender). - once. - with("farkle"). - and_throw(RuntimeError) - - assert_raise(Qpid::Messaging::KeyError) {@session.sender "farkle"} - end - - def test_receiver - @session_impl. - should_receive(:getReceiver). - once. - with("farkle"). - and_return(@receiver_impl) - @Receiver_class. - should_receive(:for_impl). - once. - with(@receiver_impl). - and_return(@receiver) - - result = @session.receiver "farkle" - - assert_same @receiver, result - end - - def test_receiver_with_invalid_name - @session_impl. - should_receive(:getReceiver). - once. - with("farkle"). - and_throw(RuntimeError) - - assert_raise(Qpid::Messaging::KeyError) {@session.receiver "farkle"} - end - - def test_connection - @session_impl. - should_receive(:getConnection). - once. - and_return(@connection_impl) - - result = @session.connection - - assert_same @connection_impl, result.connection_impl - end - - def test_error_with_none - @session_impl. - should_receive(:hasError). - once. - and_return(false) - - assert !@session.error? - end - - def test_error - @session_impl. - should_receive(:hasError). - once. - and_return(true) - - assert @session.error? - end - - def test_check_error - @session_impl. - should_receive(:checkError). - once - - @session.check_error - end - - def test_is_valid - @session_impl. - should_receive(:isValid). - once. - and_return(false) - - assert !@session.valid? - end - - def test_is_null - @session_impl. - should_receive(:isNull). - once. - and_return(false) - - assert !@session.null? - end - - def test_swap - @other_session. - should_receive(:session_impl). - once. - and_return(@other_session_impl) - @session_impl. - should_receive(:swap). - once. - with(@other_session_impl) - - @session.swap @other_session - end - -end diff --git a/cpp/bindings/qpid/ruby/test/ts_bindings.rb b/cpp/bindings/qpid/ruby/test/ts_bindings.rb deleted file mode 100644 index 7aa410c8f8..0000000000 --- a/cpp/bindings/qpid/ruby/test/ts_bindings.rb +++ /dev/null @@ -1,30 +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. -# - -$:.unshift File.join(File.dirname(__FILE__), "..", "lib") - -require 'test/unit' -require 'test_encoding' -require 'test_address' -require 'test_message' -require 'test_sender' -require 'test_receiver' -require 'test_session' -require 'test_connection' - diff --git a/cpp/bindings/swig_python_typemaps.i b/cpp/bindings/swig_python_typemaps.i index 18bfd48f72..b69784a6de 100644 --- a/cpp/bindings/swig_python_typemaps.i +++ b/cpp/bindings/swig_python_typemaps.i @@ -17,25 +17,6 @@ * under the License. */ -/* For UUID objects, to convert them to Python uuid.UUID objects, - * we'll need a reference to the uuid module. - */ -%{ -static PyObject* pUuidModule; -%} - -%init %{ - pUuidModule = PyImport_ImportModule("uuid"); - - /* Although it is not required, we'll publish the uuid module in our - * module, as if this module was a python module and we called - * "import uuid" - */ - Py_INCREF(pUuidModule); - PyModule_AddObject(m, "uuid", pUuidModule); -%} - - %wrapper %{ #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) @@ -47,7 +28,6 @@ typedef int Py_ssize_t; PyObject* MapToPy(const qpid::types::Variant::Map*); PyObject* ListToPy(const qpid::types::Variant::List*); - PyObject* UuidToPy(const qpid::types::Uuid*); void PyToMap(PyObject*, qpid::types::Variant::Map*); void PyToList(PyObject*, qpid::types::Variant::List*); @@ -124,9 +104,6 @@ typedef int Py_ssize_t; break; } case qpid::types::VAR_UUID : { - qpid::types::Uuid uuid = v->asUuid(); - result = UuidToPy(&uuid); - break; } } } catch (qpid::types::Exception& ex) { @@ -166,30 +143,6 @@ typedef int Py_ssize_t; return result; } - PyObject* UuidToPy(const qpid::types::Uuid * uuid) { - PyObject* pUuidClass = PyObject_GetAttrString(pUuidModule, "UUID"); - if (!pUuidClass) { - // Failed to get UUID class - return 0; - } - - PyObject* pArgs = PyTuple_New(0); - PyObject* pKw = PyDict_New(); - PyObject* pData = PyString_FromStringAndSize( - (const char*)(uuid->data()), 16); - PyDict_SetItemString(pKw, "bytes", pData); - - PyObject* result = PyObject_Call(pUuidClass, pArgs, pKw); - - Py_DECREF(pData); - Py_DECREF(pKw); - Py_DECREF(pArgs); - Py_DECREF(pUuidClass); - - return result; - } - - void PyToMap(PyObject* obj, qpid::types::Variant::Map* map) { map->clear(); Py_ssize_t iter(0); @@ -351,15 +304,6 @@ typedef int Py_ssize_t; Py_INCREF($result); } -/* - * UUID type: C++ --> Python - */ -%typemap(out) qpid::types::UUID & { - $result = UuidToPy($1); - if ($result) - Py_INCREF($result); -} - /* * Variant types: Ruby --> C++ diff --git a/cpp/bindings/swig_ruby_typemaps.i b/cpp/bindings/swig_ruby_typemaps.i index 326d607c8d..79e679663d 100644 --- a/cpp/bindings/swig_ruby_typemaps.i +++ b/cpp/bindings/swig_ruby_typemaps.i @@ -49,7 +49,7 @@ } VALUE VariantToRb(const qpid::types::Variant* v) { - VALUE result = Qnil; + VALUE result; try { switch (v->getType()) { case qpid::types::VAR_VOID: { diff --git a/cpp/bld-winsdk.ps1 b/cpp/bld-winsdk.ps1 index bea46da28f..8f0a5886dc 100644 --- a/cpp/bld-winsdk.ps1 +++ b/cpp/bld-winsdk.ps1 @@ -186,6 +186,9 @@ function BuildAPlatform 'examples/qmf-console', 'examples/request-response', 'examples/tradedemo', + 'examples/old-examples.sln', + 'examples/README.*', + 'examples/verify*', 'include', 'plugins') diff --git a/cpp/configure.ac b/cpp/configure.ac index 092694d56b..ea1a1b49ea 100644 --- a/cpp/configure.ac +++ b/cpp/configure.ac @@ -68,10 +68,8 @@ if test x$GXX = xyes; then # The following warnings are deliberately omitted, they warn on valid code. # -Wunreachable-code -Wpadded -Winline # -Wshadow - warns about boost headers. - # Can't test for -Werror as whether it fails or not depends on what's in - # CFLAGS/CXXFLAGS. In any case it's been in gcc for a long time (since 2.95 at least) if test "${enableval}" = yes; then - COMPILER_FLAGS="-Werror" + gl_COMPILER_FLAGS(-Werror) gl_COMPILER_FLAGS(-pedantic) gl_COMPILER_FLAGS(-Wall) gl_COMPILER_FLAGS(-Wextra) @@ -523,19 +521,18 @@ AM_PATH_PYTHON() builddir_lib_suffix="/.libs" AC_SUBST([builddir_lib_suffix]) -# Files to generate +# Files to generate AC_CONFIG_FILES([ Makefile examples/Makefile - examples/old_api/Makefile - examples/old_api/direct/Makefile - examples/old_api/fanout/Makefile - examples/old_api/pub-sub/Makefile - examples/old_api/request-response/Makefile - examples/old_api/failover/Makefile - examples/old_api/xml-exchange/Makefile + examples/direct/Makefile + examples/fanout/Makefile + examples/pub-sub/Makefile + examples/request-response/Makefile + examples/failover/Makefile + examples/xml-exchange/Makefile examples/qmf-console/Makefile - examples/old_api/tradedemo/Makefile + examples/tradedemo/Makefile examples/messaging/Makefile bindings/qpid/Makefile bindings/qpid/ruby/Makefile diff --git a/cpp/design_docs/hot-standby-design.txt b/cpp/design_docs/hot-standby-design.txt deleted file mode 100644 index 99a5dc0199..0000000000 --- a/cpp/design_docs/hot-standby-design.txt +++ /dev/null @@ -1,239 +0,0 @@ --*-org-*- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -* Another new design for Qpid clustering. - -For background see [[./new-cluster-design.txt]] which describes the issues -with the old design and a new active-active design that could replace it. - -This document describes an alternative hot-standby approach. - -** Delivery guarantee - -We guarantee N-way redundant, at least once delivey. Once a message -from a client has been acknowledged by the broker, it will be -delivered even if N-1 brokers subsequently fail. There may be -duplicates in the event of a failure. We don't make duplicates -during normal operation (i.e when no brokers have failed) - -This is the same guarantee as the old cluster and the alternative -active-active design. - -** Active-active vs. hot standby (aka primary-backup) - -An active-active cluster allows clients to connect to any broker in -the cluster. If a broker fails, clients can fail-over to any other -live broker. - -A hot-standby cluster has only one active broker at a time (the -"primary") and one or more brokers on standby (the "backups"). Clients -are only served by the leader, clients that connect to a backup are -redirected to the leader. The backpus are kept up-to-date in real time -by the primary, if the primary fails a backup is elected to be the new -primary. - -Aside: A cold-standby cluster is possible using a standalone broker, -CMAN and shared storage. In this scenario only one broker runs at a -time writing to a shared store. If it fails, another broker is started -(by CMAN) and recovers from the store. This bears investigation but -the store recovery time is probably too long for failover. - -** Why hot standby? - -Active-active has some advantages: -- Finding a broker on startup or failover is simple, just pick any live broker. -- All brokers are always running in active mode, there's no -- Distributing clients across brokers gives better performance, but see [1]. -- A broker failure affects only clients connected to that broker. - -The main problem with active-active is co-ordinating consumers of the -same queue on multiple brokers such that there are no duplicates in -normal operation. There are 2 approaches: - -Predictive: each broker predicts which messages others will take. This -the main weakness of the old design so not appealing. - -Locking: brokers "lock" a queue in order to take messages. This is -complex to implement, its not straighforward to determine the most -performant strategie for passing the lock. - -Hot-standby removes this problem. Only the primary can modify queues -so it just has to tell the backups what it is doing, there's no -locking. - -The primary can enqueue messages and replicate asynchronously - -exactly like the store does, but it "writes" to the replicas over the -network rather than writing to disk. - -** Failover in a hot-standby cluster. - -Hot-standby has some potential performance issues around failover: - -- Failover "spike": when the primary fails every client will fail over - at the same time, putting strain on the system. - -- Until a new primary is elected, cluster cannot serve any clients or - redirect clients to the primary. - -We want to minimize the number of re-connect attempts that clients -have to make. The cluster can use a well-known algorithm to choose the -new primary (e.g. round robin on a known sequence of brokers) so that -clients can guess the new primary correctly in most cases. - -Even if clients do guess correctly it may be that the new primary is -not yet aware of the death of the old primary, which is may to cause -multiple failed connect attempts before clients eventually get -connected. We will need to prototype to see how much this happens in -reality and how we can best get clients redirected. - -** Threading and performance. - -The primary-backup cluster operates analogously to the way the disk store does now: -- use the same MessageStore interface as the store to interact with the broker -- use the same asynchronous-completion model for replicating messages. -- use the same recovery interfaces (?) for new backups joining. - -Re-using the well-established store design gives credibility to the new cluster design. - -The single CPG dispatch thread was a severe performance bottleneck for the old cluster. - -The primary has the same threading model as a a standalone broker with -a store, which we know that this performs well. - -If we use CPG for replication of messages, the backups will receive -messages in the CPG dispatch thread. To get more concurency, the CPG -thread can dump work onto internal PollableQueues to be processed in -parallel. - -Messages from the same broker queue need to go onto the same -PollableQueue. There could be a separate PollableQueue for each broker -queue. If that's too resource intensive we can use a fixed set of -PollableQueues and assign broker queues to PollableQueues via hashing -or round robin. - -Another possible optimization is to use multiple CPG queues: one per -queue or a hashed set, to get more concurrency in the CPG layer. The -old cluster is not able to keep CPG busy. - -TODO: Transactions pose a challenge with these concurrent models: how -to co-ordinate multiple messages being added (commit a publish or roll -back an accept) to multiple queues so that all replicas end up with -the same message sequence while respecting atomicity. - -** Use of CPG - -CPG provides several benefits in the old cluster: -- tracking membership (essential for determining the primary) -- handling "spit brain" (integrates with partition support from CMAN) -- reliable multicast protocol to distribute messages. - -I believe we still need CPG for membership and split brain. We could -experiment with sending the bulk traffic over AMQP conections. - -** Flow control - -Need to ensure that -1) In-memory internal queues used by the cluster don't overflow. -2) The backups don't fall too far behind on processing CPG messages - -** Recovery -When a new backup joins an active cluster it must get a snapshot -from one of the other backups, or the primary if there are none. In -store terms this is "recovery" (old cluster called it an "update) - -Compared to old cluster we only replidate well defined data set of the store. -This is the crucial sore spot of old cluster. - -We can also replicated it more efficiently by recovering queues in -reverse (LIFO) order. That means as clients actively consume messages -from the front of the queue, they are redeucing the work we have to do -in recovering from the back. (NOTE: this may not be compatible with -using the same recovery interfaces as the store.) - -** Selective replication -In this model it's easy to support selective replication of individual queues via -configuration. -- Explicit exchange/queue declare argument and message boolean: x-qpid-replicate. - Treated analogously to persistent/durable properties for the store. -- if not explicitly marked, provide a choice of default - - default is replicate (replicated message on replicated queue) - - default is don't replicate - - default is replicate persistent/durable messages. - -** Inconsistent errors - -The new design eliminates most sources of inconsistent errors in the -old design (connections, sessions, security, management etc.) and -eliminates the need to stall the whole cluster till an error is -resolved. We still have to handle inconsistent store errors when store -and cluster are used together. - -We also have to include error handling in the async completion loop to -guarantee N-way at least once: we should only report success to the -client when we know the message was replicated and stored on all N-1 -backups. - -TODO: We have a lot more options than the old cluster, need to figure -out the best approach, or possibly allow mutliple approaches. Need to -go thru the various failure cases. We may be able to do recovery on a -per-queue basis rather than restarting an entire node. - -** New members joining - -We should be able to catch up much faster than the the old design. A -new backup can catch up ("recover") the current cluster state on a -per-queue basis. -- queues can be updated in parallel -- "live" updates avoid the the "endless chase" - -During a "live" update several things are happening on a queue: -- clients are publishing messages to the back of the queue, replicated to the backup -- clients are consuming messages from the front of the queue, replicated to the backup. -- the primary is sending pre-existing messages to the new backup. - -The primary sends pre-existing messages in LIFO order - starting from -the back of the queue, at the same time clients are consuming from the front. -The active consumers actually reduce the amount of work to be done, as there's -no need to replicate messages that are no longer on the queue. - -* Steps to get there - -** Baseline replication -Validate the overall design get initial notion of performance. Just -message+wiring replication, no update/recovery for new members joining, -single CPG dispatch thread on backups, no failover, no transactions. - -** Failover -Electing primary, backups redirect to primary. Measure failover time -for large # clients. Strategies to minimise number of retries after a -failure. - -** Flow Control -Keep internal queues from over-flowing. Similar to internal flow control in old cluster. -Needed for realistic performance/stress tests - -** Concurrency -Experiment with multiple threads on backups, multiple CPG groups. - -** Recovery/new member joining -Initial status handshake for new member. Recovering queues from the back. - -** Transactions -TODO: How to implement transactions with concurrency. Worst solution: -a global --cluster-use-transactions flag that forces single thread -mode. Need to find a better solution. diff --git a/cpp/design_docs/new-cluster-design.txt b/cpp/design_docs/new-cluster-design.txt index a162ea68ec..7adb46fee3 100644 --- a/cpp/design_docs/new-cluster-design.txt +++ b/cpp/design_docs/new-cluster-design.txt @@ -17,6 +17,7 @@ # under the License. * A new design for Qpid clustering. + ** Issues with current design. The cluster is based on virtual synchrony: each broker multicasts @@ -94,9 +95,8 @@ Use a moving queue ownership protocol to agree order of dequeues. No longer relies on identical state and lock-step behavior to cause identical dequeues on each broker. -Use multiple CPG groups to process different queues in parallel. Use a -fixed set of groups and hash queue names to choose the group for each -queue. +Each queue has an associated thread-context. Events for a queue are executed +in that queues context, in parallel with events for other queues. *** Requirements @@ -149,7 +149,7 @@ a release-queue event, allowing another interested broker to take ownership. *** Asynchronous completion of accept - +### HERE In acknowledged mode a message is not forgotten until it is accepted, to allow for requeue on rejection or crash. The accept should not be completed till the message has been forgotten. @@ -162,32 +162,19 @@ On receiving an accept the broker: NOTE: The message store does not currently implement asynchronous completions of accept, this is a bug. -*** Multiple CPG groups. - -The old cluster was bottlenecked by processing everything in a single -CPG deliver thread. - -The new cluster uses a set of CPG groups, one per core. Queue names -are hashed to give group indexes, so statistically queues are likely -to be spread over the set of groups. - -Operations on a given queue always use the same group, so we have -order within each queue, but operations on different queues can use -different groups giving greater throughput sending to CPG and multiple -handler threads to process CPG messages. - ** Inconsistent errors. -An inconsistent error means that after multicasting an enqueue, accept -or dequeue, some brokers succeed in processing it and others fail. +The new design eliminates most sources of inconsistent errors +(connections, sessions, security, management etc.) The only points +where inconsistent errors can occur are at enqueue and dequeue (most +likely store-related errors.) -The new design eliminates most sources of inconsistent errors in the -old broker: connections, sessions, security, management etc. Only -store journal errors remain. +The new design can use the exisiting error-handling protocol with one +major improvement: since brokers are no longer required to maintain +identical state they do not have to stall processing while an error is +being resolved. -The new inconsistent error protocol is similar to the old one with one -major improvement: brokers do not have to stall processing while an -error is being resolved. +#TODO: The only source of dequeue errors is probably an unrecoverable journal failure. ** Updating new members @@ -206,44 +193,60 @@ catch up (which is not guaranteed to happen in a bounded time.) With the new cluster design only exchanges, queues, bindings and messages need to be replicated. -We update individual objects (queues and exchanges) independently. -- create queues first, then update all queues and exchanges in parallel. -- multiple updater threads, per queue/exchange. +Update of wiring (exchanges, queues, bindings) is the same as current +design. + +Update of messages is different: +- per-queue rather than per-broker, separate queues can be updated in parallel. +- updates queues in reverse order to eliminate unbounded catch-up +- does not require updater & updatee to stall during update. -Queue updater: -- marks the queue position at the sync point -- sends messages starting from the sync point working towards the head of the queue. -- send "done" message. +Replication events, multicast to cluster: +- enqueue(q,m): message m pushed on back of queue q . +- acquire(q,m): mark m acquired +- dequeue(q,m): forget m. +Messages sent on update connection: +- update_front(q,m): during update, receiver pushes m to *front* of q +- update_done(q): during update, update of q is complete. -Queue updatee: -- enqueues received from CPG: add to back of queue as normal. -- dequeues received from CPG: apply if found, else save to check at end of update. -- messages from updater: add to the *front* of the queue. -- update complete: apply any saved dequeues. +Updater: +- when updatee joins set iterator i = q.end() +- while i != q.begin(): --i; send update_front(q,*i) to updatee +- send update_done(q) to updatee -Exchange updater: -- updater: send snapshot of exchange as it was at the sync point. +Updatee: +- q initially in locked state, can't dequeue locally. +- start processing replication events for q immediately (enqueue, dequeue, acquire etc.) +- receive update_front(q,m): q.push_front(m) +- receive update_done(q): q can be unlocked for local dequeing. -Exchange updatee: -- queue exchange operations after the sync point. -- when snapshot is received: apply saved operations. +Benefits: +- Stall only for wiring update: updater & updatee can process multicast messages while messages are updated. +- No unbounded catch-up: update consists of at most N update_front() messages where N=q.size() at start of update. +- During update consumers actually help by removing messages before they need to be updated. +- Needs no separate "work to do" queue, only the broker queues themselves. -Note: -- Updater is active throughout, no stalling. -- Consuming clients actually reduce the size of the update. -- Updatee stalls clients until the update completes. - (Note: May be possible to avoid updatee stall as well, needs thought) +# TODO how can we recover from updater crashing before update complete? +# Clear queues that are not updated & send request for udpates on those queues? -** Internal cluster interface +# TODO updatee may receive a dequeue for a message it has not yet seen, needs +# to hold on to that so it can drop the message when it is seen. +# Similar problem exists for wiring? -The new cluster interface is similar to the MessageStore interface, but -provides more detail (message positions) and some additional call -points (e.g. acquire) +** Cluster API + +The new cluster API is similar to the MessageStore interface. +(Initially I thought it would be an extension of the MessageStore interface, +but as the design develops it seems better to make it a separate interface.) The cluster interface captures these events: - wiring changes: queue/exchange declare/bind - message enqueued/acquired/released/rejected/dequeued. -- transactional events. + +The cluster will require some extensions to the Queue: +- Queues can be "locked", locked queues are ignored by IO-driven output. +- Cluster must be able to apply queue events from the cluster to a queue. + These appear to fit into existing queue operations. ** Maintainability @@ -270,48 +273,106 @@ A number of specific ways the code will be simplified: ** Performance -The standalone broker processes _connections_ concurrently, so CPU -usage increases as you add more connections. - -The new cluster processes _queues_ concurrently, so CPU usage increases as you -add more queues. - -In both cases, CPU usage peaks when the number of "units of - concurrency" (connections or queues) goes above the number of cores. - -When all consumers on a queue are connected to the same broker the new -cluster uses the same messagea allocation threading/logic as a -standalone broker, with a little extra asynchronous book-keeping. - -If a queue has multiple consumers connected to multiple brokers, the -new cluster time-shares the queue which is less efficient than having -all consumers on a queue connected to the same broker. +The only way to verify the relative performance of the new design is +to prototype & profile. The following points suggest the new design +may scale/perform better: + +Some work moved from virtual synchrony thread to connection threads: +- All connection/session logic moves to connection thread. +- Exchange routing logic moves to connection thread. +- On local broker dequeueing is done in connection thread +- Local broker dequeue is IO driven as for a standalone broker. + +For queues with all consumers on a single node dequeue is all +IO-driven in connection thread. Pay for time-sharing only if queue has +consumers on multiple brokers. + +Doing work for different queues in parallel scales on multi-core boxes when +there are multiple queues. + +One difference works against performance, thre is an extra +encode/decode. The old design multicasts raw client data and decodes +it in the virtual synchrony thread. The new design would decode +messages in the connection thread, re-encode them for multicast, and +decode (on non-local brokers) in the virtual synchrony thread. There +is extra work here, but only in the *connection* thread: on a +multi-core machine this happens in parallel for every connection, so +it probably is not a bottleneck. There may be scope to optimize +decode/re-encode by re-using some of the original encoded data, this +could also benefit the stand-alone broker. + +** Asynchronous queue replication + +The existing "asynchronous queue replication" feature maintains a +passive backup passive backup of queues on a remote broker over a TCP +connection. + +The new cluster replication protocol could be re-used to implement +asynchronous queue replication: its just a special case where the +active broker is always the queue owner and the enqueue/dequeue +messages are sent over a TCP connection rather than multicast. + +The new update update mechanism could also work with 'asynchronous +queue replication', allowing such replication (over a TCP connection +on a WAN say) to be initiated after the queue had already been created +and been in use (one of the key missing features). + +** Increasing Concurrency and load sharing + +The current cluster is bottlenecked by processing everything in the +CPG deliver thread. By removing the need for identical operation on +each broker, we open up the possiblility of greater concurrency. + +Handling multicast enqueue, acquire, accpet, release etc: concurrency +per queue. Operatons on different queues can be done in different +threads. + +The new design does not force each broker to do all the work in the +CPG thread so spreading load across cluster members should give some +scale-up. + +** Misc outstanding issues & notes + +Replicating wiring +- Need async completion of wiring commands? +- qpid.sequence_counter: need extra work to support in new design, do we care? + +Cluster+persistence: +- finish async completion: dequeue completion for store & cluster +- cluster restart from store: clean stores *not* identical, pick 1, all others update. +- need to generate cluster ids for messages recovered from store. + +Live updates: we don't need to stall brokers during an update! +- update on queue-by-queue basis. +- updatee locks queues during update, no dequeue. +- update in reverse: don't update messages dequeued during update. +- updatee adds update messages at front (as normal), replicated messages at back. +- updater starts from back, sends "update done" when it hits front of queue. + +Flow control: need to throttle multicasting +1. bound the number of outstanding multicasts. +2. ensure the entire cluster keeps up, no unbounded "lag" +The existing design uses read-credit to solve 1., and does not solve 2. +New design should stop reading on all connections while flow control +condition exists? + +Can federation also be unified, at least in configuration? + +Consider queues (and exchanges?) as having "reliability" attributes: +- persistent: is the message stored on disk. +- backed-up (to another broker): active/passive async replication. +- replicated (to a cluster): active/active multicast replication to cluster. +- federated: federation link to a queue/exchange on another broker. + +"Reliability" seems right for the first 3 but not for federation, is +there a better term? + +Clustering and scalability: new design may give us the flexibility to +address scalability as part of cluster design. Think about +relationship to federation and "fragmented queues" idea. + +* Design debates/descisions -** Flow control -New design does not queue up CPG delivered messages, they are -processed immediately in the CPG deliver thread. This means that CPG's -flow control is sufficient for qpid. - -** Live upgrades - -Live upgrades refers to the ability to upgrade a cluster while it is -running, with no downtime. Each brokers in the cluster is shut down, -and then re-started with a new version of the broker code. - -To achieve this -- Cluster protocl XML file has a new element <version number=N> attached - to each method. This is the version at which the method was added. -- New versions can only add methods, existing methods cannot be changed. -- The cluster handshake for new members includes the protocol version - at each member. -- The cluster's version is the lowest version among its members. -- A newer broker can join and older cluster. When it does, it must restrict - itself to speaking the older version protocol. -- When the cluster version increases (because the lowest version member has left) - the remaining members may move up to the new version. - - -* Design debates ** Active/active vs. active passive An active-active cluster can be used in an active-passive mode. In @@ -324,7 +385,7 @@ An active/passive implementation allows some simplifications over active/active: - can do immediate local enqueue and still guarantee order. Active/passive introduces a few extra requirements: -- Exactly one broker has to take over if primary fails. +- Exactly one broker hast to take over if primary fails. - Passive members must refuse client connections. - On failover, clients must re-try all known addresses till they find the active member. @@ -332,17 +393,43 @@ Active/active benefits: - A broker failure only affects the subset of clients connected to that broker. - Clients can switch to any other broker on failover - Backup brokers are immediately available on failover. -- As long as a client can connect to any broker in the cluster, it can be served. +- Some load sharing: reading from client + multicast only done on direct node. + +Active/active drawbacks: +- Co-ordinating message acquisition may impact performance (not tested) +- Code may be more complex that active/passive. Active/passive benefits: -- Don't need to replicate message allocation, can feed consumers at top speed. +- Don't need message allocation strategy, can feed consumers at top speed. +- Code may be simpler than active/active. Active/passive drawbacks: - All clients on one node so a failure affects every client in the system. - After a failure there is a "reconnect storm" as every client reconnects to the new active node. - After a failure there is a period where no broker is active, until the other brokers realize the primary is gone and agree on the new primary. - Clients must find the single active node, may involve multiple connect attempts. -- No service if a partition separates a client from the active broker, - even if the client can see other brokers. +** Total ordering. + +Initial thinking: allow message ordering to differ between brokers. +New thinking: use CPG total ordering, get identical ordering on all brokers. +- Allowing variation in order introduces too much chance of unexpected behavior. +- Usign total order allows other optimizations, see Message Identifiers below. + +** Message identifiers. + +Initial thinking: message ID = CPG node id + 64 bit sequence number. +This involves a lot of mapping between cluster IDs and broker messsages. + +New thinking: message ID = queue name + queue position. +- Removes most of the mapping and memory management for cluster code. +- Requires total ordering of messages (see above) + +** Message rejection + +Initial thinking: add special reject/rejected points to cluster interface so +rejected messages could be re-queued without multicast. +New thinking: treat re-queueing after reject as entirely new message. +- Simplifies cluster interface & implementation +- Not on the critical path. diff --git a/cpp/design_docs/new-cluster-plan.txt b/cpp/design_docs/new-cluster-plan.txt index 32e3f710e7..781876e55a 100644 --- a/cpp/design_docs/new-cluster-plan.txt +++ b/cpp/design_docs/new-cluster-plan.txt @@ -17,150 +17,376 @@ # specific language governing permissions and limitations # under the License. -* Status of impementation -Meaning of priorities: -[#A] Essential for basic functioning. -[#B] Required for first release. -[#C] Can be addressed in a later release. +Notes on new cluster implementation. See also: new-cluster-design.txt -The existig prototype is bare bones to do performance benchmarks: -- Implements publish and consumer locking protocol. -- Defered delivery and asynchronous completion of message. -- Optimize the case all consumers are on the same node. -- No new member updates, no failover updates, no transactions, no persistence etc. +* Implementation plan. -Prototype code is on branch qpid-2920-active, in cpp/src/qpid/cluster/exp/ +Co-existence with old cluster code and tests: +- Separate plugin cluster2, options --cluster2-*. Eventually renamed to replace cluster. +- Double up tests with old version/new version as the new code develops. -** Similarities to existing cluster. +Minimal POC for message delivery & perf test. +- no wiring replication, no updates, no failover, no persistence, no async completion. +- just implement publish and acquire/dequeue locking protocol. +- optimize the special case where all consumers are on the same node. +- measure performance: compare active-passive and active-active modes of use. -/Active-active/: the new cluster can be a drop-in replacement for the -old, existing tests & customer deployment configurations are still -valid. +Full implementation of transient cluster +- Update (based on existing update), async completion etc. +- Passing all existing transient cluster tests. -/Virtual synchrony/: Uses corosync to co-ordinate activity of members. +Persistent cluster +- Make sure async completion works correctly. +- InitialStatus protoocl etc. to support persistent start-up (existing code) +- cluster restart from store: stores not identical. Load one, update the rest. + - assign cluster ID's to messages recovered from store, don't replicate. -/XML controls/: Uses XML to define the primitives multicast to the -cluster. +Improved update protocol +- per-queue, less stalling, bounded catch-up. -** Differences with existing cluster. +* Task list -/Report rather than predict consumption/: brokers explicitly tell each -other which messages have been acquired or dequeued. This removes the -major cause of bugs in the existing cluster. +** TODO [#A] Minimal POC: publish/acquire/dequeue protocol. -/Queue consumer locking/: to avoid duplicates only one broker can acquire or -dequeue messages at a time - while has the consume-lock on the -queue. If multiple brokers are consuming from the same queue the lock -is passed around to time-share access to the queue. +NOTE: as implementation questions arise, take the easiest option and make +a note for later optimization/improvement. -/Per-queue concurrency/: uses a fixed-size set of CPG groups (reflecting -the concurrency of the host) to allow concurrent processing on -different queues. Queues are hashed onto the groups. +*** Tests +- python test: 4 senders, numbered messages, 4 receivers, verify message set. +- acquire then release messages: verify can be dequeued on any member +- acquire then kill broker: verify can be dequeued other members. +- acquire then reject: verify goes on alt-exchange once only. -* Completed tasks -** DONE [#A] Minimal POC: publish/acquire/dequeue protocol. - CLOSED: [2011-10-05 Wed 16:03] +*** DONE broker::Cluster interface and call points. -Defines broker::Cluster interface and call points. -Initial interface commite +Initial interface commited. -Main classes -Core: central object holding cluster classes together (replaces cluster::Cluster) -BrokerContext: implements broker::Cluster interface. -QueueContext: Attached to a broker::Queue, holds cluster status. -MessageHolder:holds local messages while they are being enqueued. +*** Main classes -Implements multiple CPG groups for better concurrency. +BrokerHandler: +- implements broker::Cluster intercept points. +- sends mcast events to inform cluster of local actions. +- thread safe, called in connection threads. -** DONE [#A] Large message replication. - CLOSED: [2011-10-05 Wed 17:22] -Multicast using fixed-size (64k) buffers, allow fragmetation of messages across buffers (frame by frame) +LocalMessageMap: +- Holds local messages while they are being enqueued. +- thread safe: called by both BrokerHandler and MessageHandler + +MessageHandler: +- handles delivered mcast messages related to messages. +- initiates local actions in response to mcast events. +- thread unsafe, only called in deliver thread. +- maintains view of cluster state regarding messages. -* Open questions +QueueOwnerHandler: +- handles delivered mcast messages related to queue consumer ownership. +- thread safe, called in deliver, connection and timer threads. +- maintains view of cluster state regarding queue ownership. + +cluster::Core: class to hold new cluster together (replaces cluster::Cluster) +- thread safe: manage state used by both MessageHandler and BrokerHandler + +The following code sketch illustrates only the "happy path" error handling +is omitted. + +*** BrokerHandler +Types: +- struct QueuedMessage { Message msg; QueueName q; SequenceNumber position; } +- struct + +NOTE: +- Messages on queues are identified by a queue name + a position. +- Messages being routed are identified by a sequence number. + +Members: +- thread_local bool noReplicate // suppress replication. +- thread_local bool isRouting // suppress operations while routing +- Message localMessage[SequenceNumber] // local messages being routed. +- thread_local SequenceNumber routingSequence + +NOTE: localMessage is also modified by MessageHandler. + +broker::Cluster intercept functions: + +routing(msg) + if noReplicate: return + # Supress everything except enqueues while we are routing. + # We don't want to replicate acquires & dequeues caused by an enqueu, + # e.g. removal of messages from ring/LV queues. + isRouting = true + +enqueue(qmsg): + if noReplicate: return + if routingSequence == 0 # thread local + routingSequence = nextRoutingSequence() + mcast create(encode(qmsg.msg),routingSeq) + mcast enqueue(qmsg.q,routingSeq) + +routed(msg): + if noReplicate: return + isRouting = false + +acquire(qmsg): + if noReplicate: return + if isRouting: return # Ignore while we are routing a message. + if msg.id: mcast acquire(qmsg) + +release(QueuedMessage) + if noReplicate: return + if isRouting: return # Ignore while we are routing a message. + mcast release(qmsg) + +accept(QueuedMessage): + if noReplicate: return + if isRouting: return # Ignore while we are routing a message. + mcast accept(qmsg) + +reject(QueuedMessage): + isRejecting = true + mcast reject(qmsg) + +# FIXME no longer needed? +drop(QueuedMessage) + cleanup(qmsg) + +*** MessageHandler and mcast messages +Types: +- struct QueueEntry { QueuedMessage qmsg; NodeId acquired; } +- struct QueueKey { MessageId id; QueueName q; } +- typedef map<QueueKey, QueueEntry> Queue +- struct Node { Message routing[SequenceNumber]; list<QueueKey> acquired; } + +Members: +- QueueEntry enqueued[QueueKey] +- Node node[NodeId] + +Mcast messages in Message class: + +create(msg,seq) + if sender != self: node[sender].routing[seq] = decode(msg) + +enqueue(q,seq): + id = (sender,seq) + if sender == self: + enqueued[id,q] = (localMessage[seq], acquired=None) + else: + msg = sender.routing[seq] + enqueued[id,q] = (qmsg, acquired=None) + with noReplicate=true: qmsg = broker.getQueue(q).push(msg) + +routed(seq): + if sender == self: localMessage.erase(msg.id.seq) + else: sender.routing.erase(seq) + +acquire(id,q): + enqueued[id,q].acquired = sender + node[sender].acquired.push_back((id,q)) + if sender != self: + with noReplicate=true: broker.getQueue(q).acquire(enqueued[id,q]) + +release(id,q) + enqueued[id,q].acquired = None + node[sender].acquired.erase((id,q)) + if sender != self + with noReplicate=true: broker.getQueue(q).requeue(enqueued[id,q]) + +reject(id,q): + sender.routing[id] = enqueued[id,q] # prepare for re-queueing + +rejected(id,q) + sender.routing.erase[id] + +dequeue(id,q) + entry = enqueued[id,q] + enqueued.erase[id,q] + node[entry.acquired].acquired.erase(id,q) + if sender != self: + with noReplicate=true: broker.getQueue(q).dequeue(entry.qmsg) + +member m leaves cluster: + for key in node[m].acquired: + release(key.id, key.q) + node.erase(m) + +*** Queue consumer locking + +When a queue is locked it does not deliver messages to its consumers. + +New broker::Queue functions: +- stopConsumers(): set consumersStopped flag, wait for currently busy consumers to exit. +- startConsumers(): reset consumersStopped flag + +Implementation sketch, locking omitted: + +void Queue::stopConsumers() { + consumersStopped = true; + while (consumersBusy) consumersBusyMonitor.wait(); +} + +void Queue::startConsumers() { + consumersStopped = false; + listeners.notify(); +} + +bool Queue::dispatch(consumer) { + if (consumersStopped) return false; + ++consumersBusy; + do_regular_dispatch_body() + if (--consumersBusy == 0) consumersBusyMonitor.notify(); +} + +*** QueueOwnerHandler + +Invariants: +- Each queue is owned by at most one node at any time. +- Each node is interested in a set of queues at any given time. +- A queue is un-owned if no node is interested. + +The queue owner releases the queue when +- it loses interest i.e. queue has no consumers with credit. +- a configured time delay expires and there are other interested nodes. + +The owner mcasts release(q). On delivery the new queue owner is the +next node in node-id order (treating nodes as a circular list) +starting from the old owner that is interested in the queue. + +Queue consumers initially are stopped, only started when we get +ownership from the cluster. + +Thread safety: called by deliver, connection and timer threads, needs locking. + +Thread safe object per queue holding queue ownership status. +Called by deliver, connection and timer threads. + +class QueueOwnership { + bool owned; + Timer timer; + BrokerQueue q; + + drop(): # locked + if owned: + owned = false + q.stopConsumers() + mcast release(q.name, false) + timer.stop() + + take(): # locked + if not owned: + owned = true + q.startConsumers() + timer.start(timeout) + + timer.fire(): drop() +} + +Data Members, only modified/examined in deliver thread: +- typedef set<NodeId> ConsumerSet +- map<QueueName, ConsumerSet> consumers +- map<QueueName, NodeId> owner -** TODO [#A] Queue sequence numbers vs. independant message IDs. - SCHEDULED: <2011-10-07 Fri> +Thread safe data members, accessed in connection threads (via BrokerHandler): +- map<QueueName, QueueOwnership> ownership -Current prototype uses queue sequence numbers to identify -message. This is tricky for updating new members as the sequence -numbers are only known on delivery. +Multicast messages in QueueOwner class: -Independent message IDs that can be generated and sent with the message simplify -this and potentially allow performance benefits by relaxing total ordering. -However they imply additional map lookups that might hurt performance. +consume(q): + if sender==self and consumers[q].empty(): ownership[q].take() + consumers[q].insert(sender) -- [ ] Prototype independent message IDs, check performance. +release(q): + asssert(owner[q] == sender and owner[q] in consumers[q]) + owner[q] = circular search from sender in consumers[q] + if owner==self: ownership[q].take() -* Outstanding Tasks -** TODO [#A] Defer and async completion of wiring commands. +cancel(q): + assert(queue[q].owner != sender) # sender must release() before cancel() + consumers[q].erase(sender) -Testing requirement: Many tests assume wiring changes are visible -across the cluster once the commad completes. +member-leaves: + for q in queue: if owner[q] = left: left.release(q) -Name clashes: need to avoid race if same name queue/exchange declared -on 2 brokers simultaneously +Need 2 more intercept points in broker::Cluster: -** TODO [#A] Passing all existing cluster tests. +consume(q,consumer,consumerCount) - Queue::consume() + if consumerCount == 1: mcast consume(q) -The new cluster should be a drop-in replacement for the old, so it -should be able to pass all the existing tests. +cancel(q,consumer,consumerCount) - Queue::cancel() + if consumerCount == 0: + ownership[q].drop() + mcast cancel(q) -** TODO [#A] Update to new members joining. +#TODO: lifecycle, updating cluster data structures when queues are destroyed + +*** Increasing concurrency +The major performance limitation of the old cluster is that it does +everything in the single CPG deliver thread context. + +We can get additional concurrency by creating a thread context _per queue_ +for queue operations: enqueue, acquire, accept etc. + +We associate a PollableQueue of queue operations with each AMQP queue. +The CPG deliver thread would +- build messages and associate with cluster IDs. +- push queue ops to the appropriate PollableQueue to be dispatched the queues thread. + +Serializing operations on the same queue avoids contention, but takes advantage +of the independence of operations on separate queues. -Need to resolve [[Queue sequence numbers vs. independant message IDs]] first. -- implicit sequence numbers are more tricky to replicate to new member. +*** Re-use of existing cluster code +- re-use Event +- re-use Multicaster +- re-use same PollableQueueSetup (may experiment later) +- new Core class to replace Cluster. +- keep design modular, keep threading rules clear. -Update individual objects (queues and exchanges) independently. -- create queues first, then update all queues and exchanges in parallel. -- multiple updater threads, per queue/exchange. -- updater sends messages to special exchange(s) (not using extended AMQP controls) +** TODO [#B] Large message replication. +Multicast should encode messages in fixed size buffers (64k)? +Can't assume we can send message in one chunk. +For 0-10 can use channel numbers & send whole frames packed into larger buffer. +** TODO [#B] Transaction support. +Extend broker::Cluster interface to capture transaction context and completion. +Sequence number to generate per-node tx IDs. +Replicate transaction completion. +** TODO [#B] Batch CPG multicast messages +The new cluster design involves a lot of small multicast messages, +they need to be batched into larger CPG messages for efficiency. +** TODO [#B] Genuine async completion +Replace current synchronous waiting implementation with genuine async completion. -Queue updater: -- marks the queue position at the sync point -- sends messages starting from the sync point working towards the head of the queue. -- send "done" message. -Note: updater remains active throughout, consuming clients actually reduce the -size of the update. +Test: enhance test_store.cpp to defer enqueueComplete till special message received. -Queue updatee: -- enqueues received from CPG: add to back of queue as normal. -- dequeues received from CPG: apply if found, else save to check at end of update. -- messages from updater: add to the *front* of the queue. -- update complete: apply any saved dequeues. +Async callback uses *requestIOProcessing* to queue action on IO thread. -Exchange updater: -- updater: send snapshot of exchange as it was at the sync point. +** TODO [#B] Async completion of accept when dequeue completes. +Interface is already there on broker::Message, just need to ensure +that store and cluster implementations call it appropriately. -Exchange updatee: -- queue exchange operations after the sync point. -- when snapshot is received: apply saved operations. +** TODO [#B] Replicate wiring. +From messageStore create/destroy/bind, replicate encoded declare/destroy/bind command. -Updater remains active throughout. -Updatee stalls clients until the update completes. +** TODO [#B] New members joining - first pass -Updating queue/exchange/binding objects is via the same encode/decode -that is used by the store. Updatee to use recovery interfaces to -recover? +Re-use update code from old cluster but don't replicate sessions & +connections. -** TODO [#A] Failover updates to client. -Implement the amq.failover exchange to notify clients of membership. +Need to extend it to send cluster IDs with messages. -** TODO [#B] Initial status protocol. -Handshake to give status of each broker member to new members joining. -Status includes -- persistent store state (clean, dirty) -- cluster protocol version. +Need to replicate the queue ownership data as part of the update. -** TODO [#B] Persistent cluster support. -Initial status protoocl to support persistent start-up (see existing code) +** TODO [#B] Persistence support. +InitialStatus protoocl etc. to support persistent start-up (existing code) Only one broker recovers from store, update to others. Assign cluster IDs to messages recovered from store, don't replicate. See Queue::recover. -** TODO [#B] Management support -Replicate management methods that modify queues - e.g. move, purge. +** TODO [#B] Handle other ways that messages can leave a queue. + +Other ways (other than via a consumer) that messages are take off a queue. + +NOTE: Not controlled by queue lock, how to make them consistent? + Target broker may not have all messages on other brokers for purge/destroy. - Queue::move() - need to wait for lock? Replicate? - Queue::get() - ??? @@ -169,38 +395,66 @@ Target broker may not have all messages on other brokers for purge/destroy. Need to add callpoints & mcast messages to replicate these? -** TODO [#B] TX transaction support. -Extend broker::Cluster interface to capture transaction context and completion. -Running brokers exchange TX information. -New broker update includes TX information. - - // FIXME aconway 2010-10-18: As things stand the cluster is not - // compatible with transactions - // - enqueues occur after routing is complete - // - no call to Cluster::enqueue, should be in Queue::process? - // - no transaction context associated with messages in the Cluster interface. - // - no call to Cluster::accept in Queue::dequeueCommitted - -** TODO [#B] DTX transaction support. -Extend broker::Cluster interface to capture transaction context and completion. -Running brokers exchange DTX information. -New broker update includes DTX information. - -** TODO [#B] Async completion of accept. -When this is fixed in the standalone broker, it should be fixed for cluster. - -** TODO [#B] Network partitions and quorum. -Re-use existing implementation. +** TODO [#B] Flow control for internal queues. + +Need to bound the size of internal queues: delivery and multicast. +- stop polling for read on client connections when we reach a bound. +- restart polling when we get back under it. + +That will stop local multicasting, we still have to deal with remote +multicasting (note existing cluster does not do this.) Something like: +- when over bounds multicast a flow-control event. +- on delivery of flow-control all members stop polling to read client connections +- when back under bounds send flow-control-end, all members resume +- if flow-controling member dies others resume + +** TODO [#B] Integration with transactions. +Do we want to replicate during transaction & replicate commit/rollback +or replicate only on commit? +No integration with DTX transactions. +** TODO [#B] Make new cluster work with replication exchange. +Possibly re-use some common logic. Replication exchange is like clustering +except over TCP. +** TODO [#B] Better concurrency, scalabiility on multi-cores. +Introduce PollableQueue of operations per broker queue. Queue up mcast +operations (enqueue, acquire, accept etc.) to be handled concurrently +on different queue. Performance testing to verify improved scalability. +** TODO [#C] Async completion for declare, bind, destroy queues and exchanges. +Cluster needs to complete these asynchronously to guarantee resources +exist across the cluster when the command completes. ** TODO [#C] Allow non-replicated exchanges, queues. -Set qpid.replicate=false in declare arguments, set flag on Exchange, Queue objects. +Set qpid.replicated=false in declare arguments, set flag on Exchange, Queue objects. - save replicated status to store. - support in management tools. +Replicated exchange: replicate binds to replicated queues. Replicated queue: replicate all messages. -Replicated exchange: replicate bindings to replicated queues only. -Configurable default? Defaults to true. +** TODO [#C] New members joining - improved. + +Replicate wiring like old cluster, stall for wiring but not for +messages. Update messages on a per-queue basis from back to front. + +Updater: +- stall & push wiring: declare exchanges, queues, bindings. +- start update iterator thread on each queue. +- unstall and process normally while iterator threads run. + +Update iterator thread: +- starts at back of updater queue, message m. +- send update_front(q,m) to updatee and advance towards front +- at front: send update_done(q) + +Updatee: +- stall, receive wiring, lock all queues, mark queues "updating", unstall +- update_front(q,m): push m to *front* of q +- update_done(q): mark queue "ready" + +Updatee cannot take the queue consume lock for a queue that is updating. +Updatee *can* push messages onto a queue that is updating. + +TODO: Is there any way to eliminate the stall for wiring? ** TODO [#C] Refactoring of common concerns. @@ -215,40 +469,9 @@ Look for ways to capitalize on the similarity & simplify the code. In particular QueuedEvents (async replication) strongly resembles cluster replication, but over TCP rather than multicast. - +** TODO [#C] Concurrency for enqueue events. +All enqueue events are being processed in the CPG deliver thread context which +serializes all the work. We only need ordering on a per queue basis, can we +enqueue in parallel on different queues and will that improve performance? ** TODO [#C] Handling immediate messages in a cluster Include remote consumers in descision to deliver an immediate message? -** TODO [#C] Remove old cluster hacks and workarounds -The old cluster has workarounds in the broker code that can be removed. -- [ ] drop code to replicate management model. -- [ ] drop timer workarounds for TTL, management, heartbeats. -- [ ] drop "cluster-safe assertions" in broker code. -- [ ] drop connections, sessions, management from cluster update. -- [ ] drop security workarounds: cluster code now operates after message decoding. -- [ ] drop connection tracking in cluster code. -- [ ] simper inconsistent-error handling code, no need to stall. -** TODO [#C] Support for live upgrades. - -Allow brokers in a running cluster to be replaced one-by-one with a new version. - -The old cluster protocol was unstable because any changes in broker -state caused changes to the cluster protocol.The new design should be -much more stable. - -Points to implement: -- Brokers should ignore unknown controls (with a warning) rather than an error. -- Limit logging frequency for unknown control warnings. -- Add a version number at front of every CPG message. Determines how the - rest of the message is decoded. (allows for entirely new encodings e.g. AMQP 1.0) -- Protocol version XML element in cluster.xml, on each control. -- Initial status protocol to include protocol version number. - -** TODO [#C] Support for AMQP 1.0. - -* Testing -** TODO [#A] Pass all existing cluster tests. -Requires [[Defer and async completion of wiring commands.]] -** TODO [#A] New cluster tests. -Stress tests & performance benchmarks focused on changes in new cluster: -- concurrency by queues rather than connections. -- different handling shared queues when consuemrs are on different brokers. diff --git a/cpp/docs/api/developer.doxygen.in b/cpp/docs/api/developer.doxygen.in index 1e1fddab80..fd3a9ac621 100644 --- a/cpp/docs/api/developer.doxygen.in +++ b/cpp/docs/api/developer.doxygen.in @@ -1029,7 +1029,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= QMFE_EXTERN= +PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/cpp/docs/api/doxygen_mainpage.h b/cpp/docs/api/doxygen_mainpage.h index 9acae52da4..cb36d7edb0 100644 --- a/cpp/docs/api/doxygen_mainpage.h +++ b/cpp/docs/api/doxygen_mainpage.h @@ -266,46 +266,7 @@ * else * session.rollback(); * </pre> - * - * <h3>Exceptions</h3> - * - * All exceptions for the messaging API have MessagingException as - * their base class. - - * A common class of exception are those related to processing - * addresses used to create senders and/or receivers. These all have - * AddressError as their base class. - * - * Where there is a syntax error in the address itself, a - * MalformedAddress will be thrown. Where the address is valid, but - * there is an error in interpreting (i.e. resolving) it, a - * ResolutionError - or a sub-class of it - will be thrown. If the - * address has assertions enabled for a given context and the asserted - * node properties are not in fact correct then AssertionFailed will - * be thrown. If the node is not found, NotFound will be thrown. - * - * The loss of the underlying connection (e.g. the TCP connection) - * results in TransportFailure being thrown. If automatic reconnect is - * enabled, this will be caught be the library which will then try to - * reconnect. If reconnection - as configured by the connection - * options - fails, then TransportFailure will be thrown. This can - * occur on any call to the messaging API. - * - * Sending a message may also result in an exception - * (e.g. TargetCapacityExceeded if a queue to which the message is - * delivered cannot enqueue it due to lack of capacity). For - * asynchronous send the exception may not be thrown on the send - * invocation that actually triggers it, but on a subsequent method - * call on the API. - * - * Certain exceptions may render the session invalid; once these - * occur, subsequent calls on the session will throw the same class of - * exception. This is not an intrinsic property of the class of - * exception, but is a result of the current mapping of the API to the - * underlying AMQP 0-10 protocol. You can test whether the session is - * valid at any time using the hasError() and/or checkError() methods - * on Session. - * + * * <h3>Logging</h3> * * The Qpidd broker and C++ clients can both use environment variables to diff --git a/cpp/docs/api/footer.html b/cpp/docs/api/footer.html index 5a31e81821..883410ce25 100644 --- a/cpp/docs/api/footer.html +++ b/cpp/docs/api/footer.html @@ -25,7 +25,7 @@ Qpid C++ API Reference</small></address> <address style="text-align: right;"> <small> -Generated on $date for $projectname by <a href="http://www.doxygen.org/index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> $doxygenversion</small> +Generated on $datetime for $projectname by <a href="http://www.doxygen.org/index.html"><img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> $doxygenversion</small> </address> </body> </html> diff --git a/cpp/docs/api/user.doxygen.in b/cpp/docs/api/user.doxygen.in index ec0fd1361c..2728df47e4 100644 --- a/cpp/docs/api/user.doxygen.in +++ b/cpp/docs/api/user.doxygen.in @@ -1021,7 +1021,7 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= QMFE_EXTERN= +PREDEFINED = QPID_CLIENT_EXTERN= QPID_COMMON_EXTERN= QPID_CONSOLE_EXTERN= QPID_BROKER_EXTERN= QPID_MESSAGING_EXTERN= QMF_EXTERN= # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/cpp/docs/man/Makefile.am b/cpp/docs/man/Makefile.am index b821568f81..14295f73bf 100644 --- a/cpp/docs/man/Makefile.am +++ b/cpp/docs/man/Makefile.am @@ -16,29 +16,10 @@ # specific language governing permissions and limitations # under the License. # - -# Generate makefile from qpidd --help -# -# Note: qiddd.1 is normally a _checked in_ pre-generated file, so that -# make dist does not have to build the entire source just for the man page. -# -# To update the checked-in file (e.g. for a new release) do the following: -# -# - start with a completely clean checkout. -# - make sure there are no modules installed in your configured prefix, -# we don't want to pick up configuration from optional modules -# - do bootstrap; configure -# - in build-dir: cd src; make # build the broker -# - in source-dir: cd docs/man; rm qpidd.1 # remove checked-in man page. -# - in build-dir: cd docs/man; make # make new man page -# - edit qpidd.1 to remove all default values referring to file/directory locations. -# these values will differ between builds depending on configuration. -# - if source-dir != build-dir: copy qpidd.1 from build-dir/docs/man to source-dir/docs/man - dist_man_MANS = qpidd.1 -man_aux = $(dist_man_MANS:.1=.x) -EXTRA_DIST = $(man_aux) generate_manpage groffify_options.sed groffify_template.sed +man_aux = $(dist_man_MANS:.1=.x) +EXTRA_DIST = $(man_aux) generate_manpage groffify_options.sed groffify_template.sed DISTCLEANFILES = $(dist_man_MANS) CLEANFILES=qpidd.1 diff --git a/cpp/docs/man/qpidd.1 b/cpp/docs/man/qpidd.1 deleted file mode 100644 index d2cff454cf..0000000000 --- a/cpp/docs/man/qpidd.1 +++ /dev/null @@ -1,247 +0,0 @@ -.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. -.TH QPIDD "1" "March 2011" "qpidd (qpidc) version 0.11" "User Commands" -.SH NAME - -qpidd \- the Qpid AMQP Message Broker Daemon -.SH SYNOPSIS - -qpidd [-p port] [--config config_file] [--data-dir directory] -.SH DESCRIPTION - -An AMQP message broker daemon that stores, routes and forwards -messages using the Advanced Message Queueing Protocol (AMQP). -.SH OPTIONS - -The options below are built-in to qpidd. Installing add-on modules provides additional options. To see the full set of options available type "qpidd --help" - -Options may be specified via command line, environment variable or configuration file. See FILES and ENVIRONMENT below for details. -.PP - -.TP -\fB\-h\fR [ \fB\-\-help\fR ] -Displays the help message -.TP -\fB\-v\fR [ \fB\-\-version\fR ] -Displays version information -.TP -\fB\-\-config\fR FILE -Reads configuration from FILE -.SS "Module options:" -.TP -\fB\-\-module\-dir\fR DIR -Load all shareable modules in this -directory -.TP -\fB\-\-load\-module\fR FILE -Specifies additional module(s) to be -loaded -.TP -\fB\-\-no\-module\-dir\fR -Don't load modules from module -directory -.SS "Broker Options:" -.TP -\fB\-\-data\-dir\fR DIR -Directory to contain persistent data -generated by the broker -.TP -\fB\-\-no\-data\-dir\fR -Don't use a data directory. No -persistent configuration will be loaded -or stored -.TP -\fB\-p\fR [ \fB\-\-port\fR ] PORT (5672) -Tells the broker to listen on PORT -.TP -\fB\-\-worker\-threads\fR N (3) -Sets the broker thread pool size -.TP -\fB\-\-max\-connections\fR N (500) -Sets the maximum allowed connections -.TP -\fB\-\-connection\-backlog\fR N (10) -Sets the connection backlog limit for -the server socket -.TP -\fB\-m\fR [ \fB\-\-mgmt\-enable\fR ] yes|no (1) -Enable Management -.TP -\fB\-\-mgmt\-qmf2\fR yes|no (1) -Enable broadcast of management -information over QMF v2 -.TP -\fB\-\-mgmt\-qmf1\fR yes|no (1) -Enable broadcast of management -information over QMF v1 -.TP -\fB\-\-mgmt\-pub\-interval\fR SECONDS (10) -Management Publish Interval -.TP -\fB\-\-queue\-purge\-interval\fR SECONDS (600) -Interval between attempts to purge any -expired messages from queues -.TP -\fB\-\-auth\fR yes|no (1) -Enable authentication, if disabled all -incoming connections will be trusted -.TP -\fB\-\-realm\fR REALM (QPID) -Use the given realm when performing -authentication -.TP -\fB\-\-default\-queue\-limit\fR BYTES (104857600) -Default maximum size for queues (in -bytes) -.TP -\fB\-\-tcp\-nodelay\fR -Set TCP_NODELAY on TCP connections -.TP -\fB\-\-require\-encryption\fR -Only accept connections that are -encrypted -.TP -\fB\-\-known\-hosts\-url\fR URL or 'none' -URL to send as 'known\-hosts' to clients -('none' implies empty list) -.TP -\fB\-\-sasl\-config\fR DIR -gets sasl config info from nonstandard -location -.TP -\fB\-\-max\-session\-rate\fR MESSAGES/S (0) -Sets the maximum message rate per -session (0=unlimited) -.TP -\fB\-\-async\-queue\-events\fR yes|no (0) -Set Queue Events async, used for -services like replication -.TP -\fB\-\-default\-flow\-stop\-threshold\fR PERCENT (80) -Percent of queue's maximum capacity at -which flow control is activated. -.TP -\fB\-\-default\-flow\-resume\-threshold\fR PERCENT (70) -Percent of queue's maximum capacity at -which flow control is de\-activated. -.TP -\fB\-\-default\-event\-threshold\-ratio\fR %age of limit (80) -The ratio of any specified queue limit -at which an event will be raised -.SS "Logging options:" -.TP -\fB\-t\fR [ \fB\-\-trace\fR ] -Enables all logging -.TP -\fB\-\-log\-enable\fR RULE (notice+) -Enables logging for selected levels and -components. RULE is in the form -\&'LEVEL[+][:PATTERN]' Levels are one of: -.IP -trace debug info notice warning error -.IP -critical -For example: -\&'\-\-log\-enable warning+' logs all -warning, error and critical messages. -\&'\-\-log\-enable debug:framing' logs debug -messages from the framing namespace. -This option can be used multiple times -.TP -\fB\-\-log\-time\fR yes|no (1) -Include time in log messages -.TP -\fB\-\-log\-level\fR yes|no (1) -Include severity level in log messages -.TP -\fB\-\-log\-source\fR yes|no (0) -Include source file:line in log -messages -.TP -\fB\-\-log\-thread\fR yes|no (0) -Include thread ID in log messages -.TP -\fB\-\-log\-function\fR yes|no (0) -Include function signature in log -messages -.TP -\fB\-\-log\-prefix\fR STRING -Prefix to append to all log messages -.SS "Logging sink options:" -.TP -\fB\-\-log\-to\-stderr\fR yes|no (1) -Send logging output to stderr -.TP -\fB\-\-log\-to\-stdout\fR yes|no (0) -Send logging output to stdout -.TP -\fB\-\-log\-to\-file\fR FILE -Send log output to FILE. -.TP -\fB\-\-log\-to\-syslog\fR yes|no (0) -Send logging output to syslog; -customize using \fB\-\-syslog\-name\fR and -\fB\-\-syslog\-facility\fR -.TP -\fB\-\-syslog\-name\fR NAME (lt\-qpidd) -Name to use in syslog messages -.TP -\fB\-\-syslog\-facility\fR LOG_XXX (LOG_DAEMON) -Facility to use in syslog messages -.SS "Daemon options:" -.TP -\fB\-d\fR [ \fB\-\-daemon\fR ] -Run as a daemon. Logs to syslog by -default in this mode. -.TP -\fB\-\-transport\fR TRANSPORT (tcp) -The transport for which to return the -port -.TP -\fB\-\-pid\-dir\fR DIR -Directory where port\-specific PID file -is stored -.TP -\fB\-w\fR [ \fB\-\-wait\fR ] SECONDS (600) -Sets the maximum wait time to -initialize the daemon. If the daemon -fails to initialize, prints an error -and returns 1 -.TP -\fB\-c\fR [ \fB\-\-check\fR ] -Prints the daemon's process ID to -stdout and returns 0 if the daemon is -running, otherwise returns 1 -.TP -\fB\-q\fR [ \fB\-\-quit\fR ] -Tells the daemon to shut down -.SH ENVIRONMENT -.I QPID_<option> -.RS -There is an environment variable for each option. -.RE - -The environment variable is the option name in uppercase, prefixed with QPID_ and '.' or '-' are replaced with '_'. Environment settings are over-ridden by command line settings. For example: - - export QPID_PORT=6000 - export QPID_MAX_CONNECTIONS=10 - export QPID_LOG_TO_FILE=/tmp/qpidd.log -.SH FILES -.I /etc/qpidd.conf -.RS -Default configuration file. -.RE - -Configuration file settings are over-ridden by command line or environment variable settings. '--config <file>' or 'export QPID_CONFIG=<file>' specifies an alternate file. - -Each line is a name=value pair. Blank lines and lines beginning with # are ignored. For example: - - # My qpidd configuration file. - port=6000 - max-connections=10 - log-to-file=/tmp/qpidd.log -.SH AUTHOR - -The Apache Qpid Project, dev@qpid.apache.org -.SH "REPORTING BUGS" - -Please report bugs to users@qpid.apache.org diff --git a/cpp/docs/man/qpidd.x b/cpp/docs/man/qpidd.x index 0ccf3b562a..af5d9628ee 100644 --- a/cpp/docs/man/qpidd.x +++ b/cpp/docs/man/qpidd.x @@ -13,8 +13,6 @@ messages using the Advanced Message Queueing Protocol (AMQP). [OPTIONS] -The options below are built-in to qpidd. Installing add-on modules provides additional options. To see the full set of options available type "qpidd --help" - Options may be specified via command line, environment variable or configuration file. See FILES and ENVIRONMENT below for details. [FILES] diff --git a/cpp/etc/Makefile.am b/cpp/etc/Makefile.am index 1e4db561a7..c91dbcbbad 100644 --- a/cpp/etc/Makefile.am +++ b/cpp/etc/Makefile.am @@ -30,7 +30,30 @@ nobase_sysconf_DATA = \ qpidd.conf if HAVE_SASL +SASL_DB = qpidd.sasldb + nobase_sysconf_DATA += \ $(SASL_CONF) +sasldbdir = $(localstatedir)/lib/qpidd +sasldb_DATA = $(SASL_DB) + +# Setup the default sasldb file with a single user, guest, with an +# obvious password. This user and password are the default for many +# clients. +# +# The realm specified by -u is very important, and QPID is the default +# for the broker so we use it here. The realm is important because it +# defaults to the local hostname of the machine running the +# broker. This may not seem to bad at first glance, but it means that +# the sasldb has to be tailored to each machine that would be running +# a broker, and if the machine ever changed its name the +# authentication would stop working until the sasldb was updated. For +# these reasons we always want the broker to specify a realm where its +# users live, and we want the users to exist in that realm as well. +$(SASL_DB): + echo guest | $(SASL_PASSWD) -c -p -f $(SASL_DB) -u QPID guest + +CLEANFILES=$(SASL_DB) + endif diff --git a/cpp/etc/qpidd.conf b/cpp/etc/qpidd.conf index bfe4e38bbd..8082660f6f 100644 --- a/cpp/etc/qpidd.conf +++ b/cpp/etc/qpidd.conf @@ -21,4 +21,4 @@ # # (Note: no spaces on either side of '='). Using default settings: # "qpidd --help" or "man qpidd" for more details. -cluster-mechanism=DIGEST-MD5 ANONYMOUS +cluster-mechanism=ANONYMOUS diff --git a/cpp/etc/sasl2/qpidd.conf b/cpp/etc/sasl2/qpidd.conf index d766cb8ef8..3197d7792a 100644 --- a/cpp/etc/sasl2/qpidd.conf +++ b/cpp/etc/sasl2/qpidd.conf @@ -17,8 +17,8 @@ # under the License. # # -# This configuation allows for either SASL ANONYMOUS or DIGEST-MD5 -# authentication. The DIGEST-MD5 authentication is done on a +# This configuation allows for either SASL PLAIN or ANONYMOUS +# authentication. The PLAIN authentication is done on a # username+password, which is stored in the sasldb_path # file. Usernames and passwords can be added to the file using the # command: @@ -39,7 +39,6 @@ pwcheck_method: auxprop auxprop_plugin: sasldb sasldb_path: /var/lib/qpidd/qpidd.sasldb -mech_list: DIGEST-MD5 ANONYMOUS #following line stops spurious 'sql_select option missing' errors when #cyrus-sql-sasl plugin is installed diff --git a/cpp/examples/CMakeLists.txt b/cpp/examples/CMakeLists.txt index 1b28cfd031..da8e39e944 100644 --- a/cpp/examples/CMakeLists.txt +++ b/cpp/examples/CMakeLists.txt @@ -77,14 +77,25 @@ macro(add_example subdir example) endmacro(add_example) install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.txt + ${CMAKE_CURRENT_SOURCE_DIR}/README.verify + ${CMAKE_CURRENT_SOURCE_DIR}/verify + ${CMAKE_CURRENT_SOURCE_DIR}/verify_all DESTINATION ${QPID_INSTALL_EXAMPLESDIR} COMPONENT ${QPID_COMPONENT_EXAMPLES}) if (MSVC) install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/examples.sln + ${CMAKE_CURRENT_SOURCE_DIR}/old-examples.sln DESTINATION ${QPID_INSTALL_EXAMPLESDIR} COMPONENT ${QPID_COMPONENT_EXAMPLES}) endif (MSVC) +add_subdirectory(direct) +add_subdirectory(failover) +add_subdirectory(fanout) +add_subdirectory(pub-sub) +#add_subdirectory(qmf-agent) add_subdirectory(qmf-console) +add_subdirectory(request-response) +add_subdirectory(tradedemo) +add_subdirectory(xml-exchange) add_subdirectory(messaging) -add_subdirectory(old_api) diff --git a/cpp/examples/Makefile.am b/cpp/examples/Makefile.am index 6b2bb73587..c6cc308d98 100644 --- a/cpp/examples/Makefile.am +++ b/cpp/examples/Makefile.am @@ -16,7 +16,15 @@ # specific language governing permissions and limitations # under the License. # -SUBDIRS = qmf-console messaging old_api +SUBDIRS = direct fanout pub-sub request-response failover qmf-console tradedemo messaging +if HAVE_XML + SUBDIRS += xml-exchange + broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so" +endif +if !HAVE_XML + exclude_examples_regexp="xml" # Exclude XML examples. + broker_args = "--no-module-dir --data-dir \"\" --auth no" +endif MAKEDIST=.libs/Makefile @@ -29,9 +37,13 @@ $(MAKEDIST): Makefile examplesdir=$(pkgdatadir)/examples dist_examples_DATA = README.txt $(MAKEDIST) -EXTRA_DIST = examples.sln CMakeLists.txt +EXTRA_DIST = README.verify verify verify_all examples.sln CMakeLists.txt # For older versions of automake abs_top_srcdir = @abs_top_srcdir@ abs_top_builddir = @abs_top_builddir@ +# Verify the examples in the buid tree. +check-local: + $(srcdir)/verify_all $(abs_top_srcdir)/.. $(abs_top_builddir) $(broker_args) $(exclude_examples_regexp) + diff --git a/cpp/examples/old_api/README.verify b/cpp/examples/README.verify index e1370764c9..e1370764c9 100644 --- a/cpp/examples/old_api/README.verify +++ b/cpp/examples/README.verify diff --git a/cpp/examples/old_api/direct/CMakeLists.txt b/cpp/examples/direct/CMakeLists.txt index 2ec1b2b813..2ec1b2b813 100644 --- a/cpp/examples/old_api/direct/CMakeLists.txt +++ b/cpp/examples/direct/CMakeLists.txt diff --git a/cpp/examples/old_api/direct/Makefile.am b/cpp/examples/direct/Makefile.am index 24f783fcc7..b07db2cfd6 100644 --- a/cpp/examples/old_api/direct/Makefile.am +++ b/cpp/examples/direct/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/direct +examplesdir=$(pkgdatadir)/examples/direct MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/direct/declare_queues.cpp b/cpp/examples/direct/declare_queues.cpp index 9a51d1982b..9a51d1982b 100644 --- a/cpp/examples/old_api/direct/declare_queues.cpp +++ b/cpp/examples/direct/declare_queues.cpp diff --git a/cpp/examples/old_api/direct/direct_declare_queues.vcproj b/cpp/examples/direct/direct_declare_queues.vcproj index 083474b9ef..083474b9ef 100644 --- a/cpp/examples/old_api/direct/direct_declare_queues.vcproj +++ b/cpp/examples/direct/direct_declare_queues.vcproj diff --git a/cpp/examples/old_api/direct/direct_direct_producer.vcproj b/cpp/examples/direct/direct_direct_producer.vcproj index f091fbf291..f091fbf291 100644 --- a/cpp/examples/old_api/direct/direct_direct_producer.vcproj +++ b/cpp/examples/direct/direct_direct_producer.vcproj diff --git a/cpp/examples/old_api/direct/direct_listener.vcproj b/cpp/examples/direct/direct_listener.vcproj index dce1d3ec28..dce1d3ec28 100644 --- a/cpp/examples/old_api/direct/direct_listener.vcproj +++ b/cpp/examples/direct/direct_listener.vcproj diff --git a/cpp/examples/old_api/direct/direct_producer.cpp b/cpp/examples/direct/direct_producer.cpp index ecc9675189..ecc9675189 100644 --- a/cpp/examples/old_api/direct/direct_producer.cpp +++ b/cpp/examples/direct/direct_producer.cpp diff --git a/cpp/examples/old_api/direct/listener.cpp b/cpp/examples/direct/listener.cpp index 38bf24ec41..38bf24ec41 100644 --- a/cpp/examples/old_api/direct/listener.cpp +++ b/cpp/examples/direct/listener.cpp diff --git a/cpp/examples/old_api/direct/verify b/cpp/examples/direct/verify index f598bacc1f..f598bacc1f 100644 --- a/cpp/examples/old_api/direct/verify +++ b/cpp/examples/direct/verify diff --git a/cpp/examples/old_api/direct/verify.in b/cpp/examples/direct/verify.in index d1e95f1151..d1e95f1151 100644 --- a/cpp/examples/old_api/direct/verify.in +++ b/cpp/examples/direct/verify.in diff --git a/cpp/examples/examples.sln b/cpp/examples/examples.sln index 6f96105d97..8511fe3cce 100644 --- a/cpp/examples/examples.sln +++ b/cpp/examples/examples.sln @@ -32,14 +32,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_drain", "messagin EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "messaging_spout", "messaging\messaging_spout.vcproj", "{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_console", "qmf-console\qmf-console_console.vcproj", "{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_ping", "qmf-console\qmf-console_ping.vcproj", "{C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_printevents", "qmf-console\qmf-console_printevents.vcproj", "{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_queuestats", "qmf-console\qmf-console_queuestats.vcproj", "{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -96,22 +88,6 @@ Global {D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|Win32.Build.0 = Release|Win32
{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|x64.ActiveCfg = Release|x64
{D3115AC9-91C4-4D79-BCAC-DE837C70F1EA}.Release|x64.Build.0 = Release|x64
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.ActiveCfg = Debug|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.Build.0 = Debug|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.ActiveCfg = Release|Win32
- {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.Build.0 = Release|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
- {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/cpp/examples/old_api/failover/CMakeLists.txt b/cpp/examples/failover/CMakeLists.txt index 05db8fad51..05db8fad51 100644 --- a/cpp/examples/old_api/failover/CMakeLists.txt +++ b/cpp/examples/failover/CMakeLists.txt diff --git a/cpp/examples/old_api/failover/Makefile.am b/cpp/examples/failover/Makefile.am index 8b1da80f2c..48846fdf79 100644 --- a/cpp/examples/old_api/failover/Makefile.am +++ b/cpp/examples/failover/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/failover +examplesdir=$(pkgdatadir)/examples/failover MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/failover/declare_queues.cpp b/cpp/examples/failover/declare_queues.cpp index a677870c53..a677870c53 100644 --- a/cpp/examples/old_api/failover/declare_queues.cpp +++ b/cpp/examples/failover/declare_queues.cpp diff --git a/cpp/examples/old_api/failover/failover_declare_queues.vcproj b/cpp/examples/failover/failover_declare_queues.vcproj index c87c72affd..c87c72affd 100644 --- a/cpp/examples/old_api/failover/failover_declare_queues.vcproj +++ b/cpp/examples/failover/failover_declare_queues.vcproj diff --git a/cpp/examples/old_api/failover/failover_replaying_sender.vcproj b/cpp/examples/failover/failover_replaying_sender.vcproj index 6d22fa6770..6d22fa6770 100644 --- a/cpp/examples/old_api/failover/failover_replaying_sender.vcproj +++ b/cpp/examples/failover/failover_replaying_sender.vcproj diff --git a/cpp/examples/old_api/failover/failover_resuming_receiver.vcproj b/cpp/examples/failover/failover_resuming_receiver.vcproj index ba5061e248..ba5061e248 100644 --- a/cpp/examples/old_api/failover/failover_resuming_receiver.vcproj +++ b/cpp/examples/failover/failover_resuming_receiver.vcproj diff --git a/cpp/examples/old_api/failover/replaying_sender.cpp b/cpp/examples/failover/replaying_sender.cpp index 22a7e1ebd3..22a7e1ebd3 100644 --- a/cpp/examples/old_api/failover/replaying_sender.cpp +++ b/cpp/examples/failover/replaying_sender.cpp diff --git a/cpp/examples/old_api/failover/resuming_receiver.cpp b/cpp/examples/failover/resuming_receiver.cpp index d1886ce861..d1886ce861 100644 --- a/cpp/examples/old_api/failover/resuming_receiver.cpp +++ b/cpp/examples/failover/resuming_receiver.cpp diff --git a/cpp/examples/old_api/fanout/CMakeLists.txt b/cpp/examples/fanout/CMakeLists.txt index 3f89d67650..3f89d67650 100644 --- a/cpp/examples/old_api/fanout/CMakeLists.txt +++ b/cpp/examples/fanout/CMakeLists.txt diff --git a/cpp/examples/old_api/fanout/Makefile.am b/cpp/examples/fanout/Makefile.am index 3ab43b0279..6e2e821eae 100644 --- a/cpp/examples/old_api/fanout/Makefile.am +++ b/cpp/examples/fanout/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/fanout +examplesdir=$(pkgdatadir)/examples/fanout MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj b/cpp/examples/fanout/fanout_fanout_producer.vcproj index daff5f3cf0..daff5f3cf0 100644 --- a/cpp/examples/old_api/fanout/fanout_fanout_producer.vcproj +++ b/cpp/examples/fanout/fanout_fanout_producer.vcproj diff --git a/cpp/examples/old_api/fanout/fanout_listener.vcproj b/cpp/examples/fanout/fanout_listener.vcproj index f0e91b7dc6..f0e91b7dc6 100644 --- a/cpp/examples/old_api/fanout/fanout_listener.vcproj +++ b/cpp/examples/fanout/fanout_listener.vcproj diff --git a/cpp/examples/old_api/fanout/fanout_producer.cpp b/cpp/examples/fanout/fanout_producer.cpp index decd4d314d..decd4d314d 100644 --- a/cpp/examples/old_api/fanout/fanout_producer.cpp +++ b/cpp/examples/fanout/fanout_producer.cpp diff --git a/cpp/examples/old_api/fanout/listener.cpp b/cpp/examples/fanout/listener.cpp index cd3071c29a..cd3071c29a 100644 --- a/cpp/examples/old_api/fanout/listener.cpp +++ b/cpp/examples/fanout/listener.cpp diff --git a/cpp/examples/old_api/fanout/verify b/cpp/examples/fanout/verify index 2eaadff56b..2eaadff56b 100644 --- a/cpp/examples/old_api/fanout/verify +++ b/cpp/examples/fanout/verify diff --git a/cpp/examples/old_api/fanout/verify.in b/cpp/examples/fanout/verify.in index 8f8612ce67..8f8612ce67 100644 --- a/cpp/examples/old_api/fanout/verify.in +++ b/cpp/examples/fanout/verify.in diff --git a/cpp/examples/messaging/drain.cpp b/cpp/examples/messaging/drain.cpp index 563e5e5060..5c938e9742 100644 --- a/cpp/examples/messaging/drain.cpp +++ b/cpp/examples/messaging/drain.cpp @@ -45,12 +45,12 @@ struct Options : OptionParser url("127.0.0.1"), timeout(0), forever(false), - count(0) + count(1) { add("broker,b", url, "url of broker to connect to"); add("timeout,t", timeout, "timeout in seconds to wait before exiting"); add("forever,f", forever, "ignore timeout and wait forever"); - add("connection-options", connectionOptions, "connection options string in the form {name1:value1, name2:value2}"); + add("connection-options", connectionOptions, "connection options string in the form {name1=value1, name2=value2}"); add("count,c", count, "number of messages to read before exiting"); } diff --git a/cpp/examples/messaging/server.cpp b/cpp/examples/messaging/server.cpp index aa271d91f9..ab72694c61 100644 --- a/cpp/examples/messaging/server.cpp +++ b/cpp/examples/messaging/server.cpp @@ -39,8 +39,8 @@ using std::string; int main(int argc, char** argv) { const char* url = argc>1 ? argv[1] : "amqp:tcp:127.0.0.1:5672"; - std::string connectionOptions = argc > 2 ? argv[2] : ""; - + std::string connectionOptions = argc > 3 ? argv[3] : ""; + Connection connection(url, connectionOptions); try { connection.open(); diff --git a/cpp/examples/messaging/spout.cpp b/cpp/examples/messaging/spout.cpp index cd11a7ad81..57b955c1de 100644 --- a/cpp/examples/messaging/spout.cpp +++ b/cpp/examples/messaging/spout.cpp @@ -65,7 +65,7 @@ struct Options : OptionParser add("property,P", properties, "specify message property"); add("map,M", entries, "specify entry for map content"); add("content", content, "specify textual content"); - add("connection-options", connectionOptions, "connection options string in the form {name1:value1, name2:value2}"); + add("connection-options", connectionOptions, "connection options string in the form {name1=value1, name2=value2}"); } static bool nameval(const std::string& in, std::string& name, std::string& value) diff --git a/cpp/examples/old_api/old-examples.sln b/cpp/examples/old-examples.sln index e6ec9a0d66..7f2fa3e8b0 100644 --- a/cpp/examples/old_api/old-examples.sln +++ b/cpp/examples/old-examples.sln @@ -40,6 +40,14 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_listener", "p EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pub_sub_topic_publisher", "pub-sub\pub-sub_topic_publisher.vcproj", "{05158653-FECA-1BAD-A430-FD5330E23A2D}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_console", "qmf-console\qmf-console_console.vcproj", "{490473E1-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_ping", "qmf-console\qmf-console_ping.vcproj", "{C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_printevents", "qmf-console\qmf-console_printevents.vcproj", "{72C74624-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "qmf_console_queuestats", "qmf-console\qmf-console_queuestats.vcproj", "{B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request_response_client", "request-response\request-response_client.vcproj", "{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "request_response_server", "request-response\request-response_server.vcproj", "{46817425-FECA-1BAD-BD3A-8A467D0C5CCC}"
@@ -96,6 +104,22 @@ Global {05158653-FECA-1BAD-A430-FD5330E23A2D}.Debug|Win32.Build.0 = Debug|Win32
{05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.ActiveCfg = Release|Win32
{05158653-FECA-1BAD-A430-FD5330E23A2D}.Release|Win32.Build.0 = Release|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {490473E1-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Debug|Win32.Build.0 = Debug|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.ActiveCfg = Release|Win32
+ {C1FFDE95-3442-49AE-9985-7EEE3D45B4A3}.Release|Win32.Build.0 = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {72C74624-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Debug|Win32.Build.0 = Debug|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.ActiveCfg = Release|Win32
+ {B21825EA-FECA-1BAD-2E13-3FFA2B8669C3}.Release|Win32.Build.0 = Release|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.ActiveCfg = Debug|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Debug|Win32.Build.0 = Debug|Win32
{2691FE1E-FECA-1BAD-BD3A-8A467D0C5CCC}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/cpp/examples/old_api/CMakeLists.txt b/cpp/examples/old_api/CMakeLists.txt deleted file mode 100644 index 701f9be860..0000000000 --- a/cpp/examples/old_api/CMakeLists.txt +++ /dev/null @@ -1,25 +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. -# -add_subdirectory(direct) -add_subdirectory(failover) -add_subdirectory(fanout) -add_subdirectory(pub-sub) -add_subdirectory(request-response) -add_subdirectory(tradedemo) -add_subdirectory(xml-exchange) diff --git a/cpp/examples/old_api/Makefile.am b/cpp/examples/old_api/Makefile.am deleted file mode 100644 index 04216ffa97..0000000000 --- a/cpp/examples/old_api/Makefile.am +++ /dev/null @@ -1,48 +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. -# -SUBDIRS = direct pub-sub fanout request-response failover tradedemo -if HAVE_XML - SUBDIRS += xml-exchange - broker_args = "--no-module-dir --data-dir \"\" --auth no --load-module $(top_builddir)/src/.libs/xml.so" -endif -if !HAVE_XML - exclude_examples_regexp="xml" # Exclude XML examples. - broker_args = "--no-module-dir --data-dir \"\" --auth no" -endif - -MAKEDIST=.libs/Makefile - -$(MAKEDIST): Makefile - mkdir -p .libs - @(echo 'all clean:' ; \ - echo ' for d in $(SUBDIRS) ; do $$(MAKE) -C $$$$d $$@ ; done' ; \ - ) > $(MAKEDIST) - -examplesdir=$(pkgdatadir)/examples/old_api -dist_examples_DATA = $(MAKEDIST) -EXTRA_DIST = README.verify verify verify_all CMakeLists.txt - -# For older versions of automake -abs_top_srcdir = @abs_top_srcdir@ -abs_top_builddir = @abs_top_builddir@ - -# Verify the examples in the buid tree. -check-local: - $(srcdir)/verify_all $(abs_top_srcdir)/.. $(abs_top_builddir) $(broker_args) $(exclude_examples_regexp) - diff --git a/cpp/examples/old_api/pub-sub/CMakeLists.txt b/cpp/examples/pub-sub/CMakeLists.txt index 961de06d5a..961de06d5a 100644 --- a/cpp/examples/old_api/pub-sub/CMakeLists.txt +++ b/cpp/examples/pub-sub/CMakeLists.txt diff --git a/cpp/examples/old_api/pub-sub/Makefile.am b/cpp/examples/pub-sub/Makefile.am index 8f42ee0211..62658ebe94 100644 --- a/cpp/examples/old_api/pub-sub/Makefile.am +++ b/cpp/examples/pub-sub/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/pub-sub +examplesdir=$(pkgdatadir)/examples/pub-sub MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj b/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj index aa0b3bcaa3..aa0b3bcaa3 100644 --- a/cpp/examples/old_api/pub-sub/pub-sub_topic_listener.vcproj +++ b/cpp/examples/pub-sub/pub-sub_topic_listener.vcproj diff --git a/cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj b/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj index 76e51df4df..76e51df4df 100644 --- a/cpp/examples/old_api/pub-sub/pub-sub_topic_publisher.vcproj +++ b/cpp/examples/pub-sub/pub-sub_topic_publisher.vcproj diff --git a/cpp/examples/old_api/pub-sub/topic_listener.cpp b/cpp/examples/pub-sub/topic_listener.cpp index d38a806303..d38a806303 100644 --- a/cpp/examples/old_api/pub-sub/topic_listener.cpp +++ b/cpp/examples/pub-sub/topic_listener.cpp diff --git a/cpp/examples/old_api/pub-sub/topic_publisher.cpp b/cpp/examples/pub-sub/topic_publisher.cpp index aed5f8f033..aed5f8f033 100644 --- a/cpp/examples/old_api/pub-sub/topic_publisher.cpp +++ b/cpp/examples/pub-sub/topic_publisher.cpp diff --git a/cpp/examples/old_api/pub-sub/verify b/cpp/examples/pub-sub/verify index 528d2f401e..528d2f401e 100644 --- a/cpp/examples/old_api/pub-sub/verify +++ b/cpp/examples/pub-sub/verify diff --git a/cpp/examples/old_api/pub-sub/verify.in b/cpp/examples/pub-sub/verify.in index 6413c5c788..6413c5c788 100644 --- a/cpp/examples/old_api/pub-sub/verify.in +++ b/cpp/examples/pub-sub/verify.in diff --git a/cpp/examples/qmf-console/ping.cpp b/cpp/examples/qmf-console/ping.cpp index e6d6d138d5..fe537d48d2 100644 --- a/cpp/examples/qmf-console/ping.cpp +++ b/cpp/examples/qmf-console/ping.cpp @@ -31,7 +31,9 @@ using namespace qpid::console; int main_int(int /*argc*/, char** /*argv*/) { // - // Declare connection settings for the messaging broker. + // Declare connection settings for the messaging broker. The settings default to + // localhost:5672 with user guest (password guest). Refer to the header file + // <qpid/client/ConnectionSettings.h> for full details. // qpid::client::ConnectionSettings connSettings; diff --git a/cpp/examples/qmf-console/printevents.cpp b/cpp/examples/qmf-console/printevents.cpp index ac3e449a2c..3a0a2ab68b 100644 --- a/cpp/examples/qmf-console/printevents.cpp +++ b/cpp/examples/qmf-console/printevents.cpp @@ -64,7 +64,9 @@ struct Main { Listener listener; // - // Declare connection settings for the messaging broker. + // Declare connection settings for the messaging broker. The settings default to + // localhost:5672 with user guest (password guest). Refer to the header file + // <qpid/client/ConnectionSettings.h> for full details. // qpid::client::ConnectionSettings connSettings; diff --git a/cpp/examples/old_api/request-response/CMakeLists.txt b/cpp/examples/request-response/CMakeLists.txt index 873a0cfa86..873a0cfa86 100644 --- a/cpp/examples/old_api/request-response/CMakeLists.txt +++ b/cpp/examples/request-response/CMakeLists.txt diff --git a/cpp/examples/old_api/request-response/Makefile.am b/cpp/examples/request-response/Makefile.am index f48762da51..48b3d989f0 100644 --- a/cpp/examples/old_api/request-response/Makefile.am +++ b/cpp/examples/request-response/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/request-response +examplesdir=$(pkgdatadir)/examples/request-response MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/request-response/client.cpp b/cpp/examples/request-response/client.cpp index 679d1c5fc2..679d1c5fc2 100644 --- a/cpp/examples/old_api/request-response/client.cpp +++ b/cpp/examples/request-response/client.cpp diff --git a/cpp/examples/old_api/request-response/request-response_client.vcproj b/cpp/examples/request-response/request-response_client.vcproj index 5f9eadde36..5f9eadde36 100644 --- a/cpp/examples/old_api/request-response/request-response_client.vcproj +++ b/cpp/examples/request-response/request-response_client.vcproj diff --git a/cpp/examples/old_api/request-response/request-response_server.vcproj b/cpp/examples/request-response/request-response_server.vcproj index 54352b9f46..54352b9f46 100644 --- a/cpp/examples/old_api/request-response/request-response_server.vcproj +++ b/cpp/examples/request-response/request-response_server.vcproj diff --git a/cpp/examples/old_api/request-response/server.cpp b/cpp/examples/request-response/server.cpp index 65a4717b35..65a4717b35 100644 --- a/cpp/examples/old_api/request-response/server.cpp +++ b/cpp/examples/request-response/server.cpp diff --git a/cpp/examples/old_api/request-response/verify b/cpp/examples/request-response/verify index dee82413e7..dee82413e7 100644 --- a/cpp/examples/old_api/request-response/verify +++ b/cpp/examples/request-response/verify diff --git a/cpp/examples/old_api/request-response/verify.in b/cpp/examples/request-response/verify.in index 7925dc5671..7925dc5671 100644 --- a/cpp/examples/old_api/request-response/verify.in +++ b/cpp/examples/request-response/verify.in diff --git a/cpp/examples/old_api/tradedemo/CMakeLists.txt b/cpp/examples/tradedemo/CMakeLists.txt index e61fc1467d..e61fc1467d 100644 --- a/cpp/examples/old_api/tradedemo/CMakeLists.txt +++ b/cpp/examples/tradedemo/CMakeLists.txt diff --git a/cpp/examples/old_api/tradedemo/Makefile.am b/cpp/examples/tradedemo/Makefile.am index 445b15b367..f4d8686d05 100644 --- a/cpp/examples/old_api/tradedemo/Makefile.am +++ b/cpp/examples/tradedemo/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/tradedemo +examplesdir=$(pkgdatadir)/examples/tradedemo MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/tradedemo/declare_queues.cpp b/cpp/examples/tradedemo/declare_queues.cpp index b1f2cc3510..b1f2cc3510 100644 --- a/cpp/examples/old_api/tradedemo/declare_queues.cpp +++ b/cpp/examples/tradedemo/declare_queues.cpp diff --git a/cpp/examples/old_api/tradedemo/topic_listener.cpp b/cpp/examples/tradedemo/topic_listener.cpp index c488e7fb69..c488e7fb69 100644 --- a/cpp/examples/old_api/tradedemo/topic_listener.cpp +++ b/cpp/examples/tradedemo/topic_listener.cpp diff --git a/cpp/examples/old_api/tradedemo/topic_publisher.cpp b/cpp/examples/tradedemo/topic_publisher.cpp index e22c185bc7..e22c185bc7 100644 --- a/cpp/examples/old_api/tradedemo/topic_publisher.cpp +++ b/cpp/examples/tradedemo/topic_publisher.cpp diff --git a/cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj b/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj index 34b5cb3b2b..34b5cb3b2b 100644 --- a/cpp/examples/old_api/tradedemo/tradedemo_declare_queues.vcproj +++ b/cpp/examples/tradedemo/tradedemo_declare_queues.vcproj diff --git a/cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj b/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj index 965be2e88b..965be2e88b 100644 --- a/cpp/examples/old_api/tradedemo/tradedemo_topic_listener.vcproj +++ b/cpp/examples/tradedemo/tradedemo_topic_listener.vcproj diff --git a/cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj b/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj index 77fd511e15..77fd511e15 100644 --- a/cpp/examples/old_api/tradedemo/tradedemo_topic_publisher.vcproj +++ b/cpp/examples/tradedemo/tradedemo_topic_publisher.vcproj diff --git a/cpp/examples/old_api/verify b/cpp/examples/verify index 9a1ed078d6..9a1ed078d6 100755 --- a/cpp/examples/old_api/verify +++ b/cpp/examples/verify diff --git a/cpp/examples/old_api/verify_all b/cpp/examples/verify_all index fbe51377b6..cb4c5283fa 100755 --- a/cpp/examples/old_api/verify_all +++ b/cpp/examples/verify_all @@ -32,7 +32,7 @@ trap "$qpidd -q" exit QPID_PORT=`$qpidd -dp0 $broker_args` || { echo "Can't run qpidd" ; exit 1; } export QPID_PORT -find="find $topsrcdir/cpp/examples/old_api" +find="find $topsrcdir/cpp/examples" find="$find -mindepth 2 -name verify" all_examples=`$find` diff --git a/cpp/examples/old_api/xml-exchange/CMakeLists.txt b/cpp/examples/xml-exchange/CMakeLists.txt index 3fea47a208..3fea47a208 100644 --- a/cpp/examples/old_api/xml-exchange/CMakeLists.txt +++ b/cpp/examples/xml-exchange/CMakeLists.txt diff --git a/cpp/examples/old_api/xml-exchange/Makefile.am b/cpp/examples/xml-exchange/Makefile.am index 3e1082cdb2..9001e3fa61 100644 --- a/cpp/examples/old_api/xml-exchange/Makefile.am +++ b/cpp/examples/xml-exchange/Makefile.am @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -examplesdir=$(pkgdatadir)/examples/old_api/xml-exchange +examplesdir=$(pkgdatadir)/examples/xml-exchange MAKELDFLAGS=$(CLIENTFLAGS) include $(top_srcdir)/examples/makedist.mk diff --git a/cpp/examples/old_api/xml-exchange/README.txt b/cpp/examples/xml-exchange/README.txt index 85caebe352..85caebe352 100644 --- a/cpp/examples/old_api/xml-exchange/README.txt +++ b/cpp/examples/xml-exchange/README.txt diff --git a/cpp/examples/old_api/xml-exchange/declare_queues.cpp b/cpp/examples/xml-exchange/declare_queues.cpp index ad08642019..ad08642019 100644 --- a/cpp/examples/old_api/xml-exchange/declare_queues.cpp +++ b/cpp/examples/xml-exchange/declare_queues.cpp diff --git a/cpp/examples/old_api/xml-exchange/listener.cpp b/cpp/examples/xml-exchange/listener.cpp index 11bcb9f669..11bcb9f669 100644 --- a/cpp/examples/old_api/xml-exchange/listener.cpp +++ b/cpp/examples/xml-exchange/listener.cpp diff --git a/cpp/examples/old_api/xml-exchange/xml_producer.cpp b/cpp/examples/xml-exchange/xml_producer.cpp index af1a7e60c7..af1a7e60c7 100644 --- a/cpp/examples/old_api/xml-exchange/xml_producer.cpp +++ b/cpp/examples/xml-exchange/xml_producer.cpp diff --git a/cpp/include/qmf/Agent.h b/cpp/include/qmf/Agent.h index 94083be4f3..8c0f48b8b1 100644 --- a/cpp/include/qmf/Agent.h +++ b/cpp/include/qmf/Agent.h @@ -42,7 +42,7 @@ namespace qmf { class SchemaId; class Schema; - class QMF_CLASS_EXTERN Agent : public qmf::Handle<AgentImpl> { + class Agent : public qmf::Handle<AgentImpl> { public: QMF_EXTERN Agent(AgentImpl* impl = 0); QMF_EXTERN Agent(const Agent&); diff --git a/cpp/include/qmf/AgentEvent.h b/cpp/include/qmf/AgentEvent.h index 0f93a9bb0a..59a41c3267 100644 --- a/cpp/include/qmf/AgentEvent.h +++ b/cpp/include/qmf/AgentEvent.h @@ -46,7 +46,7 @@ namespace qmf { AGENT_THREAD_FAILED = 8 }; - class QMF_CLASS_EXTERN AgentEvent : public qmf::Handle<AgentEventImpl> { + class AgentEvent : public qmf::Handle<AgentEventImpl> { public: QMF_EXTERN AgentEvent(AgentEventImpl* impl = 0); QMF_EXTERN AgentEvent(const AgentEvent&); diff --git a/cpp/include/qmf/AgentSession.h b/cpp/include/qmf/AgentSession.h index 589d364bcc..9e29d6b54b 100644 --- a/cpp/include/qmf/AgentSession.h +++ b/cpp/include/qmf/AgentSession.h @@ -40,7 +40,7 @@ namespace qmf { class Data; class DataAddr; - class QMF_CLASS_EXTERN AgentSession : public qmf::Handle<AgentSessionImpl> { + class AgentSession : public qmf::Handle<AgentSessionImpl> { public: QMF_EXTERN AgentSession(AgentSessionImpl* impl = 0); QMF_EXTERN AgentSession(const AgentSession&); @@ -71,20 +71,15 @@ namespace qmf { * If False: Listen only on the routable direct address * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network * - If False: Operate more flexibly with regard to use of messaging facilities [default] - * max-thread-wait-time:N - Time (in seconds) the session thread will wait for messages from the network between - * periodic background processing passes. [default: 5] - * Must not be greater than 'interval'. Larger numbers will cause fewer wake-ups but will - * increase the time it takes to shut down the process. This setting will not affect the - * agent's response time for queries or method invocation. */ - QMF_EXTERN AgentSession(qpid::messaging::Connection& conn, const std::string& options=""); + QMF_EXTERN AgentSession(qpid::messaging::Connection&, const std::string& options=""); /** * setDomain - Change the QMF domain that this agent will operate in. If this is not called, * the domain will be "default". Agents in a domain can be seen only by consoles in the same domain. * This must be called prior to opening the agent session. */ - QMF_EXTERN void setDomain(const std::string& domain); + QMF_EXTERN void setDomain(const std::string&); /** * Set identifying attributes of this agent. @@ -93,16 +88,16 @@ namespace qmf { * setInstance - Set the unique instance name (if not set, a UUID will be assigned) * These must be called prior to opening the agent session. */ - QMF_EXTERN void setVendor(const std::string& vendor); - QMF_EXTERN void setProduct(const std::string& product); - QMF_EXTERN void setInstance(const std::string& instance); + QMF_EXTERN void setVendor(const std::string&); + QMF_EXTERN void setProduct(const std::string&); + QMF_EXTERN void setInstance(const std::string&); /** * setAttribute - Set an arbitrary attribute for this agent. The attributes are not used * to uniquely identify the agent but can be used as a search criteria when looking for agents. * This must be called prior to opening the agent session. */ - QMF_EXTERN void setAttribute(const std::string& key, const qpid::types::Variant& value); + QMF_EXTERN void setAttribute(const std::string&, const qpid::types::Variant&); /** * Get the identifying name of the agent. @@ -124,19 +119,13 @@ namespace qmf { * Get the next event from the agent session. Events represent actions that must be acted upon by the * agent application. This method blocks for up to the timeout if there are no events to be handled. * This method will typically be the focus of the agent application's main execution loop. - * If the timeout is set to Duration::IMMEDIATE, the call will not block. */ - QMF_EXTERN bool nextEvent(AgentEvent& outEvent, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER); - - /** - * Return the number of events pending for nextEvent. This method will never block. - */ - QMF_EXTERN int pendingEvents() const; + QMF_EXTERN bool nextEvent(AgentEvent&, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER); /** * Register a schema to be exposed by this agent. */ - QMF_EXTERN void registerSchema(Schema& schema); + QMF_EXTERN void registerSchema(Schema&); /** * Add data to be managed internally by the agent. If the option external:True is selected, this call @@ -149,12 +138,12 @@ namespace qmf { * across different sessions. If persistent, it is the agent application's * responsibility to ensure the name is the same each time it is added. */ - QMF_EXTERN DataAddr addData(Data& data, const std::string& name="", bool persistent=false); + QMF_EXTERN DataAddr addData(Data&, const std::string& name="", bool persistent=false); /** * Delete data from internal agent management. */ - QMF_EXTERN void delData(const DataAddr& dataAddr); + QMF_EXTERN void delData(const DataAddr&); /** * The following methods are used to respond to events received in nextEvent. @@ -166,13 +155,13 @@ namespace qmf { * complete - Indicate that the response to a query is complete (external:True only) * methodSuccess - Indicate the successful completion of a method call. */ - QMF_EXTERN void authAccept(AgentEvent& event); - QMF_EXTERN void authReject(AgentEvent& event, const std::string& diag=""); - QMF_EXTERN void raiseException(AgentEvent& event, const std::string& errorText); - QMF_EXTERN void raiseException(AgentEvent& event, const Data& errorData); - QMF_EXTERN void response(AgentEvent& event, const Data& responseData); - QMF_EXTERN void complete(AgentEvent& event); - QMF_EXTERN void methodSuccess(AgentEvent& event); + QMF_EXTERN void authAccept(AgentEvent&); + QMF_EXTERN void authReject(AgentEvent&, const std::string& diag=""); + QMF_EXTERN void raiseException(AgentEvent&, const std::string&); + QMF_EXTERN void raiseException(AgentEvent&, const Data&); + QMF_EXTERN void response(AgentEvent&, const Data&); + QMF_EXTERN void complete(AgentEvent&); + QMF_EXTERN void methodSuccess(AgentEvent&); /** * Raise an event to be sent into the QMF network. @@ -188,7 +177,6 @@ namespace qmf { #ifndef SWIG private: friend class qmf::PrivateImplRef<AgentSession>; - friend struct AgentSessionImplAccess; #endif }; diff --git a/cpp/include/qmf/ConsoleEvent.h b/cpp/include/qmf/ConsoleEvent.h index 94600f9357..b836b629af 100644 --- a/cpp/include/qmf/ConsoleEvent.h +++ b/cpp/include/qmf/ConsoleEvent.h @@ -57,7 +57,7 @@ namespace qmf { AGENT_DEL_FILTER = 2 }; - class QMF_CLASS_EXTERN ConsoleEvent : public qmf::Handle<ConsoleEventImpl> { + class ConsoleEvent : public qmf::Handle<ConsoleEventImpl> { public: QMF_EXTERN ConsoleEvent(ConsoleEventImpl* impl = 0); QMF_EXTERN ConsoleEvent(const ConsoleEvent&); diff --git a/cpp/include/qmf/ConsoleSession.h b/cpp/include/qmf/ConsoleSession.h index 022485cfa7..0c73e7a6db 100644 --- a/cpp/include/qmf/ConsoleSession.h +++ b/cpp/include/qmf/ConsoleSession.h @@ -38,7 +38,7 @@ namespace qmf { class ConsoleSessionImpl; class ConsoleEvent; - class QMF_CLASS_EXTERN ConsoleSession : public qmf::Handle<ConsoleSessionImpl> { + class ConsoleSession : public qmf::Handle<ConsoleSessionImpl> { public: QMF_EXTERN ConsoleSession(ConsoleSessionImpl* impl = 0); QMF_EXTERN ConsoleSession(const ConsoleSession&); @@ -61,53 +61,15 @@ namespace qmf { * If False: Listen only on the routable direct address * strict-security:{True,False} - If True: Cooperate with the broker to enforce strict access control to the network * - If False: Operate more flexibly with regard to use of messaging facilities [default] - * max-thread-wait-time:N - Time (in seconds) the session thread will wait for messages from the network between - * periodic background processing passes. - * Must not be greater than 60. Larger numbers will cause fewer wake-ups but will - * increase the time it takes to shut down the process. [default: 5] - */ - QMF_EXTERN ConsoleSession(qpid::messaging::Connection& conn, const std::string& options=""); - - /** - * setDomain - Change the QMF domain that this console will operate in. If this is not called, - * the domain will be "default". Agents in a domain can be seen only by consoles in the same domain. - * This must be called prior to opening the console session. - */ - QMF_EXTERN void setDomain(const std::string& domain); - QMF_EXTERN void setAgentFilter(const std::string& filter); - - /** - * Open the console session. After opening the session, the domain cannot be changed. */ + QMF_EXTERN ConsoleSession(qpid::messaging::Connection&, const std::string& options=""); + QMF_EXTERN void setDomain(const std::string&); + QMF_EXTERN void setAgentFilter(const std::string&); QMF_EXTERN void open(); - - /** - * Close the session. Once closed, the session no longer communicates on the messaging network. - */ QMF_EXTERN void close(); - - /** - * Get the next event from the console session. Events represent actions that must be acted upon by the - * console application. This method blocks for up to the timeout if there are no events to be handled. - * This method will typically be the focus of the console application's main execution loop. - * If the timeout is set to Duration::IMMEDIATE, the call will not block. - */ - QMF_EXTERN bool nextEvent(ConsoleEvent& outEvent, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER); - - /** - * Return the number of events pending for nextEvent. This method will never block. - */ - QMF_EXTERN int pendingEvents() const; - - /** - * getAgentCount, getAgent - Retrieve the set of agents that match the console session's agent filter. - */ + QMF_EXTERN bool nextEvent(ConsoleEvent&, qpid::messaging::Duration timeout=qpid::messaging::Duration::FOREVER); QMF_EXTERN uint32_t getAgentCount() const; - QMF_EXTERN Agent getAgent(uint32_t agentIndex) const; - - /** - * Get the agent for the connected broker (i.e. the agent embedded in the broker to which we have a connection). - */ + QMF_EXTERN Agent getAgent(uint32_t) const; QMF_EXTERN Agent getConnectedBrokerAgent() const; /** @@ -117,13 +79,12 @@ namespace qmf { * will involve all known agents. If agentFilter is non-empty, it will be applied only to the set of known * agents. A subscription cannot be created that involves an agent not known by the session. */ - QMF_EXTERN Subscription subscribe(const Query& query, const std::string& agentFilter = "", const std::string& options = ""); - QMF_EXTERN Subscription subscribe(const std::string& query, const std::string& agentFilter = "", const std::string& options = ""); + QMF_EXTERN Subscription subscribe(const Query&, const std::string& agentFilter = "", const std::string& options = ""); + QMF_EXTERN Subscription subscribe(const std::string&, const std::string& agentFilter = "", const std::string& options = ""); #ifndef SWIG private: friend class qmf::PrivateImplRef<ConsoleSession>; - friend struct ConsoleSessionImplAccess; #endif }; diff --git a/cpp/include/qmf/Data.h b/cpp/include/qmf/Data.h index 487a02fe95..82f1569a0b 100644 --- a/cpp/include/qmf/Data.h +++ b/cpp/include/qmf/Data.h @@ -39,7 +39,7 @@ namespace qmf { class DataAddr; class Agent; - class QMF_CLASS_EXTERN Data : public qmf::Handle<DataImpl> { + class Data : public qmf::Handle<DataImpl> { public: QMF_EXTERN Data(DataImpl* impl = 0); QMF_EXTERN Data(const Data&); diff --git a/cpp/include/qmf/DataAddr.h b/cpp/include/qmf/DataAddr.h index 20c469081e..72de0c986a 100644 --- a/cpp/include/qmf/DataAddr.h +++ b/cpp/include/qmf/DataAddr.h @@ -34,7 +34,7 @@ namespace qmf { class DataAddrImpl; - class QMF_CLASS_EXTERN DataAddr : public qmf::Handle<DataAddrImpl> { + class DataAddr : public qmf::Handle<DataAddrImpl> { public: QMF_EXTERN DataAddr(DataAddrImpl* impl = 0); QMF_EXTERN DataAddr(const DataAddr&); @@ -51,9 +51,6 @@ namespace qmf { QMF_EXTERN uint32_t getAgentEpoch() const; QMF_EXTERN qpid::types::Variant::Map asMap() const; - QMF_EXTERN bool operator==(const DataAddr&) const; - QMF_EXTERN bool operator<(const DataAddr&) const; - #ifndef SWIG private: friend class qmf::PrivateImplRef<DataAddr>; diff --git a/cpp/include/qmf/Handle.h b/cpp/include/qmf/Handle.h index 50971ea626..510e2993aa 100644 --- a/cpp/include/qmf/Handle.h +++ b/cpp/include/qmf/Handle.h @@ -39,22 +39,22 @@ template <class T> class Handle { public: /**@return true if handle is valid, i.e. not null. */ - QMF_INLINE_EXTERN bool isValid() const { return impl; } + QMF_EXTERN bool isValid() const { return impl; } /**@return true if handle is null. It is an error to call any function on a null handle. */ - QMF_INLINE_EXTERN bool isNull() const { return !impl; } + QMF_EXTERN bool isNull() const { return !impl; } /** Conversion to bool supports idiom if (handle) { handle->... } */ - QMF_INLINE_EXTERN operator bool() const { return impl; } + QMF_EXTERN operator bool() const { return impl; } /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */ - QMF_INLINE_EXTERN bool operator !() const { return !impl; } + QMF_EXTERN bool operator !() const { return !impl; } void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; } protected: typedef T Impl; - QMF_INLINE_EXTERN Handle() :impl() {} + QMF_EXTERN Handle() :impl() {} // Not implemented,subclasses must implement. QMF_EXTERN Handle(const Handle&); diff --git a/cpp/include/qmf/ImportExport.h b/cpp/include/qmf/ImportExport.h index 7405c15259..f5e1d9127c 100644 --- a/cpp/include/qmf/ImportExport.h +++ b/cpp/include/qmf/ImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - -#if defined(QMF_EXPORT) || defined (qmf2_EXPORTS) -# define QMF_EXTERN QPID_EXPORT -# define QMF_CLASS_EXTERN QPID_CLASS_EXPORT -# define QMF_INLINE_EXTERN QPID_INLINE_EXPORT +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) +# if defined(QMF_EXPORT) || defined (qmfcommon_EXPORTS) +# define QMF_EXTERN __declspec(dllexport) +# else +# define QMF_EXTERN __declspec(dllimport) +# endif #else -# define QMF_EXTERN QPID_IMPORT -# define QMF_CLASS_EXTERN QPID_CLASS_IMPORT -# define QMF_INLINE_EXTERN QPID_INLINE_IMPORT +# define QMF_EXTERN #endif #endif diff --git a/cpp/include/qmf/Query.h b/cpp/include/qmf/Query.h index c1264f8901..fec4660bd7 100644 --- a/cpp/include/qmf/Query.h +++ b/cpp/include/qmf/Query.h @@ -43,7 +43,7 @@ namespace qmf { QUERY_SCHEMA_ID = 4 }; - class QMF_CLASS_EXTERN Query : public qmf::Handle<QueryImpl> { + class Query : public qmf::Handle<QueryImpl> { public: QMF_EXTERN Query(QueryImpl* impl = 0); QMF_EXTERN Query(const Query&); @@ -65,7 +65,7 @@ namespace qmf { #ifndef SWIG private: friend class qmf::PrivateImplRef<Query>; - friend struct QueryImplAccess; + friend class QueryImplAccess; #endif }; diff --git a/cpp/include/qmf/Schema.h b/cpp/include/qmf/Schema.h index 6cfd2e2a56..cf316138c1 100644 --- a/cpp/include/qmf/Schema.h +++ b/cpp/include/qmf/Schema.h @@ -38,7 +38,7 @@ namespace qmf { class SchemaProperty; class SchemaMethod; - class QMF_CLASS_EXTERN Schema : public qmf::Handle<SchemaImpl> { + class Schema : public qmf::Handle<SchemaImpl> { public: QMF_EXTERN Schema(SchemaImpl* impl = 0); QMF_EXTERN Schema(const Schema&); diff --git a/cpp/include/qmf/SchemaId.h b/cpp/include/qmf/SchemaId.h index 2dafc1c091..13fb1cb902 100644 --- a/cpp/include/qmf/SchemaId.h +++ b/cpp/include/qmf/SchemaId.h @@ -35,7 +35,7 @@ namespace qmf { class SchemaIdImpl; - class QMF_CLASS_EXTERN SchemaId : public qmf::Handle<SchemaIdImpl> { + class SchemaId : public qmf::Handle<SchemaIdImpl> { public: QMF_EXTERN SchemaId(SchemaIdImpl* impl = 0); QMF_EXTERN SchemaId(const SchemaId&); diff --git a/cpp/include/qmf/SchemaMethod.h b/cpp/include/qmf/SchemaMethod.h index b5944dc29e..47302b62b9 100644 --- a/cpp/include/qmf/SchemaMethod.h +++ b/cpp/include/qmf/SchemaMethod.h @@ -36,7 +36,7 @@ namespace qmf { class SchemaMethodImpl; class SchemaProperty; - class QMF_CLASS_EXTERN SchemaMethod : public qmf::Handle<SchemaMethodImpl> { + class SchemaMethod : public qmf::Handle<SchemaMethodImpl> { public: QMF_EXTERN SchemaMethod(SchemaMethodImpl* impl = 0); QMF_EXTERN SchemaMethod(const SchemaMethod&); diff --git a/cpp/include/qmf/SchemaProperty.h b/cpp/include/qmf/SchemaProperty.h index bbb603fa50..a3a328b60b 100644 --- a/cpp/include/qmf/SchemaProperty.h +++ b/cpp/include/qmf/SchemaProperty.h @@ -36,7 +36,7 @@ namespace qmf { class SchemaPropertyImpl; - class QMF_CLASS_EXTERN SchemaProperty : public Handle<SchemaPropertyImpl> { + class SchemaProperty : public Handle<SchemaPropertyImpl> { public: QMF_EXTERN SchemaProperty(SchemaPropertyImpl* impl = 0); QMF_EXTERN SchemaProperty(const SchemaProperty&); diff --git a/cpp/include/qmf/Subscription.h b/cpp/include/qmf/Subscription.h index 398a45b922..4e60eb984e 100644 --- a/cpp/include/qmf/Subscription.h +++ b/cpp/include/qmf/Subscription.h @@ -35,7 +35,7 @@ namespace qmf { class SubscriptionImpl; class Data; - class QMF_CLASS_EXTERN Subscription : public qmf::Handle<SubscriptionImpl> { + class Subscription : public qmf::Handle<SubscriptionImpl> { public: QMF_EXTERN Subscription(SubscriptionImpl* impl = 0); QMF_EXTERN Subscription(const Subscription&); @@ -73,7 +73,7 @@ namespace qmf { #ifndef SWIG private: friend class qmf::PrivateImplRef<Subscription>; - friend struct SubscriptionImplAccess; + friend class SubscriptionImplAccess; #endif }; diff --git a/cpp/include/qmf/engine/QmfEngineImportExport.h b/cpp/include/qmf/engine/QmfEngineImportExport.h index cf8fffdb17..373617e046 100644 --- a/cpp/include/qmf/engine/QmfEngineImportExport.h +++ b/cpp/include/qmf/engine/QmfEngineImportExport.h @@ -26,17 +26,8 @@ # else # define QMFE_EXTERN __declspec(dllimport) # endif -# ifdef _MSC_VER -# define QMFE_CLASS_EXTERN -# define QMFE_INLINE_EXTERN QMFE_EXTERN -# else -# define QMFE_CLASS_EXTERN QMFE_EXTERN -# define QMFE_INLINE_EXTERN -# endif #else # define QMFE_EXTERN -# define QMFE_CLASS_EXTERN -# define QMFE_INLINE_EXTERN #endif #endif diff --git a/cpp/include/qmf/exceptions.h b/cpp/include/qmf/exceptions.h index c7ffa68ce2..7959499d63 100644 --- a/cpp/include/qmf/exceptions.h +++ b/cpp/include/qmf/exceptions.h @@ -31,24 +31,24 @@ namespace qmf { /** \ingroup qmf */ - struct QMF_CLASS_EXTERN QmfException : public qpid::types::Exception { + struct QmfException : public qpid::types::Exception { QMF_EXTERN QmfException(const std::string& msg); QMF_EXTERN virtual ~QmfException() throw(); qpid::types::Variant::Map detail; }; - struct QMF_CLASS_EXTERN KeyNotFound : public QmfException { + struct KeyNotFound : public QmfException { QMF_EXTERN KeyNotFound(const std::string& msg); QMF_EXTERN virtual ~KeyNotFound() throw(); }; - struct QMF_CLASS_EXTERN IndexOutOfRange : public QmfException { + struct IndexOutOfRange : public QmfException { QMF_EXTERN IndexOutOfRange(); QMF_EXTERN virtual ~IndexOutOfRange() throw(); }; - struct QMF_CLASS_EXTERN OperationTimedOut : public QmfException { + struct OperationTimedOut : public QmfException { QMF_EXTERN OperationTimedOut(); QMF_EXTERN virtual ~OperationTimedOut() throw(); }; diff --git a/cpp/include/qmf/posix/EventNotifier.h b/cpp/include/qmf/posix/EventNotifier.h deleted file mode 100644 index ebc1cb5364..0000000000 --- a/cpp/include/qmf/posix/EventNotifier.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef __QMF_POSIX_EVENT_NOTIFIER_H -#define __QMF_POSIX_EVENT_NOTIFIER_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 <qmf/ImportExport.h> -#include "qmf/Handle.h" -#include "qmf/AgentSession.h" -#include "qmf/ConsoleSession.h" - -namespace qmf { - - class PosixEventNotifierImpl; - class PosixEventNotifierImplAccess; - -namespace posix { - -#ifndef SWIG - template <class> class PrivateImplRef; -#endif - - class QMF_CLASS_EXTERN EventNotifier : public qmf::Handle<qmf::PosixEventNotifierImpl> { - public: - QMF_EXTERN EventNotifier(PosixEventNotifierImpl* impl = 0); - QMF_EXTERN EventNotifier(::qmf::AgentSession& agentSession); - QMF_EXTERN EventNotifier(::qmf::ConsoleSession& consoleSession); - QMF_EXTERN EventNotifier(const EventNotifier& that); - - QMF_EXTERN ~EventNotifier(); - - QMF_EXTERN EventNotifier& operator=(const EventNotifier& that); - - QMF_EXTERN int getHandle() const; - -#ifndef SWIG - private: - friend class qmf::PrivateImplRef<EventNotifier>; - friend struct qmf::PosixEventNotifierImplAccess; -#endif - - }; - -}} - -#endif - diff --git a/cpp/include/qpid/Address.h b/cpp/include/qpid/Address.h index f5b19d0532..57c9139f87 100755 --- a/cpp/include/qpid/Address.h +++ b/cpp/include/qpid/Address.h @@ -36,7 +36,7 @@ public: static const std::string TCP; // Default TCP protocol tag. static const uint16_t AMQP_PORT=5672; // Default AMQP port. - QPID_COMMON_INLINE_EXTERN explicit Address( + QPID_COMMON_EXTERN explicit Address( const std::string& protocol_=std::string(), const std::string& host_=std::string(), uint16_t port_=0 diff --git a/cpp/include/qpid/CommonImportExport.h b/cpp/include/qpid/CommonImportExport.h index dd2b900b73..02c06ed7af 100644 --- a/cpp/include/qpid/CommonImportExport.h +++ b/cpp/include/qpid/CommonImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) #if defined(COMMON_EXPORT) || defined (qpidcommon_EXPORTS) -# define QPID_COMMON_EXTERN QPID_EXPORT -# define QPID_COMMON_CLASS_EXTERN QPID_CLASS_EXPORT -# define QPID_COMMON_INLINE_EXTERN QPID_INLINE_EXPORT +#define QPID_COMMON_EXTERN __declspec(dllexport) +#else +#define QPID_COMMON_EXTERN __declspec(dllimport) +#endif #else -# define QPID_COMMON_EXTERN QPID_IMPORT -# define QPID_COMMON_CLASS_EXTERN QPID_CLASS_IMPORT -# define QPID_COMMON_INLINE_EXTERN QPID_INLINE_IMPORT +#define QPID_COMMON_EXTERN #endif #endif diff --git a/cpp/include/qpid/Exception.h b/cpp/include/qpid/Exception.h index cbd175214d..fa7111160c 100644 --- a/cpp/include/qpid/Exception.h +++ b/cpp/include/qpid/Exception.h @@ -36,7 +36,7 @@ namespace qpid /** * Base class for Qpid runtime exceptions. */ -class QPID_COMMON_CLASS_EXTERN Exception : public std::exception +class Exception : public std::exception { public: QPID_COMMON_EXTERN explicit Exception(const std::string& message=std::string()) throw(); @@ -51,30 +51,30 @@ class QPID_COMMON_CLASS_EXTERN Exception : public std::exception }; /** Exception that includes an errno message. */ -struct QPID_COMMON_CLASS_EXTERN ErrnoException : public Exception { +struct ErrnoException : public Exception { ErrnoException(const std::string& msg, int err) : Exception(msg+": "+qpid::sys::strError(err)) {} ErrnoException(const std::string& msg) : Exception(msg+": "+qpid::sys::strError(errno)) {} }; -struct QPID_COMMON_CLASS_EXTERN SessionException : public Exception { +struct SessionException : public Exception { const framing::execution::ErrorCode code; SessionException(framing::execution::ErrorCode code_, const std::string& message) : Exception(message), code(code_) {} }; -struct QPID_COMMON_CLASS_EXTERN ChannelException : public Exception { +struct ChannelException : public Exception { const framing::session::DetachCode code; ChannelException(framing::session::DetachCode _code, const std::string& message) : Exception(message), code(_code) {} }; -struct QPID_COMMON_CLASS_EXTERN ConnectionException : public Exception { +struct ConnectionException : public Exception { const framing::connection::CloseCode code; ConnectionException(framing::connection::CloseCode _code, const std::string& message) : Exception(message), code(_code) {} }; -struct QPID_COMMON_CLASS_EXTERN ClosedException : public Exception { +struct ClosedException : public Exception { QPID_COMMON_EXTERN ClosedException(const std::string& msg=std::string()); QPID_COMMON_EXTERN std::string getPrefix() const; }; diff --git a/cpp/include/qpid/ImportExport.h b/cpp/include/qpid/ImportExport.h deleted file mode 100644 index e62399faf7..0000000000 --- a/cpp/include/qpid/ImportExport.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef QPID_IMPORTEXPORT_H -#define QPID_IMPORTEXPORT_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. - */ - -// -// This header file defines the following macros for the control of library/DLL -// import and export: -// -// QPID_EXPORT - Export declaration for Methods -// QPID_CLASS_EXPORT - Export declaration for Classes -// QPID_INLINE_EXPORT - Export declaration for Inline methods -// -// QPID_IMPORT - Import declaration for Methods -// QPID_CLASS_IMPORT - Import declaration for Classes -// QPID_INLINE_IMPORT - Import declaration for Inline methods -// - -#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) - // - // Import and Export definitions for Windows: - // -# define QPID_EXPORT __declspec(dllexport) -# define QPID_IMPORT __declspec(dllimport) -# ifdef _MSC_VER - // - // Specific to the Microsoft compiler: - // -# define QPID_CLASS_EXPORT -# define QPID_CLASS_IMPORT -# define QPID_INLINE_EXPORT QPID_EXPORT -# define QPID_INLINE_IMPORT QPID_IMPORT -# else - // - // Specific to non-Microsoft compilers (mingw32): - // -# define QPID_CLASS_EXPORT QPID_EXPORT -# define QPID_CLASS_IMPORT QPID_IMPORT -# define QPID_INLINE_EXPORT -# define QPID_INLINE_IMPORT -# endif -#else - // - // Non-Windows (Linux, etc.) definitions: - // -# define QPID_EXPORT -# define QPID_IMPORT -# define QPID_CLASS_EXPORT -# define QPID_CLASS_IMPORT -# define QPID_INLINE_EXPORT -# define QPID_INLINE_IMPORT -#endif - -#endif /*!QPID_IMPORTEXPORT_H*/ diff --git a/cpp/include/qpid/Msg.h b/cpp/include/qpid/Msg.h index 5f0b11bc60..e1837c29e5 100644 --- a/cpp/include/qpid/Msg.h +++ b/cpp/include/qpid/Msg.h @@ -24,7 +24,6 @@ #include <sstream> #include <iostream> -#include "qpid/types/ImportExport.h" namespace qpid { diff --git a/cpp/include/qpid/Options.h b/cpp/include/qpid/Options.h index 63d91c2d72..078a6b4d95 100644 --- a/cpp/include/qpid/Options.h +++ b/cpp/include/qpid/Options.h @@ -133,6 +133,77 @@ inline po::value_semantic* optValue(bool& value) { return po::bool_switch(&value +/* + * --------------------------------------------- + * Explanation for Boost 103200 conditional code + * --------------------------------------------- + * + * This boost version has an implementation of the program_options library + * that has no provision for allowing unregistered options to pass by. + * + * But that means that, if you have a program that loads optional modules + * after start-up, and those modules each have their own set of options, + * then if you parse the command line too soon, you will get spurious + * reports of unrecognized options -- and the program will exit! + * + * And we must process the command-line before module-loading, because we + * need to look at the "bootstrap" options. + * + * This conditional code: + * + * 1. implements it's own functor class, derived from the Boost + * "options_description_easy_init" class. This functor is used + * to process added options and do the functor chaining, so that + * I can snoop on the arguments before doing an explicit call + * to its parent. + * + * 2. It implements two static vectors, one to hold long names, and + * one for short names, so that options declared by modules are + * not forgotten when their options_description goes out of scope. + * + * I will be thrilled to personally delete this code if we ever decide + * that qpid doesn't really need to support this antique version of Boost. + * + */ + +#if ( BOOST_VERSION == 103200 ) +struct Options; + + +struct +options_description_less_easy_init + : public po::options_description_easy_init +{ + options_description_less_easy_init ( Options * my_owner, + po::options_description * my_parents_owner + ) + : po::options_description_easy_init(my_parents_owner) + { + owner = my_owner; + } + + + options_description_less_easy_init& + operator()(char const * name, + char const * description); + + + options_description_less_easy_init& + operator()(char const * name, + const po::value_semantic* s); + + + options_description_less_easy_init& + operator()(const char* name, + const po::value_semantic* s, + const char* description); + + + Options * owner; +}; +#endif + + struct Options : public po::options_description { struct Exception : public qpid::Exception { @@ -151,9 +222,26 @@ struct Options : public po::options_description { bool allowUnknown = false); + #if ( BOOST_VERSION == 103200 ) + options_description_less_easy_init m_less_easy; + + options_description_less_easy_init addOptions() { + return m_less_easy; + } + + bool + is_registered_option ( std::string s ); + + void + register_names ( std::string s ); + + static std::vector<std::string> long_names; + static std::vector<std::string> short_names; + #else boost::program_options::options_description_easy_init addOptions() { return add_options(); } + #endif }; diff --git a/cpp/include/qpid/Url.h b/cpp/include/qpid/Url.h index 915b08ac5f..353e9d5599 100644 --- a/cpp/include/qpid/Url.h +++ b/cpp/include/qpid/Url.h @@ -66,7 +66,7 @@ struct Url : public std::vector<Address> { *@exception Invalid if the url is invalid. */ QPID_COMMON_EXTERN void parse(const char* url); - QPID_COMMON_INLINE_EXTERN void parse(const std::string& url) { parse(url.c_str()); } + QPID_COMMON_EXTERN void parse(const std::string& url) { parse(url.c_str()); } /** Replace contesnts with parsed URL. Replace with empty URL if invalid. */ QPID_COMMON_EXTERN void parseNoThrow(const char* url); diff --git a/cpp/include/qpid/agent/ManagementAgent.h b/cpp/include/qpid/agent/ManagementAgent.h index 10bc6527a9..e2451244c1 100644 --- a/cpp/include/qpid/agent/ManagementAgent.h +++ b/cpp/include/qpid/agent/ManagementAgent.h @@ -110,8 +110,8 @@ class ManagementAgent 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") = 0; diff --git a/cpp/include/qpid/agent/QmfAgentImportExport.h b/cpp/include/qpid/agent/QmfAgentImportExport.h index 3f923ac4b2..e41425a7ba 100644 --- a/cpp/include/qpid/agent/QmfAgentImportExport.h +++ b/cpp/include/qpid/agent/QmfAgentImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - -#if defined(QMF_EXPORT) || defined (qmf_EXPORTS) -# define QMF_AGENT_EXTERN QPID_EXPORT -# define QMF_AGENT_CLASS_EXTERN QPID_CLASS_EXPORT -# define QMF_AGENT_INLINE_EXTERN QPID_INLINE_EXPORT +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) +#if defined (qmf_EXPORTS) +#define QMF_AGENT_EXTERN __declspec(dllexport) +#else +#define QMF_AGENT_EXTERN __declspec(dllimport) +#endif #else -# define QMF_AGENT_EXTERN QPID_IMPORT -# define QMF_AGENT_CLASS_EXTERN QPID_CLASS_IMPORT -# define QMF_AGENT_INLINE_EXTERN QPID_INLINE_IMPORT +#define QMF_AGENT_EXTERN #endif #endif diff --git a/cpp/include/qpid/amqp_0_10/Codecs.h b/cpp/include/qpid/amqp_0_10/Codecs.h index 73846f33a8..08275402fc 100644 --- a/cpp/include/qpid/amqp_0_10/Codecs.h +++ b/cpp/include/qpid/amqp_0_10/Codecs.h @@ -34,14 +34,14 @@ namespace amqp_0_10 { * Codec for encoding/decoding a map of Variants using the AMQP 0-10 * map encoding. */ -class QPID_COMMON_CLASS_EXTERN MapCodec +class QPID_COMMON_EXTERN MapCodec { public: typedef qpid::types::Variant::Map ObjectType; - static void QPID_COMMON_EXTERN encode(const ObjectType&, std::string&); - static void QPID_COMMON_EXTERN decode(const std::string&, ObjectType&); - static size_t QPID_COMMON_EXTERN encodedSize(const ObjectType&); - static const QPID_COMMON_EXTERN std::string contentType; + static void encode(const ObjectType&, std::string&); + static void decode(const std::string&, ObjectType&); + static size_t encodedSize(const ObjectType&); + static const std::string contentType; private: }; @@ -49,14 +49,14 @@ class QPID_COMMON_CLASS_EXTERN MapCodec * Codec for encoding/decoding a list of Variants using the AMQP 0-10 * list encoding. */ -class QPID_COMMON_CLASS_EXTERN ListCodec +class QPID_COMMON_EXTERN ListCodec { public: typedef qpid::types::Variant::List ObjectType; - static void QPID_COMMON_EXTERN encode(const ObjectType&, std::string&); - static void QPID_COMMON_EXTERN decode(const std::string&, ObjectType&); - static size_t QPID_COMMON_EXTERN encodedSize(const ObjectType&); - static const QPID_COMMON_EXTERN std::string contentType; + static void encode(const ObjectType&, std::string&); + static void decode(const std::string&, ObjectType&); + static size_t encodedSize(const ObjectType&); + static const std::string contentType; private: }; diff --git a/cpp/include/qpid/client/ClientImportExport.h b/cpp/include/qpid/client/ClientImportExport.h index 2a3a5a52e9..42b02e33c3 100644 --- a/cpp/include/qpid/client/ClientImportExport.h +++ b/cpp/include/qpid/client/ClientImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) #if defined(CLIENT_EXPORT) || defined (qpidclient_EXPORTS) -# define QPID_CLIENT_EXTERN QPID_EXPORT -# define QPID_CLIENT_CLASS_EXTERN QPID_CLASS_EXPORT -# define QPID_CLIENT_INLINE_EXTERN QPID_INLINE_EXPORT +#define QPID_CLIENT_EXTERN __declspec(dllexport) +#else +#define QPID_CLIENT_EXTERN __declspec(dllimport) +#endif #else -# define QPID_CLIENT_EXTERN QPID_IMPORT -# define QPID_CLIENT_CLASS_EXTERN QPID_CLASS_IMPORT -# define QPID_CLIENT_INLINE_EXTERN QPID_INLINE_IMPORT +#define QPID_CLIENT_EXTERN #endif #endif diff --git a/cpp/include/qpid/client/Completion.h b/cpp/include/qpid/client/Completion.h index 9546db9258..99d940f031 100644 --- a/cpp/include/qpid/client/Completion.h +++ b/cpp/include/qpid/client/Completion.h @@ -41,7 +41,7 @@ template <class T> class PrivateImplRef; * *\ingroup clientapi */ -class QPID_CLIENT_CLASS_EXTERN Completion : public Handle<CompletionImpl> +class Completion : public Handle<CompletionImpl> { public: QPID_CLIENT_EXTERN Completion(CompletionImpl* = 0); diff --git a/cpp/include/qpid/client/Connection.h b/cpp/include/qpid/client/Connection.h index c0db0f301d..6ed0d98bc0 100644 --- a/cpp/include/qpid/client/Connection.h +++ b/cpp/include/qpid/client/Connection.h @@ -60,7 +60,7 @@ class ConnectionImpl; * */ -class QPID_CLIENT_CLASS_EXTERN Connection +class Connection { framing::ProtocolVersion version; @@ -102,8 +102,8 @@ class QPID_CLIENT_CLASS_EXTERN Connection * within a single broker). */ QPID_CLIENT_EXTERN void open(const std::string& host, int port = 5672, - const std::string& uid = "", - const std::string& pwd = "", + const std::string& uid = "guest", + const std::string& pwd = "guest", const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); /** @@ -124,8 +124,8 @@ class QPID_CLIENT_CLASS_EXTERN Connection * within a single broker). */ QPID_CLIENT_EXTERN void open(const Url& url, - const std::string& uid = "", - const std::string& pwd = "", + const std::string& uid = "guest", + const std::string& pwd = "guest", const std::string& virtualhost = "/", uint16_t maxFrameSize=65535); /** diff --git a/cpp/include/qpid/client/ConnectionSettings.h b/cpp/include/qpid/client/ConnectionSettings.h index 2b6b86f891..1c2ee28b1b 100644 --- a/cpp/include/qpid/client/ConnectionSettings.h +++ b/cpp/include/qpid/client/ConnectionSettings.h @@ -37,7 +37,7 @@ namespace client { /** * Settings for a Connection. */ -struct QPID_CLIENT_CLASS_EXTERN ConnectionSettings { +struct ConnectionSettings { QPID_CLIENT_EXTERN ConnectionSettings(); QPID_CLIENT_EXTERN virtual ~ConnectionSettings(); diff --git a/cpp/include/qpid/client/FailoverListener.h b/cpp/include/qpid/client/FailoverListener.h index 53c7c26211..59108eb7cb 100644 --- a/cpp/include/qpid/client/FailoverListener.h +++ b/cpp/include/qpid/client/FailoverListener.h @@ -48,7 +48,7 @@ namespace client { * FailoverListener::decode to extract a list of broker URLs from a * failover exchange message. */ -class QPID_CLIENT_CLASS_EXTERN FailoverListener : private MessageListener, private qpid::sys::Runnable +class FailoverListener : private MessageListener, private qpid::sys::Runnable { public: /** The name of the standard failover exchange amq.failover */ diff --git a/cpp/include/qpid/client/FailoverManager.h b/cpp/include/qpid/client/FailoverManager.h index d3a0dbc976..0d30e2ed60 100644 --- a/cpp/include/qpid/client/FailoverManager.h +++ b/cpp/include/qpid/client/FailoverManager.h @@ -42,7 +42,7 @@ struct CannotConnectException : qpid::Exception /** * Utility to manage failover. */ -class QPID_CLIENT_CLASS_EXTERN FailoverManager +class FailoverManager { public: /** diff --git a/cpp/include/qpid/client/Future.h b/cpp/include/qpid/client/Future.h index 630a7e03c0..09088e68f6 100644 --- a/cpp/include/qpid/client/Future.h +++ b/cpp/include/qpid/client/Future.h @@ -34,7 +34,7 @@ namespace qpid { namespace client { /**@internal */ -class QPID_CLIENT_CLASS_EXTERN Future +class Future { framing::SequenceNumber command; boost::shared_ptr<FutureResult> result; diff --git a/cpp/include/qpid/client/FutureResult.h b/cpp/include/qpid/client/FutureResult.h index ead4929571..b2b663daa1 100644 --- a/cpp/include/qpid/client/FutureResult.h +++ b/cpp/include/qpid/client/FutureResult.h @@ -34,7 +34,7 @@ namespace client { class SessionImpl; ///@internal -class QPID_CLIENT_CLASS_EXTERN FutureResult : public FutureCompletion +class FutureResult : public FutureCompletion { std::string result; public: diff --git a/cpp/include/qpid/client/Handle.h b/cpp/include/qpid/client/Handle.h index b8315481a9..088e836fcf 100644 --- a/cpp/include/qpid/client/Handle.h +++ b/cpp/include/qpid/client/Handle.h @@ -40,22 +40,22 @@ template <class T> class Handle { public: /**@return true if handle is valid, i.e. not null. */ - QPID_CLIENT_INLINE_EXTERN bool isValid() const { return impl; } + QPID_CLIENT_EXTERN bool isValid() const { return impl; } /**@return true if handle is null. It is an error to call any function on a null handle. */ - QPID_CLIENT_INLINE_EXTERN bool isNull() const { return !impl; } + QPID_CLIENT_EXTERN bool isNull() const { return !impl; } /** Conversion to bool supports idiom if (handle) { handle->... } */ - QPID_CLIENT_INLINE_EXTERN operator bool() const { return impl; } + QPID_CLIENT_EXTERN operator bool() const { return impl; } /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */ - QPID_CLIENT_INLINE_EXTERN bool operator !() const { return !impl; } + QPID_CLIENT_EXTERN bool operator !() const { return !impl; } void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; } protected: typedef T Impl; - QPID_CLIENT_INLINE_EXTERN Handle() :impl() {} + QPID_CLIENT_EXTERN Handle() :impl() {} // Not implemented,subclasses must implement. QPID_CLIENT_EXTERN Handle(const Handle&); diff --git a/cpp/include/qpid/client/LocalQueue.h b/cpp/include/qpid/client/LocalQueue.h index 1a19a8499d..70e4cebcf1 100644 --- a/cpp/include/qpid/client/LocalQueue.h +++ b/cpp/include/qpid/client/LocalQueue.h @@ -71,7 +71,7 @@ template <class T> class PrivateImplRef; * </ul> */ -class QPID_CLIENT_CLASS_EXTERN LocalQueue : public Handle<LocalQueueImpl> { +class LocalQueue : public Handle<LocalQueueImpl> { public: /** Create a local queue. Subscribe the local queue to a remote broker * queue with a SubscriptionManager. diff --git a/cpp/include/qpid/client/Message.h b/cpp/include/qpid/client/Message.h index ba50dda9ba..2401cbdc92 100644 --- a/cpp/include/qpid/client/Message.h +++ b/cpp/include/qpid/client/Message.h @@ -112,7 +112,7 @@ class MessageImpl; * * */ -class QPID_CLIENT_CLASS_EXTERN Message +class Message { public: /** Create a Message. diff --git a/cpp/include/qpid/client/MessageListener.h b/cpp/include/qpid/client/MessageListener.h index 3ca2fa964a..d200f8cf21 100644 --- a/cpp/include/qpid/client/MessageListener.h +++ b/cpp/include/qpid/client/MessageListener.h @@ -84,7 +84,7 @@ namespace client { * */ - class QPID_CLIENT_CLASS_EXTERN MessageListener{ + class MessageListener{ public: QPID_CLIENT_EXTERN virtual ~MessageListener(); diff --git a/cpp/include/qpid/client/MessageReplayTracker.h b/cpp/include/qpid/client/MessageReplayTracker.h index 06a3f29c7d..6f5a0f4ac3 100644 --- a/cpp/include/qpid/client/MessageReplayTracker.h +++ b/cpp/include/qpid/client/MessageReplayTracker.h @@ -34,7 +34,7 @@ namespace client { * Utility to track messages sent asynchronously, allowing those that * are indoubt to be replayed over a new session. */ -class QPID_CLIENT_CLASS_EXTERN MessageReplayTracker +class MessageReplayTracker { public: QPID_CLIENT_EXTERN MessageReplayTracker(uint flushInterval); diff --git a/cpp/include/qpid/client/QueueOptions.h b/cpp/include/qpid/client/QueueOptions.h index 3984b63fdd..f8a4963f06 100644 --- a/cpp/include/qpid/client/QueueOptions.h +++ b/cpp/include/qpid/client/QueueOptions.h @@ -35,7 +35,7 @@ enum QueueOrderingPolicy {FIFO, LVQ, LVQ_NO_BROWSE}; * A help class to set options on the Queue. Create a configured args while * still allowing any custom configuration via the FieldTable base class */ -class QPID_CLIENT_CLASS_EXTERN QueueOptions: public framing::FieldTable +class QueueOptions: public framing::FieldTable { public: QPID_CLIENT_EXTERN QueueOptions(); diff --git a/cpp/include/qpid/client/SessionBase_0_10.h b/cpp/include/qpid/client/SessionBase_0_10.h index ea50ab32f7..3b5c84e74b 100644 --- a/cpp/include/qpid/client/SessionBase_0_10.h +++ b/cpp/include/qpid/client/SessionBase_0_10.h @@ -54,7 +54,7 @@ enum CreditUnit { MESSAGE_CREDIT=0, BYTE_CREDIT=1, UNLIMITED_CREDIT=0xFFFFFFFF } * Subclasses provide the AMQP commands for a given * version of the protocol. */ -class QPID_CLIENT_CLASS_EXTERN SessionBase_0_10 { +class SessionBase_0_10 { public: ///@internal diff --git a/cpp/include/qpid/client/Subscription.h b/cpp/include/qpid/client/Subscription.h index bb9b98e8ff..425b6b92e2 100644 --- a/cpp/include/qpid/client/Subscription.h +++ b/cpp/include/qpid/client/Subscription.h @@ -39,7 +39,7 @@ class SubscriptionManager; * A handle to an active subscription. Provides methods to query the subscription status * and control acknowledgement (acquire and accept) of messages. */ -class QPID_CLIENT_CLASS_EXTERN Subscription : public Handle<SubscriptionImpl> { +class Subscription : public Handle<SubscriptionImpl> { public: QPID_CLIENT_EXTERN Subscription(SubscriptionImpl* = 0); QPID_CLIENT_EXTERN Subscription(const Subscription&); @@ -91,13 +91,13 @@ class QPID_CLIENT_CLASS_EXTERN Subscription : public Handle<SubscriptionImpl> { QPID_CLIENT_EXTERN void release(const SequenceSet& messageIds); /* Acquire a single message */ - QPID_CLIENT_INLINE_EXTERN void acquire(const Message& m) { acquire(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void acquire(const Message& m) { acquire(SequenceSet(m.getId())); } /* Accept a single message */ - QPID_CLIENT_INLINE_EXTERN void accept(const Message& m) { accept(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void accept(const Message& m) { accept(SequenceSet(m.getId())); } /* Release a single message */ - QPID_CLIENT_INLINE_EXTERN void release(const Message& m) { release(SequenceSet(m.getId())); } + QPID_CLIENT_EXTERN void release(const Message& m) { release(SequenceSet(m.getId())); } /** Get the session associated with this subscription */ QPID_CLIENT_EXTERN Session getSession() const; diff --git a/cpp/include/qpid/client/SubscriptionManager.h b/cpp/include/qpid/client/SubscriptionManager.h index b69819a8ff..e70e05f73a 100644 --- a/cpp/include/qpid/client/SubscriptionManager.h +++ b/cpp/include/qpid/client/SubscriptionManager.h @@ -94,7 +94,7 @@ class SubscriptionManagerImpl; * </ul> * */ -class QPID_CLIENT_CLASS_EXTERN SubscriptionManager : public sys::Runnable, public Handle<SubscriptionManagerImpl> +class SubscriptionManager : public sys::Runnable, public Handle<SubscriptionManagerImpl> { public: /** Create a new SubscriptionManager associated with a session */ diff --git a/cpp/include/qpid/console/Agent.h b/cpp/include/qpid/console/Agent.h index 629dd71dee..97d75da250 100644 --- a/cpp/include/qpid/console/Agent.h +++ b/cpp/include/qpid/console/Agent.h @@ -31,17 +31,17 @@ namespace console { * * \ingroup qmfconsoleapi */ - class QPID_CONSOLE_CLASS_EXTERN Agent { + class QPID_CONSOLE_EXTERN Agent { public: typedef std::vector<Agent*> Vector; - QPID_CONSOLE_INLINE_EXTERN Agent(Broker* _broker, uint32_t _bank, const std::string& _label) : + Agent(Broker* _broker, uint32_t _bank, const std::string& _label) : broker(_broker), brokerBank(broker->getBrokerBank()), agentBank(_bank), label(_label) {} - QPID_CONSOLE_INLINE_EXTERN Broker* getBroker() const { return broker; } - QPID_CONSOLE_INLINE_EXTERN uint32_t getBrokerBank() const { return brokerBank; } - QPID_CONSOLE_INLINE_EXTERN uint32_t getAgentBank() const { return agentBank; } - QPID_CONSOLE_INLINE_EXTERN const std::string& getLabel() const { return label; } + Broker* getBroker() const { return broker; } + uint32_t getBrokerBank() const { return brokerBank; } + uint32_t getAgentBank() const { return agentBank; } + const std::string& getLabel() const { return label; } private: Broker* broker; @@ -50,7 +50,7 @@ namespace console { const std::string label; }; - std::ostream& operator<<(std::ostream& o, const Agent& agent); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Agent& agent); } } diff --git a/cpp/include/qpid/console/Broker.h b/cpp/include/qpid/console/Broker.h index c2ba8ac81f..0b2d1bcb61 100644 --- a/cpp/include/qpid/console/Broker.h +++ b/cpp/include/qpid/console/Broker.h @@ -55,12 +55,12 @@ namespace console { client::ConnectionSettings& settings); QPID_CONSOLE_EXTERN ~Broker(); - QPID_CONSOLE_INLINE_EXTERN bool isConnected() const { return connected; } - QPID_CONSOLE_INLINE_EXTERN const std::string& getError() const { return error; } - QPID_CONSOLE_INLINE_EXTERN const std::string& getSessionId() const { return amqpSessionId; } - QPID_CONSOLE_INLINE_EXTERN const framing::Uuid& getBrokerId() const { return brokerId; } - QPID_CONSOLE_INLINE_EXTERN uint32_t getBrokerBank() const { return 1; } - QPID_CONSOLE_INLINE_EXTERN void addBinding(const std::string& key) { + QPID_CONSOLE_EXTERN bool isConnected() const { return connected; } + QPID_CONSOLE_EXTERN const std::string& getError() const { return error; } + QPID_CONSOLE_EXTERN const std::string& getSessionId() const { return amqpSessionId; } + QPID_CONSOLE_EXTERN const framing::Uuid& getBrokerId() const { return brokerId; } + QPID_CONSOLE_EXTERN uint32_t getBrokerBank() const { return 1; } + QPID_CONSOLE_EXTERN void addBinding(const std::string& key) { connThreadBody.bindExchange("qpid.management", key); } QPID_CONSOLE_EXTERN std::string getUrl() const; @@ -123,10 +123,10 @@ namespace console { void setBrokerId(const framing::Uuid& id) { brokerId = id; } void appendAgents(std::vector<Agent*>& agents) const; - friend std::ostream& operator<<(std::ostream& o, const Broker& k); + friend QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k); }; - std::ostream& operator<<(std::ostream& o, const Broker& k); + QPID_CONSOLE_EXTERN std::ostream& operator<<(std::ostream& o, const Broker& k); } } diff --git a/cpp/include/qpid/console/ClassKey.h b/cpp/include/qpid/console/ClassKey.h index 5f7c50351a..95cd2627f1 100644 --- a/cpp/include/qpid/console/ClassKey.h +++ b/cpp/include/qpid/console/ClassKey.h @@ -33,24 +33,24 @@ namespace console { * * \ingroup qmfconsoleapi */ - class QPID_CONSOLE_CLASS_EXTERN ClassKey { + class QPID_CONSOLE_EXTERN ClassKey { public: - QPID_CONSOLE_EXTERN static const int HASH_SIZE = 16; + static const int HASH_SIZE = 16; - QPID_CONSOLE_EXTERN ClassKey(const std::string& package, const std::string& name, const uint8_t* hash); + ClassKey(const std::string& package, const std::string& name, const uint8_t* hash); - const QPID_CONSOLE_EXTERN std::string& getPackageName() const { return package; } - const QPID_CONSOLE_EXTERN std::string& getClassName() const { return name; } - const QPID_CONSOLE_EXTERN uint8_t* getHash() const { return hash; } - QPID_CONSOLE_EXTERN std::string getHashString() const; - QPID_CONSOLE_EXTERN std::string str() const; - QPID_CONSOLE_EXTERN bool operator==(const ClassKey& other) const; - QPID_CONSOLE_EXTERN bool operator!=(const ClassKey& other) const; - QPID_CONSOLE_EXTERN bool operator<(const ClassKey& other) const; - QPID_CONSOLE_EXTERN bool operator>(const ClassKey& other) const; - QPID_CONSOLE_EXTERN bool operator<=(const ClassKey& other) const; - QPID_CONSOLE_EXTERN bool operator>=(const ClassKey& other) const; - QPID_CONSOLE_EXTERN void encode(framing::Buffer& buffer) const; + const std::string& getPackageName() const { return package; } + const std::string& getClassName() const { return name; } + const uint8_t* getHash() const { return hash; } + std::string getHashString() const; + std::string str() const; + bool operator==(const ClassKey& other) const; + bool operator!=(const ClassKey& other) const; + bool operator<(const ClassKey& other) const; + bool operator>(const ClassKey& other) const; + bool operator<=(const ClassKey& other) const; + bool operator>=(const ClassKey& other) const; + void encode(framing::Buffer& buffer) const; private: std::string package; diff --git a/cpp/include/qpid/console/ConsoleImportExport.h b/cpp/include/qpid/console/ConsoleImportExport.h index aac30858f7..c2d7cb3a14 100644 --- a/cpp/include/qpid/console/ConsoleImportExport.h +++ b/cpp/include/qpid/console/ConsoleImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) #if defined(CONSOLE_EXPORT) || defined (qmfconsole_EXPORTS) -# define QPID_CONSOLE_EXTERN QPID_EXPORT -# define QPID_CONSOLE_CLASS_EXTERN QPID_CLASS_EXPORT -# define QPID_CONSOLE_INLINE_EXTERN QPID_INLINE_EXPORT +#define QPID_CONSOLE_EXTERN __declspec(dllexport) +#else +#define QPID_CONSOLE_EXTERN __declspec(dllimport) +#endif #else -# define QPID_CONSOLE_EXTERN QPID_IMPORT -# define QPID_CONSOLE_CLASS_EXTERN QPID_CLASS_IMPORT -# define QPID_CONSOLE_INLINE_EXTERN QPID_INLINE_IMPORT +#define QPID_CONSOLE_EXTERN #endif #endif diff --git a/cpp/include/qpid/console/ObjectId.h b/cpp/include/qpid/console/ObjectId.h index 0722eaebeb..7904c85598 100644 --- a/cpp/include/qpid/console/ObjectId.h +++ b/cpp/include/qpid/console/ObjectId.h @@ -40,10 +40,10 @@ namespace console { ObjectId() : first(0), second(0) {} ObjectId(framing::Buffer& buffer); - uint8_t getFlags() const { return (uint8_t)((first & 0xF000000000000000LL) >> 60); } - uint16_t getSequence() const { return (uint16_t)((first & 0x0FFF000000000000LL) >> 48); } - uint32_t getBrokerBank() const { return (uint32_t)((first & 0x0000FFFFF0000000LL) >> 28); } - uint32_t getAgentBank() const { return (uint32_t) (first & 0x000000000FFFFFFFLL); } + uint8_t getFlags() const { return (first & 0xF000000000000000LL) >> 60; } + uint16_t getSequence() const { return (first & 0x0FFF000000000000LL) >> 48; } + uint32_t getBrokerBank() const { return (first & 0x0000FFFFF0000000LL) >> 28; } + uint32_t getAgentBank() const { return first & 0x000000000FFFFFFFLL; } uint64_t getObject() const { return second; } bool isDurable() const { return getSequence() == 0; } void decode(framing::Buffer& buffer); diff --git a/cpp/include/qpid/framing/Array.h b/cpp/include/qpid/framing/Array.h index 1e97be3bb4..d3bdd36aa6 100644 --- a/cpp/include/qpid/framing/Array.h +++ b/cpp/include/qpid/framing/Array.h @@ -34,7 +34,7 @@ namespace framing { class Buffer; -class QPID_COMMON_CLASS_EXTERN Array +class Array { public: typedef boost::shared_ptr<FieldValue> ValuePtr; @@ -55,25 +55,25 @@ class QPID_COMMON_CLASS_EXTERN Array //creates a longstr array QPID_COMMON_EXTERN Array(const std::vector<std::string>& in); - QPID_COMMON_INLINE_EXTERN TypeCode getType() const { return type; } + QPID_COMMON_EXTERN TypeCode getType() const { return type; } // std collection interface. - QPID_COMMON_INLINE_EXTERN const_iterator begin() const { return values.begin(); } - QPID_COMMON_INLINE_EXTERN const_iterator end() const { return values.end(); } - QPID_COMMON_INLINE_EXTERN iterator begin() { return values.begin(); } - QPID_COMMON_INLINE_EXTERN iterator end(){ return values.end(); } + QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); } + QPID_COMMON_EXTERN const_iterator end() const { return values.end(); } + QPID_COMMON_EXTERN iterator begin() { return values.begin(); } + QPID_COMMON_EXTERN iterator end(){ return values.end(); } - QPID_COMMON_INLINE_EXTERN ValuePtr front() const { return values.front(); } - QPID_COMMON_INLINE_EXTERN ValuePtr back() const { return values.back(); } - QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } + QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); } + QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); } + QPID_COMMON_EXTERN size_t size() const { return values.size(); } QPID_COMMON_EXTERN void insert(iterator i, ValuePtr value); - QPID_COMMON_INLINE_EXTERN void erase(iterator i) { values.erase(i); } - QPID_COMMON_INLINE_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } - QPID_COMMON_INLINE_EXTERN void pop_back() { values.pop_back(); } + QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); } + QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } + QPID_COMMON_EXTERN void pop_back() { values.pop_back(); } // Non-std interface - QPID_COMMON_INLINE_EXTERN void add(ValuePtr value) { push_back(value); } + QPID_COMMON_EXTERN void add(ValuePtr value) { push_back(value); } template <class T> void collect(std::vector<T>& out) const diff --git a/cpp/include/qpid/framing/Buffer.h b/cpp/include/qpid/framing/Buffer.h index 8b08e60762..04583433c5 100644 --- a/cpp/include/qpid/framing/Buffer.h +++ b/cpp/include/qpid/framing/Buffer.h @@ -29,14 +29,14 @@ namespace qpid { namespace framing { -struct QPID_COMMON_CLASS_EXTERN OutOfBounds : qpid::Exception { +struct OutOfBounds : qpid::Exception { OutOfBounds() : qpid::Exception(std::string("Out of Bounds")) {} }; class Content; class FieldTable; -class QPID_COMMON_CLASS_EXTERN Buffer +class Buffer { uint32_t size; char* data; @@ -72,12 +72,12 @@ class QPID_COMMON_CLASS_EXTERN Buffer QPID_COMMON_EXTERN void restore(bool reRecord = false); QPID_COMMON_EXTERN void reset(); - QPID_COMMON_INLINE_EXTERN uint32_t available() { return size - position; } - QPID_COMMON_INLINE_EXTERN uint32_t getSize() { return size; } - QPID_COMMON_INLINE_EXTERN uint32_t getPosition() { return position; } - QPID_COMMON_INLINE_EXTERN void setPosition(uint32_t p) { position = p; } - QPID_COMMON_INLINE_EXTERN Iterator getIterator() { return Iterator(*this); } - QPID_COMMON_INLINE_EXTERN char* getPointer() { return data; } + QPID_COMMON_EXTERN uint32_t available() { return size - position; } + QPID_COMMON_EXTERN uint32_t getSize() { return size; } + QPID_COMMON_EXTERN uint32_t getPosition() { return position; } + QPID_COMMON_EXTERN void setPosition(uint32_t p) { position = p; } + QPID_COMMON_EXTERN Iterator getIterator() { return Iterator(*this); } + QPID_COMMON_EXTERN char* getPointer() { return data; } QPID_COMMON_EXTERN void putOctet(uint8_t i); QPID_COMMON_EXTERN void putShort(uint16_t i); diff --git a/cpp/include/qpid/framing/FieldTable.h b/cpp/include/qpid/framing/FieldTable.h index bdcef6d7fd..fdb1a28b9d 100644 --- a/cpp/include/qpid/framing/FieldTable.h +++ b/cpp/include/qpid/framing/FieldTable.h @@ -56,7 +56,7 @@ class FieldTable typedef ValueMap::reference reference; typedef ValueMap::value_type value_type; - QPID_COMMON_INLINE_EXTERN FieldTable() {}; + QPID_COMMON_EXTERN FieldTable() {}; QPID_COMMON_EXTERN FieldTable(const FieldTable& ft); QPID_COMMON_EXTERN ~FieldTable(); QPID_COMMON_EXTERN FieldTable& operator=(const FieldTable& ft); @@ -65,11 +65,9 @@ class FieldTable QPID_COMMON_EXTERN void decode(Buffer& buffer); QPID_COMMON_EXTERN int count() const; - QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } - QPID_COMMON_INLINE_EXTERN bool empty() { return size() == 0; } QPID_COMMON_EXTERN void set(const std::string& name, const ValuePtr& value); QPID_COMMON_EXTERN ValuePtr get(const std::string& name) const; - QPID_COMMON_INLINE_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; } + QPID_COMMON_EXTERN bool isSet(const std::string& name) const { return get(name).get() != 0; } QPID_COMMON_EXTERN void setString(const std::string& name, const std::string& value); QPID_COMMON_EXTERN void setInt(const std::string& name, const int value); diff --git a/cpp/include/qpid/framing/FieldValue.h b/cpp/include/qpid/framing/FieldValue.h index 458de62fdf..19220e74d5 100644 --- a/cpp/include/qpid/framing/FieldValue.h +++ b/cpp/include/qpid/framing/FieldValue.h @@ -41,14 +41,14 @@ namespace framing { * * \ingroup clientapi */ -class QPID_COMMON_CLASS_EXTERN FieldValueException : public qpid::Exception {}; +class FieldValueException : public qpid::Exception {}; /** * Exception thrown when we can't perform requested conversion * * \ingroup clientapi */ -struct QPID_COMMON_CLASS_EXTERN InvalidConversionException : public FieldValueException { +struct InvalidConversionException : public FieldValueException { InvalidConversionException() {} }; @@ -59,7 +59,7 @@ class List; * * \ingroup clientapi */ -class QPID_COMMON_CLASS_EXTERN FieldValue { +class FieldValue { public: /* * Abstract type for content of different types @@ -90,7 +90,7 @@ class QPID_COMMON_CLASS_EXTERN FieldValue { void encode(Buffer& buffer); void decode(Buffer& buffer); QPID_COMMON_EXTERN bool operator==(const FieldValue&) const; - QPID_COMMON_INLINE_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); } + QPID_COMMON_EXTERN bool operator!=(const FieldValue& v) const { return !(*this == v); } QPID_COMMON_EXTERN void print(std::ostream& out) const; @@ -98,7 +98,6 @@ class QPID_COMMON_CLASS_EXTERN FieldValue { template <typename T> T get() const { throw InvalidConversionException(); } template <class T, int W> T getIntegerValue() const; - template <class T> T getIntegerValue() const; template <class T, int W> T getFloatingPointValue() const; template <int W> void getFixedWidthValue(unsigned char*) const; template <class T> bool get(T&) const; @@ -197,18 +196,6 @@ inline T FieldValue::getIntegerValue() const } } -template <class T> -inline T FieldValue::getIntegerValue() const -{ - FixedWidthValue<1>* const fwv = dynamic_cast< FixedWidthValue<1>* const>(data.get()); - if (fwv) { - uint8_t* octets = fwv->rawOctets(); - return octets[0]; - } else { - throw InvalidConversionException(); - } -} - template <class T, int W> inline T FieldValue::getFloatingPointValue() const { FixedWidthValue<W>* const fwv = dynamic_cast< FixedWidthValue<W>* const>(data.get()); diff --git a/cpp/include/qpid/framing/List.h b/cpp/include/qpid/framing/List.h index 681445947c..0f17c7884c 100644 --- a/cpp/include/qpid/framing/List.h +++ b/cpp/include/qpid/framing/List.h @@ -36,11 +36,10 @@ class FieldValue; /** * Representation of an AMQP 0-10 list */ -class QPID_COMMON_CLASS_EXTERN List +class List { public: typedef boost::shared_ptr<FieldValue> ValuePtr; - typedef ValuePtr value_type; typedef std::list<ValuePtr> Values; typedef Values::const_iterator const_iterator; typedef Values::iterator iterator; @@ -54,19 +53,19 @@ class QPID_COMMON_CLASS_EXTERN List QPID_COMMON_EXTERN bool operator==(const List& other) const; // std collection interface. - QPID_COMMON_INLINE_EXTERN const_iterator begin() const { return values.begin(); } - QPID_COMMON_INLINE_EXTERN const_iterator end() const { return values.end(); } - QPID_COMMON_INLINE_EXTERN iterator begin() { return values.begin(); } - QPID_COMMON_INLINE_EXTERN iterator end(){ return values.end(); } + QPID_COMMON_EXTERN const_iterator begin() const { return values.begin(); } + QPID_COMMON_EXTERN const_iterator end() const { return values.end(); } + QPID_COMMON_EXTERN iterator begin() { return values.begin(); } + QPID_COMMON_EXTERN iterator end(){ return values.end(); } - QPID_COMMON_INLINE_EXTERN ValuePtr front() const { return values.front(); } - QPID_COMMON_INLINE_EXTERN ValuePtr back() const { return values.back(); } - QPID_COMMON_INLINE_EXTERN size_t size() const { return values.size(); } + QPID_COMMON_EXTERN ValuePtr front() const { return values.front(); } + QPID_COMMON_EXTERN ValuePtr back() const { return values.back(); } + QPID_COMMON_EXTERN size_t size() const { return values.size(); } - QPID_COMMON_INLINE_EXTERN iterator insert(iterator i, ValuePtr value) { return values.insert(i, value); } - QPID_COMMON_INLINE_EXTERN void erase(iterator i) { values.erase(i); } - QPID_COMMON_INLINE_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } - QPID_COMMON_INLINE_EXTERN void pop_back() { values.pop_back(); } + QPID_COMMON_EXTERN iterator insert(iterator i, ValuePtr value) { return values.insert(i, value); } + QPID_COMMON_EXTERN void erase(iterator i) { values.erase(i); } + QPID_COMMON_EXTERN void push_back(ValuePtr value) { values.insert(end(), value); } + QPID_COMMON_EXTERN void pop_back() { values.pop_back(); } private: Values values; diff --git a/cpp/include/qpid/framing/ProtocolVersion.h b/cpp/include/qpid/framing/ProtocolVersion.h index 30094c165d..e7e75d75f6 100644 --- a/cpp/include/qpid/framing/ProtocolVersion.h +++ b/cpp/include/qpid/framing/ProtocolVersion.h @@ -29,7 +29,7 @@ namespace qpid namespace framing { -class QPID_COMMON_CLASS_EXTERN ProtocolVersion +class ProtocolVersion { private: uint8_t major_; @@ -39,16 +39,16 @@ public: explicit ProtocolVersion(uint8_t _major=0, uint8_t _minor=0) : major_(_major), minor_(_minor) {} - QPID_COMMON_INLINE_EXTERN uint8_t getMajor() const { return major_; } - QPID_COMMON_INLINE_EXTERN void setMajor(uint8_t major) { major_ = major; } - QPID_COMMON_INLINE_EXTERN uint8_t getMinor() const { return minor_; } - QPID_COMMON_INLINE_EXTERN void setMinor(uint8_t minor) { minor_ = minor; } + QPID_COMMON_EXTERN uint8_t getMajor() const { return major_; } + QPID_COMMON_EXTERN void setMajor(uint8_t major) { major_ = major; } + QPID_COMMON_EXTERN uint8_t getMinor() const { return minor_; } + QPID_COMMON_EXTERN void setMinor(uint8_t minor) { minor_ = minor; } QPID_COMMON_EXTERN const std::string toString() const; QPID_COMMON_EXTERN ProtocolVersion& operator=(ProtocolVersion p); QPID_COMMON_EXTERN bool operator==(ProtocolVersion p) const; - QPID_COMMON_INLINE_EXTERN bool operator!=(ProtocolVersion p) const { return ! (*this == p); } + QPID_COMMON_EXTERN bool operator!=(ProtocolVersion p) const { return ! (*this == p); } }; } // namespace framing diff --git a/cpp/include/qpid/framing/SequenceNumber.h b/cpp/include/qpid/framing/SequenceNumber.h index eed15a4b75..1e53058df8 100644 --- a/cpp/include/qpid/framing/SequenceNumber.h +++ b/cpp/include/qpid/framing/SequenceNumber.h @@ -34,7 +34,7 @@ class Buffer; /** * 4-byte sequence number that 'wraps around'. */ -class QPID_COMMON_CLASS_EXTERN SequenceNumber : public +class SequenceNumber : public boost::equality_comparable< SequenceNumber, boost::less_than_comparable< SequenceNumber, boost::incrementable< diff --git a/cpp/include/qpid/framing/SequenceSet.h b/cpp/include/qpid/framing/SequenceSet.h index 0a78e418ba..39395e9ad7 100644 --- a/cpp/include/qpid/framing/SequenceSet.h +++ b/cpp/include/qpid/framing/SequenceSet.h @@ -29,7 +29,7 @@ namespace qpid { namespace framing { class Buffer; -class QPID_COMMON_CLASS_EXTERN SequenceSet : public RangeSet<SequenceNumber> { +class SequenceSet : public RangeSet<SequenceNumber> { public: SequenceSet() {} SequenceSet(const RangeSet<SequenceNumber>& r) diff --git a/cpp/include/qpid/framing/StructHelper.h b/cpp/include/qpid/framing/StructHelper.h index 21f9b91fa9..fc9a7909cc 100644 --- a/cpp/include/qpid/framing/StructHelper.h +++ b/cpp/include/qpid/framing/StructHelper.h @@ -30,7 +30,7 @@ namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN StructHelper +class StructHelper { public: diff --git a/cpp/include/qpid/framing/Uuid.h b/cpp/include/qpid/framing/Uuid.h index ccfd7e9534..d0a8d02411 100644 --- a/cpp/include/qpid/framing/Uuid.h +++ b/cpp/include/qpid/framing/Uuid.h @@ -52,22 +52,22 @@ struct Uuid : public boost::array<uint8_t, 16> { // boost::array gives us ==, < etc. /** Copy from 16 bytes of data. */ - QPID_COMMON_EXTERN void assign(const uint8_t* data); + void assign(const uint8_t* data); /** Set to a new unique identifier. */ QPID_COMMON_EXTERN void generate(); /** Set to all zeros. */ - QPID_COMMON_EXTERN void clear(); + void clear(); /** Test for null (all zeros). */ QPID_COMMON_EXTERN bool isNull() const; - QPID_COMMON_INLINE_EXTERN operator bool() const { return !isNull(); } - QPID_COMMON_INLINE_EXTERN bool operator!() const { return isNull(); } + operator bool() const { return !isNull(); } + bool operator!() const { return isNull(); } QPID_COMMON_EXTERN void encode(framing::Buffer& buf) const; QPID_COMMON_EXTERN void decode(framing::Buffer& buf); - QPID_COMMON_INLINE_EXTERN uint32_t encodedSize() const + QPID_COMMON_EXTERN uint32_t encodedSize() const { return static_cast<uint32_t>(size()); } /** String value in format 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb. */ diff --git a/cpp/include/qpid/log/Logger.h b/cpp/include/qpid/log/Logger.h index d255b7e150..783ab7bdb9 100644 --- a/cpp/include/qpid/log/Logger.h +++ b/cpp/include/qpid/log/Logger.h @@ -33,10 +33,10 @@ namespace log { * is handled by Logger::Output-derived classes instantiated by the * platform's sink-related options. */ -class QPID_COMMON_CLASS_EXTERN Logger : private boost::noncopyable { +class Logger : private boost::noncopyable { public: /** Flags indicating what to include in the log output */ - enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32, HIRES=64}; + enum FormatFlag { FILE=1, LINE=2, FUNCTION=4, LEVEL=8, TIME=16, THREAD=32}; /** * Logging output sink. @@ -93,7 +93,7 @@ class QPID_COMMON_CLASS_EXTERN Logger : private boost::noncopyable { QPID_COMMON_EXTERN void clear(); /** Get the options used to configure the logger. */ - QPID_COMMON_INLINE_EXTERN const Options& getOptions() const { return options; } + QPID_COMMON_EXTERN const Options& getOptions() const { return options; } private: diff --git a/cpp/include/qpid/log/Options.h b/cpp/include/qpid/log/Options.h index 17cbfde9bc..bbc47b47d3 100644 --- a/cpp/include/qpid/log/Options.h +++ b/cpp/include/qpid/log/Options.h @@ -39,7 +39,7 @@ struct Options : public qpid::Options { std::string argv0; std::string name; std::vector<std::string> selectors; - bool time, level, thread, source, function, hiresTs; + bool time, level, thread, source, function; bool trace; std::string prefix; std::auto_ptr<SinkOptions> sinkOptions; diff --git a/cpp/include/qpid/management/ManagementObject.h b/cpp/include/qpid/management/ManagementObject.h index 16bf21038c..747edda150 100644 --- a/cpp/include/qpid/management/ManagementObject.h +++ b/cpp/include/qpid/management/ManagementObject.h @@ -58,14 +58,14 @@ protected: std::string agentName; void fromString(const std::string&); public: - QPID_COMMON_INLINE_EXTERN ObjectId() : agent(0), first(0), second(0), agentEpoch(0) {} - QPID_COMMON_INLINE_EXTERN ObjectId(const types::Variant& map) : + QPID_COMMON_EXTERN ObjectId() : agent(0), first(0), second(0), agentEpoch(0) {} + QPID_COMMON_EXTERN ObjectId(const types::Variant& map) : agent(0), first(0), second(0), agentEpoch(0) { mapDecode(map.asMap()); } QPID_COMMON_EXTERN ObjectId(uint8_t flags, uint16_t seq, uint32_t broker); QPID_COMMON_EXTERN ObjectId(AgentAttachment* _agent, uint8_t flags, uint16_t seq); QPID_COMMON_EXTERN ObjectId(std::istream&); QPID_COMMON_EXTERN ObjectId(const std::string&); - QPID_COMMON_INLINE_EXTERN ObjectId(const std::string& agentAddress, const std::string& key, + QPID_COMMON_EXTERN ObjectId(const std::string& agentAddress, const std::string& key, uint64_t epoch=0) : agent(0), first(0), second(0), agentEpoch(epoch), v2Key(key), agentName(agentAddress) {} @@ -76,15 +76,15 @@ public: QPID_COMMON_EXTERN void mapEncode(types::Variant::Map& map) const; QPID_COMMON_EXTERN void mapDecode(const types::Variant::Map& map); QPID_COMMON_EXTERN operator types::Variant::Map() const; - QPID_COMMON_INLINE_EXTERN uint32_t encodedSize() const { return 16; }; + QPID_COMMON_EXTERN uint32_t encodedSize() const { return 16; }; QPID_COMMON_EXTERN void encode(std::string& buffer) const; QPID_COMMON_EXTERN void decode(const std::string& buffer); QPID_COMMON_EXTERN bool equalV1(const ObjectId &other) const; - QPID_COMMON_INLINE_EXTERN void setV2Key(const std::string& _key) { v2Key = _key; } + QPID_COMMON_EXTERN void setV2Key(const std::string& _key) { v2Key = _key; } QPID_COMMON_EXTERN void setV2Key(const ManagementObject& object); - QPID_COMMON_INLINE_EXTERN void setAgentName(const std::string& _name) { agentName = _name; } - QPID_COMMON_INLINE_EXTERN const std::string& getAgentName() const { return agentName; } - QPID_COMMON_INLINE_EXTERN const std::string& getV2Key() const { return v2Key; } + QPID_COMMON_EXTERN void setAgentName(const std::string& _name) { agentName = _name; } + QPID_COMMON_EXTERN const std::string& getAgentName() const { return agentName; } + QPID_COMMON_EXTERN const std::string& getV2Key() const { return v2Key; } friend QPID_COMMON_EXTERN std::ostream& operator<<(std::ostream&, const ObjectId&); }; @@ -131,7 +131,7 @@ public: virtual ~ManagementItem() {} }; -class QPID_COMMON_CLASS_EXTERN ManagementObject : public ManagementItem +class ManagementObject : public ManagementItem { protected: diff --git a/cpp/include/qpid/messaging/Address.h b/cpp/include/qpid/messaging/Address.h index 63dce0c49d..bebbfc72f6 100644 --- a/cpp/include/qpid/messaging/Address.h +++ b/cpp/include/qpid/messaging/Address.h @@ -119,7 +119,7 @@ class AddressImpl; * * An address has value semantics. */ -class QPID_MESSAGING_CLASS_EXTERN Address +class Address { public: QPID_MESSAGING_EXTERN Address(); diff --git a/cpp/include/qpid/messaging/Connection.h b/cpp/include/qpid/messaging/Connection.h index 165573e2ef..1ad7a7242f 100644 --- a/cpp/include/qpid/messaging/Connection.h +++ b/cpp/include/qpid/messaging/Connection.h @@ -42,7 +42,7 @@ class Session; * A connection represents a network connection to a remote endpoint. */ -class QPID_MESSAGING_CLASS_EXTERN Connection : public qpid::messaging::Handle<ConnectionImpl> +class Connection : public qpid::messaging::Handle<ConnectionImpl> { public: QPID_MESSAGING_EXTERN Connection(ConnectionImpl* impl); @@ -54,27 +54,27 @@ class QPID_MESSAGING_CLASS_EXTERN Connection : public qpid::messaging::Handle<Co * username * password * heartbeat - * tcp_nodelay - * sasl_mechanisms - * sasl_service - * sasl_min_ssf - * sasl_max_ssf + * tcp-nodelay + * sasl-mechanism + * sasl-service + * sasl-min-ssf + * sasl-max-ssf * transport * * Reconnect behaviour can be controlled through the following options: * * reconnect: true/false (enables/disables reconnect entirely) - * reconnect_timeout: number of seconds (give up and report failure after specified time) - * reconnect_limit: n (give up and report failure after specified number of attempts) - * reconnect_interval_min: number of seconds (initial delay between failed reconnection attempts) - * reconnect_interval_max: number of seconds (maximum delay between failed reconnection attempts) - * reconnect_interval: shorthand for setting the same reconnect_interval_min/max - * reconnect_urls: list of alternate urls to try when connecting + * reconnect-timeout: number of seconds (give up and report failure after specified time) + * reconnect-limit: n (give up and report failure after specified number of attempts) + * reconnect-interval-min: number of seconds (initial delay between failed reconnection attempts) + * reconnect-interval-max: number of seconds (maximum delay between failed reconnection attempts) + * reconnect-interval: shorthand for setting the same reconnect_interval_min/max + * reconnect-urls: list of alternate urls to try when connecting * - * The reconnect_interval is the time that the client waits + * The reconnect-interval is the time that the client waits * for after a failed attempt to reconnect before retrying. It - * starts at the value of the min_retry_interval and is - * doubled every failure until the value of max_retry_interval + * starts at the value of the min-retry-interval and is + * doubled every failure until the value of max-retry-interval * is reached. */ QPID_MESSAGING_EXTERN Connection(const std::string& url, const qpid::types::Variant::Map& options = qpid::types::Variant::Map()); diff --git a/cpp/include/qpid/messaging/Duration.h b/cpp/include/qpid/messaging/Duration.h index 6b8f05c7c6..abcf169090 100644 --- a/cpp/include/qpid/messaging/Duration.h +++ b/cpp/include/qpid/messaging/Duration.h @@ -32,7 +32,7 @@ namespace messaging { /** \ingroup messaging * A duration is a time in milliseconds. */ -class QPID_MESSAGING_CLASS_EXTERN Duration +class Duration { public: QPID_MESSAGING_EXTERN explicit Duration(uint64_t milliseconds); @@ -46,11 +46,9 @@ class QPID_MESSAGING_CLASS_EXTERN Duration }; QPID_MESSAGING_EXTERN Duration operator*(const Duration& duration, - uint64_t multiplier); + uint64_t multiplier); QPID_MESSAGING_EXTERN Duration operator*(uint64_t multiplier, - const Duration& duration); -QPID_MESSAGING_EXTERN bool operator==(const Duration& a, const Duration& b); -QPID_MESSAGING_EXTERN bool operator!=(const Duration& a, const Duration& b); + const Duration& duration); }} // namespace qpid::messaging diff --git a/cpp/include/qpid/messaging/FailoverUpdates.h b/cpp/include/qpid/messaging/FailoverUpdates.h index 6d7314620a..14a1a31b63 100644 --- a/cpp/include/qpid/messaging/FailoverUpdates.h +++ b/cpp/include/qpid/messaging/FailoverUpdates.h @@ -32,7 +32,7 @@ struct FailoverUpdatesImpl; * A utility to listen for updates on cluster membership and update * the list of known urls for a connection accordingly. */ -class QPID_MESSAGING_CLASS_EXTERN FailoverUpdates +class FailoverUpdates { public: QPID_MESSAGING_EXTERN FailoverUpdates(Connection& connection); diff --git a/cpp/include/qpid/messaging/Handle.h b/cpp/include/qpid/messaging/Handle.h index 97a8f00b54..1e634ef888 100644 --- a/cpp/include/qpid/messaging/Handle.h +++ b/cpp/include/qpid/messaging/Handle.h @@ -40,22 +40,22 @@ template <class T> class Handle { public: /**@return true if handle is valid, i.e. not null. */ - QPID_MESSAGING_INLINE_EXTERN bool isValid() const { return impl; } + QPID_MESSAGING_EXTERN bool isValid() const { return impl; } /**@return true if handle is null. It is an error to call any function on a null handle. */ - QPID_MESSAGING_INLINE_EXTERN bool isNull() const { return !impl; } + QPID_MESSAGING_EXTERN bool isNull() const { return !impl; } /** Conversion to bool supports idiom if (handle) { handle->... } */ - QPID_MESSAGING_INLINE_EXTERN operator bool() const { return impl; } + QPID_MESSAGING_EXTERN operator bool() const { return impl; } /** Operator ! supports idiom if (!handle) { do_if_handle_is_null(); } */ - QPID_MESSAGING_INLINE_EXTERN bool operator !() const { return !impl; } + QPID_MESSAGING_EXTERN bool operator !() const { return !impl; } void swap(Handle<T>& h) { T* t = h.impl; h.impl = impl; impl = t; } protected: typedef T Impl; - QPID_MESSAGING_INLINE_EXTERN Handle() :impl() {} + QPID_MESSAGING_EXTERN Handle() :impl() {} // Not implemented,subclasses must implement. QPID_MESSAGING_EXTERN Handle(const Handle&); diff --git a/cpp/include/qpid/messaging/ImportExport.h b/cpp/include/qpid/messaging/ImportExport.h index ab5f21f618..52f3eb8568 100644 --- a/cpp/include/qpid/messaging/ImportExport.h +++ b/cpp/include/qpid/messaging/ImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) #if defined(CLIENT_EXPORT) || defined (qpidmessaging_EXPORTS) -# define QPID_MESSAGING_EXTERN QPID_EXPORT -# define QPID_MESSAGING_CLASS_EXTERN QPID_CLASS_EXPORT -# define QPID_MESSAGING_INLINE_EXTERN QPID_INLINE_EXPORT +#define QPID_MESSAGING_EXTERN __declspec(dllexport) +#else +#define QPID_MESSAGING_EXTERN __declspec(dllimport) +#endif #else -# define QPID_MESSAGING_EXTERN QPID_IMPORT -# define QPID_MESSAGING_CLASS_EXTERN QPID_CLASS_IMPORT -# define QPID_MESSAGING_INLINE_EXTERN QPID_INLINE_IMPORT +#define QPID_MESSAGING_EXTERN #endif #endif /*!QPID_MESSAGING_IMPORTEXPORT_H*/ diff --git a/cpp/include/qpid/messaging/Message.h b/cpp/include/qpid/messaging/Message.h index e89a6ce02f..d48af35cc0 100644 --- a/cpp/include/qpid/messaging/Message.h +++ b/cpp/include/qpid/messaging/Message.h @@ -39,7 +39,7 @@ struct MessageImpl; /** \ingroup messaging * Representation of a message. */ -class QPID_MESSAGING_CLASS_EXTERN Message +class Message { public: QPID_MESSAGING_EXTERN Message(const std::string& bytes = std::string()); @@ -55,58 +55,23 @@ class QPID_MESSAGING_CLASS_EXTERN Message QPID_MESSAGING_EXTERN void setSubject(const std::string&); QPID_MESSAGING_EXTERN const std::string& getSubject() const; - /** - * Set the content type (i.e. the MIME type) for the message. This - * should be set by the sending application and indicates to - * recipients of message how to interpret or decode the content. - */ QPID_MESSAGING_EXTERN void setContentType(const std::string&); - /** - * Returns the content type (i.e. the MIME type) for the - * message. This can be used to determine how to decode the - * message content. - */ QPID_MESSAGING_EXTERN const std::string& getContentType() const; - /** - * Set an application defined identifier for the message. At - * present this must be a stringfied UUID (support for less - * restrictive IDs is anticipated however). - */ QPID_MESSAGING_EXTERN void setMessageId(const std::string&); QPID_MESSAGING_EXTERN const std::string& getMessageId() const; - /** - * Sets the user id of the message. This should in general be the - * user-id as which the sending connection authenticated itself as - * the messaging infrastructure will verify this. See - * Connection::getAuthenticatedUsername() - */ QPID_MESSAGING_EXTERN void setUserId(const std::string&); QPID_MESSAGING_EXTERN const std::string& getUserId() const; - /** - * Can be used to set application specific correlation identifiers - * as part of a protocol for message exchange patterns. E.g. a - * request-reponse pattern might require the correlation-id of the - * request and response to match, or might use the message-id of - * the request as the correlation-id on the response etc. - */ QPID_MESSAGING_EXTERN void setCorrelationId(const std::string&); QPID_MESSAGING_EXTERN const std::string& getCorrelationId() const; - /** - * Sets a priority level on the message. This may be used by the - * messaging infrastructure to prioritise delivery of higher - * priority messages. - */ QPID_MESSAGING_EXTERN void setPriority(uint8_t); QPID_MESSAGING_EXTERN uint8_t getPriority() const; /** - * Set the time to live for this message in milliseconds. This can - * be used by the messaging infrastructure to discard messages - * that are no longer of relevance. + * Set the time to live for this message in milliseconds. */ QPID_MESSAGING_EXTERN void setTtl(Duration ttl); /** @@ -114,62 +79,24 @@ class QPID_MESSAGING_CLASS_EXTERN Message */ QPID_MESSAGING_EXTERN Duration getTtl() const; - /** - * Mark the message as durable. This is a hint to the messaging - * infrastructure that the message should be persisted or - * otherwise stored such that failoures or shutdown do not cause - * it to be lost. - */ QPID_MESSAGING_EXTERN void setDurable(bool durable); QPID_MESSAGING_EXTERN bool getDurable() const; - /** - * The redelivered flag if set implies that the message *may* have - * been previously delivered and thus is a hint to the application - * or messaging infrastructure that if de-duplication is required - * this message should be examined to determine if it is a - * duplicate. - */ QPID_MESSAGING_EXTERN bool getRedelivered() const; - /** - * Can be used to provide a hint to the application or messaging - * infrastructure that if de-duplication is required this message - * should be examined to determine if it is a duplicate. - */ QPID_MESSAGING_EXTERN void setRedelivered(bool); - /** - * In addition to a payload (i.e. the content), messages can - * include annotations describing aspectf of the message. In - * addition to the standard annotations such as TTL and content - * type, application- or context- specific properties can also be - * defined. Each message has a map of name values for such custom - * properties. The value is specified as a Variant. - */ QPID_MESSAGING_EXTERN const qpid::types::Variant::Map& getProperties() const; QPID_MESSAGING_EXTERN qpid::types::Variant::Map& getProperties(); - /** - * Set the content to the data held in the string parameter. Note: - * this is treated as raw bytes and need not be text. Consider - * setting the content-type to indicate how the data should be - * interpreted by recipients. - */ QPID_MESSAGING_EXTERN void setContent(const std::string&); /** - * Copy count bytes from the region pointed to by chars as the - * message content. + * Note that chars are copied. */ QPID_MESSAGING_EXTERN void setContent(const char* chars, size_t count); /** Get the content as a std::string */ QPID_MESSAGING_EXTERN std::string getContent() const; - /** - * Get a const pointer to the start of the content data. The - * memory pointed to is owned by the message. The getContentSize() - * method indicates how much data there is (i.e. the extent of the - * memory region pointed to by the return value of this method). - */ + /** Get a const pointer to the start of the content data. */ QPID_MESSAGING_EXTERN const char* getContentPtr() const; /** Get the size of content in bytes. */ QPID_MESSAGING_EXTERN size_t getContentSize() const; @@ -180,9 +107,9 @@ class QPID_MESSAGING_CLASS_EXTERN Message friend struct MessageImplAccess; }; -struct QPID_MESSAGING_CLASS_EXTERN EncodingException : qpid::types::Exception +struct EncodingException : qpid::types::Exception { - QPID_MESSAGING_EXTERN EncodingException(const std::string& msg); + EncodingException(const std::string& msg); }; /** @@ -195,8 +122,8 @@ struct QPID_MESSAGING_CLASS_EXTERN EncodingException : qpid::types::Exception * @exception EncodingException */ QPID_MESSAGING_EXTERN void decode(const Message& message, - qpid::types::Variant::Map& map, - const std::string& encoding = std::string()); + qpid::types::Variant::Map& map, + const std::string& encoding = std::string()); /** * Decodes message content into a Variant::List. * @@ -207,8 +134,8 @@ QPID_MESSAGING_EXTERN void decode(const Message& message, * @exception EncodingException */ QPID_MESSAGING_EXTERN void decode(const Message& message, - qpid::types::Variant::List& list, - const std::string& encoding = std::string()); + qpid::types::Variant::List& list, + const std::string& encoding = std::string()); /** * Encodes a Variant::Map into a message. * @@ -219,8 +146,8 @@ QPID_MESSAGING_EXTERN void decode(const Message& message, * @exception EncodingException */ QPID_MESSAGING_EXTERN void encode(const qpid::types::Variant::Map& map, - Message& message, - const std::string& encoding = std::string()); + Message& message, + const std::string& encoding = std::string()); /** * Encodes a Variant::List into a message. * @@ -231,8 +158,8 @@ QPID_MESSAGING_EXTERN void encode(const qpid::types::Variant::Map& map, * @exception EncodingException */ QPID_MESSAGING_EXTERN void encode(const qpid::types::Variant::List& list, - Message& message, - const std::string& encoding = std::string()); + Message& message, + const std::string& encoding = std::string()); }} // namespace qpid::messaging diff --git a/cpp/include/qpid/messaging/Receiver.h b/cpp/include/qpid/messaging/Receiver.h index 13317dfcbd..6f3ae961db 100644 --- a/cpp/include/qpid/messaging/Receiver.h +++ b/cpp/include/qpid/messaging/Receiver.h @@ -41,7 +41,7 @@ class Session; /** \ingroup messaging * Interface through which messages are received. */ -class QPID_MESSAGING_CLASS_EXTERN Receiver : public qpid::messaging::Handle<ReceiverImpl> +class Receiver : public qpid::messaging::Handle<ReceiverImpl> { public: QPID_MESSAGING_EXTERN Receiver(ReceiverImpl* impl = 0); diff --git a/cpp/include/qpid/messaging/Sender.h b/cpp/include/qpid/messaging/Sender.h index 8e1c5846e9..85658f37cc 100644 --- a/cpp/include/qpid/messaging/Sender.h +++ b/cpp/include/qpid/messaging/Sender.h @@ -40,7 +40,7 @@ class Session; /** \ingroup messaging * Interface through which messages are sent. */ -class QPID_MESSAGING_CLASS_EXTERN Sender : public qpid::messaging::Handle<SenderImpl> +class Sender : public qpid::messaging::Handle<SenderImpl> { public: QPID_MESSAGING_EXTERN Sender(SenderImpl* impl = 0); diff --git a/cpp/include/qpid/messaging/Session.h b/cpp/include/qpid/messaging/Session.h index e8d6efb35d..6c023629e0 100644 --- a/cpp/include/qpid/messaging/Session.h +++ b/cpp/include/qpid/messaging/Session.h @@ -46,7 +46,7 @@ class SessionImpl; * A session represents a distinct 'conversation' which can involve * sending and receiving messages to and from different addresses. */ -class QPID_MESSAGING_CLASS_EXTERN Session : public qpid::messaging::Handle<SessionImpl> +class Session : public qpid::messaging::Handle<SessionImpl> { public: QPID_MESSAGING_EXTERN Session(SessionImpl* impl = 0); @@ -62,12 +62,6 @@ class QPID_MESSAGING_CLASS_EXTERN Session : public qpid::messaging::Handle<Sessi */ QPID_MESSAGING_EXTERN void close(); - /** - * Commits the sessions transaction. - * - * @exception TransactionAborted if the original session is lost - * forcing an automatic rollback. - */ QPID_MESSAGING_EXTERN void commit(); QPID_MESSAGING_EXTERN void rollback(); @@ -84,10 +78,6 @@ class QPID_MESSAGING_CLASS_EXTERN Session : public qpid::messaging::Handle<Sessi */ QPID_MESSAGING_EXTERN void acknowledge(Message&, bool sync=false); /** - * Acknowledges all message up to the specified message. - */ - QPID_MESSAGING_EXTERN void acknowledgeUpTo(Message&, bool sync=false); - /** * Rejects the specified message. The broker does not redeliver a * message that has been rejected. Once a message has been * acknowledged, it can no longer be rejected. @@ -145,51 +135,25 @@ class QPID_MESSAGING_CLASS_EXTERN Session : public qpid::messaging::Handle<Sessi /** * Create a new sender through which messages can be sent to the * specified address. - * - * @exception ResolutionError if there is an error in resolving - * the address */ QPID_MESSAGING_EXTERN Sender createSender(const Address& address); - /** - * Create a new sender through which messages can be sent to the - * specified address. - * - * @exception ResolutionError if there is an error in resolving - * the address - * - * @exception MalformedAddress if the syntax of address is not - * valid - */ QPID_MESSAGING_EXTERN Sender createSender(const std::string& address); /** * Create a new receiver through which messages can be received * from the specified address. - * - * @exception ResolutionError if there is an error in resolving - * the address */ QPID_MESSAGING_EXTERN Receiver createReceiver(const Address& address); - /** - * Create a new receiver through which messages can be received - * from the specified address. - * - * @exception ResolutionError if there is an error in resolving - * the address - * - * @exception MalformedAddress if the syntax of address is not - * valid - */ QPID_MESSAGING_EXTERN Receiver createReceiver(const std::string& address); /** * Returns the sender with the specified name. - * @exception KeyError if there is none for that name. + *@exception KeyError if there is none for that name. */ QPID_MESSAGING_EXTERN Sender getSender(const std::string& name) const; /** * Returns the receiver with the specified name. - * @exception KeyError if there is none for that name. + *@exception KeyError if there is none for that name. */ QPID_MESSAGING_EXTERN Receiver getReceiver(const std::string& name) const; /** @@ -198,16 +162,7 @@ class QPID_MESSAGING_CLASS_EXTERN Session : public qpid::messaging::Handle<Sessi */ QPID_MESSAGING_EXTERN Connection getConnection() const; - /** - * @returns true if the session has been rendered invalid by some - * exception, false if it is valid for use. - */ QPID_MESSAGING_EXTERN bool hasError(); - /** - * If the session has been rendered invalid by some exception, - * this method will result in that exception being thrown on - * calling this method. - */ QPID_MESSAGING_EXTERN void checkError(); #ifndef SWIG diff --git a/cpp/include/qpid/messaging/exceptions.h b/cpp/include/qpid/messaging/exceptions.h index 31e2488d91..0ff608b343 100644 --- a/cpp/include/qpid/messaging/exceptions.h +++ b/cpp/include/qpid/messaging/exceptions.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,47 +29,34 @@ namespace qpid { namespace messaging { -/** \ingroup messaging +/** \ingroup messaging */ -/** - * This is the base class for all messaging related exceptions thrown - * by this API. - */ -struct QPID_MESSAGING_CLASS_EXTERN MessagingException : public qpid::types::Exception +struct MessagingException : public qpid::types::Exception { QPID_MESSAGING_EXTERN MessagingException(const std::string& msg); QPID_MESSAGING_EXTERN virtual ~MessagingException() throw(); - + qpid::types::Variant::Map detail; //TODO: override what() to include detail if present }; -/** - * Thrown when the syntax of the option string used to configure a - * connection in not valid - */ -struct QPID_MESSAGING_CLASS_EXTERN InvalidOptionString : public MessagingException +struct InvalidOptionString : public MessagingException { QPID_MESSAGING_EXTERN InvalidOptionString(const std::string& msg); }; -/** - * Thrown to indicate a failed lookup of some local object. For - * example when attempting to retrieve a session, sender or receiver - * by name. - */ -struct QPID_MESSAGING_CLASS_EXTERN KeyError : public MessagingException +struct KeyError : public MessagingException { QPID_MESSAGING_EXTERN KeyError(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN LinkError : public MessagingException +struct LinkError : public MessagingException { QPID_MESSAGING_EXTERN LinkError(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN AddressError : public LinkError +struct AddressError : public LinkError { QPID_MESSAGING_EXTERN AddressError(const std::string&); }; @@ -78,118 +65,85 @@ struct QPID_MESSAGING_CLASS_EXTERN AddressError : public LinkError * Thrown when a syntactically correct address cannot be resolved or * used. */ -struct QPID_MESSAGING_CLASS_EXTERN ResolutionError : public AddressError +struct ResolutionError : public AddressError { QPID_MESSAGING_EXTERN ResolutionError(const std::string& msg); }; -/** - * Thrown when creating a sender or receiver for an address for which - * some asserted property of the node is not matched. - */ -struct QPID_MESSAGING_CLASS_EXTERN AssertionFailed : public ResolutionError +struct AssertionFailed : public ResolutionError { QPID_MESSAGING_EXTERN AssertionFailed(const std::string& msg); }; -/** - * Thrown on attempts to create a sender or receiver to a non-existent - * node. - */ -struct QPID_MESSAGING_CLASS_EXTERN NotFound : public ResolutionError +struct NotFound : public ResolutionError { QPID_MESSAGING_EXTERN NotFound(const std::string& msg); }; /** - * Thrown when an address string with invalid syntax is used. + * Thrown when an address string with inalid sytanx is used. */ -struct QPID_MESSAGING_CLASS_EXTERN MalformedAddress : public AddressError +struct MalformedAddress : public AddressError { QPID_MESSAGING_EXTERN MalformedAddress(const std::string& msg); }; -struct QPID_MESSAGING_CLASS_EXTERN ReceiverError : public LinkError +struct ReceiverError : public LinkError { QPID_MESSAGING_EXTERN ReceiverError(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN FetchError : public ReceiverError +struct FetchError : public ReceiverError { QPID_MESSAGING_EXTERN FetchError(const std::string&); }; -/** - * Thrown by Receiver::fetch(), Receiver::get() and - * Session::nextReceiver() to indicate that there no message was - * available before the timeout specified. - */ -struct QPID_MESSAGING_CLASS_EXTERN NoMessageAvailable : public FetchError +struct NoMessageAvailable : public FetchError { QPID_MESSAGING_EXTERN NoMessageAvailable(); }; -struct QPID_MESSAGING_CLASS_EXTERN SenderError : public LinkError +struct SenderError : public LinkError { QPID_MESSAGING_EXTERN SenderError(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN SendError : public SenderError +struct SendError : public SenderError { QPID_MESSAGING_EXTERN SendError(const std::string&); }; -/** - * Thrown to indicate that the sender attempted to send a message that - * would result in the target node on the peer exceeding a - * preconfigured capacity. - */ -struct QPID_MESSAGING_CLASS_EXTERN TargetCapacityExceeded : public SendError +struct TargetCapacityExceeded : public SendError { QPID_MESSAGING_EXTERN TargetCapacityExceeded(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN SessionError : public MessagingException +struct SessionError : public MessagingException { QPID_MESSAGING_EXTERN SessionError(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN TransactionError : public SessionError +struct TransactionError : public SessionError { QPID_MESSAGING_EXTERN TransactionError(const std::string&); }; -/** - * Thrown on Session::commit() if reconnection results in the - * transaction being automatically aborted. - */ -struct QPID_MESSAGING_CLASS_EXTERN TransactionAborted : public TransactionError +struct TransactionAborted : public TransactionError { QPID_MESSAGING_EXTERN TransactionAborted(const std::string&); }; -/** - * Thrown to indicate that the application attempted to do something - * for which it was not authorised by its peer. - */ -struct QPID_MESSAGING_CLASS_EXTERN UnauthorizedAccess : public SessionError +struct UnauthorizedAccess : public SessionError { QPID_MESSAGING_EXTERN UnauthorizedAccess(const std::string&); }; -struct QPID_MESSAGING_CLASS_EXTERN ConnectionError : public MessagingException +struct ConnectionError : public MessagingException { QPID_MESSAGING_EXTERN ConnectionError(const std::string&); }; -/** - * Thrown to indicate loss of underlying connection. When - * auto-reconnect is used this will be caught by the library and used - * to trigger reconnection attempts. If reconnection fails (according - * to whatever settings have been configured), then an instnace of - * this class will be thrown to signal that. - */ -struct QPID_MESSAGING_CLASS_EXTERN TransportFailure : public MessagingException +struct TransportFailure : public MessagingException { QPID_MESSAGING_EXTERN TransportFailure(const std::string&); }; diff --git a/cpp/include/qpid/sys/ExceptionHolder.h b/cpp/include/qpid/sys/ExceptionHolder.h index 4bc934cf75..9eff1d64c7 100644 --- a/cpp/include/qpid/sys/ExceptionHolder.h +++ b/cpp/include/qpid/sys/ExceptionHolder.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 @@ -42,11 +42,14 @@ class ExceptionHolder : public Raisable { public: ExceptionHolder() {} // Use default copy & assign. - + /** Take ownership of ex */ template <class Ex> ExceptionHolder(Ex* ex) { wrap(ex); } - template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; } + template <class Ex> ExceptionHolder(const boost::shared_ptr<Ex>& ex) { wrap(ex.release()); } + template <class Ex> ExceptionHolder& operator=(Ex* ex) { wrap(ex); return *this; } + template <class Ex> ExceptionHolder& operator=(boost::shared_ptr<Ex> ex) { wrap(ex.release()); return *this; } + void raise() const { if (wrapper.get()) wrapper->raise() ; } std::string what() const { return wrapper.get() ? wrapper->what() : std::string(); } bool empty() const { return !wrapper.get(); } @@ -63,7 +66,7 @@ class ExceptionHolder : public Raisable { template <class Ex> void wrap(Ex* ex) { wrapper.reset(new Wrapper<Ex>(ex)); } boost::shared_ptr<Raisable> wrapper; }; - + }} // namespace qpid::sys diff --git a/cpp/include/qpid/sys/IntegerTypes.h b/cpp/include/qpid/sys/IntegerTypes.h index 75fa921de0..89635f033e 100755 --- a/cpp/include/qpid/sys/IntegerTypes.h +++ b/cpp/include/qpid/sys/IntegerTypes.h @@ -21,7 +21,7 @@ * */ -#if (defined(_WINDOWS) || defined (WIN32)) +#if (defined(_WINDOWS) || defined (WIN32)) && defined(_MSC_VER) #include "qpid/sys/windows/IntegerTypes.h" #endif #if !defined _WINDOWS && !defined WIN32 diff --git a/cpp/include/qpid/sys/Runnable.h b/cpp/include/qpid/sys/Runnable.h index fed7663cb6..0f1243a277 100644 --- a/cpp/include/qpid/sys/Runnable.h +++ b/cpp/include/qpid/sys/Runnable.h @@ -30,7 +30,7 @@ namespace sys { /** * Interface for objects that can be run, e.g. in a thread. */ -class QPID_COMMON_CLASS_EXTERN Runnable +class Runnable { public: /** Type to represent a runnable as a Functor */ diff --git a/cpp/include/qpid/sys/Thread.h b/cpp/include/qpid/sys/Thread.h index f556612908..45a39e796f 100644 --- a/cpp/include/qpid/sys/Thread.h +++ b/cpp/include/qpid/sys/Thread.h @@ -25,11 +25,7 @@ #include "qpid/CommonImportExport.h" #ifdef _WIN32 -# ifdef _MSC_VER -# define QPID_TSS __declspec(thread) -# else -# define QPID_TSS __thread -# endif +# define QPID_TSS __declspec(thread) #elif defined (__GNUC__) # define QPID_TSS __thread #elif defined (__SUNPRO_CC) diff --git a/cpp/include/qpid/sys/Time.h b/cpp/include/qpid/sys/Time.h index 9c5ac66e9a..d3ab832229 100644 --- a/cpp/include/qpid/sys/Time.h +++ b/cpp/include/qpid/sys/Time.h @@ -119,7 +119,7 @@ class Duration { friend class AbsTime; public: - QPID_COMMON_INLINE_EXTERN inline Duration(int64_t time0 = 0); + QPID_COMMON_EXTERN inline Duration(int64_t time0 = 0); QPID_COMMON_EXTERN explicit Duration(const AbsTime& start, const AbsTime& finish); inline operator int64_t() const; }; @@ -167,9 +167,6 @@ QPID_COMMON_EXTERN void usleep(uint64_t usecs); /** Output formatted date/time for now*/ void outputFormattedNow(std::ostream&); -/** Output unformatted nanosecond-resolution time for now */ -void outputHiresNow(std::ostream&); - }} #endif /*!_sys_Time_h*/ diff --git a/cpp/include/qpid/sys/windows/IntegerTypes.h b/cpp/include/qpid/sys/windows/IntegerTypes.h index 28b82da1a0..ece1a618e9 100755 --- a/cpp/include/qpid/sys/windows/IntegerTypes.h +++ b/cpp/include/qpid/sys/windows/IntegerTypes.h @@ -22,17 +22,13 @@ */ typedef unsigned char uint8_t; +typedef char int8_t; typedef unsigned short uint16_t; typedef short int16_t; typedef unsigned int uint32_t; typedef int int32_t; -#if defined(_MSC_VER) -typedef signed char int8_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; -#else -#include <stdint.h> -#endif // Visual Studio doesn't define other common types, so set them up here too. typedef unsigned int uint; diff --git a/cpp/include/qpid/types/Exception.h b/cpp/include/qpid/types/Exception.h index 483d104cc8..d061a7df0e 100644 --- a/cpp/include/qpid/types/Exception.h +++ b/cpp/include/qpid/types/Exception.h @@ -28,7 +28,7 @@ namespace qpid { namespace types { -class QPID_TYPES_CLASS_EXTERN Exception : public std::exception +class Exception : public std::exception { public: QPID_TYPES_EXTERN explicit Exception(const std::string& message=std::string()) throw(); diff --git a/cpp/include/qpid/types/ImportExport.h b/cpp/include/qpid/types/ImportExport.h index 8fa41884fb..bb10575fcd 100644 --- a/cpp/include/qpid/types/ImportExport.h +++ b/cpp/include/qpid/types/ImportExport.h @@ -20,16 +20,14 @@ * under the License. */ -#include "qpid/ImportExport.h" - +#if defined(WIN32) && !defined(QPID_DECLARE_STATIC) #if defined(TYPES_EXPORT) || defined (qpidtypes_EXPORTS) -# define QPID_TYPES_EXTERN QPID_EXPORT -# define QPID_TYPES_CLASS_EXTERN QPID_CLASS_EXPORT -# define QPID_TYPES_INLINE_EXTERN QPID_INLINE_EXPORT +#define QPID_TYPES_EXTERN __declspec(dllexport) +#else +#define QPID_TYPES_EXTERN __declspec(dllimport) +#endif #else -# define QPID_TYPES_EXTERN QPID_IMPORT -# define QPID_TYPES_CLASS_EXTERN QPID_CLASS_IMPORT -# define QPID_TYPES_INLINE_EXTERN QPID_INLINE_IMPORT +#define QPID_TYPES_EXTERN #endif #endif /*!QPID_TYPES_IMPORTEXPORT_H*/ diff --git a/cpp/include/qpid/types/Uuid.h b/cpp/include/qpid/types/Uuid.h index 02af4c7e7f..467a895184 100644 --- a/cpp/include/qpid/types/Uuid.h +++ b/cpp/include/qpid/types/Uuid.h @@ -29,7 +29,7 @@ namespace qpid { namespace types { -class QPID_TYPES_CLASS_EXTERN Uuid +class Uuid { public: static const size_t SIZE; diff --git a/cpp/include/qpid/types/Variant.h b/cpp/include/qpid/types/Variant.h index 4459fc4123..9ae672b7c2 100644 --- a/cpp/include/qpid/types/Variant.h +++ b/cpp/include/qpid/types/Variant.h @@ -36,7 +36,7 @@ namespace types { /** * Thrown when an illegal conversion of a variant is attempted. */ -struct QPID_TYPES_CLASS_EXTERN InvalidConversion : public Exception +struct InvalidConversion : public Exception { InvalidConversion(const std::string& msg); }; @@ -60,14 +60,12 @@ enum VariantType { VAR_UUID }; -std::string getTypeName(VariantType type); - class VariantImpl; /** * Represents a value of variable type. */ -class QPID_TYPES_CLASS_EXTERN Variant +class Variant { public: typedef std::map<std::string, Variant> Map; diff --git a/cpp/managementgen/Makefile.am b/cpp/managementgen/Makefile.am index 4fc5edcad4..6c2024ccaa 100644 --- a/cpp/managementgen/Makefile.am +++ b/cpp/managementgen/Makefile.am @@ -19,26 +19,20 @@ qmfpythondir = $(pythondir) dist_bin_SCRIPTS = \ qmf-gen - -pkgpyexec_qmfgendir = $(pyexecdir)/qmfgen -pkgpyexec_qmfgen_PYTHON = \ +nobase_qmfpython_DATA = \ qmfgen/__init__.py \ qmfgen/generate.py \ qmfgen/schema.py \ - qmfgen/management-types.xml - -pkgpyexec_qmfgentmpldir = $(pyexecdir)/qmfgen/templates -pkgpyexec_qmfgentmpl_PYTHON = \ qmfgen/templates/Args.h \ qmfgen/templates/Class.cpp \ qmfgen/templates/Class.h \ - qmfgen/templates/CMakeLists.cmake \ qmfgen/templates/Event.cpp \ qmfgen/templates/Event.h \ qmfgen/templates/Makefile.mk \ qmfgen/templates/Package.cpp \ qmfgen/templates/Package.h \ qmfgen/templates/V2Package.cpp \ - qmfgen/templates/V2Package.h + qmfgen/templates/V2Package.h \ + qmfgen/management-types.xml EXTRA_DIST = $(nobase_qmfpython_DATA) CMakeLists.txt diff --git a/cpp/managementgen/qmfgen/schema.py b/cpp/managementgen/qmfgen/schema.py index 59e951fb6e..afdfe42639 100755 --- a/cpp/managementgen/qmfgen/schema.py +++ b/cpp/managementgen/qmfgen/schema.py @@ -1731,9 +1731,9 @@ class SchemaPackage: stream.write(" qmf::SchemaProperty arg(\"%s\", %s);\n" % (arg.name, typeName)) if subType: stream.write(" arg.setSubtype(\"%s\");\n" % subType) - if arg.unit: + if stat.unit: stream.write(" arg.setUnit(\"%s\");\n" % arg.unit) - if arg.desc: + if stat.desc: stream.write(" arg.setDesc(\"%s\");\n" % arg.desc) stream.write(" arg.setDirection(%s);\n" % self.qmfv2Dir(arg.dir)) stream.write(" method.addArgument(arg);\n") diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index ef193f5fd0..7366599eba 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -252,7 +252,7 @@ class Specification < CppGen include "#{@dir}/specification" namespace(@ns) { genl "template <class F, class R=typename F::result_type>" - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", "ProxyTemplate") { + cpp_class("ProxyTemplate") { public genl "ProxyTemplate(F f=F()) : functor(f) {}" @amqp.classes.each { |c| diff --git a/cpp/rubygen/MethodBodyDefaultVisitor.rb b/cpp/rubygen/MethodBodyDefaultVisitor.rb index 11dbcb8f83..4f9b369117 100755 --- a/cpp/rubygen/MethodBodyDefaultVisitor.rb +++ b/cpp/rubygen/MethodBodyDefaultVisitor.rb @@ -33,7 +33,7 @@ class MethodBodyDefaultVisitorGen < CppGen include "qpid/framing/MethodBodyConstVisitor" namespace(@namespace) { genl - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", @classname, "public MethodBodyConstVisitor") { + cpp_class(@classname, "public MethodBodyConstVisitor") { genl "public:" genl "virtual void defaultVisit() = 0;" @amqp.methods_.each { |m| diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb index 88720cad5f..69e65a4056 100755 --- a/cpp/rubygen/amqpgen.rb +++ b/cpp/rubygen/amqpgen.rb @@ -61,8 +61,7 @@ end class Module # Add trailing _ to avoid conflict with Object methods. def mangle(sym) - sym = (sym.to_s+"_").to_sym if (Object.method_defined?(sym) or sym == :type) - sym + (Object.method_defined? sym) ? (sym.to_s+"_").intern : sym end # Add attribute reader for XML attribute. @@ -191,8 +190,7 @@ class AmqpElement "command-fragments" => "session.command-fragment", "in-doubt" => "dtx.xid", "tx-publish" => "str-8", - "queues" => "str-8", - "prepared" => "str-8" + "queues" => "str-8" } def array_type(name) diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index 7dc21fe1bc..f0995105f1 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -377,9 +377,6 @@ class CppGen < Generator def cpp_class(name, *bases, &block) struct_class("class", name, bases, &block); end - def cpp_extern_class(scope, name, *bases, &block) - struct_class("class "+scope, name, bases, &block); - end def typedef(type, name) genl "typedef #{type} #{name};\n"; end diff --git a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb index 4c58ff2bbb..00962de4f9 100755 --- a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb +++ b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb @@ -33,7 +33,7 @@ class MethodBodyDefaultVisitorGen < CppGen include "qpid/CommonImportExport.h" namespace(@namespace) { genl "class AMQMethodBody;" - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", @classname, "public MethodBodyConstVisitor") { + cpp_class(@classname, "public MethodBodyConstVisitor") { genl "public:" genl "virtual void defaultVisit(const AMQMethodBody&) = 0;" @amqp.methods_.each { |m| diff --git a/cpp/rubygen/framing.0-10/OperationsInvoker.rb b/cpp/rubygen/framing.0-10/OperationsInvoker.rb index f9b5ce58d8..f9b6cac76b 100755 --- a/cpp/rubygen/framing.0-10/OperationsInvoker.rb +++ b/cpp/rubygen/framing.0-10/OperationsInvoker.rb @@ -69,7 +69,7 @@ class OperationsInvokerGen < CppGen def invoker_h(invoker, target, methods) return if methods.empty? genl - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", invoker, "public qpid::framing::Invoker") { + cpp_class(invoker, "public qpid::framing::Invoker") { genl "#{target}& target;" public genl("Invoker(#{target}& target_) : target(target_) {}") diff --git a/cpp/rubygen/framing.0-10/Proxy.rb b/cpp/rubygen/framing.0-10/Proxy.rb index 3325616754..6e3cb4fd4d 100755 --- a/cpp/rubygen/framing.0-10/Proxy.rb +++ b/cpp/rubygen/framing.0-10/Proxy.rb @@ -37,7 +37,7 @@ class ProxyGen < CppGen def inner_class_decl(c) cname=c.name.caps - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", cname, "public Proxy") { + cpp_class(cname, "public Proxy") { gen <<EOS public: #{cname}(FrameHandler& f) : Proxy(f) {} @@ -69,7 +69,7 @@ EOS include "qpid/CommonImportExport.h" namespace("qpid::framing") { - cpp_extern_class("QPID_COMMON_CLASS_EXTERN", @classname, "public Proxy") { + cpp_class(@classname, "public Proxy") { public genl "QPID_COMMON_EXTERN #{@classname}(FrameHandler& out);" genl diff --git a/cpp/rubygen/framing.0-10/Session.rb b/cpp/rubygen/framing.0-10/Session.rb index e800df9b2e..61f0e03a8b 100755 --- a/cpp/rubygen/framing.0-10/Session.rb +++ b/cpp/rubygen/framing.0-10/Session.rb @@ -56,8 +56,8 @@ module SyncAsync def decl_ctor_opeq() genl genl "QPID_CLIENT_EXTERN #{@classname}();" - genl "QPID_CLIENT_INLINE_EXTERN #{@classname}(const #{@version_base}& other);" - genl "QPID_CLIENT_INLINE_EXTERN #{@classname}& operator=(const #{@version_base}& other);" + genl "QPID_CLIENT_EXTERN #{@classname}(const #{@version_base}& other);" + genl "QPID_CLIENT_EXTERN #{@classname}& operator=(const #{@version_base}& other);" end def defn_ctor_opeq(inline="") diff --git a/cpp/rubygen/framing.0-10/structs.rb b/cpp/rubygen/framing.0-10/structs.rb index 62b33ce773..c3684aea66 100755 --- a/cpp/rubygen/framing.0-10/structs.rb +++ b/cpp/rubygen/framing.0-10/structs.rb @@ -406,7 +406,7 @@ EOS namespace qpid { namespace framing { -class QPID_COMMON_CLASS_EXTERN #{classname} #{inheritance} { +class #{classname} #{inheritance} { EOS if (is_packed(s)) indent { s.fields.each { |f| genl "#{f.cpptype.name} #{f.cppname};" unless f.type_ == "bit"} } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 0dbcf8e2e6..60f505a10e 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -96,7 +96,7 @@ MACRO (add_msvc_version_full verProject verProjectType verProjectFileExt verFN1 inherit_value ("winver_${verProject}_InternalName" "${verProject}") inherit_value ("winver_${verProject}_OriginalFilename" "${verProject}.${verProjectFileExt}") inherit_value ("winver_${verProject}_ProductName" "${winver_DESCRIPTION_SUMMARY}") - + # Create strings to be substituted into the template file set ("winverFileVersionBinary" "${winver_${verProject}_FileVersionBinary}") set ("winverProductVersionBinary" "${winver_${verProject}_ProductVersionBinary}") @@ -126,7 +126,7 @@ ENDMACRO (add_msvc_version_full) # MACRO (add_msvc_version verProject verProjectType verProjectFileExt) if (MSVC) - add_msvc_version_full (${verProject} + add_msvc_version_full (${verProject} ${verProjectType} ${verProjectFileExt} ${winver_FILE_VERSION_N1} @@ -313,6 +313,10 @@ if (NOT Boost_FILESYSTEM_LIBRARY) set(Boost_FILESYSTEM_LIBRARY boost_filesystem) endif (NOT Boost_FILESYSTEM_LIBRARY) +if (NOT Boost_SYSTEM_LIBRARY) + set(Boost_SYSTEM_LIBRARY boost_system) +endif (NOT Boost_SYSTEM_LIBRARY) + if (NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) set(Boost_UNIT_TEST_FRAMEWORK_LIBRARY boost_unit_test_framework) endif (NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) @@ -580,15 +584,6 @@ include (ssl.cmake) check_symbol_exists (LOG_AUTHPRIV "sys/syslog.h" HAVE_LOG_AUTHPRIV) check_symbol_exists (LOG_FTP "sys/syslog.h" HAVE_LOG_FTP) -# Allow MSVC user to select 'WinXP-SP3/Windows Server 2003' as build target version -set (win32_winnt_default OFF) -if (CMAKE_SYSTEM_NAME STREQUAL Windows) - if (MSVC) - set (win32_winnt_default ON) - endif (MSVC) -endif (CMAKE_SYSTEM_NAME STREQUAL Windows) -option(SET_WIN32_WINNT "In Windows-MSVC build: define _WIN32_WINNT=0x0502 to select target version: Windows XP with SP3" ${win32_winnt_default}) - if (CMAKE_SYSTEM_NAME STREQUAL Windows) if (MSVC) add_definitions( @@ -598,11 +593,10 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) /wd4244 /wd4800 /wd4355 - /wd4267 ) - if (SET_WIN32_WINNT) - add_definitions(/D "_WIN32_WINNT=0x0502") - endif (SET_WIN32_WINNT) + if (MSVC80) + add_definitions(/D "_WIN32_WINNT=0x0501") + endif (MSVC80) # set the RelWithDebInfo compile/link switches to equal Release set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "/MD /O2 /Ob2 /D NDEBUG") @@ -634,7 +628,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) qpid/sys/windows/LockFile.cpp qpid/sys/windows/PipeHandle.cpp qpid/sys/windows/PollableCondition.cpp - qpid/sys/windows/SCM.cpp qpid/sys/windows/Shlib.cpp qpid/sys/windows/Socket.cpp qpid/sys/windows/SocketAddress.cpp @@ -647,7 +640,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) ) set (qpidcommon_platform_LIBS - ${Boost_THREAD_LIBRARY} ${windows_ssl_libs} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ws2_32 ) + ${windows_ssl_libs} ws2_32 + ) set (qpidbroker_platform_SOURCES qpid/broker/windows/BrokerDefaults.cpp qpid/broker/windows/SaslAuthenticator.cpp @@ -666,8 +660,9 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows) set (qpidd_platform_SOURCES windows/QpiddBroker.cpp + windows/SCM.cpp ) - + set (qpidmessaging_platform_SOURCES qpid/messaging/HandleInstantiator.cpp ) @@ -925,6 +920,8 @@ set (qpidmessaging_SOURCES qpid/client/amqp0_10/SessionImpl.cpp qpid/client/amqp0_10/SenderImpl.h qpid/client/amqp0_10/SenderImpl.cpp + qpid/client/amqp0_10/SimpleUrlParser.h + qpid/client/amqp0_10/SimpleUrlParser.cpp ) add_msvc_version (qpidmessaging library dll) @@ -946,7 +943,7 @@ if (NOT QPID_GENERATED_HEADERS_IN_SOURCE) endif (NOT QPID_GENERATED_HEADERS_IN_SOURCE) -if (MSVC) +if (WIN32) # Install the DtcPlugin project and call it qpidxarm. set(AMQP_WCF_DIR ${qpid-cpp_SOURCE_DIR}/../wcf) set(qpidxarm_SOURCES ${AMQP_WCF_DIR}/src/Apache/Qpid/DtcPlugin/DtcPlugin.cpp) @@ -959,7 +956,7 @@ if (MSVC) COMPONENT ${QPID_COMPONENT_CLIENT}) install_pdb (qpidxarm ${QPID_COMPONENT_CLIENT}) endif (EXISTS ${qpidxarm_SOURCES}) -endif (MSVC) +endif (WIN32) set (qpidbroker_SOURCES ${mgen_broker_cpp} @@ -977,8 +974,6 @@ set (qpidbroker_SOURCES qpid/broker/Queue.cpp qpid/broker/QueueCleaner.cpp qpid/broker/QueueListeners.cpp - qpid/broker/FifoDistributor.cpp - qpid/broker/MessageGroupManager.cpp qpid/broker/PersistableMessage.cpp qpid/broker/Bridge.cpp qpid/broker/Connection.cpp @@ -995,6 +990,7 @@ set (qpidbroker_SOURCES qpid/broker/ExchangeRegistry.cpp qpid/broker/FanOutExchange.cpp qpid/broker/HeadersExchange.cpp + qpid/broker/IncompleteMessageList.cpp qpid/broker/Link.cpp qpid/broker/LinkRegistry.cpp qpid/broker/Message.cpp @@ -1007,7 +1003,7 @@ set (qpidbroker_SOURCES qpid/broker/QueueEvents.cpp qpid/broker/QueuePolicy.cpp qpid/broker/QueueRegistry.cpp - qpid/broker/QueueFlowLimit.cpp + qpid/broker/RateTracker.cpp qpid/broker/RecoveryManagerImpl.cpp qpid/broker/RecoveredEnqueue.cpp qpid/broker/RecoveredDequeue.cpp @@ -1073,15 +1069,13 @@ endif (CPACK_GENERATOR STREQUAL "NSIS") # REVISION => Version of underlying implementation. # Bump if implementation changes but API/ABI doesn't # AGE => Number of API/ABI versions this is backward compatible with -set (qmf_version 2.0.0) -set (qmf2_version 1.0.0) +set (qmf_version 1.0.0) set (qmfengine_version 1.0.0) set (qmf_SOURCES qpid/agent/ManagementAgentImpl.cpp qpid/agent/ManagementAgentImpl.h ) - add_msvc_version (qmf library dll) add_library (qmf SHARED ${qmf_SOURCES}) target_link_libraries (qmf qpidclient) @@ -1092,88 +1086,6 @@ install (TARGETS qmf OPTIONAL COMPONENT ${QPID_COMPONENT_QMF}) install_pdb (qmf ${QPID_COMPONENT_QMF}) -if(NOT WIN32) - set (qmf2_HEADERS - ../include/qmf/AgentEvent.h - ../include/qmf/Agent.h - ../include/qmf/AgentSession.h - ../include/qmf/ConsoleEvent.h - ../include/qmf/ConsoleSession.h - ../include/qmf/DataAddr.h - ../include/qmf/Data.h - ../include/qmf/exceptions.h - ../include/qmf/Handle.h - ../include/qmf/ImportExport.h - ../include/qmf/posix/EventNotifier.h - ../include/qmf/Query.h - ../include/qmf/Schema.h - ../include/qmf/SchemaId.h - ../include/qmf/SchemaMethod.h - ../include/qmf/SchemaProperty.h - ../include/qmf/SchemaTypes.h - ../include/qmf/Subscription.h - ) - - set (qmf2_SOURCES - ${qmf2_HEADERS} - qmf/agentCapability.h - qmf/Agent.cpp - qmf/AgentEvent.cpp - qmf/AgentEventImpl.h - qmf/AgentImpl.h - qmf/AgentSession.cpp - qmf/AgentSubscription.cpp - qmf/AgentSubscription.h - qmf/ConsoleEvent.cpp - qmf/ConsoleEventImpl.h - qmf/ConsoleSession.cpp - qmf/ConsoleSessionImpl.h - qmf/constants.cpp - qmf/constants.h - qmf/DataAddr.cpp - qmf/DataAddrImpl.h - qmf/Data.cpp - qmf/DataImpl.h - qmf/EventNotifierImpl.h - qmf/EventNotifierImpl.cpp - qmf/PosixEventNotifier.cpp - qmf/PosixEventNotifierImpl.cpp - qmf/exceptions.cpp - qmf/Expression.cpp - qmf/Expression.h - qmf/Hash.cpp - qmf/Hash.h - qmf/PrivateImplRef.h - qmf/Query.cpp - qmf/QueryImpl.h - qmf/Schema.cpp - qmf/SchemaCache.cpp - qmf/SchemaCache.h - qmf/SchemaId.cpp - qmf/SchemaIdImpl.h - qmf/SchemaImpl.h - qmf/SchemaMethod.cpp - qmf/SchemaMethodImpl.h - qmf/SchemaProperty.cpp - qmf/SchemaPropertyImpl.h - qmf/Subscription.cpp - qmf/SubscriptionImpl.h - ) - - add_msvc_version (qmf2 library dll) - add_library (qmf2 SHARED ${qmf2_SOURCES}) - target_link_libraries (qmf2 qpidmessaging qpidtypes qpidclient qpidcommon) - set_target_properties (qmf2 PROPERTIES - VERSION ${qmf2_version}) - install (TARGETS qmf2 OPTIONAL - DESTINATION ${QPID_INSTALL_LIBDIR} - COMPONENT ${QPID_COMPONENT_QMF}) - install (FILES ${qmf2_HEADERS} - DESTINATION ${QPID_INSTALL_INCLUDEDIR}/qmf - COMPONENT ${QPID_COMPONENT_QMF}) - install_pdb (qmf2 ${QPID_COMPONENT_QMF}) -endif (NOT WIN32) - set (qmfengine_SOURCES qmf/engine/Agent.cpp qmf/engine/BrokerProxyImpl.cpp diff --git a/cpp/src/CMakeWinVersions.cmake b/cpp/src/CMakeWinVersions.cmake index 0bac7cab47..9bffd2ba0e 100644 --- a/cpp/src/CMakeWinVersions.cmake +++ b/cpp/src/CMakeWinVersions.cmake @@ -34,11 +34,11 @@ # set ("winver_PACKAGE_NAME" "qpid-cpp")
# set ("winver_DESCRIPTION_SUMMARY" "Apache Qpid C++")
# set ("winver_FILE_VERSION_N1" "0")
-# set ("winver_FILE_VERSION_N2" "11")
+# set ("winver_FILE_VERSION_N2" "9")
# set ("winver_FILE_VERSION_N3" "0")
# set ("winver_FILE_VERSION_N4" "0")
# set ("winver_PRODUCT_VERSION_N1" "0")
-# set ("winver_PRODUCT_VERSION_N2" "11")
+# set ("winver_PRODUCT_VERSION_N2" "9")
# set ("winver_PRODUCT_VERSION_N3" "0")
# set ("winver_PRODUCT_VERSION_N4" "0")
# set ("winver_LEGAL_COPYRIGHT" "")
@@ -46,10 +46,10 @@ #
# Specification of per-project settings:
#
-# set ("winver_${projectName}_FileVersionBinary" "0,11,0,0")
-# set ("winver_${projectName}_ProductVersionBinary" "0,11,0,0")
-# set ("winver_${projectName}_FileVersionString" "0, 11, 0, 0")
-# set ("winver_${projectName}_ProductVersionString" "0, 11, 0, 0")
+# set ("winver_${projectName}_FileVersionBinary" "0,9,0,0")
+# set ("winver_${projectName}_ProductVersionBinary" "0,9,0,0")
+# set ("winver_${projectName}_FileVersionString" "0, 9, 0, 0")
+# set ("winver_${projectName}_ProductVersionString" "0, 9, 0, 0")
# set ("winver_${projectName}_FileDescription" "qpid-cpp-qpidcommon Library")
# set ("winver_${projectName}_LegalCopyright" "")
# set ("winver_${projectName}_InternalName" "qpidcommon")
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am index 6230a8f6f6..2cd6ad462f 100644 --- a/cpp/src/Makefile.am +++ b/cpp/src/Makefile.am @@ -37,7 +37,6 @@ windows_dist = \ qpid/sys/windows/IOHandle.cpp \ qpid/sys/windows/IoHandlePrivate.h \ qpid/sys/windows/LockFile.cpp \ - qpid/sys/windows/mingw32_compat.h \ qpid/sys/windows/PollableCondition.cpp \ qpid/sys/windows/PipeHandle.cpp \ ../include/qpid/sys/windows/Mutex.h \ @@ -89,7 +88,7 @@ rgen_cmd=ruby -I $(rgen_dir) $(rgen_dir)/generate . ../include $(specs) all $(rgen_srcs) $(srcdir)/rubygen.mk: rgen.timestamp rgen.timestamp: $(rgen_generator) $(specs) - $(rgen_cmd) $(srcdir)/rubygen.mk && touch $@ + $(rgen_cmd) $(srcdir)/rubygen.mk; touch $@ $(rgen_generator): # The CMake version is needed for dist @@ -128,14 +127,14 @@ qpidexec_SCRIPTS = qpidtestdir = $(qpidexecdir)/tests qpidtest_PROGRAMS = qpidtest_SCRIPTS = -tmoduleexecdir = $(libdir)/qpid/tests -tmoduleexec_LTLIBRARIES= +tmoduledir = $(libdir)/qpid/tests +tmodule_LTLIBRARIES= AM_CXXFLAGS += -DBOOST_FILESYSTEM_VERSION=2 ## Automake macros to build libraries and executables. -qpidd_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDD_MODULE_DIR=\"$(dmoduleexecdir)\" -DQPIDD_CONF_FILE=\"$(sysconfdir)/qpidd.conf\" -libqpidclient_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_MODULE_DIR=\"$(cmoduleexecdir)\" -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\" +qpidd_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDD_MODULE_DIR=\"$(dmoduledir)\" -DQPIDD_CONF_FILE=\"$(sysconfdir)/qpidd.conf\" +libqpidclient_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_MODULE_DIR=\"$(cmoduledir)\" -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.conf\" qpidd_LDADD = \ libqpidbroker.la \ @@ -177,7 +176,7 @@ nobase_include_HEADERS += \ ../include/qpid/sys/posix/Time.h \ ../include/qpid/sys/posix/check.h -if HAVE_EPOLL +if HAVE_EPOLL poller = qpid/sys/epoll/EpollPoller.cpp endif @@ -196,15 +195,15 @@ libqpidcommon_la_SOURCES += $(poller) $(systeminfo) posix_broker_src = \ qpid/broker/posix/BrokerDefaults.cpp -lib_LTLIBRARIES = libqpidtypes.la libqpidcommon.la libqpidbroker.la libqpidclient.la libqpidmessaging.la +lib_LTLIBRARIES = libqpidtypes.la libqpidcommon.la libqpidbroker.la libqpidclient.la libqpidmessaging.la # Definitions for client and daemon plugins PLUGINLDFLAGS=-no-undefined -module -avoid-version confdir=$(sysconfdir)/qpid -dmoduleexecdir=$(libdir)/qpid/daemon -cmoduleexecdir=$(libdir)/qpid/client -dmoduleexec_LTLIBRARIES = -cmoduleexec_LTLIBRARIES = +dmoduledir=$(libdir)/qpid/daemon +cmoduledir=$(libdir)/qpid/client +dmodule_LTLIBRARIES = +cmodule_LTLIBRARIES = include cluster.mk include acl.mk @@ -246,7 +245,7 @@ rdma_la_LIBADD = \ rdma_la_LDFLAGS = $(PLUGINLDFLAGS) rdma_la_CXXFLAGS = \ $(AM_CXXFLAGS) -Wno-missing-field-initializers -dmoduleexec_LTLIBRARIES += \ +dmodule_LTLIBRARIES += \ rdma.la rdmaconnector_la_SOURCES = \ @@ -258,7 +257,7 @@ rdmaconnector_la_LIBADD = \ rdmaconnector_la_LDFLAGS = $(PLUGINLDFLAGS) rdmaconnector_la_CXXFLAGS = \ $(AM_CXXFLAGS) -Wno-missing-field-initializers -cmoduleexec_LTLIBRARIES += \ +cmodule_LTLIBRARIES += \ rdmaconnector.la # RDMA test/sample programs @@ -333,7 +332,6 @@ libqpidcommon_la_SOURCES += \ qpid/Address.cpp \ qpid/DataDir.cpp \ qpid/DataDir.h \ - qpid/DisableExceptionLogging.h \ qpid/Exception.cpp \ qpid/Modules.cpp \ qpid/Modules.h \ @@ -343,7 +341,6 @@ libqpidcommon_la_SOURCES += \ qpid/RefCounted.h \ qpid/RefCountedBuffer.cpp \ qpid/RefCountedBuffer.h \ - qpid/BufferRef.h \ qpid/Sasl.h \ qpid/SaslFactory.cpp \ qpid/SaslFactory.h \ @@ -564,7 +561,8 @@ libqpidbroker_la_SOURCES = \ qpid/broker/HandlerImpl.h \ qpid/broker/HeadersExchange.cpp \ qpid/broker/HeadersExchange.h \ - qpid/broker/AsyncCompletion.h \ + qpid/broker/IncompleteMessageList.cpp \ + qpid/broker/IncompleteMessageList.h \ qpid/broker/LegacyLVQ.h \ qpid/broker/LegacyLVQ.cpp \ qpid/broker/Link.cpp \ @@ -614,9 +612,9 @@ libqpidbroker_la_SOURCES = \ qpid/broker/QueueRegistry.cpp \ qpid/broker/QueueRegistry.h \ qpid/broker/QueuedMessage.h \ - qpid/broker/QueueFlowLimit.h \ - qpid/broker/QueueFlowLimit.cpp \ qpid/broker/RateFlowcontrol.h \ + qpid/broker/RateTracker.cpp \ + qpid/broker/RateTracker.h \ qpid/broker/RecoverableConfig.h \ qpid/broker/RecoverableExchange.h \ qpid/broker/RecoverableMessage.h \ @@ -653,7 +651,6 @@ libqpidbroker_la_SOURCES = \ qpid/broker/SessionState.h \ qpid/broker/SignalHandler.cpp \ qpid/broker/SignalHandler.h \ - qpid/broker/StatefulQueueObserver.h \ qpid/broker/System.cpp \ qpid/broker/System.h \ qpid/broker/ThresholdAlerts.cpp \ @@ -671,11 +668,6 @@ libqpidbroker_la_SOURCES = \ qpid/broker/TxPublish.h \ qpid/broker/Vhost.cpp \ qpid/broker/Vhost.h \ - qpid/broker/MessageDistributor.h \ - qpid/broker/FifoDistributor.h \ - qpid/broker/FifoDistributor.cpp \ - qpid/broker/MessageGroupManager.cpp \ - qpid/broker/MessageGroupManager.h \ qpid/management/ManagementAgent.cpp \ qpid/management/ManagementAgent.h \ qpid/management/ManagementDirectExchange.cpp \ @@ -747,7 +739,7 @@ libqpidclient_la_SOURCES = \ QPIDCLIENT_VERSION_INFO = 2:0:0 libqpidclient_la_LDFLAGS = -version-info $(QPIDCLIENT_VERSION_INFO) -libqpidtypes_la_LIBADD= -luuid +libqpidtypes_la_libadd=-luuid libqpidtypes_la_SOURCES= \ qpid/types/Exception.cpp \ qpid/types/Uuid.cpp \ @@ -794,7 +786,9 @@ libqpidmessaging_la_SOURCES = \ qpid/client/amqp0_10/SessionImpl.h \ qpid/client/amqp0_10/SessionImpl.cpp \ qpid/client/amqp0_10/SenderImpl.h \ - qpid/client/amqp0_10/SenderImpl.cpp + qpid/client/amqp0_10/SenderImpl.cpp \ + qpid/client/amqp0_10/SimpleUrlParser.h \ + qpid/client/amqp0_10/SimpleUrlParser.cpp QPIDMESSAGING_VERSION_INFO = 2:0:0 libqpidmessaging_la_LDFLAGS = -version-info $(QPIDMESSAGING_VERSION_INFO) @@ -807,7 +801,6 @@ nobase_include_HEADERS += \ ../include/qpid/Address.h \ ../include/qpid/CommonImportExport.h \ ../include/qpid/Exception.h \ - ../include/qpid/ImportExport.h \ ../include/qpid/InlineAllocator.h \ ../include/qpid/InlineVector.h \ ../include/qpid/Msg.h \ @@ -890,10 +883,14 @@ nobase_include_HEADERS += \ ../include/qpid/types/Variant.h \ ../include/qpid/types/ImportExport.h +# Force build of qpidd during dist phase so help2man will work. +dist-hook: $(BUILT_SOURCES) + $(MAKE) qpidd + # Create the default data directory install-data-local: $(mkinstalldirs) $(DESTDIR)/$(localstatedir)/lib/qpidd -# Support for pkg-config +# Support for pkg-config pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = qpid.pc diff --git a/cpp/src/acl.mk b/cpp/src/acl.mk index b8e2ff0e13..bcd1d88335 100644 --- a/cpp/src/acl.mk +++ b/cpp/src/acl.mk @@ -18,8 +18,8 @@ # # # acl library makefile fragment, to be included in Makefile.am -# -dmoduleexec_LTLIBRARIES += acl.la +# +dmodule_LTLIBRARIES += acl.la acl_la_SOURCES = \ qpid/acl/Acl.cpp \ diff --git a/cpp/src/cluster.mk b/cpp/src/cluster.mk index 3ce4ce25b3..a791b2d41a 100644 --- a/cpp/src/cluster.mk +++ b/cpp/src/cluster.mk @@ -18,7 +18,7 @@ # # # Cluster library makefile fragment, to be included in Makefile.am -# +# # Optional CMAN support @@ -34,7 +34,7 @@ endif if HAVE_LIBCPG -dmoduleexec_LTLIBRARIES += cluster.la +dmodule_LTLIBRARIES += cluster.la cluster_la_SOURCES = \ $(CMAN_SOURCES) \ @@ -102,7 +102,7 @@ cluster_la_CXXFLAGS = $(AM_CXXFLAGS) -fno-strict-aliasing cluster_la_LDFLAGS = $(PLUGINLDFLAGS) # The watchdog plugin and helper executable -dmoduleexec_LTLIBRARIES += watchdog.la +dmodule_LTLIBRARIES += watchdog.la watchdog_la_SOURCES = qpid/cluster/WatchDogPlugin.cpp watchdog_la_LIBADD = libqpidbroker.la watchdog_la_LDFLAGS = $(PLUGINLDFLAGS) diff --git a/cpp/src/posix/QpiddBroker.cpp b/cpp/src/posix/QpiddBroker.cpp index 1cebcfc3ac..86504ba7fc 100644 --- a/cpp/src/posix/QpiddBroker.cpp +++ b/cpp/src/posix/QpiddBroker.cpp @@ -138,9 +138,6 @@ struct QpiddDaemon : public Daemon { brokerPtr->accept(); uint16_t port=brokerPtr->getPort(options->daemon.transport); ready(port); // Notify parent. - if (options->parent->broker.enableMgmt && (options->parent->broker.port == 0 || options->daemon.transport != TCP)) { - dynamic_cast<qmf::org::apache::qpid::broker::Broker*>(brokerPtr->GetManagementObject())->set_port(port); - } brokerPtr->run(); } }; @@ -185,13 +182,8 @@ int QpiddBroker::execute (QpiddOptions *options) { boost::intrusive_ptr<Broker> brokerPtr(new Broker(options->broker)); ScopedSetBroker ssb(brokerPtr); brokerPtr->accept(); - if (options->broker.port == 0 || myOptions->daemon.transport != TCP) { - uint16_t port = brokerPtr->getPort(myOptions->daemon.transport); - cout << port << endl; - if (options->broker.enableMgmt) { - dynamic_cast<qmf::org::apache::qpid::broker::Broker*>(brokerPtr->GetManagementObject())->set_port(port); - } - } + if (options->broker.port == 0 || myOptions->daemon.transport != TCP) + cout << uint16_t(brokerPtr->getPort(myOptions->daemon.transport)) << endl; brokerPtr->run(); } return 0; diff --git a/cpp/src/qmf.mk b/cpp/src/qmf.mk index 3b6583bfaf..f3462f1a93 100644 --- a/cpp/src/qmf.mk +++ b/cpp/src/qmf.mk @@ -43,7 +43,6 @@ QMF2_API = \ ../include/qmf/ConsoleSession.h \ ../include/qmf/DataAddr.h \ ../include/qmf/Data.h \ - ../include/qmf/posix/EventNotifier.h \ ../include/qmf/exceptions.h \ ../include/qmf/Handle.h \ ../include/qmf/ImportExport.h \ @@ -93,7 +92,6 @@ libqmf2_la_SOURCES = \ qmf/AgentEventImpl.h \ qmf/AgentImpl.h \ qmf/AgentSession.cpp \ - qmf/AgentSessionImpl.h \ qmf/AgentSubscription.cpp \ qmf/AgentSubscription.h \ qmf/ConsoleEvent.cpp \ @@ -106,22 +104,17 @@ libqmf2_la_SOURCES = \ qmf/DataAddrImpl.h \ qmf/Data.cpp \ qmf/DataImpl.h \ - qmf/EventNotifierImpl.cpp \ - qmf/EventNotifierImpl.h \ qmf/exceptions.cpp \ qmf/Expression.cpp \ qmf/Expression.h \ qmf/Hash.cpp \ qmf/Hash.h \ - qmf/PosixEventNotifier.cpp \ - qmf/PosixEventNotifierImpl.cpp \ - qmf/PosixEventNotifierImpl.h \ qmf/PrivateImplRef.h \ qmf/Query.cpp \ qmf/QueryImpl.h \ + qmf/Schema.cpp \ qmf/SchemaCache.cpp \ qmf/SchemaCache.h \ - qmf/Schema.cpp \ qmf/SchemaId.cpp \ qmf/SchemaIdImpl.h \ qmf/SchemaImpl.h \ diff --git a/cpp/src/qmf/Agent.cpp b/cpp/src/qmf/Agent.cpp index 684f8e4fba..915f2a1c88 100644 --- a/cpp/src/qmf/Agent.cpp +++ b/cpp/src/qmf/Agent.cpp @@ -72,7 +72,7 @@ Schema Agent::getSchema(const SchemaId& s, Duration t) { return impl->getSchema( AgentImpl::AgentImpl(const std::string& n, uint32_t e, ConsoleSessionImpl& s) : name(n), directSubject(n), epoch(e), session(s), touched(true), untouchedCount(0), capability(0), - sender(session.directSender), schemaCache(s.schemaCache) + sender(session.directSender), nextCorrelator(1), schemaCache(s.schemaCache) { } @@ -102,11 +102,12 @@ const Variant& AgentImpl::getAttribute(const string& k) const ConsoleEvent AgentImpl::query(const Query& query, Duration timeout) { boost::shared_ptr<SyncContext> context(new SyncContext()); - uint32_t correlator(session.correlator()); + uint32_t correlator; ConsoleEvent result; { qpid::sys::Mutex::ScopedLock l(lock); + correlator = nextCorrelator++; contextMap[correlator] = context; } try { @@ -150,7 +151,12 @@ ConsoleEvent AgentImpl::query(const string& text, Duration timeout) uint32_t AgentImpl::queryAsync(const Query& query) { - uint32_t correlator(session.correlator()); + uint32_t correlator; + + { + qpid::sys::Mutex::ScopedLock l(lock); + correlator = nextCorrelator++; + } sendQuery(query, correlator); return correlator; @@ -166,11 +172,12 @@ uint32_t AgentImpl::queryAsync(const string& text) ConsoleEvent AgentImpl::callMethod(const string& method, const Variant::Map& args, const DataAddr& addr, Duration timeout) { boost::shared_ptr<SyncContext> context(new SyncContext()); - uint32_t correlator(session.correlator()); + uint32_t correlator; ConsoleEvent result; { qpid::sys::Mutex::ScopedLock l(lock); + correlator = nextCorrelator++; contextMap[correlator] = context; } try { @@ -206,7 +213,12 @@ ConsoleEvent AgentImpl::callMethod(const string& method, const Variant::Map& arg uint32_t AgentImpl::callMethodAsync(const string& method, const Variant::Map& args, const DataAddr& addr) { - uint32_t correlator(session.correlator()); + uint32_t correlator; + + { + qpid::sys::Mutex::ScopedLock l(lock); + correlator = nextCorrelator++; + } sendMethod(method, args, addr, correlator); return correlator; @@ -584,7 +596,12 @@ void AgentImpl::sendMethod(const string& method, const Variant::Map& args, const void AgentImpl::sendSchemaRequest(const SchemaId& id) { - uint32_t correlator(session.correlator()); + uint32_t correlator; + + { + qpid::sys::Mutex::ScopedLock l(lock); + correlator = nextCorrelator++; + } if (capability >= AGENT_CAPABILITY_V2_SCHEMA) { Query query(QUERY_SCHEMA, id); diff --git a/cpp/src/qmf/AgentImpl.h b/cpp/src/qmf/AgentImpl.h index 09754a3a7e..7fa4f4373a 100644 --- a/cpp/src/qmf/AgentImpl.h +++ b/cpp/src/qmf/AgentImpl.h @@ -99,6 +99,7 @@ namespace qmf { uint32_t capability; qpid::messaging::Sender sender; qpid::types::Variant::Map attributes; + uint32_t nextCorrelator; std::map<uint32_t, boost::shared_ptr<SyncContext> > contextMap; boost::shared_ptr<SchemaCache> schemaCache; mutable std::set<std::string> packageSet; diff --git a/cpp/src/qmf/AgentSession.cpp b/cpp/src/qmf/AgentSession.cpp index 251c25fd44..4c5a72a467 100644 --- a/cpp/src/qmf/AgentSession.cpp +++ b/cpp/src/qmf/AgentSession.cpp @@ -19,7 +19,132 @@ * */ -#include "qmf/AgentSessionImpl.h" +#include "qpid/RefCounted.h" +#include "qmf/PrivateImplRef.h" +#include "qmf/exceptions.h" +#include "qmf/AgentSession.h" +#include "qmf/AgentEventImpl.h" +#include "qmf/SchemaIdImpl.h" +#include "qmf/SchemaImpl.h" +#include "qmf/DataAddrImpl.h" +#include "qmf/DataImpl.h" +#include "qmf/QueryImpl.h" +#include "qmf/agentCapability.h" +#include "qmf/constants.h" +#include "qpid/sys/Mutex.h" +#include "qpid/sys/Condition.h" +#include "qpid/sys/Thread.h" +#include "qpid/sys/Runnable.h" +#include "qpid/log/Statement.h" +#include "qpid/messaging/Connection.h" +#include "qpid/messaging/Session.h" +#include "qpid/messaging/Receiver.h" +#include "qpid/messaging/Sender.h" +#include "qpid/messaging/Message.h" +#include "qpid/messaging/AddressParser.h" +#include "qpid/management/Buffer.h" +#include <queue> +#include <map> +#include <set> +#include <iostream> +#include <memory> + +using namespace std; +using namespace qpid::messaging; +using namespace qmf; +using qpid::types::Variant; + +namespace qmf { + class AgentSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable { + public: + ~AgentSessionImpl(); + + // + // Methods from API handle + // + AgentSessionImpl(Connection& c, const string& o); + void setDomain(const string& d) { checkOpen(); domain = d; } + void setVendor(const string& v) { checkOpen(); attributes["_vendor"] = v; } + void setProduct(const string& p) { checkOpen(); attributes["_product"] = p; } + void setInstance(const string& i) { checkOpen(); attributes["_instance"] = i; } + void setAttribute(const string& k, const qpid::types::Variant& v) { checkOpen(); attributes[k] = v; } + const string& getName() const { return agentName; } + void open(); + void close(); + bool nextEvent(AgentEvent& e, Duration t); + + void registerSchema(Schema& s); + DataAddr addData(Data& d, const string& n, bool persist); + void delData(const DataAddr&); + + void authAccept(AgentEvent& e); + void authReject(AgentEvent& e, const string& m); + void raiseException(AgentEvent& e, const string& s); + void raiseException(AgentEvent& e, const Data& d); + void response(AgentEvent& e, const Data& d); + void complete(AgentEvent& e); + void methodSuccess(AgentEvent& e); + void raiseEvent(const Data& d); + void raiseEvent(const Data& d, int s); + + private: + typedef map<DataAddr, Data, DataAddrCompare> DataIndex; + typedef map<SchemaId, Schema, SchemaIdCompare> SchemaMap; + + mutable qpid::sys::Mutex lock; + qpid::sys::Condition cond; + Connection connection; + Session session; + Sender directSender; + Sender topicSender; + string domain; + Variant::Map attributes; + Variant::Map options; + string agentName; + bool opened; + queue<AgentEvent> eventQueue; + qpid::sys::Thread* thread; + bool threadCanceled; + uint32_t bootSequence; + uint32_t interval; + uint64_t lastHeartbeat; + uint64_t lastVisit; + bool forceHeartbeat; + bool externalStorage; + bool autoAllowQueries; + bool autoAllowMethods; + uint32_t maxSubscriptions; + uint32_t minSubInterval; + uint32_t subLifetime; + bool publicEvents; + bool listenOnDirect; + bool strictSecurity; + uint64_t schemaUpdateTime; + string directBase; + string topicBase; + + SchemaMap schemata; + DataIndex globalIndex; + map<SchemaId, DataIndex, SchemaIdCompareNoHash> schemaIndex; + + void checkOpen(); + void setAgentName(); + void enqueueEvent(const AgentEvent&); + void handleLocateRequest(const Variant::List& content, const Message& msg); + void handleMethodRequest(const Variant::Map& content, const Message& msg); + void handleQueryRequest(const Variant::Map& content, const Message& msg); + void handleSchemaRequest(AgentEvent&); + void handleV1SchemaRequest(qpid::management::Buffer&, uint32_t, const Message&); + void dispatch(Message); + void sendHeartbeat(); + void send(Message, const Address&); + void flushResponses(AgentEvent&, bool); + void periodicProcessing(uint64_t); + void run(); + }; +} + +typedef qmf::PrivateImplRef<AgentSession> PI; AgentSession::AgentSession(AgentSessionImpl* impl) { PI::ctor(*this, impl); } AgentSession::AgentSession(const AgentSession& s) : qmf::Handle<AgentSessionImpl>() { PI::copy(*this, s); } @@ -36,7 +161,6 @@ const string& AgentSession::getName() const { return impl->getName(); } void AgentSession::open() { impl->open(); } void AgentSession::close() { impl->close(); } bool AgentSession::nextEvent(AgentEvent& e, Duration t) { return impl->nextEvent(e, t); } -int AgentSession::pendingEvents() const { return impl->pendingEvents(); } void AgentSession::registerSchema(Schema& s) { impl->registerSchema(s); } DataAddr AgentSession::addData(Data& d, const string& n, bool p) { return impl->addData(d, n, p); } void AgentSession::delData(const DataAddr& a) { impl->delData(a); } @@ -55,11 +179,11 @@ void AgentSession::raiseEvent(const Data& d, int s) { impl->raiseEvent(d, s); } //======================================================================================== AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) : - connection(c), domain("default"), opened(false), eventNotifier(0), thread(0), threadCanceled(false), + connection(c), domain("default"), opened(false), thread(0), threadCanceled(false), bootSequence(1), interval(60), lastHeartbeat(0), lastVisit(0), forceHeartbeat(false), externalStorage(false), autoAllowQueries(true), autoAllowMethods(true), maxSubscriptions(64), minSubInterval(3000), subLifetime(300), publicEvents(true), - listenOnDirect(true), strictSecurity(false), maxThreadWaitTime(5), + listenOnDirect(true), strictSecurity(false), schemaUpdateTime(uint64_t(qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()))) { // @@ -120,14 +244,7 @@ AgentSessionImpl::AgentSessionImpl(Connection& c, const string& options) : iter = optMap.find("strict-security"); if (iter != optMap.end()) strictSecurity = iter->second.asBool(); - - iter = optMap.find("max-thread-wait-time"); - if (iter != optMap.end()) - maxThreadWaitTime = iter->second.asUint32(); } - - if (maxThreadWaitTime > interval) - maxThreadWaitTime = interval; } @@ -135,11 +252,6 @@ AgentSessionImpl::~AgentSessionImpl() { if (opened) close(); - - if (thread) { - thread->join(); - delete thread; - } } @@ -148,12 +260,6 @@ void AgentSessionImpl::open() if (opened) throw QmfException("The session is already open"); - // If the thread exists, join and delete it before creating a new one. - if (thread) { - thread->join(); - delete thread; - } - const string addrArgs(";{create:never,node:{type:topic}}"); const string routableAddr("direct-agent.route." + qpid::types::Uuid(true).str()); attributes["_direct_subject"] = routableAddr; @@ -191,26 +297,19 @@ void AgentSessionImpl::open() } -void AgentSessionImpl::closeAsync() +void AgentSessionImpl::close() { if (!opened) return; - // Stop the receiver thread. Don't join it until the destructor is called or open() is called. + // Stop and join the receiver thread threadCanceled = true; - opened = false; -} + thread->join(); + delete thread; - -void AgentSessionImpl::close() -{ - closeAsync(); - - if (thread) { - thread->join(); - delete thread; - thread = 0; - } + // Close the AMQP session + session.close(); + opened = false; } @@ -219,19 +318,13 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout) uint64_t milliseconds = timeout.getMilliseconds(); qpid::sys::Mutex::ScopedLock l(lock); - if (eventQueue.empty() && milliseconds > 0) { - int64_t nsecs(qpid::sys::TIME_INFINITE); - if ((uint64_t)(nsecs / 1000000) > milliseconds) - nsecs = (int64_t) milliseconds * 1000000; - qpid::sys::Duration then(nsecs); - cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), then)); - } + if (eventQueue.empty()) + cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), + qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC))); if (!eventQueue.empty()) { event = eventQueue.front(); eventQueue.pop(); - if (eventQueue.empty()) - alertEventNotifierLH(false); return true; } @@ -239,26 +332,6 @@ bool AgentSessionImpl::nextEvent(AgentEvent& event, Duration timeout) } -int AgentSessionImpl::pendingEvents() const -{ - qpid::sys::Mutex::ScopedLock l(lock); - return eventQueue.size(); -} - - -void AgentSessionImpl::setEventNotifier(EventNotifierImpl* notifier) -{ - qpid::sys::Mutex::ScopedLock l(lock); - eventNotifier = notifier; -} - -EventNotifierImpl* AgentSessionImpl::getEventNotifier() const -{ - qpid::sys::Mutex::ScopedLock l(lock); - return eventNotifier; -} - - void AgentSessionImpl::registerSchema(Schema& schema) { if (!schema.isFinalized()) @@ -514,10 +587,8 @@ void AgentSessionImpl::enqueueEvent(const AgentEvent& event) qpid::sys::Mutex::ScopedLock l(lock); bool notify = eventQueue.empty(); eventQueue.push(event); - if (notify) { + if (notify) cond.notify(); - alertEventNotifierLH(true); - } } @@ -961,13 +1032,6 @@ void AgentSessionImpl::periodicProcessing(uint64_t seconds) } -void AgentSessionImpl::alertEventNotifierLH(bool readable) -{ - if (eventNotifier) - eventNotifier->setReadable(readable); -} - - void AgentSessionImpl::run() { QPID_LOG(debug, "AgentSession thread started for agent " << agentName); @@ -977,7 +1041,7 @@ void AgentSessionImpl::run() periodicProcessing((uint64_t) qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now()) / qpid::sys::TIME_SEC); Receiver rx; - bool valid = session.nextReceiver(rx, Duration::SECOND * maxThreadWaitTime); + bool valid = session.nextReceiver(rx, Duration::SECOND); if (threadCanceled) break; if (valid) { @@ -994,19 +1058,6 @@ void AgentSessionImpl::run() enqueueEvent(AgentEvent(new AgentEventImpl(AGENT_THREAD_FAILED))); } - session.close(); QPID_LOG(debug, "AgentSession thread exiting for agent " << agentName); } - -AgentSessionImpl& AgentSessionImplAccess::get(AgentSession& session) -{ - return *session.impl; -} - - -const AgentSessionImpl& AgentSessionImplAccess::get(const AgentSession& session) -{ - return *session.impl; -} - diff --git a/cpp/src/qmf/AgentSessionImpl.h b/cpp/src/qmf/AgentSessionImpl.h deleted file mode 100644 index ae512a4054..0000000000 --- a/cpp/src/qmf/AgentSessionImpl.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef __QMF_AGENT_SESSION_IMPL_H -#define __QMF_AGENT_SESSION_IMPL_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 "qmf/PrivateImplRef.h" -#include "qmf/exceptions.h" -#include "qmf/AgentSession.h" -#include "qmf/AgentEventImpl.h" -#include "qmf/EventNotifierImpl.h" -#include "qpid/messaging/Connection.h" -#include "qpid/sys/Runnable.h" -#include "qpid/sys/Mutex.h" -#include "qpid/sys/Condition.h" -#include "qpid/sys/Thread.h" -#include "qpid/sys/Runnable.h" -#include "qpid/log/Statement.h" -#include "qpid/messaging/Connection.h" -#include "qpid/messaging/Session.h" -#include "qpid/messaging/Receiver.h" -#include "qpid/messaging/Sender.h" -#include "qpid/messaging/Message.h" -#include "qpid/messaging/AddressParser.h" -#include "qpid/management/Buffer.h" -#include "qpid/RefCounted.h" -#include "qmf/PrivateImplRef.h" -#include "qmf/AgentSession.h" -#include "qmf/exceptions.h" -#include "qmf/AgentSession.h" -#include "qmf/SchemaIdImpl.h" -#include "qmf/SchemaImpl.h" -#include "qmf/DataAddrImpl.h" -#include "qmf/DataImpl.h" -#include "qmf/QueryImpl.h" -#include "qmf/agentCapability.h" -#include "qmf/constants.h" - -#include <queue> -#include <map> -#include <iostream> -#include <memory> - -using namespace std; -using namespace qpid::messaging; -using namespace qmf; -using qpid::types::Variant; - -typedef qmf::PrivateImplRef<AgentSession> PI; - -namespace qmf { - class AgentSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable { - public: - ~AgentSessionImpl(); - - // - // Methods from API handle - // - AgentSessionImpl(Connection& c, const string& o); - void setDomain(const string& d) { checkOpen(); domain = d; } - void setVendor(const string& v) { checkOpen(); attributes["_vendor"] = v; } - void setProduct(const string& p) { checkOpen(); attributes["_product"] = p; } - void setInstance(const string& i) { checkOpen(); attributes["_instance"] = i; } - void setAttribute(const string& k, const qpid::types::Variant& v) { checkOpen(); attributes[k] = v; } - const string& getName() const { return agentName; } - void open(); - void closeAsync(); - void close(); - bool nextEvent(AgentEvent& e, Duration t); - int pendingEvents() const; - - void setEventNotifier(EventNotifierImpl* eventNotifier); - EventNotifierImpl* getEventNotifier() const; - - void registerSchema(Schema& s); - DataAddr addData(Data& d, const string& n, bool persist); - void delData(const DataAddr&); - - void authAccept(AgentEvent& e); - void authReject(AgentEvent& e, const string& m); - void raiseException(AgentEvent& e, const string& s); - void raiseException(AgentEvent& e, const Data& d); - void response(AgentEvent& e, const Data& d); - void complete(AgentEvent& e); - void methodSuccess(AgentEvent& e); - void raiseEvent(const Data& d); - void raiseEvent(const Data& d, int s); - - private: - typedef map<DataAddr, Data, DataAddrCompare> DataIndex; - typedef map<SchemaId, Schema, SchemaIdCompare> SchemaMap; - - mutable qpid::sys::Mutex lock; - qpid::sys::Condition cond; - Connection connection; - Session session; - Sender directSender; - Sender topicSender; - string domain; - Variant::Map attributes; - Variant::Map options; - string agentName; - bool opened; - queue<AgentEvent> eventQueue; - EventNotifierImpl* eventNotifier; - qpid::sys::Thread* thread; - bool threadCanceled; - uint32_t bootSequence; - uint32_t interval; - uint64_t lastHeartbeat; - uint64_t lastVisit; - bool forceHeartbeat; - bool externalStorage; - bool autoAllowQueries; - bool autoAllowMethods; - uint32_t maxSubscriptions; - uint32_t minSubInterval; - uint32_t subLifetime; - bool publicEvents; - bool listenOnDirect; - bool strictSecurity; - uint32_t maxThreadWaitTime; - uint64_t schemaUpdateTime; - string directBase; - string topicBase; - - SchemaMap schemata; - DataIndex globalIndex; - map<SchemaId, DataIndex, SchemaIdCompareNoHash> schemaIndex; - - void checkOpen(); - void setAgentName(); - void enqueueEvent(const AgentEvent&); - void alertEventNotifierLH(bool readable); - void handleLocateRequest(const Variant::List& content, const Message& msg); - void handleMethodRequest(const Variant::Map& content, const Message& msg); - void handleQueryRequest(const Variant::Map& content, const Message& msg); - void handleSchemaRequest(AgentEvent&); - void handleV1SchemaRequest(qpid::management::Buffer&, uint32_t, const Message&); - void dispatch(Message); - void sendHeartbeat(); - void send(Message, const Address&); - void flushResponses(AgentEvent&, bool); - void periodicProcessing(uint64_t); - void run(); - }; - - struct AgentSessionImplAccess { - static AgentSessionImpl& get(AgentSession& session); - static const AgentSessionImpl& get(const AgentSession& session); - }; -} - - -#endif - diff --git a/cpp/src/qmf/ConsoleSession.cpp b/cpp/src/qmf/ConsoleSession.cpp index 2dfc894c58..e12c1152f6 100644 --- a/cpp/src/qmf/ConsoleSession.cpp +++ b/cpp/src/qmf/ConsoleSession.cpp @@ -54,7 +54,6 @@ void ConsoleSession::setAgentFilter(const string& f) { impl->setAgentFilter(f); void ConsoleSession::open() { impl->open(); } void ConsoleSession::close() { impl->close(); } bool ConsoleSession::nextEvent(ConsoleEvent& e, Duration t) { return impl->nextEvent(e, t); } -int ConsoleSession::pendingEvents() const { return impl->pendingEvents(); } uint32_t ConsoleSession::getAgentCount() const { return impl->getAgentCount(); } Agent ConsoleSession::getAgent(uint32_t i) const { return impl->getAgent(i); } Agent ConsoleSession::getConnectedBrokerAgent() const { return impl->getConnectedBrokerAgent(); } @@ -66,9 +65,9 @@ Subscription ConsoleSession::subscribe(const string& q, const string& f, const s //======================================================================================== ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) : - connection(c), domain("default"), maxAgentAgeMinutes(5), listenOnDirect(true), strictSecurity(false), maxThreadWaitTime(5), - opened(false), eventNotifier(0), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0), - connectedBrokerInAgentList(false), schemaCache(new SchemaCache()), nextCorrelator(1) + connection(c), domain("default"), maxAgentAgeMinutes(5), + opened(false), thread(0), threadCanceled(false), lastVisit(0), lastAgePass(0), + connectedBrokerInAgentList(false), schemaCache(new SchemaCache()) { if (!options.empty()) { qpid::messaging::AddressParser parser(options); @@ -92,14 +91,7 @@ ConsoleSessionImpl::ConsoleSessionImpl(Connection& c, const string& options) : iter = optMap.find("strict-security"); if (iter != optMap.end()) strictSecurity = iter->second.asBool(); - - iter = optMap.find("max-thread-wait-time"); - if (iter != optMap.end()) - maxThreadWaitTime = iter->second.asUint32(); } - - if (maxThreadWaitTime > 60) - maxThreadWaitTime = 60; } @@ -107,11 +99,6 @@ ConsoleSessionImpl::~ConsoleSessionImpl() { if (opened) close(); - - if (thread) { - thread->join(); - delete thread; - } } @@ -166,12 +153,6 @@ void ConsoleSessionImpl::open() if (opened) throw QmfException("The session is already open"); - // If the thread exists, join and delete it before creating a new one. - if (thread) { - thread->join(); - delete thread; - } - // Establish messaging addresses directBase = "qmf." + domain + ".direct"; topicBase = "qmf." + domain + ".topic"; @@ -200,36 +181,30 @@ void ConsoleSessionImpl::open() // Start the receiver thread threadCanceled = false; - opened = true; thread = new qpid::sys::Thread(*this); // Send an agent_locate to direct address 'broker' to identify the connected-broker-agent. sendBrokerLocate(); if (agentQuery) sendAgentLocate(); + + opened = true; } -void ConsoleSessionImpl::closeAsync() +void ConsoleSessionImpl::close() { if (!opened) throw QmfException("The session is already closed"); - // Stop the receiver thread. Don't join it until the destructor is called or open() is called. + // Stop and join the receiver thread threadCanceled = true; - opened = false; -} - + thread->join(); + delete thread; -void ConsoleSessionImpl::close() -{ - closeAsync(); - - if (thread) { - thread->join(); - delete thread; - thread = 0; - } + // Close the AMQP session + session.close(); + opened = false; } @@ -238,19 +213,13 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout) uint64_t milliseconds = timeout.getMilliseconds(); qpid::sys::Mutex::ScopedLock l(lock); - if (eventQueue.empty() && milliseconds > 0) { - int64_t nsecs(qpid::sys::TIME_INFINITE); - if ((uint64_t)(nsecs / 1000000) > milliseconds) - nsecs = (int64_t) milliseconds * 1000000; - qpid::sys::Duration then(nsecs); - cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), then)); - } + if (eventQueue.empty()) + cond.wait(lock, qpid::sys::AbsTime(qpid::sys::now(), + qpid::sys::Duration(milliseconds * qpid::sys::TIME_MSEC))); if (!eventQueue.empty()) { event = eventQueue.front(); eventQueue.pop(); - if (eventQueue.empty()) - alertEventNotifierLH(false); return true; } @@ -258,27 +227,6 @@ bool ConsoleSessionImpl::nextEvent(ConsoleEvent& event, Duration timeout) } -int ConsoleSessionImpl::pendingEvents() const -{ - qpid::sys::Mutex::ScopedLock l(lock); - return eventQueue.size(); -} - - -void ConsoleSessionImpl::setEventNotifier(EventNotifierImpl* notifier) -{ - qpid::sys::Mutex::ScopedLock l(lock); - eventNotifier = notifier; -} - - -EventNotifierImpl* ConsoleSessionImpl::getEventNotifier() const -{ - qpid::sys::Mutex::ScopedLock l(lock); - return eventNotifier; -} - - uint32_t ConsoleSessionImpl::getAgentCount() const { qpid::sys::Mutex::ScopedLock l(lock); @@ -320,10 +268,8 @@ void ConsoleSessionImpl::enqueueEventLH(const ConsoleEvent& event) { bool notify = eventQueue.empty(); eventQueue.push(event); - if (notify) { + if (notify) cond.notify(); - alertEventNotifierLH(true); - } } @@ -475,23 +421,7 @@ void ConsoleSessionImpl::handleAgentUpdate(const string& agentName, const Varian iter = content.find("_values"); if (iter == content.end()) return; - const Variant::Map& in_attrs(iter->second.asMap()); - Variant::Map attrs; - - // - // Copy the map from the message to "attrs". Translate any old-style - // keys to their new key values in the process. - // - for (iter = in_attrs.begin(); iter != in_attrs.end(); iter++) { - if (iter->first == "epoch") - attrs[protocol::AGENT_ATTR_EPOCH] = iter->second; - else if (iter->first == "timestamp") - attrs[protocol::AGENT_ATTR_TIMESTAMP] = iter->second; - else if (iter->first == "heartbeat_interval") - attrs[protocol::AGENT_ATTR_HEARTBEAT_INTERVAL] = iter->second; - else - attrs[iter->first] = iter->second; - } + Variant::Map attrs(iter->second.asMap()); iter = attrs.find(protocol::AGENT_ATTR_EPOCH); if (iter != attrs.end()) @@ -632,13 +562,6 @@ void ConsoleSessionImpl::periodicProcessing(uint64_t seconds) } -void ConsoleSessionImpl::alertEventNotifierLH(bool readable) -{ - if (eventNotifier) - eventNotifier->setReadable(readable); -} - - void ConsoleSessionImpl::run() { QPID_LOG(debug, "ConsoleSession thread started"); @@ -649,7 +572,7 @@ void ConsoleSessionImpl::run() qpid::sys::TIME_SEC); Receiver rx; - bool valid = session.nextReceiver(rx, Duration::SECOND * maxThreadWaitTime); + bool valid = session.nextReceiver(rx, Duration::SECOND); if (threadCanceled) break; if (valid) { @@ -666,18 +589,6 @@ void ConsoleSessionImpl::run() enqueueEvent(ConsoleEvent(new ConsoleEventImpl(CONSOLE_THREAD_FAILED))); } - session.close(); QPID_LOG(debug, "ConsoleSession thread exiting"); } - -ConsoleSessionImpl& ConsoleSessionImplAccess::get(ConsoleSession& session) -{ - return *session.impl; -} - - -const ConsoleSessionImpl& ConsoleSessionImplAccess::get(const ConsoleSession& session) -{ - return *session.impl; -} diff --git a/cpp/src/qmf/ConsoleSessionImpl.h b/cpp/src/qmf/ConsoleSessionImpl.h index e2b30602fa..675c8bcfb5 100644 --- a/cpp/src/qmf/ConsoleSessionImpl.h +++ b/cpp/src/qmf/ConsoleSessionImpl.h @@ -27,7 +27,6 @@ #include "qmf/SchemaId.h" #include "qmf/Schema.h" #include "qmf/ConsoleEventImpl.h" -#include "qmf/EventNotifierImpl.h" #include "qmf/SchemaCache.h" #include "qmf/Query.h" #include "qpid/sys/Mutex.h" @@ -42,13 +41,9 @@ #include "qpid/messaging/Address.h" #include "qpid/management/Buffer.h" #include "qpid/types/Variant.h" - -#include <boost/shared_ptr.hpp> #include <map> #include <queue> -using namespace std; - namespace qmf { class ConsoleSessionImpl : public virtual qpid::RefCounted, public qpid::sys::Runnable { public: @@ -61,14 +56,8 @@ namespace qmf { void setDomain(const std::string& d) { domain = d; } void setAgentFilter(const std::string& f); void open(); - void closeAsync(); void close(); bool nextEvent(ConsoleEvent& e, qpid::messaging::Duration t); - int pendingEvents() const; - - void setEventNotifier(EventNotifierImpl* notifier); - EventNotifierImpl* getEventNotifier() const; - uint32_t getAgentCount() const; Agent getAgent(uint32_t i) const; Agent getConnectedBrokerAgent() const { return connectedBrokerAgent; } @@ -86,11 +75,9 @@ namespace qmf { uint32_t maxAgentAgeMinutes; bool listenOnDirect; bool strictSecurity; - uint32_t maxThreadWaitTime; Query agentQuery; bool opened; std::queue<ConsoleEvent> eventQueue; - EventNotifierImpl* eventNotifier; qpid::sys::Thread* thread; bool threadCanceled; uint64_t lastVisit; @@ -102,8 +89,6 @@ namespace qmf { std::string directBase; std::string topicBase; boost::shared_ptr<SchemaCache> schemaCache; - qpid::sys::Mutex corrlock; - uint32_t nextCorrelator; void enqueueEvent(const ConsoleEvent&); void enqueueEventLH(const ConsoleEvent&); @@ -113,17 +98,10 @@ namespace qmf { void handleAgentUpdate(const std::string&, const qpid::types::Variant::Map&, const qpid::messaging::Message&); void handleV1SchemaResponse(qpid::management::Buffer&, uint32_t, const qpid::messaging::Message&); void periodicProcessing(uint64_t); - void alertEventNotifierLH(bool readable); void run(); - uint32_t correlator() { qpid::sys::Mutex::ScopedLock l(corrlock); return nextCorrelator++; } friend class AgentImpl; }; - - struct ConsoleSessionImplAccess { - static ConsoleSessionImpl& get(ConsoleSession& session); - static const ConsoleSessionImpl& get(const ConsoleSession& session); - }; } #endif diff --git a/cpp/src/qmf/DataAddr.cpp b/cpp/src/qmf/DataAddr.cpp index d16e12062e..fb51d5787f 100644 --- a/cpp/src/qmf/DataAddr.cpp +++ b/cpp/src/qmf/DataAddr.cpp @@ -36,9 +36,7 @@ DataAddr::~DataAddr() { PI::dtor(*this); } DataAddr& DataAddr::operator=(const DataAddr& s) { return PI::assign(*this, s); } bool DataAddr::operator==(const DataAddr& o) { return *impl == *o.impl; } -bool DataAddr::operator==(const DataAddr& o) const { return *impl == *o.impl; } bool DataAddr::operator<(const DataAddr& o) { return *impl < *o.impl; } -bool DataAddr::operator<(const DataAddr& o) const { return *impl < *o.impl; } DataAddr::DataAddr(const qpid::types::Variant::Map& m) { PI::ctor(*this, new DataAddrImpl(m)); } DataAddr::DataAddr(const string& n, const string& a, uint32_t e) { PI::ctor(*this, new DataAddrImpl(n, a, e)); } @@ -47,7 +45,7 @@ const string& DataAddr::getAgentName() const { return impl->getAgentName(); } uint32_t DataAddr::getAgentEpoch() const { return impl->getAgentEpoch(); } Variant::Map DataAddr::asMap() const { return impl->asMap(); } -bool DataAddrImpl::operator==(const DataAddrImpl& other) const +bool DataAddrImpl::operator==(const DataAddrImpl& other) { return agentName == other.agentName && @@ -56,7 +54,7 @@ bool DataAddrImpl::operator==(const DataAddrImpl& other) const } -bool DataAddrImpl::operator<(const DataAddrImpl& other) const +bool DataAddrImpl::operator<(const DataAddrImpl& other) { if (agentName < other.agentName) return true; if (agentName > other.agentName) return false; diff --git a/cpp/src/qmf/DataAddrImpl.h b/cpp/src/qmf/DataAddrImpl.h index 11d512f0c4..3f9cae9453 100644 --- a/cpp/src/qmf/DataAddrImpl.h +++ b/cpp/src/qmf/DataAddrImpl.h @@ -38,8 +38,8 @@ namespace qmf { // // Methods from API handle // - bool operator==(const DataAddrImpl&) const; - bool operator<(const DataAddrImpl&) const; + bool operator==(const DataAddrImpl&); + bool operator<(const DataAddrImpl&); DataAddrImpl(const qpid::types::Variant::Map&); DataAddrImpl(const std::string& _name, const std::string& _agentName, uint32_t _agentEpoch=0) : agentName(_agentName), name(_name), agentEpoch(_agentEpoch) {} diff --git a/cpp/src/qmf/EventNotifierImpl.cpp b/cpp/src/qmf/EventNotifierImpl.cpp deleted file mode 100644 index 20114aaa5e..0000000000 --- a/cpp/src/qmf/EventNotifierImpl.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "qmf/EventNotifierImpl.h" -#include "qmf/AgentSessionImpl.h" -#include "qmf/ConsoleSessionImpl.h" - -EventNotifierImpl::EventNotifierImpl(AgentSession& agentSession) - : readable(false), agent(agentSession) -{ - AgentSessionImplAccess::get(agent).setEventNotifier(this); -} - - -EventNotifierImpl::EventNotifierImpl(ConsoleSession& consoleSession) - : readable(false), console(consoleSession) -{ - ConsoleSessionImplAccess::get(console).setEventNotifier(this); -} - - -EventNotifierImpl::~EventNotifierImpl() -{ - if (agent.isValid()) - AgentSessionImplAccess::get(agent).setEventNotifier(NULL); - if (console.isValid()) - ConsoleSessionImplAccess::get(console).setEventNotifier(NULL); -} - -void EventNotifierImpl::setReadable(bool readable) -{ - update(readable); - this->readable = readable; -} - - -bool EventNotifierImpl::isReadable() const -{ - return this->readable; -} diff --git a/cpp/src/qmf/PosixEventNotifier.cpp b/cpp/src/qmf/PosixEventNotifier.cpp deleted file mode 100644 index a364cc155d..0000000000 --- a/cpp/src/qmf/PosixEventNotifier.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "qmf/posix/EventNotifier.h" -#include "qmf/PosixEventNotifierImpl.h" -#include "qmf/PrivateImplRef.h" - -using namespace qmf; -using namespace std; - -typedef qmf::PrivateImplRef<posix::EventNotifier> PI; - -posix::EventNotifier::EventNotifier(PosixEventNotifierImpl* impl) { PI::ctor(*this, impl); } - -posix::EventNotifier::EventNotifier(AgentSession& agentSession) -{ - PI::ctor(*this, new PosixEventNotifierImpl(agentSession)); -} - - -posix::EventNotifier::EventNotifier(ConsoleSession& consoleSession) -{ - PI::ctor(*this, new PosixEventNotifierImpl(consoleSession)); -} - - -posix::EventNotifier::EventNotifier(const posix::EventNotifier& that) - : Handle<PosixEventNotifierImpl>() -{ - PI::copy(*this, that); -} - - -posix::EventNotifier::~EventNotifier() -{ - PI::dtor(*this); -} - -posix::EventNotifier& posix::EventNotifier::operator=(const posix::EventNotifier& that) -{ - return PI::assign(*this, that); -} - - -int posix::EventNotifier::getHandle() const -{ - return impl->getHandle(); -} - diff --git a/cpp/src/qmf/PosixEventNotifierImpl.cpp b/cpp/src/qmf/PosixEventNotifierImpl.cpp deleted file mode 100644 index 011dbcc214..0000000000 --- a/cpp/src/qmf/PosixEventNotifierImpl.cpp +++ /dev/null @@ -1,112 +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 "PosixEventNotifierImpl.h" -#include "qpid/log/Statement.h" - -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#define BUFFER_SIZE 10 - -using namespace qmf; - -PosixEventNotifierImpl::PosixEventNotifierImpl(AgentSession& agentSession) - : EventNotifierImpl(agentSession) -{ - openHandle(); -} - - -PosixEventNotifierImpl::PosixEventNotifierImpl(ConsoleSession& consoleSession) - : EventNotifierImpl(consoleSession) -{ - openHandle(); -} - - -PosixEventNotifierImpl::~PosixEventNotifierImpl() -{ - closeHandle(); -} - - -void PosixEventNotifierImpl::update(bool readable) -{ - char buffer[BUFFER_SIZE]; - - if(readable && !this->isReadable()) { - if (::write(myHandle, "1", 1) == -1) - QPID_LOG(error, "PosixEventNotifierImpl::update write failed: " << errno); - } - else if(!readable && this->isReadable()) { - if (::read(yourHandle, buffer, BUFFER_SIZE) == -1) - QPID_LOG(error, "PosixEventNotifierImpl::update read failed: " << errno); - } -} - - -void PosixEventNotifierImpl::openHandle() -{ - int pair[2]; - - if(::pipe(pair) == -1) - throw QmfException("Unable to open event notifier handle."); - - yourHandle = pair[0]; - myHandle = pair[1]; - - int flags; - - flags = ::fcntl(yourHandle, F_GETFL); - if((::fcntl(yourHandle, F_SETFL, flags | O_NONBLOCK)) == -1) - throw QmfException("Unable to make remote handle non-blocking."); - - flags = ::fcntl(myHandle, F_GETFL); - if((::fcntl(myHandle, F_SETFL, flags | O_NONBLOCK)) == -1) - throw QmfException("Unable to make local handle non-blocking."); -} - - -void PosixEventNotifierImpl::closeHandle() -{ - if(myHandle > 0) { - ::close(myHandle); - myHandle = -1; - } - - if(yourHandle > 0) { - ::close(yourHandle); - yourHandle = -1; - } -} - - -PosixEventNotifierImpl& PosixEventNotifierImplAccess::get(posix::EventNotifier& notifier) -{ - return *notifier.impl; -} - - -const PosixEventNotifierImpl& PosixEventNotifierImplAccess::get(const posix::EventNotifier& notifier) -{ - return *notifier.impl; -} - diff --git a/cpp/src/qmf/PosixEventNotifierImpl.h b/cpp/src/qmf/PosixEventNotifierImpl.h deleted file mode 100644 index c8a7446bd5..0000000000 --- a/cpp/src/qmf/PosixEventNotifierImpl.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __QMF_POSIX_EVENT_NOTIFIER_IMPL_H -#define __QMF_POSIX_EVENT_NOTIFIER_IMPL_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 "qmf/posix/EventNotifier.h" -#include "qmf/EventNotifierImpl.h" -#include "qpid/RefCounted.h" - -namespace qmf -{ - class AgentSession; - class ConsoleSession; - - class PosixEventNotifierImpl : public EventNotifierImpl, public virtual qpid::RefCounted - { - public: - PosixEventNotifierImpl(AgentSession& agentSession); - PosixEventNotifierImpl(ConsoleSession& consoleSession); - virtual ~PosixEventNotifierImpl(); - - int getHandle() const { return yourHandle; } - - private: - int myHandle; - int yourHandle; - - void openHandle(); - void closeHandle(); - - protected: - void update(bool readable); - }; - - struct PosixEventNotifierImplAccess - { - static PosixEventNotifierImpl& get(posix::EventNotifier& notifier); - static const PosixEventNotifierImpl& get(const posix::EventNotifier& notifier); - }; - -} - -#endif - diff --git a/cpp/src/qmf/PrivateImplRef.h b/cpp/src/qmf/PrivateImplRef.h index 960cbb2e09..8b698c4199 100644 --- a/cpp/src/qmf/PrivateImplRef.h +++ b/cpp/src/qmf/PrivateImplRef.h @@ -23,8 +23,8 @@ */ #include "qmf/ImportExport.h" -#include "qpid/RefCounted.h" #include <boost/intrusive_ptr.hpp> +#include "qpid/RefCounted.h" namespace qmf { diff --git a/cpp/src/qmf/engine/ResilientConnection.cpp b/cpp/src/qmf/engine/ResilientConnection.cpp index 41dd9ff00c..ab65b8d768 100644 --- a/cpp/src/qmf/engine/ResilientConnection.cpp +++ b/cpp/src/qmf/engine/ResilientConnection.cpp @@ -334,7 +334,8 @@ void ResilientConnectionImpl::notify() { if (notifyFd != -1) { - (void) ::write(notifyFd, ".", 1); + int unused_ret; //Suppress warnings about ignoring return value. + unused_ret = ::write(notifyFd, ".", 1); } } @@ -431,7 +432,8 @@ void ResilientConnectionImpl::EnqueueEvent(ResilientConnectionEvent::EventKind k if (notifyFd != -1) { - (void) ::write(notifyFd, ".", 1); + int unused_ret; //Suppress warnings about ignoring return value. + unused_ret = ::write(notifyFd, ".", 1); } } diff --git a/cpp/src/qmf/engine/SchemaImpl.cpp b/cpp/src/qmf/engine/SchemaImpl.cpp index 9d363d3012..e0948a9911 100644 --- a/cpp/src/qmf/engine/SchemaImpl.cpp +++ b/cpp/src/qmf/engine/SchemaImpl.cpp @@ -35,17 +35,17 @@ using qpid::framing::Uuid; SchemaHash::SchemaHash() { for (int idx = 0; idx < 16; idx++) - hash.b[idx] = 0x5A; + hash[idx] = 0x5A; } void SchemaHash::encode(Buffer& buffer) const { - buffer.putBin128(hash.b); + buffer.putBin128(hash); } void SchemaHash::decode(Buffer& buffer) { - buffer.getBin128(hash.b); + buffer.getBin128(hash); } void SchemaHash::update(uint8_t data) @@ -55,8 +55,9 @@ void SchemaHash::update(uint8_t data) void SchemaHash::update(const char* data, uint32_t len) { - uint64_t* first = &hash.q[0]; - uint64_t* second = &hash.q[1]; + uint64_t* first = (uint64_t*) hash; + uint64_t* second = (uint64_t*) hash + 1; + for (uint32_t idx = 0; idx < len; idx++) { *first = *first ^ (uint64_t) data[idx]; *second = *second << 1; diff --git a/cpp/src/qmf/engine/SchemaImpl.h b/cpp/src/qmf/engine/SchemaImpl.h index 683fb6f8f0..8b079a5ec6 100644 --- a/cpp/src/qmf/engine/SchemaImpl.h +++ b/cpp/src/qmf/engine/SchemaImpl.h @@ -35,10 +35,7 @@ namespace engine { // they've been registered. class SchemaHash { - union h { - uint8_t b[16]; - uint64_t q[2]; - } hash; + uint8_t hash[16]; public: SchemaHash(); void encode(qpid::framing::Buffer& buffer) const; @@ -50,7 +47,7 @@ namespace engine { void update(Direction d) { update((uint8_t) d); } void update(Access a) { update((uint8_t) a); } void update(bool b) { update((uint8_t) (b ? 1 : 0)); } - const uint8_t* get() const { return hash.b; } + const uint8_t* get() const { return hash; } bool operator==(const SchemaHash& other) const; bool operator<(const SchemaHash& other) const; bool operator>(const SchemaHash& other) const; 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/broker/RateTracker.cpp b/cpp/src/qpid/broker/RateTracker.cpp new file mode 100644 index 0000000000..048349b658 --- /dev/null +++ b/cpp/src/qpid/broker/RateTracker.cpp @@ -0,0 +1,51 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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/RateTracker.h" + +using qpid::sys::AbsTime; +using qpid::sys::Duration; +using qpid::sys::TIME_SEC; + +namespace qpid { +namespace broker { + +RateTracker::RateTracker() : currentCount(0), lastCount(0), lastTime(AbsTime::now()) {} + +RateTracker& RateTracker::operator++() +{ + ++currentCount; + return *this; +} + +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/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"; diff --git a/cpp/src/replication.mk b/cpp/src/replication.mk index e5da32f88b..dbe071f405 100644 --- a/cpp/src/replication.mk +++ b/cpp/src/replication.mk @@ -19,14 +19,14 @@ # Make file for building two plugins for asynchronously replicating # queues. -dmoduleexec_LTLIBRARIES += replicating_listener.la replication_exchange.la +dmodule_LTLIBRARIES += replicating_listener.la replication_exchange.la # a queue event listener plugin that creates messages on a replication # queue corresponding to enqueue and dequeue events: replicating_listener_la_SOURCES = \ qpid/replication/constants.h \ qpid/replication/ReplicatingEventListener.cpp \ - qpid/replication/ReplicatingEventListener.h + qpid/replication/ReplicatingEventListener.h replicating_listener_la_LIBADD = libqpidbroker.la if SUNOS @@ -41,7 +41,7 @@ replicating_listener_la_LDFLAGS = $(PLUGINLDFLAGS) replication_exchange_la_SOURCES = \ qpid/replication/constants.h \ qpid/replication/ReplicationExchange.cpp \ - qpid/replication/ReplicationExchange.h + qpid/replication/ReplicationExchange.h replication_exchange_la_LIBADD = libqpidbroker.la diff --git a/cpp/src/ssl.mk b/cpp/src/ssl.mk index 4dba9bb61c..5fbdd55438 100644 --- a/cpp/src/ssl.mk +++ b/cpp/src/ssl.mk @@ -18,7 +18,7 @@ # # # Makefile fragment, conditionally included in Makefile.am -# +# libsslcommon_la_SOURCES = \ qpid/sys/ssl/check.h \ qpid/sys/ssl/check.cpp \ @@ -47,7 +47,7 @@ ssl_la_CXXFLAGS=$(AM_CXXFLAGS) $(SSL_CFLAGS) ssl_la_LDFLAGS = $(PLUGINLDFLAGS) -dmoduleexec_LTLIBRARIES += ssl.la +dmodule_LTLIBRARIES += ssl.la sslconnector_la_SOURCES = \ qpid/client/SslConnector.cpp @@ -60,5 +60,5 @@ sslconnector_la_CXXFLAGS = $(AM_CXXFLAGS) -DQPIDC_CONF_FILE=\"$(confdir)/qpidc.c sslconnector_la_LDFLAGS = $(PLUGINLDFLAGS) -cmoduleexec_LTLIBRARIES += \ +cmodule_LTLIBRARIES += \ sslconnector.la diff --git a/cpp/src/tests/.valgrind.supp b/cpp/src/tests/.valgrind.supp index 2c6a1509ff..0e3e045437 100644 --- a/cpp/src/tests/.valgrind.supp +++ b/cpp/src/tests/.valgrind.supp @@ -73,6 +73,61 @@ } { + boost 103200 -- we think Boost is responsible for these leaks. + Memcheck:Leak + fun:_Znwm + fun:_ZN5boost15program_options??options_description* +} + +{ + boost 103200 -- we think Boost is responsible for these leaks. + Memcheck:Leak + fun:_Znwm + fun:_ZN5boost9unit_test9test_case* +} + +{ + boost 103200 -- we think Boost is responsible for these leaks. + Memcheck:Leak + fun:calloc + fun:_dlerror_run + fun:dlopen@@GLIBC_2.2.5 + fun:_ZN4qpid3sys5Shlib4loadEPKc + fun:_Z9testShlibv + fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv + obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0 + fun:_ZN5boost17execution_monitor7executeEbi + fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi + fun:_ZN5boost9unit_test9test_case3runEv + fun:_ZN5boost9unit_test10test_suite6do_runEv + fun:_ZN5boost9unit_test9test_case3runEv + fun:main +} + +{ + boost 103200 -- we think Boost is responsible for these leaks. + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.2.5 + fun:_ZN4qpid6broker5Timer5startEv + fun:_ZN4qpid6broker5TimerC1Ev + fun:_ZN4qpid6broker10DtxManagerC1Ev + fun:_ZN4qpid6broker6BrokerC1ERKNS1_7OptionsE + fun:_ZN4qpid6broker6Broker6createERKNS1_7OptionsE + fun:_ZN15SessionFixtureTI15ProxyConnectionEC2Ev + fun:_Z14testQueueQueryv + fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor8functionEv + obj:/usr/lib64/libboost_unit_test_framework.so.1.32.0 + fun:_ZN5boost17execution_monitor7executeEbi + fun:_ZN5boost9unit_test9ut_detail17unit_test_monitor21execute_and_translateEPNS0_9test_caseEMS3_FvvEi + fun:_ZN5boost9unit_test9test_case3runEv + fun:_ZN5boost9unit_test10test_suite6do_runEv + fun:_ZN5boost9unit_test9test_case3runEv + fun:main +} + +{ INVESTIGATE Memcheck:Leak fun:calloc @@ -100,6 +155,25 @@ } { + boost 103200 -- mgoulish -- fix this, sometime + Memcheck:Leak + fun:* + fun:* + obj:* + fun:* + fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_ +} + +{ + boost 103200 -- mgoulish -- fix this, sometime + Memcheck:Leak + fun:* + fun:* + fun:* + fun:_ZN4qpid34options_description_less_easy_initclEPKcPKN5boost15program_options14value_semanticES2_ +} + +{ INVESTIGATE Memcheck:Param socketcall.sendto(msg) diff --git a/cpp/src/tests/Address.cpp b/cpp/src/tests/Address.cpp index 0fd3585958..f41f27b6df 100644 --- a/cpp/src/tests/Address.cpp +++ b/cpp/src/tests/Address.cpp @@ -119,17 +119,6 @@ QPID_AUTO_TEST_CASE(testParseQuotedNameAndSubject) BOOST_CHECK_EQUAL(std::string("my subject with ; in it"), address.getSubject()); } -QPID_AUTO_TEST_CASE(testParseOptionsWithEmptyStringAsValue) -{ - Address address("my-topic; {a:'', x:101}"); - BOOST_CHECK_EQUAL(std::string("my-topic"), address.getName()); - Variant a = address.getOptions()["a"]; - BOOST_CHECK_EQUAL(VAR_STRING, a.getType()); - std::string aVal = a; - BOOST_CHECK(aVal.size() == 0); - BOOST_CHECK_EQUAL((uint16_t) 101, address.getOptions()["x"].asInt64()); -} - QPID_AUTO_TEST_SUITE_END() }} diff --git a/cpp/src/tests/BrokerFixture.h b/cpp/src/tests/BrokerFixture.h index 92c6d22b57..672d954572 100644 --- a/cpp/src/tests/BrokerFixture.h +++ b/cpp/src/tests/BrokerFixture.h @@ -22,6 +22,8 @@ * */ +#include "SocketProxy.h" + #include "qpid/broker/Broker.h" #include "qpid/client/Connection.h" #include "qpid/client/ConnectionImpl.h" @@ -69,15 +71,16 @@ struct BrokerFixture : private boost::noncopyable { brokerThread = qpid::sys::Thread(*broker); }; - void shutdownBroker() { - if (broker) { - broker->shutdown(); - brokerThread.join(); - broker = BrokerPtr(); - } + void shutdownBroker() + { + broker->shutdown(); + broker = BrokerPtr(); } - ~BrokerFixture() { shutdownBroker(); } + ~BrokerFixture() { + if (broker) broker->shutdown(); + brokerThread.join(); + } /** Open a connection to the broker. */ void open(qpid::client::Connection& c) { @@ -94,6 +97,20 @@ struct LocalConnection : public qpid::client::Connection { ~LocalConnection() { close(); } }; +/** A local client connection via a socket proxy. */ +struct ProxyConnection : public qpid::client::Connection { + SocketProxy proxy; + ProxyConnection(int brokerPort) : proxy(brokerPort) { + open("localhost", proxy.getPort()); + } + ProxyConnection(const qpid::client::ConnectionSettings& s) : proxy(s.port) { + qpid::client::ConnectionSettings proxySettings(s); + proxySettings.port = proxy.getPort(); + open(proxySettings); + } + ~ProxyConnection() { close(); } +}; + /** Convenience class to create and open a connection and session * and some related useful objects. */ @@ -130,6 +147,7 @@ struct SessionFixtureT : BrokerFixture, ClientT<ConnectionType,SessionType> { }; typedef SessionFixtureT<LocalConnection> SessionFixture; +typedef SessionFixtureT<ProxyConnection> ProxySessionFixture; }} // namespace qpid::tests diff --git a/cpp/src/tests/BrokerMgmtAgent.cpp b/cpp/src/tests/BrokerMgmtAgent.cpp index 1d5289dc90..d0c6668b72 100644 --- a/cpp/src/tests/BrokerMgmtAgent.cpp +++ b/cpp/src/tests/BrokerMgmtAgent.cpp @@ -599,12 +599,13 @@ namespace qpid { // populate the agent with multiple test objects const size_t objCount = 50; std::vector<TestManageable *> tmv; + uint32_t objLen; for (size_t i = 0; i < objCount; i++) { std::stringstream key; key << "testobj-" << i; TestManageable *tm = new TestManageable(agent, key.str()); - (void) tm->GetManagementObject()->writePropertiesSize(); + objLen = tm->GetManagementObject()->writePropertiesSize(); agent->addObject(tm->GetManagementObject(), key.str()); tmv.push_back(tm); } diff --git a/cpp/src/tests/BrokerOptions.cpp b/cpp/src/tests/BrokerOptions.cpp deleted file mode 100644 index b36d96916a..0000000000 --- a/cpp/src/tests/BrokerOptions.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright (c) 2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** Unit tests for various broker configuration options **/ - -#include "unit_test.h" -#include "test_tools.h" -#include "MessagingFixture.h" - -#include "qpid/messaging/Address.h" -#include "qpid/messaging/Connection.h" -#include "qpid/messaging/Message.h" -#include "qpid/messaging/Receiver.h" -#include "qpid/messaging/Sender.h" -#include "qpid/messaging/Session.h" - -namespace qpid { -namespace tests { - -QPID_AUTO_TEST_SUITE(BrokerOptionsTestSuite) - -using namespace qpid::broker; -using namespace qpid::messaging; -using namespace qpid::types; -using namespace qpid; - -QPID_AUTO_TEST_CASE(testDisabledTimestamp) -{ - // by default, there should be no timestamp added by the broker - MessagingFixture fix; - - Sender sender = fix.session.createSender("test-q; {create:always, delete:sender}"); - messaging::Message msg("hi"); - sender.send(msg); - - Receiver receiver = fix.session.createReceiver("test-q"); - messaging::Message in; - BOOST_CHECK(receiver.fetch(in, Duration::IMMEDIATE)); - Variant::Map props = in.getProperties(); - BOOST_CHECK(props.find("x-amqp-0-10.timestamp") == props.end()); -} - -QPID_AUTO_TEST_CASE(testEnabledTimestamp) -{ - // when enabled, the 0.10 timestamp is added by the broker - Broker::Options opts; - opts.timestampRcvMsgs = true; - MessagingFixture fix(opts, true); - - Sender sender = fix.session.createSender("test-q; {create:always, delete:sender}"); - messaging::Message msg("one"); - sender.send(msg); - - Receiver receiver = fix.session.createReceiver("test-q"); - messaging::Message in; - BOOST_CHECK(receiver.fetch(in, Duration::IMMEDIATE)); - Variant::Map props = in.getProperties(); - BOOST_CHECK(props.find("x-amqp-0-10.timestamp") != props.end()); - BOOST_CHECK(props["x-amqp-0-10.timestamp"]); -} - -QPID_AUTO_TEST_SUITE_END() - -}} diff --git a/cpp/src/tests/CMakeLists.txt b/cpp/src/tests/CMakeLists.txt index 7d781e5eb3..3b3b232671 100644 --- a/cpp/src/tests/CMakeLists.txt +++ b/cpp/src/tests/CMakeLists.txt @@ -107,6 +107,7 @@ set(unit_tests_to_build MessagingSessionTests SequenceSet StringUtils + IncompleteMessageList RangeSet AtomicValue QueueTest @@ -118,7 +119,6 @@ set(unit_tests_to_build MessageTest QueueRegistryTest QueuePolicyTest - QueueFlowLimitTest FramingTest HeaderTest SequenceNumberTest @@ -264,19 +264,6 @@ add_executable (qpid-send qpid-send.cpp Statistics.cpp ${platform_test_additions target_link_libraries (qpid-send qpidmessaging) remember_location(qpid-send) -add_executable (qpid-ping qpid-ping.cpp ${platform_test_additions}) -target_link_libraries (qpid-ping qpidclient) -remember_location(qpid-ping) - -add_executable (datagen datagen.cpp ${platform_test_additions}) -target_link_libraries (datagen qpidclient) -remember_location(datagen) - -add_executable (msg_group_test msg_group_test.cpp ${platform_test_additions}) -target_link_libraries (msg_group_test qpidmessaging) -remember_location(msg_group_test) - - # qpid-perftest and qpid-latency-test are generally useful so install them install (TARGETS qpid-perftest qpid-latency-test RUNTIME DESTINATION ${QPID_INSTALL_BINDIR}) @@ -291,7 +278,7 @@ set(test_wrap ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_test${test_script_suffix} add_test (unit_test ${test_wrap} ${unit_test_LOCATION}) add_test (start_broker ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/start_broker${test_script_suffix}) -add_test (qpid-client-test ${test_wrap} ${qpid-client-test_LOCATION}) +add_test (qpid-client-test ${test_wrap} ${qpid-client_test_LOCATION}) add_test (quick_perftest ${test_wrap} ${qpid-perftest_LOCATION} --summary --count 100) add_test (quick_topictest ${test_wrap} ${CMAKE_CURRENT_SOURCE_DIR}/quick_topictest${test_script_suffix}) add_test (quick_txtest ${test_wrap} ${qpid-txtest_LOCATION} --queues 4 --tx-count 10 --quiet) @@ -301,7 +288,6 @@ if (PYTHON_EXECUTABLE) endif (PYTHON_EXECUTABLE) add_test (stop_broker ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/stop_broker${test_script_suffix}) if (PYTHON_EXECUTABLE) - add_test (ipv6_test ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/ipv6_test${test_script_suffix}) add_test (federation_tests ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_federation_tests${test_script_suffix}) if (BUILD_ACL) add_test (acl_tests ${shell} ${CMAKE_CURRENT_SOURCE_DIR}/run_acl_tests${test_script_suffix}) diff --git a/cpp/src/tests/ClientSessionTest.cpp b/cpp/src/tests/ClientSessionTest.cpp index 30441cd03c..939f8f2b88 100644 --- a/cpp/src/tests/ClientSessionTest.cpp +++ b/cpp/src/tests/ClientSessionTest.cpp @@ -102,9 +102,9 @@ struct SimpleListener : public MessageListener } }; -struct ClientSessionFixture : public SessionFixture +struct ClientSessionFixture : public ProxySessionFixture { - ClientSessionFixture(Broker::Options opts = Broker::Options()) : SessionFixture(opts) { + ClientSessionFixture(Broker::Options opts = Broker::Options()) : ProxySessionFixture(opts) { session.queueDeclare(arg::queue="my-queue"); } }; @@ -150,6 +150,16 @@ QPID_AUTO_TEST_CASE(testDispatcherThread) BOOST_CHECK_EQUAL(boost::lexical_cast<string>(i), listener.messages[i].getData()); } +// FIXME aconway 2009-06-17: test for unimplemented feature, enable when implemented. +void testSuspend0Timeout() { + ClientSessionFixture fix; + fix.session.suspend(); // session has 0 timeout. + try { + fix.connection.resume(fix.session); + BOOST_FAIL("Expected InvalidArgumentException."); + } catch(const InternalErrorException&) {} +} + QPID_AUTO_TEST_CASE(testUseSuspendedError) { ClientSessionFixture fix; @@ -161,6 +171,18 @@ QPID_AUTO_TEST_CASE(testUseSuspendedError) } catch(const NotAttachedException&) {} } +// FIXME aconway 2009-06-17: test for unimplemented feature, enable when implemented. +void testSuspendResume() { + ClientSessionFixture fix; + fix.session.timeout(60); + fix.session.suspend(); + // Make sure we are still subscribed after resume. + fix.connection.resume(fix.session); + fix.session.messageTransfer(arg::content=Message("my-message", "my-queue")); + BOOST_CHECK_EQUAL("my-message", fix.subs.get("my-queue", TIME_SEC).getData()); +} + + QPID_AUTO_TEST_CASE(testSendToSelf) { ClientSessionFixture fix; SimpleListener mylistener; @@ -249,12 +271,8 @@ QPID_AUTO_TEST_CASE(testOpenFailure) { QPID_AUTO_TEST_CASE(testPeriodicExpiration) { Broker::Options opts; opts.queueCleanInterval = 1; - opts.queueFlowStopRatio = 0; - opts.queueFlowResumeRatio = 0; ClientSessionFixture fix(opts); - FieldTable args; - args.setInt("qpid.max_count",10); - fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); + fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true); for (uint i = 0; i < 10; i++) { Message m((boost::format("Message_%1%") % (i+1)).str(), "my-queue"); @@ -265,7 +283,6 @@ QPID_AUTO_TEST_CASE(testPeriodicExpiration) { BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 10u); qpid::sys::sleep(2); BOOST_CHECK_EQUAL(fix.session.queueQuery(string("my-queue")).getMessageCount(), 5u); - fix.session.messageTransfer(arg::content=Message("Message_11", "my-queue"));//ensure policy is also updated } QPID_AUTO_TEST_CASE(testExpirationOnPop) { diff --git a/cpp/src/tests/ExchangeTest.cpp b/cpp/src/tests/ExchangeTest.cpp index fe72f42a46..88a1cd99c2 100644 --- a/cpp/src/tests/ExchangeTest.cpp +++ b/cpp/src/tests/ExchangeTest.cpp @@ -253,7 +253,7 @@ QPID_AUTO_TEST_CASE(testIVEOption) TopicExchange topic ("topic1", false, args); intrusive_ptr<Message> msg1 = cmessage("direct1", "abc"); - msg1->insertCustomProperty("a", "abc"); + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString("a", "abc"); DeliverableMessage dmsg1(msg1); FieldTable args2; diff --git a/cpp/src/tests/ForkedBroker.cpp b/cpp/src/tests/ForkedBroker.cpp index 10674b5175..53eaa7e1ce 100644 --- a/cpp/src/tests/ForkedBroker.cpp +++ b/cpp/src/tests/ForkedBroker.cpp @@ -68,7 +68,8 @@ ForkedBroker::~ForkedBroker() { } if (!dataDir.empty()) { - (void) ::system(("rm -rf "+dataDir).c_str()); + int unused_ret; // Suppress warnings about ignoring return value. + unused_ret = ::system(("rm -rf "+dataDir).c_str()); } } diff --git a/cpp/src/tests/IncompleteMessageList.cpp b/cpp/src/tests/IncompleteMessageList.cpp new file mode 100644 index 0000000000..10782572e5 --- /dev/null +++ b/cpp/src/tests/IncompleteMessageList.cpp @@ -0,0 +1,134 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +#include <iostream> +#include <sstream> +#include "qpid/broker/Message.h" +#include "qpid/broker/NullMessageStore.h" +#include "qpid/broker/Queue.h" +#include "qpid/broker/IncompleteMessageList.h" + +#include "unit_test.h" + +namespace qpid { +namespace tests { + +QPID_AUTO_TEST_SUITE(IncompleteMessageListTestSuite) + +using namespace qpid::broker; +using namespace qpid::framing; + +struct Checker +{ + std::list<SequenceNumber> ids; + + Checker() { } + + Checker(uint start, uint end) { + for (uint i = start; i <= end; i++) { + ids.push_back(i); + } + } + + Checker& expect(const SequenceNumber& id) { + ids.push_back(id); + return *this; + } + + void operator()(boost::intrusive_ptr<Message> msg) { + BOOST_CHECK(!ids.empty()); + BOOST_CHECK_EQUAL(msg->getCommandId(), ids.front()); + ids.pop_front(); + } +}; + +QPID_AUTO_TEST_CASE(testProcessSimple) +{ + IncompleteMessageList list; + SequenceNumber counter(1); + //fill up list with messages + for (int i = 0; i < 5; i++) { + boost::intrusive_ptr<Message> msg(new Message(counter++)); + list.add(msg); + } + //process and ensure they are all passed to completion listener + list.process(Checker(1, 5), false); + //process again and ensure none are resent to listener + list.process(Checker(), false); +} + +QPID_AUTO_TEST_CASE(testProcessWithIncomplete) +{ + Queue::shared_ptr queue; + IncompleteMessageList list; + SequenceNumber counter(1); + boost::intrusive_ptr<Message> middle; + //fill up list with messages + for (int i = 0; i < 5; i++) { + boost::intrusive_ptr<Message> msg(new Message(counter++)); + list.add(msg); + if (i == 2) { + //mark a message in the middle as incomplete + msg->enqueueAsync(queue, 0); + middle = msg; + } + } + //process and ensure only message upto incomplete message are passed to listener + list.process(Checker(1, 2), false); + //mark message complete and re-process to get remaining messages sent to listener + middle->enqueueComplete(); + list.process(Checker(3, 5), false); +} + + +struct MockStore : public NullMessageStore +{ + Queue::shared_ptr queue; + boost::intrusive_ptr<Message> msg; + + void flush(const qpid::broker::PersistableQueue& q) { + BOOST_CHECK_EQUAL(queue.get(), &q); + msg->enqueueComplete(); + } +}; + +QPID_AUTO_TEST_CASE(testSyncProcessWithIncomplete) +{ + IncompleteMessageList list; + SequenceNumber counter(1); + MockStore store; + store.queue = Queue::shared_ptr(new Queue("mock-queue", false, &store)); + //fill up list with messages + for (int i = 0; i < 5; i++) { + boost::intrusive_ptr<Message> msg(new Message(counter++)); + list.add(msg); + if (i == 2) { + //mark a message in the middle as incomplete + msg->enqueueAsync(store.queue, &store); + store.msg = msg; + } + } + //process with sync bit specified and ensure that all messages are passed to listener + list.process(Checker(1, 5), true); +} + +QPID_AUTO_TEST_SUITE_END() + +}} // namespace qpid::tests diff --git a/cpp/src/tests/Makefile.am b/cpp/src/tests/Makefile.am index 3c9ca1b70f..07405bcd8f 100644 --- a/cpp/src/tests/Makefile.am +++ b/cpp/src/tests/Makefile.am @@ -75,7 +75,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \ MessagingThreadTests.cpp \ MessagingFixture.h \ ClientSessionTest.cpp \ - BrokerFixture.h \ + BrokerFixture.h SocketProxy.h \ exception_test.cpp \ RefCounted.cpp \ SessionState.cpp logging.cpp \ @@ -87,6 +87,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \ InlineVector.cpp \ SequenceSet.cpp \ StringUtils.cpp \ + IncompleteMessageList.cpp \ RangeSet.cpp \ AtomicValue.cpp \ QueueTest.cpp \ @@ -98,7 +99,6 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \ MessageTest.cpp \ QueueRegistryTest.cpp \ QueuePolicyTest.cpp \ - QueueFlowLimitTest.cpp \ FramingTest.cpp \ HeaderTest.cpp \ SequenceNumberTest.cpp \ @@ -124,8 +124,7 @@ unit_test_SOURCES= unit_test.cpp unit_test.h \ Variant.cpp \ Address.cpp \ ClientMessage.cpp \ - Qmf2.cpp \ - BrokerOptions.cpp + Qmf2.cpp if HAVE_XML unit_test_SOURCES+= XmlClientSessionTest.cpp @@ -287,27 +286,31 @@ check_PROGRAMS+=datagen datagen_SOURCES=datagen.cpp datagen_LDADD=$(lib_common) $(lib_client) +check_PROGRAMS+=qrsh_server +qrsh_server_SOURCES=qrsh_server.cpp +qrsh_server_LDADD=$(lib_client) + +check_PROGRAMS+=qrsh_run +qrsh_run_SOURCES=qrsh_run.cpp +qrsh_run_LDADD=$(lib_client) + +check_PROGRAMS+=qrsh +qrsh_SOURCES=qrsh.cpp +qrsh_LDADD=$(lib_client) + check_PROGRAMS+=qpid-stream qpid_stream_INCLUDES=$(PUBLIC_INCLUDES) qpid_stream_SOURCES=qpid-stream.cpp qpid_stream_LDADD=$(lib_messaging) -check_PROGRAMS+=msg_group_test -msg_group_test_INCLUDES=$(PUBLIC_INCLUDES) -msg_group_test_SOURCES=msg_group_test.cpp -msg_group_test_LDADD=$(lib_messaging) - TESTS_ENVIRONMENT = \ VALGRIND=$(VALGRIND) \ LIBTOOL="$(LIBTOOL)" \ QPID_DATA_DIR= \ $(srcdir)/run_test -system_tests = qpid-client-test quick_perftest quick_topictest run_header_test quick_txtest \ - run_msg_group_tests -TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests run_federation_sys_tests \ - run_acl_tests run_cli_tests replication_test dynamic_log_level_test \ - run_queue_flow_limit_tests ipv6_test +system_tests = qpid-client-test quick_perftest quick_topictest run_header_test quick_txtest +TESTS += start_broker $(system_tests) python_tests stop_broker run_federation_tests run_acl_tests run_cli_tests replication_test dynamic_log_level_test EXTRA_DIST += \ run_test vg_check \ @@ -322,8 +325,6 @@ EXTRA_DIST += \ config.null \ ais_check \ run_federation_tests \ - run_federation_sys_tests \ - run_long_federation_sys_tests \ run_cli_tests \ run_acl_tests \ .valgrind.supp \ @@ -348,10 +349,7 @@ EXTRA_DIST += \ run_test.ps1 \ start_broker.ps1 \ stop_broker.ps1 \ - topictest.ps1 \ - run_queue_flow_limit_tests \ - run_msg_group_tests \ - ipv6_test + topictest.ps1 check_LTLIBRARIES += libdlclose_noop.la libdlclose_noop_la_LDFLAGS = -module -rpath $(abs_builddir) @@ -362,11 +360,7 @@ CLEANFILES+=valgrind.out *.log *.vglog* dummy_test qpidd.port $(unit_wrappers) # Longer running stability tests, not run by default check: target. # Not run under valgrind, too slow -LONG_TESTS+=start_broker \ - fanout_perftest shared_perftest multiq_perftest topic_perftest run_ring_queue_test \ - run_msg_group_tests_soak \ - stop_broker \ - run_long_federation_sys_tests \ +LONG_TESTS+=start_broker fanout_perftest shared_perftest multiq_perftest topic_perftest run_ring_queue_test stop_broker \ run_failover_soak reliable_replication_test \ federated_cluster_test_with_node_failure @@ -378,8 +372,7 @@ EXTRA_DIST+= \ run_failover_soak \ reliable_replication_test \ federated_cluster_test_with_node_failure \ - sasl_test_setup.sh \ - run_msg_group_tests_soak + sasl_test_setup.sh check-long: $(MAKE) check TESTS="$(LONG_TESTS)" VALGRIND= diff --git a/cpp/src/tests/MessageReplayTracker.cpp b/cpp/src/tests/MessageReplayTracker.cpp index e35f673683..3d79ee53c2 100644 --- a/cpp/src/tests/MessageReplayTracker.cpp +++ b/cpp/src/tests/MessageReplayTracker.cpp @@ -51,7 +51,7 @@ class ReplayBufferChecker QPID_AUTO_TEST_CASE(testReplay) { - SessionFixture fix; + ProxySessionFixture fix; fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true); MessageReplayTracker tracker(10); @@ -77,7 +77,7 @@ QPID_AUTO_TEST_CASE(testReplay) QPID_AUTO_TEST_CASE(testCheckCompletion) { - SessionFixture fix; + ProxySessionFixture fix; fix.session.queueDeclare(arg::queue="my-queue", arg::exclusive=true, arg::autoDelete=true); MessageReplayTracker tracker(10); diff --git a/cpp/src/tests/MessagingFixture.h b/cpp/src/tests/MessagingFixture.h index 2312a87e9d..715de09bad 100644 --- a/cpp/src/tests/MessagingFixture.h +++ b/cpp/src/tests/MessagingFixture.h @@ -27,19 +27,15 @@ #include "qpid/client/Connection.h" #include "qpid/client/Session.h" #include "qpid/framing/Uuid.h" -#include "qpid/messaging/Address.h" #include "qpid/messaging/Connection.h" #include "qpid/messaging/Session.h" #include "qpid/messaging/Sender.h" #include "qpid/messaging/Receiver.h" #include "qpid/messaging/Message.h" -#include "qpid/types/Variant.h" namespace qpid { namespace tests { -using qpid::types::Variant; - struct BrokerAdmin { qpid::client::Connection connection; @@ -227,119 +223,6 @@ inline void receive(messaging::Receiver& receiver, uint count = 1, uint start = } } - -class MethodInvoker -{ - public: - MethodInvoker(messaging::Session& session) : replyTo("#; {create:always, node:{x-declare:{auto-delete:true}}}"), - sender(session.createSender("qmf.default.direct/broker")), - receiver(session.createReceiver(replyTo)) {} - - void createExchange(const std::string& name, const std::string& type, bool durable=false) - { - Variant::Map params; - params["name"]=name; - params["type"]="exchange"; - params["properties"] = Variant::Map(); - params["properties"].asMap()["exchange-type"] = type; - params["properties"].asMap()["durable"] = durable; - methodRequest("create", params); - } - - void deleteExchange(const std::string& name) - { - Variant::Map params; - params["name"]=name; - params["type"]="exchange"; - methodRequest("delete", params); - } - - void createQueue(const std::string& name, bool durable=false, bool autodelete=false, - const Variant::Map& options=Variant::Map()) - { - Variant::Map params; - params["name"]=name; - params["type"]="queue"; - params["properties"] = options; - params["properties"].asMap()["durable"] = durable; - params["properties"].asMap()["auto-delete"] = autodelete; - methodRequest("create", params); - } - - void deleteQueue(const std::string& name) - { - Variant::Map params; - params["name"]=name; - params["type"]="queue"; - methodRequest("delete", params); - } - - void bind(const std::string& exchange, const std::string& queue, const std::string& key, - const Variant::Map& options=Variant::Map()) - { - Variant::Map params; - params["name"]=(boost::format("%1%/%2%/%3%") % (exchange) % (queue) % (key)).str(); - params["type"]="binding"; - params["properties"] = options; - methodRequest("create", params); - } - - void unbind(const std::string& exchange, const std::string& queue, const std::string& key) - { - Variant::Map params; - params["name"]=(boost::format("%1%/%2%/%3%") % (exchange) % (queue) % (key)).str(); - params["type"]="binding"; - methodRequest("delete", params); - } - - void methodRequest(const std::string& method, const Variant::Map& inParams, Variant::Map* outParams = 0) - { - Variant::Map content; - Variant::Map objectId; - objectId["_object_name"] = "org.apache.qpid.broker:broker:amqp-broker"; - content["_object_id"] = objectId; - content["_method_name"] = method; - content["_arguments"] = inParams; - - messaging::Message request; - request.setReplyTo(replyTo); - request.getProperties()["x-amqp-0-10.app-id"] = "qmf2"; - request.getProperties()["qmf.opcode"] = "_method_request"; - encode(content, request); - - sender.send(request); - - messaging::Message response; - if (receiver.fetch(response, messaging::Duration::SECOND*5)) { - if (response.getProperties()["x-amqp-0-10.app-id"] == "qmf2") { - std::string opcode = response.getProperties()["qmf.opcode"]; - if (opcode == "_method_response") { - if (outParams) { - Variant::Map m; - decode(response, m); - *outParams = m["_arguments"].asMap(); - } - } else if (opcode == "_exception") { - Variant::Map m; - decode(response, m); - throw Exception(QPID_MSG("Error: " << m["_values"])); - } else { - throw Exception(QPID_MSG("Invalid response received, unexpected opcode: " << opcode)); - } - } else { - throw Exception(QPID_MSG("Invalid response received, not a qmfv2 message: app-id=" - << response.getProperties()["x-amqp-0-10.app-id"])); - } - } else { - throw Exception(QPID_MSG("No response received")); - } - } - private: - messaging::Address replyTo; - messaging::Sender sender; - messaging::Receiver receiver; -}; - }} // namespace qpid::tests #endif /*!TESTS_MESSAGINGFIXTURE_H*/ diff --git a/cpp/src/tests/MessagingSessionTests.cpp b/cpp/src/tests/MessagingSessionTests.cpp index 9d5db84bb4..991ec847bf 100644 --- a/cpp/src/tests/MessagingSessionTests.cpp +++ b/cpp/src/tests/MessagingSessionTests.cpp @@ -611,28 +611,6 @@ QPID_AUTO_TEST_CASE(testAssertPolicyQueue) fix.admin.deleteQueue("q"); } -QPID_AUTO_TEST_CASE(testAssertExchangeOption) -{ - MessagingFixture fix; - std::string a1 = "e; {create:always, assert:always, node:{type:topic, x-declare:{type:direct, arguments:{qpid.msg_sequence:True}}}}"; - Sender s1 = fix.session.createSender(a1); - s1.close(); - Receiver r1 = fix.session.createReceiver(a1); - r1.close(); - - std::string a2 = "e; {assert:receiver, node:{type:topic, x-declare:{type:fanout, arguments:{qpid.msg_sequence:True}}}}"; - Sender s2 = fix.session.createSender(a2); - s2.close(); - BOOST_CHECK_THROW(fix.session.createReceiver(a2), qpid::messaging::AssertionFailed); - - std::string a3 = "e; {assert:sender, node:{x-declare:{arguments:{qpid.msg_sequence:False}}}}"; - BOOST_CHECK_THROW(fix.session.createSender(a3), qpid::messaging::AssertionFailed); - Receiver r3 = fix.session.createReceiver(a3); - r3.close(); - - fix.admin.deleteExchange("e"); -} - QPID_AUTO_TEST_CASE(testGetSender) { QueueFixture fix; @@ -912,212 +890,6 @@ QPID_AUTO_TEST_CASE(testAcknowledge) BOOST_CHECK(!fix.session.createReceiver(fix.queue).fetch(m, Duration::IMMEDIATE)); } -QPID_AUTO_TEST_CASE(testQmfCreateAndDelete) -{ - MessagingFixture fix(Broker::Options(), true/*enable management*/); - MethodInvoker control(fix.session); - control.createQueue("my-queue"); - control.createExchange("my-exchange", "topic"); - control.bind("my-exchange", "my-queue", "subject1"); - - Sender sender = fix.session.createSender("my-exchange"); - Receiver receiver = fix.session.createReceiver("my-queue"); - Message out; - out.setSubject("subject1"); - out.setContent("one"); - sender.send(out); - Message in; - BOOST_CHECK(receiver.fetch(in, Duration::SECOND*5)); - BOOST_CHECK_EQUAL(out.getContent(), in.getContent()); - control.unbind("my-exchange", "my-queue", "subject1"); - control.bind("my-exchange", "my-queue", "subject2"); - - out.setContent("two"); - sender.send(out);//should be dropped - - out.setSubject("subject2"); - out.setContent("three"); - sender.send(out);//should not be dropped - - BOOST_CHECK(receiver.fetch(in, Duration::SECOND*5)); - BOOST_CHECK_EQUAL(out.getContent(), in.getContent()); - BOOST_CHECK(!receiver.fetch(in, Duration::IMMEDIATE)); - sender.close(); - receiver.close(); - - control.deleteExchange("my-exchange"); - messaging::Session other = fix.connection.createSession(); - { - ScopedSuppressLogging sl; - BOOST_CHECK_THROW(other.createSender("my-exchange"), qpid::messaging::NotFound); - } - control.deleteQueue("my-queue"); - other = fix.connection.createSession(); - { - ScopedSuppressLogging sl; - BOOST_CHECK_THROW(other.createReceiver("my-queue"), qpid::messaging::NotFound); - } -} - -QPID_AUTO_TEST_CASE(testRejectAndCredit) -{ - //Ensure credit is restored on completing rejected messages - QueueFixture fix; - Sender sender = fix.session.createSender(fix.queue); - Receiver receiver = fix.session.createReceiver(fix.queue); - - const uint count(10); - receiver.setCapacity(count); - for (uint i = 0; i < count; i++) { - sender.send(Message((boost::format("Message_%1%") % (i+1)).str())); - } - - Message in; - for (uint i = 0; i < count; ++i) { - if (receiver.fetch(in, Duration::SECOND)) { - BOOST_CHECK_EQUAL(in.getContent(), (boost::format("Message_%1%") % (i+1)).str()); - fix.session.reject(in); - } else { - BOOST_FAIL((boost::format("Message_%1% not received as expected") % (i+1)).str()); - break; - } - } - //send another batch of messages - for (uint i = 0; i < count; i++) { - sender.send(Message((boost::format("Message_%1%") % (i+count)).str())); - } - - for (uint i = 0; i < count; ++i) { - if (receiver.fetch(in, Duration::SECOND)) { - BOOST_CHECK_EQUAL(in.getContent(), (boost::format("Message_%1%") % (i+count)).str()); - } else { - BOOST_FAIL((boost::format("Message_%1% not received as expected") % (i+count)).str()); - break; - } - } - fix.session.acknowledge(); - receiver.close(); - sender.close(); -} - -QPID_AUTO_TEST_CASE(testTtlForever) -{ - QueueFixture fix; - Sender sender = fix.session.createSender(fix.queue); - Message out("I want to live forever!"); - out.setTtl(Duration::FOREVER); - sender.send(out, true); - Receiver receiver = fix.session.createReceiver(fix.queue); - Message in = receiver.fetch(Duration::IMMEDIATE); - fix.session.acknowledge(); - BOOST_CHECK_EQUAL(in.getContent(), out.getContent()); - BOOST_CHECK(in.getTtl() == Duration::FOREVER); -} - -QPID_AUTO_TEST_CASE(testExclusiveTopicSubscriber) -{ - TopicFixture fix; - std::string address = (boost::format("%1%; { link: { name: 'my-subscription', x-declare: { auto-delete: true, exclusive: true }}}") % fix.topic).str(); - Sender sender = fix.session.createSender(fix.topic); - Receiver receiver1 = fix.session.createReceiver(address); - { - ScopedSuppressLogging sl; - try { - fix.session.createReceiver(address); - fix.session.sync(); - BOOST_FAIL("Expected exception."); - } catch (const MessagingException& /*e*/) {} - } -} - -QPID_AUTO_TEST_CASE(testNonExclusiveSubscriber) -{ - TopicFixture fix; - std::string address = (boost::format("%1%; {node:{type:topic}, link:{name:'my-subscription', x-declare:{auto-delete:true, exclusive:false}}}") % fix.topic).str(); - Receiver receiver1 = fix.session.createReceiver(address); - Receiver receiver2 = fix.session.createReceiver(address); - Sender sender = fix.session.createSender(fix.topic); - sender.send(Message("one"), true); - Message in = receiver1.fetch(Duration::IMMEDIATE); - BOOST_CHECK_EQUAL(in.getContent(), std::string("one")); - sender.send(Message("two"), true); - in = receiver2.fetch(Duration::IMMEDIATE); - BOOST_CHECK_EQUAL(in.getContent(), std::string("two")); - fix.session.acknowledge(); -} - -QPID_AUTO_TEST_CASE(testAcknowledgeUpTo) -{ - QueueFixture fix; - Sender sender = fix.session.createSender(fix.queue); - const uint count(20); - for (uint i = 0; i < count; ++i) { - sender.send(Message((boost::format("Message_%1%") % (i+1)).str())); - } - - Session other = fix.connection.createSession(); - Receiver receiver = other.createReceiver(fix.queue); - std::vector<Message> messages; - for (uint i = 0; i < count; ++i) { - Message msg = receiver.fetch(); - BOOST_CHECK_EQUAL(msg.getContent(), (boost::format("Message_%1%") % (i+1)).str()); - messages.push_back(msg); - } - const uint batch = 10; - other.acknowledgeUpTo(messages[batch-1]);//acknowledge first 10 messages only - - messages.clear(); - other.sync(); - other.close(); - - other = fix.connection.createSession(); - receiver = other.createReceiver(fix.queue); - Message msg; - for (uint i = 0; i < (count-batch); ++i) { - msg = receiver.fetch(); - BOOST_CHECK_EQUAL(msg.getContent(), (boost::format("Message_%1%") % (i+1+batch)).str()); - } - other.acknowledgeUpTo(msg); - other.sync(); - other.close(); - - Message m; - //check queue is empty - BOOST_CHECK(!fix.session.createReceiver(fix.queue).fetch(m, Duration::IMMEDIATE)); -} - -QPID_AUTO_TEST_CASE(testCreateBindingsOnStandardExchange) -{ - QueueFixture fix; - Sender sender = fix.session.createSender((boost::format("amq.direct; {create:always, node:{type:topic, x-bindings:[{queue:%1%, key:my-subject}]}}") % fix.queue).str()); - Message out("test-message"); - out.setSubject("my-subject"); - sender.send(out); - Receiver receiver = fix.session.createReceiver(fix.queue); - Message in = receiver.fetch(Duration::SECOND * 5); - fix.session.acknowledge(); - BOOST_CHECK_EQUAL(in.getContent(), out.getContent()); - BOOST_CHECK_EQUAL(in.getSubject(), out.getSubject()); -} - -QPID_AUTO_TEST_CASE(testUnsubscribeOnClose) -{ - MessagingFixture fix; - Sender sender = fix.session.createSender("my-exchange/my-subject; {create: always, delete:sender, node:{type:topic, x-declare:{alternate-exchange:amq.fanout}}}"); - Receiver receiver = fix.session.createReceiver("my-exchange/my-subject"); - Receiver deadletters = fix.session.createReceiver("amq.fanout"); - - sender.send(Message("first")); - Message in = receiver.fetch(Duration::SECOND); - BOOST_CHECK_EQUAL(in.getContent(), std::string("first")); - fix.session.acknowledge(); - receiver.close(); - sender.send(Message("second")); - in = deadletters.fetch(Duration::SECOND); - BOOST_CHECK_EQUAL(in.getContent(), std::string("second")); - fix.session.acknowledge(); -} - QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/cpp/src/tests/Qmf2.cpp b/cpp/src/tests/Qmf2.cpp index bc263d5c6d..66c774accd 100644 --- a/cpp/src/tests/Qmf2.cpp +++ b/cpp/src/tests/Qmf2.cpp @@ -23,36 +23,12 @@ #include "qmf/QueryImpl.h" #include "qmf/SchemaImpl.h" #include "qmf/exceptions.h" -#include "qpid/messaging/Connection.h" -#include "qmf/PosixEventNotifierImpl.h" -#include "qmf/AgentSession.h" -#include "qmf/AgentSessionImpl.h" -#include "qmf/ConsoleSession.h" -#include "qmf/ConsoleSessionImpl.h" + #include "unit_test.h" -using namespace std; using namespace qpid::types; -using namespace qpid::messaging; using namespace qmf; -bool isReadable(int fd) -{ - fd_set rfds; - struct timeval tv; - int nfds, result; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - nfds = fd + 1; - tv.tv_sec = 0; - tv.tv_usec = 0; - - result = select(nfds, &rfds, NULL, NULL, &tv); - - return result > 0; -} - namespace qpid { namespace tests { @@ -339,84 +315,6 @@ QPID_AUTO_TEST_CASE(testSchema) BOOST_CHECK_THROW(method.getArgument(3), QmfException); } -QPID_AUTO_TEST_CASE(testAgentSessionEventListener) -{ - Connection connection("localhost"); - AgentSession session(connection, ""); - posix::EventNotifier notifier(session); - - AgentSessionImpl& sessionImpl = AgentSessionImplAccess::get(session); - - BOOST_CHECK(sessionImpl.getEventNotifier() != 0); -} - -QPID_AUTO_TEST_CASE(testConsoleSessionEventListener) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - posix::EventNotifier notifier(session); - - ConsoleSessionImpl& sessionImpl = ConsoleSessionImplAccess::get(session); - - BOOST_CHECK(sessionImpl.getEventNotifier() != 0); -} - -QPID_AUTO_TEST_CASE(testGetHandle) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - posix::EventNotifier notifier(session); - - BOOST_CHECK(notifier.getHandle() > 0); -} - -QPID_AUTO_TEST_CASE(testSetReadableToFalse) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - posix::EventNotifier notifier(session); - PosixEventNotifierImplAccess::get(notifier).setReadable(false); - - bool readable(isReadable(notifier.getHandle())); - BOOST_CHECK(!readable); -} - -QPID_AUTO_TEST_CASE(testSetReadable) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - posix::EventNotifier notifier(session); - PosixEventNotifierImplAccess::get(notifier).setReadable(true); - - bool readable(isReadable(notifier.getHandle())); - BOOST_CHECK(readable); -} - -QPID_AUTO_TEST_CASE(testSetReadableMultiple) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - posix::EventNotifier notifier(session); - for (int i = 0; i < 15; i++) - PosixEventNotifierImplAccess::get(notifier).setReadable(true); - PosixEventNotifierImplAccess::get(notifier).setReadable(false); - - bool readable(isReadable(notifier.getHandle())); - BOOST_CHECK(!readable); -} - -QPID_AUTO_TEST_CASE(testDeleteNotifier) -{ - Connection connection("localhost"); - ConsoleSession session(connection, ""); - ConsoleSessionImpl& sessionImpl = ConsoleSessionImplAccess::get(session); - { - posix::EventNotifier notifier(session); - BOOST_CHECK(sessionImpl.getEventNotifier() != 0); - } - BOOST_CHECK(sessionImpl.getEventNotifier() == 0); -} - QPID_AUTO_TEST_SUITE_END() }} // namespace qpid::tests diff --git a/cpp/src/tests/QueueEvents.cpp b/cpp/src/tests/QueueEvents.cpp index cea8bbf0db..bd18fa45fb 100644 --- a/cpp/src/tests/QueueEvents.cpp +++ b/cpp/src/tests/QueueEvents.cpp @@ -147,7 +147,7 @@ struct EventRecorder QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing) { - SessionFixture fixture; + ProxySessionFixture fixture; //register dummy event listener to broker EventRecorder listener; fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1)); @@ -194,7 +194,7 @@ QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing) QPID_AUTO_TEST_CASE(testSystemLevelEventProcessing_enqueuesOnly) { - SessionFixture fixture; + ProxySessionFixture fixture; //register dummy event listener to broker EventRecorder listener; fixture.broker->getQueueEvents().registerListener("recorder", boost::bind(&EventRecorder::handle, &listener, _1)); diff --git a/cpp/src/tests/QueueFlowLimitTest.cpp b/cpp/src/tests/QueueFlowLimitTest.cpp deleted file mode 100644 index 8a6923fb09..0000000000 --- a/cpp/src/tests/QueueFlowLimitTest.cpp +++ /dev/null @@ -1,463 +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 <sstream> -#include <deque> -#include "unit_test.h" -#include "test_tools.h" - -#include "qpid/broker/QueuePolicy.h" -#include "qpid/broker/QueueFlowLimit.h" -#include "qpid/sys/Time.h" -#include "qpid/framing/reply_exceptions.h" -#include "MessageUtils.h" -#include "BrokerFixture.h" - -using namespace qpid::broker; -using namespace qpid::framing; - -namespace qpid { -namespace tests { - -QPID_AUTO_TEST_SUITE(QueueFlowLimitTestSuite) - -namespace { - -class TestFlow : public QueueFlowLimit -{ -public: - TestFlow(uint32_t flowStopCount, uint32_t flowResumeCount, - uint64_t flowStopSize, uint64_t flowResumeSize) : - QueueFlowLimit(0, flowStopCount, flowResumeCount, flowStopSize, flowResumeSize) - {} - virtual ~TestFlow() {} - - static TestFlow *createTestFlow(const qpid::framing::FieldTable& settings) - { - FieldTable::ValuePtr v; - - v = settings.get(flowStopCountKey); - uint32_t flowStopCount = (v) ? (uint32_t)v->get<int64_t>() : 0; - v = settings.get(flowResumeCountKey); - uint32_t flowResumeCount = (v) ? (uint32_t)v->get<int64_t>() : 0; - v = settings.get(flowStopSizeKey); - uint64_t flowStopSize = (v) ? (uint64_t)v->get<int64_t>() : 0; - v = settings.get(flowResumeSizeKey); - uint64_t flowResumeSize = (v) ? (uint64_t)v->get<int64_t>() : 0; - - return new TestFlow(flowStopCount, flowResumeCount, flowStopSize, flowResumeSize); - } - - static QueueFlowLimit *getQueueFlowLimit(const qpid::framing::FieldTable& settings) - { - return QueueFlowLimit::createLimit(0, settings); - } -}; - - - -QueuedMessage createMessage(uint32_t size) -{ - static uint32_t seqNum; - QueuedMessage msg; - msg.payload = MessageUtils::createMessage(); - msg.position = ++seqNum; - MessageUtils::addContent(msg.payload, std::string (size, 'x')); - return msg; -} -} - -QPID_AUTO_TEST_CASE(testFlowCount) -{ - FieldTable args; - args.setInt(QueueFlowLimit::flowStopCountKey, 7); - args.setInt(QueueFlowLimit::flowResumeCountKey, 5); - - std::auto_ptr<TestFlow> flow(TestFlow::createTestFlow(args)); - - BOOST_CHECK_EQUAL((uint32_t) 7, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 5, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); - - std::deque<QueuedMessage> msgs; - for (size_t i = 0; i < 6; i++) { - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(!flow->isFlowControlActive()); - } - BOOST_CHECK(!flow->isFlowControlActive()); // 6 on queue - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(!flow->isFlowControlActive()); // 7 on queue - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(flow->isFlowControlActive()); // 8 on queue, ON - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(flow->isFlowControlActive()); // 9 on queue, no change to flow control - - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 8 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 7 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 6 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 5 on queue, no change - - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); // 4 on queue, OFF -} - - -QPID_AUTO_TEST_CASE(testFlowSize) -{ - FieldTable args; - args.setUInt64(QueueFlowLimit::flowStopSizeKey, 70); - args.setUInt64(QueueFlowLimit::flowResumeSizeKey, 50); - - std::auto_ptr<TestFlow> flow(TestFlow::createTestFlow(args)); - - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL((uint32_t) 70, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint32_t) 50, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); - - std::deque<QueuedMessage> msgs; - for (size_t i = 0; i < 6; i++) { - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(!flow->isFlowControlActive()); - } - BOOST_CHECK(!flow->isFlowControlActive()); // 60 on queue - BOOST_CHECK_EQUAL(6u, flow->getFlowCount()); - BOOST_CHECK_EQUAL(60u, flow->getFlowSize()); - - QueuedMessage msg_9 = createMessage(9); - flow->enqueued(msg_9); - BOOST_CHECK(!flow->isFlowControlActive()); // 69 on queue - QueuedMessage tinyMsg_1 = createMessage(1); - flow->enqueued(tinyMsg_1); - BOOST_CHECK(!flow->isFlowControlActive()); // 70 on queue - - QueuedMessage tinyMsg_2 = createMessage(1); - flow->enqueued(tinyMsg_2); - BOOST_CHECK(flow->isFlowControlActive()); // 71 on queue, ON - msgs.push_back(createMessage(10)); - flow->enqueued(msgs.back()); - BOOST_CHECK(flow->isFlowControlActive()); // 81 on queue - BOOST_CHECK_EQUAL(10u, flow->getFlowCount()); - BOOST_CHECK_EQUAL(81u, flow->getFlowSize()); - - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 71 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 61 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // 51 on queue - - flow->dequeued(tinyMsg_1); - BOOST_CHECK(flow->isFlowControlActive()); // 50 on queue - flow->dequeued(tinyMsg_2); - BOOST_CHECK(!flow->isFlowControlActive()); // 49 on queue, OFF - - flow->dequeued(msg_9); - BOOST_CHECK(!flow->isFlowControlActive()); // 40 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); // 30 on queue - flow->dequeued(msgs.front()); - msgs.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); // 20 on queue - BOOST_CHECK_EQUAL(2u, flow->getFlowCount()); - BOOST_CHECK_EQUAL(20u, flow->getFlowSize()); -} - -QPID_AUTO_TEST_CASE(testFlowArgs) -{ - FieldTable args; - const uint64_t stop(0x2FFFFFFFFull); - const uint64_t resume(0x1FFFFFFFFull); - args.setInt(QueueFlowLimit::flowStopCountKey, 30); - args.setInt(QueueFlowLimit::flowResumeCountKey, 21); - args.setUInt64(QueueFlowLimit::flowStopSizeKey, stop); - args.setUInt64(QueueFlowLimit::flowResumeSizeKey, resume); - - std::auto_ptr<TestFlow> flow(TestFlow::createTestFlow(args)); - - BOOST_CHECK_EQUAL((uint32_t) 30, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 21, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL(stop, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL(resume, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); -} - - -QPID_AUTO_TEST_CASE(testFlowCombo) -{ - FieldTable args; - args.setInt(QueueFlowLimit::flowStopCountKey, 10); - args.setInt(QueueFlowLimit::flowResumeCountKey, 5); - args.setUInt64(QueueFlowLimit::flowStopSizeKey, 200); - args.setUInt64(QueueFlowLimit::flowResumeSizeKey, 100); - - std::deque<QueuedMessage> msgs_1; - std::deque<QueuedMessage> msgs_10; - std::deque<QueuedMessage> msgs_50; - std::deque<QueuedMessage> msgs_100; - - QueuedMessage msg; - - std::auto_ptr<TestFlow> flow(TestFlow::createTestFlow(args)); - BOOST_CHECK(!flow->isFlowControlActive()); // count:0 size:0 - - // verify flow control comes ON when only count passes its stop point. - - for (size_t i = 0; i < 10; i++) { - msgs_10.push_back(createMessage(10)); - flow->enqueued(msgs_10.back()); - BOOST_CHECK(!flow->isFlowControlActive()); - } - // count:10 size:100 - - msgs_1.push_back(createMessage(1)); - flow->enqueued(msgs_1.back()); // count:11 size: 101 ->ON - BOOST_CHECK(flow->isFlowControlActive()); - - for (size_t i = 0; i < 6; i++) { - flow->dequeued(msgs_10.front()); - msgs_10.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); - } - // count:5 size: 41 - - flow->dequeued(msgs_1.front()); // count: 4 size: 40 ->OFF - msgs_1.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); - - for (size_t i = 0; i < 4; i++) { - flow->dequeued(msgs_10.front()); - msgs_10.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); - } - // count:0 size:0 - - // verify flow control comes ON when only size passes its stop point. - - msgs_100.push_back(createMessage(100)); - flow->enqueued(msgs_100.back()); // count:1 size: 100 - BOOST_CHECK(!flow->isFlowControlActive()); - - msgs_50.push_back(createMessage(50)); - flow->enqueued(msgs_50.back()); // count:2 size: 150 - BOOST_CHECK(!flow->isFlowControlActive()); - - msgs_50.push_back(createMessage(50)); - flow->enqueued(msgs_50.back()); // count:3 size: 200 - BOOST_CHECK(!flow->isFlowControlActive()); - - msgs_1.push_back(createMessage(1)); - flow->enqueued(msgs_1.back()); // count:4 size: 201 ->ON - BOOST_CHECK(flow->isFlowControlActive()); - - flow->dequeued(msgs_100.front()); // count:3 size:101 - msgs_100.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); - - flow->dequeued(msgs_1.front()); // count:2 size:100 - msgs_1.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); - - flow->dequeued(msgs_50.front()); // count:1 size:50 ->OFF - msgs_50.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); - - // verify flow control remains ON until both thresholds drop below their - // resume point. - - for (size_t i = 0; i < 8; i++) { - msgs_10.push_back(createMessage(10)); - flow->enqueued(msgs_10.back()); - BOOST_CHECK(!flow->isFlowControlActive()); - } - // count:9 size:130 - - msgs_10.push_back(createMessage(10)); - flow->enqueued(msgs_10.back()); // count:10 size: 140 - BOOST_CHECK(!flow->isFlowControlActive()); - - msgs_1.push_back(createMessage(1)); - flow->enqueued(msgs_1.back()); // count:11 size: 141 ->ON - BOOST_CHECK(flow->isFlowControlActive()); - - msgs_100.push_back(createMessage(100)); - flow->enqueued(msgs_100.back()); // count:12 size: 241 (both thresholds crossed) - BOOST_CHECK(flow->isFlowControlActive()); - - // at this point: 9@10 + 1@50 + 1@100 + 1@1 == 12@241 - - flow->dequeued(msgs_50.front()); // count:11 size:191 - msgs_50.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); - - for (size_t i = 0; i < 9; i++) { - flow->dequeued(msgs_10.front()); - msgs_10.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); - } - // count:2 size:101 - flow->dequeued(msgs_1.front()); // count:1 size:100 - msgs_1.pop_front(); - BOOST_CHECK(flow->isFlowControlActive()); // still active due to size - - flow->dequeued(msgs_100.front()); // count:0 size:0 ->OFF - msgs_100.pop_front(); - BOOST_CHECK(!flow->isFlowControlActive()); -} - - -QPID_AUTO_TEST_CASE(testFlowDefaultArgs) -{ - QueueFlowLimit::setDefaults(2950001, // max queue byte count - 80, // 80% stop threshold - 70); // 70% resume threshold - FieldTable args; - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - - BOOST_CHECK(ptr); - std::auto_ptr<QueueFlowLimit> flow(ptr); - BOOST_CHECK_EQUAL((uint64_t) 2360001, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint64_t) 2065000, flow->getFlowResumeSize()); - BOOST_CHECK_EQUAL( 0u, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL( 0u, flow->getFlowResumeCount()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); -} - - -QPID_AUTO_TEST_CASE(testFlowOverrideArgs) -{ - QueueFlowLimit::setDefaults(2950001, // max queue byte count - 80, // 80% stop threshold - 70); // 70% resume threshold - { - FieldTable args; - args.setInt(QueueFlowLimit::flowStopCountKey, 35000); - args.setInt(QueueFlowLimit::flowResumeCountKey, 30000); - - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(ptr); - std::auto_ptr<QueueFlowLimit> flow(ptr); - - BOOST_CHECK_EQUAL((uint32_t) 35000, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 30000, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL((uint64_t) 0, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint64_t) 0, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); - } - { - FieldTable args; - args.setInt(QueueFlowLimit::flowStopSizeKey, 350000); - args.setInt(QueueFlowLimit::flowResumeSizeKey, 300000); - - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(ptr); - std::auto_ptr<QueueFlowLimit> flow(ptr); - - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 0, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL((uint64_t) 350000, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint64_t) 300000, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); - } - { - FieldTable args; - args.setInt(QueueFlowLimit::flowStopCountKey, 35000); - args.setInt(QueueFlowLimit::flowResumeCountKey, 30000); - args.setInt(QueueFlowLimit::flowStopSizeKey, 350000); - args.setInt(QueueFlowLimit::flowResumeSizeKey, 300000); - - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(ptr); - std::auto_ptr<QueueFlowLimit> flow(ptr); - - BOOST_CHECK_EQUAL((uint32_t) 35000, flow->getFlowStopCount()); - BOOST_CHECK_EQUAL((uint32_t) 30000, flow->getFlowResumeCount()); - BOOST_CHECK_EQUAL((uint64_t) 350000, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint64_t) 300000, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); - } -} - - -QPID_AUTO_TEST_CASE(testFlowOverrideDefaults) -{ - QueueFlowLimit::setDefaults(2950001, // max queue byte count - 97, // stop threshold - 73); // resume threshold - FieldTable args; - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(ptr); - std::auto_ptr<QueueFlowLimit> flow(ptr); - - BOOST_CHECK_EQUAL((uint32_t) 2861501, flow->getFlowStopSize()); - BOOST_CHECK_EQUAL((uint32_t) 2153500, flow->getFlowResumeSize()); - BOOST_CHECK(!flow->isFlowControlActive()); - BOOST_CHECK(flow->monitorFlowControl()); -} - - -QPID_AUTO_TEST_CASE(testFlowDisable) -{ - { - FieldTable args; - args.setInt(QueueFlowLimit::flowStopCountKey, 0); - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(!ptr); - } - { - FieldTable args; - args.setInt(QueueFlowLimit::flowStopSizeKey, 0); - QueueFlowLimit *ptr = TestFlow::getQueueFlowLimit(args); - BOOST_CHECK(!ptr); - } -} - - -QPID_AUTO_TEST_SUITE_END() - -}} // namespace qpid::tests diff --git a/cpp/src/tests/QueuePolicyTest.cpp b/cpp/src/tests/QueuePolicyTest.cpp index f735e09449..90af9c7dd9 100644 --- a/cpp/src/tests/QueuePolicyTest.cpp +++ b/cpp/src/tests/QueuePolicyTest.cpp @@ -23,7 +23,6 @@ #include "test_tools.h" #include "qpid/broker/QueuePolicy.h" -#include "qpid/broker/QueueFlowLimit.h" #include "qpid/client/QueueOptions.h" #include "qpid/sys/Time.h" #include "qpid/framing/reply_exceptions.h" @@ -39,7 +38,6 @@ namespace tests { QPID_AUTO_TEST_SUITE(QueuePolicyTestSuite) -namespace { QueuedMessage createMessage(uint32_t size) { QueuedMessage msg; @@ -47,7 +45,7 @@ QueuedMessage createMessage(uint32_t size) MessageUtils::addContent(msg.payload, std::string (size, 'x')); return msg; } -} + QPID_AUTO_TEST_CASE(testCount) { @@ -152,7 +150,7 @@ QPID_AUTO_TEST_CASE(testRingPolicyCount) std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING); policy->update(args); - SessionFixture f; + ProxySessionFixture f; std::string q("my-ring-queue"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); for (int i = 0; i < 10; i++) { @@ -187,7 +185,7 @@ QPID_AUTO_TEST_CASE(testRingPolicySize) std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 0, 500, QueuePolicy::RING); policy->update(args); - SessionFixture f; + ProxySessionFixture f; std::string q("my-ring-queue"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); @@ -259,7 +257,7 @@ QPID_AUTO_TEST_CASE(testStrictRingPolicy) std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::RING_STRICT); policy->update(args); - SessionFixture f; + ProxySessionFixture f; std::string q("my-ring-queue"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); LocalQueue incoming; @@ -285,7 +283,7 @@ QPID_AUTO_TEST_CASE(testPolicyWithDtx) std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT); policy->update(args); - SessionFixture f; + ProxySessionFixture f; std::string q("my-policy-queue"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); LocalQueue incoming; @@ -342,10 +340,8 @@ QPID_AUTO_TEST_CASE(testFlowToDiskWithNoStore) //fallback to rejecting messages QueueOptions args; args.setSizePolicy(FLOW_TO_DISK, 0, 5); - // Disable flow control, or else we'll never hit the max limit - args.setInt(QueueFlowLimit::flowStopCountKey, 0); - SessionFixture f; + ProxySessionFixture f; std::string q("my-queue"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); LocalQueue incoming; @@ -371,7 +367,7 @@ QPID_AUTO_TEST_CASE(testPolicyFailureOnCommit) std::auto_ptr<QueuePolicy> policy = QueuePolicy::createQueuePolicy("test", 5, 0, QueuePolicy::REJECT); policy->update(args); - SessionFixture f; + ProxySessionFixture f; std::string q("q"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); f.session.txSelect(); @@ -386,9 +382,8 @@ QPID_AUTO_TEST_CASE(testCapacityConversion) { FieldTable args; args.setString("qpid.max_count", "5"); - args.setString("qpid.flow_stop_count", "0"); - SessionFixture f; + ProxySessionFixture f; std::string q("q"); f.session.queueDeclare(arg::queue=q, arg::exclusive=true, arg::autoDelete=true, arg::arguments=args); for (int i = 0; i < 5; i++) { diff --git a/cpp/src/tests/QueueTest.cpp b/cpp/src/tests/QueueTest.cpp index aaa2721021..80c69ac386 100644 --- a/cpp/src/tests/QueueTest.cpp +++ b/cpp/src/tests/QueueTest.cpp @@ -36,9 +36,6 @@ #include "qpid/framing/AMQFrame.h" #include "qpid/framing/MessageTransferBody.h" #include "qpid/framing/reply_exceptions.h" -#include "qpid/broker/QueuePolicy.h" -#include "qpid/broker/QueueFlowLimit.h" - #include <iostream> #include "boost/format.hpp" @@ -56,12 +53,12 @@ class TestConsumer : public virtual Consumer{ public: typedef boost::shared_ptr<TestConsumer> shared_ptr; - QueuedMessage last; + intrusive_ptr<Message> last; bool received; - TestConsumer(std::string name="test", bool acquire = true):Consumer(name, acquire), received(false) {}; + TestConsumer(bool acquire = true):Consumer(acquire), received(false) {}; virtual bool deliver(QueuedMessage& msg){ - last = msg; + last = msg.payload; received = true; return true; }; @@ -81,14 +78,13 @@ public: Message& getMessage() { return *(msg.get()); } }; -intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey, uint64_t ttl = 0) { +intrusive_ptr<Message> create_message(std::string exchange, std::string routingKey) { intrusive_ptr<Message> msg(new Message()); AMQFrame method((MessageTransferBody(ProtocolVersion(), exchange, 0, 0))); AMQFrame header((AMQHeaderBody())); msg->getFrames().append(method); msg->getFrames().append(header); msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setRoutingKey(routingKey); - if (ttl) msg->getFrames().getHeaders()->get<DeliveryProperties>(true)->setTtl(ttl); return msg; } @@ -149,16 +145,16 @@ QPID_AUTO_TEST_CASE(testConsumers){ queue->deliver(msg1); BOOST_CHECK(queue->dispatch(c1)); - BOOST_CHECK_EQUAL(msg1.get(), c1->last.payload.get()); + BOOST_CHECK_EQUAL(msg1.get(), c1->last.get()); queue->deliver(msg2); BOOST_CHECK(queue->dispatch(c2)); - BOOST_CHECK_EQUAL(msg2.get(), c2->last.payload.get()); + BOOST_CHECK_EQUAL(msg2.get(), c2->last.get()); c1->received = false; queue->deliver(msg3); BOOST_CHECK(queue->dispatch(c1)); - BOOST_CHECK_EQUAL(msg3.get(), c1->last.payload.get()); + BOOST_CHECK_EQUAL(msg3.get(), c1->last.get()); //Test cancellation: queue->cancel(c1); @@ -214,7 +210,7 @@ QPID_AUTO_TEST_CASE(testDequeue){ if (!consumer->received) sleep(2); - BOOST_CHECK_EQUAL(msg3.get(), consumer->last.payload.get()); + BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get()); BOOST_CHECK_EQUAL(uint32_t(0), queue->getMessageCount()); received = queue->get().payload; @@ -248,7 +244,7 @@ QPID_AUTO_TEST_CASE(testBound){ exchange2.reset(); //unbind the queue from all exchanges it knows it has been bound to: - queue->unbind(exchanges); + queue->unbind(exchanges, queue); //ensure the remaining exchanges don't still have the queue bound to them: FailOnDeliver deliverable; @@ -258,26 +254,26 @@ QPID_AUTO_TEST_CASE(testBound){ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){ client::QueueOptions args; - args.setPersistLastNode(); + args.setPersistLastNode(); - Queue::shared_ptr queue(new Queue("my-queue", true)); + Queue::shared_ptr queue(new Queue("my-queue", true)); queue->configure(args); intrusive_ptr<Message> msg1 = create_message("e", "A"); intrusive_ptr<Message> msg2 = create_message("e", "B"); intrusive_ptr<Message> msg3 = create_message("e", "C"); - //enqueue 2 messages + //enqueue 2 messages queue->deliver(msg1); queue->deliver(msg2); - //change mode - queue->setLastNodeFailure(); + //change mode + queue->setLastNodeFailure(); - //enqueue 1 message + //enqueue 1 message queue->deliver(msg3); - //check all have persistent ids. + //check all have persistent ids. BOOST_CHECK(msg1->isPersistent()); BOOST_CHECK(msg2->isPersistent()); BOOST_CHECK(msg3->isPersistent()); @@ -287,58 +283,54 @@ QPID_AUTO_TEST_CASE(testPersistLastNodeStanding){ QPID_AUTO_TEST_CASE(testSeek){ - Queue::shared_ptr queue(new Queue("my-queue", true)); + Queue::shared_ptr queue(new Queue("my-queue", true)); intrusive_ptr<Message> msg1 = create_message("e", "A"); intrusive_ptr<Message> msg2 = create_message("e", "B"); intrusive_ptr<Message> msg3 = create_message("e", "C"); - //enqueue 2 messages + //enqueue 2 messages queue->deliver(msg1); queue->deliver(msg2); queue->deliver(msg3); - TestConsumer::shared_ptr consumer(new TestConsumer("test", false)); + TestConsumer::shared_ptr consumer(new TestConsumer(false)); SequenceNumber seq(2); consumer->position = seq; QueuedMessage qm; queue->dispatch(consumer); - - BOOST_CHECK_EQUAL(msg3.get(), consumer->last.payload.get()); + + BOOST_CHECK_EQUAL(msg3.get(), consumer->last.get()); queue->dispatch(consumer); queue->dispatch(consumer); // make sure over-run is safe - + } QPID_AUTO_TEST_CASE(testSearch){ - Queue::shared_ptr queue(new Queue("my-queue", true)); + Queue::shared_ptr queue(new Queue("my-queue", true)); intrusive_ptr<Message> msg1 = create_message("e", "A"); intrusive_ptr<Message> msg2 = create_message("e", "B"); intrusive_ptr<Message> msg3 = create_message("e", "C"); - //enqueue 2 messages + //enqueue 2 messages queue->deliver(msg1); queue->deliver(msg2); queue->deliver(msg3); SequenceNumber seq(2); - QueuedMessage qm; - TestConsumer::shared_ptr c1(new TestConsumer()); - - BOOST_CHECK(queue->find(seq, qm)); - + QueuedMessage qm = queue->find(seq); + BOOST_CHECK_EQUAL(seq.getValue(), qm.position.getValue()); - - queue->acquire(qm, c1->getName()); + + queue->acquire(qm); BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u); SequenceNumber seq1(3); - QueuedMessage qm1; - BOOST_CHECK(queue->find(seq1, qm1)); + QueuedMessage qm1 = queue->find(seq1); BOOST_CHECK_EQUAL(seq1.getValue(), qm1.position.getValue()); - + } const std::string nullxid = ""; @@ -424,10 +416,10 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){ client::QueueOptions args; // set queue mode - args.setOrdering(client::LVQ); + args.setOrdering(client::LVQ); - Queue::shared_ptr queue(new Queue("my-queue", true )); - queue->configure(args); + Queue::shared_ptr queue(new Queue("my-queue", true )); + queue->configure(args); intrusive_ptr<Message> msg1 = create_message("e", "A"); intrusive_ptr<Message> msg2 = create_message("e", "B"); @@ -438,16 +430,16 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){ //set deliever match for LVQ a,b,c,a string key; - args.getLVQKey(key); + args.getLVQKey(key); BOOST_CHECK_EQUAL(key, "qpid.LVQ_key"); - msg1->insertCustomProperty(key,"a"); - msg2->insertCustomProperty(key,"b"); - msg3->insertCustomProperty(key,"c"); - msg4->insertCustomProperty(key,"a"); + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b"); + msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c"); + msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); - //enqueue 4 message + //enqueue 4 message queue->deliver(msg1); queue->deliver(msg2); queue->deliver(msg3); @@ -467,9 +459,9 @@ QPID_AUTO_TEST_CASE(testLVQOrdering){ intrusive_ptr<Message> msg5 = create_message("e", "A"); intrusive_ptr<Message> msg6 = create_message("e", "B"); intrusive_ptr<Message> msg7 = create_message("e", "C"); - msg5->insertCustomProperty(key,"a"); - msg6->insertCustomProperty(key,"b"); - msg7->insertCustomProperty(key,"c"); + msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b"); + msg7->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c"); queue->deliver(msg5); queue->deliver(msg6); queue->deliver(msg7); @@ -504,7 +496,7 @@ QPID_AUTO_TEST_CASE(testLVQEmptyKey){ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key"); - msg1->insertCustomProperty(key,"a"); + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); queue->deliver(msg1); queue->deliver(msg2); BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u); @@ -516,8 +508,6 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){ client::QueueOptions args; // set queue mode args.setOrdering(client::LVQ); - // disable flow control, as this test violates the enqueue/dequeue sequence. - args.setInt(QueueFlowLimit::flowStopCountKey, 0); Queue::shared_ptr queue(new Queue("my-queue", true )); queue->configure(args); @@ -536,12 +526,12 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){ BOOST_CHECK_EQUAL(key, "qpid.LVQ_key"); - msg1->insertCustomProperty(key,"a"); - msg2->insertCustomProperty(key,"b"); - msg3->insertCustomProperty(key,"c"); - msg4->insertCustomProperty(key,"a"); - msg5->insertCustomProperty(key,"b"); - msg6->insertCustomProperty(key,"c"); + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b"); + msg3->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c"); + msg4->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg5->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"b"); + msg6->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"c"); //enqueue 4 message queue->deliver(msg1); @@ -556,13 +546,12 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){ QueuedMessage qmsg2(queue.get(), msg2, ++sequence); framing::SequenceNumber sequence1(10); QueuedMessage qmsg3(queue.get(), 0, sequence1); - TestConsumer::shared_ptr dummy(new TestConsumer()); - BOOST_CHECK(!queue->acquire(qmsg, dummy->getName())); - BOOST_CHECK(queue->acquire(qmsg2, dummy->getName())); + BOOST_CHECK(!queue->acquire(qmsg)); + BOOST_CHECK(queue->acquire(qmsg2)); // Acquire the massage again to test failure case. - BOOST_CHECK(!queue->acquire(qmsg2, dummy->getName())); - BOOST_CHECK(!queue->acquire(qmsg3, dummy->getName())); + BOOST_CHECK(!queue->acquire(qmsg2)); + BOOST_CHECK(!queue->acquire(qmsg3)); BOOST_CHECK_EQUAL(queue->getMessageCount(), 2u); @@ -572,7 +561,7 @@ QPID_AUTO_TEST_CASE(testLVQAcquire){ // set mode to no browse and check args.setOrdering(client::LVQ_NO_BROWSE); queue->configure(args); - TestConsumer::shared_ptr c1(new TestConsumer("test", false)); + TestConsumer::shared_ptr c1(new TestConsumer(false)); queue->dispatch(c1); queue->dispatch(c1); @@ -606,8 +595,8 @@ QPID_AUTO_TEST_CASE(testLVQMultiQueue){ args.getLVQKey(key); BOOST_CHECK_EQUAL(key, "qpid.LVQ_key"); - msg1->insertCustomProperty(key,"a"); - msg2->insertCustomProperty(key,"a"); + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); queue1->deliver(msg1); queue2->deliver(msg1); @@ -641,7 +630,7 @@ QPID_AUTO_TEST_CASE(testLVQRecover){ Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore)); intrusive_ptr<Message> received; - queue1->create(args); + queue1->configure(args); intrusive_ptr<Message> msg1 = create_message("e", "A"); intrusive_ptr<Message> msg2 = create_message("e", "A"); @@ -650,9 +639,9 @@ QPID_AUTO_TEST_CASE(testLVQRecover){ args.getLVQKey(key); BOOST_CHECK_EQUAL(key, "qpid.LVQ_key"); - msg1->insertCustomProperty(key,"a"); - msg2->insertCustomProperty(key,"a"); - // 3 + msg1->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + msg2->getProperties<MessageProperties>()->getApplicationHeaders().setString(key,"a"); + // 3 queue1->deliver(msg1); // 4 queue1->setLastNodeFailure(); @@ -671,8 +660,13 @@ QPID_AUTO_TEST_CASE(testLVQRecover){ void addMessagesToQueue(uint count, Queue& queue, uint oddTtl = 200, uint evenTtl = 0) { for (uint i = 0; i < count; i++) { - intrusive_ptr<Message> m = create_message("exchange", "key", i % 2 ? oddTtl : evenTtl); - m->computeExpiration(new broker::ExpiryPolicy); + intrusive_ptr<Message> m = create_message("exchange", "key"); + if (i % 2) { + if (oddTtl) m->getProperties<DeliveryProperties>()->setTtl(oddTtl); + } else { + if (evenTtl) m->getProperties<DeliveryProperties>()->setTtl(evenTtl); + } + m->setTimestamp(new broker::ExpiryPolicy); queue.deliver(m); } } @@ -682,7 +676,7 @@ QPID_AUTO_TEST_CASE(testPurgeExpired) { addMessagesToQueue(10, queue); BOOST_CHECK_EQUAL(queue.getMessageCount(), 10u); ::usleep(300*1000); - queue.purgeExpired(0); + queue.purgeExpired(); BOOST_CHECK_EQUAL(queue.getMessageCount(), 5u); } @@ -693,7 +687,7 @@ QPID_AUTO_TEST_CASE(testQueueCleaner) { addMessagesToQueue(10, *queue, 200, 400); BOOST_CHECK_EQUAL(queue->getMessageCount(), 10u); - QueueCleaner cleaner(queues, &timer); + QueueCleaner cleaner(queues, timer); cleaner.start(100 * qpid::sys::TIME_MSEC); ::usleep(300*1000); BOOST_CHECK_EQUAL(queue->getMessageCount(), 5u); @@ -701,280 +695,6 @@ QPID_AUTO_TEST_CASE(testQueueCleaner) { BOOST_CHECK_EQUAL(queue->getMessageCount(), 0u); } - -namespace { - // helper for group tests - void verifyAcquire( Queue::shared_ptr queue, - TestConsumer::shared_ptr c, - std::deque<QueuedMessage>& results, - const std::string& expectedGroup, - const int expectedId ) - { - queue->dispatch(c); - results.push_back(c->last); - std::string group = c->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsString("GROUP-ID"); - int id = c->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID"); - BOOST_CHECK_EQUAL( group, expectedGroup ); - BOOST_CHECK_EQUAL( id, expectedId ); - } -} - -QPID_AUTO_TEST_CASE(testGroupsMultiConsumer) { - // - // Verify that consumers of grouped messages own the groups once a message is acquired, - // and release the groups once all acquired messages have been dequeued or requeued - // - FieldTable args; - Queue::shared_ptr queue(new Queue("my_queue", true)); - args.setString("qpid.group_header_key", "GROUP-ID"); - args.setInt("qpid.shared_msg_group", 1); - queue->configure(args); - - std::string groups[] = { std::string("a"), std::string("a"), std::string("a"), - std::string("b"), std::string("b"), std::string("b"), - std::string("c"), std::string("c"), std::string("c") }; - for (int i = 0; i < 9; ++i) { - intrusive_ptr<Message> msg = create_message("e", "A"); - msg->insertCustomProperty("GROUP-ID", groups[i]); - msg->insertCustomProperty("MY-ID", i); - queue->deliver(msg); - } - - // Queue = a-0, a-1, a-2, b-3, b-4, b-5, c-6, c-7, c-8... - // Owners= ---, ---, ---, ---, ---, ---, ---, ---, ---, - - BOOST_CHECK_EQUAL(uint32_t(9), queue->getMessageCount()); - - TestConsumer::shared_ptr c1(new TestConsumer("C1")); - TestConsumer::shared_ptr c2(new TestConsumer("C2")); - - queue->consume(c1); - queue->consume(c2); - - std::deque<QueuedMessage> dequeMeC1; - std::deque<QueuedMessage> dequeMeC2; - - - verifyAcquire(queue, c1, dequeMeC1, "a", 0 ); // c1 now owns group "a" (acquire a-0) - verifyAcquire(queue, c2, dequeMeC2, "b", 3 ); // c2 should now own group "b" (acquire b-3) - - // now let c1 complete the 'a-0' message - this should free the 'a' group - queue->dequeue( 0, dequeMeC1.front() ); - dequeMeC1.pop_front(); - - // Queue = a-1, a-2, b-3, b-4, b-5, c-6, c-7, c-8... - // Owners= ---, ---, ^C2, ^C2, ^C2, ---, ---, --- - - // now c2 should pick up the next 'a-1', since it is oldest free - verifyAcquire(queue, c2, dequeMeC2, "a", 1 ); // c2 should now own groups "a" and "b" - - // Queue = a-1, a-2, b-3, b-4, b-5, c-6, c-7, c-8... - // Owners= ^C2, ^C2, ^C2, ^C2, ^C2, ---, ---, --- - - // c1 should only be able to snarf up the first "c" message now... - verifyAcquire(queue, c1, dequeMeC1, "c", 6 ); // should skip to the first "c" - - // Queue = a-1, a-2, b-3, b-4, b-5, c-6, c-7, c-8... - // Owners= ^C2, ^C2, ^C2, ^C2, ^C2, ^C1, ^C1, ^C1 - - // hmmm... what if c2 now dequeues "b-3"? (now only has a-1 acquired) - queue->dequeue( 0, dequeMeC2.front() ); - dequeMeC2.pop_front(); - - // Queue = a-1, a-2, b-4, b-5, c-6, c-7, c-8... - // Owners= ^C2, ^C2, ---, ---, ^C1, ^C1, ^C1 - - // b group is free, c is owned by c1 - c1's next get should grab 'b-4' - verifyAcquire(queue, c1, dequeMeC1, "b", 4 ); - - // Queue = a-1, a-2, b-4, b-5, c-6, c-7, c-8... - // Owners= ^C2, ^C2, ^C1, ^C1, ^C1, ^C1, ^C1 - - // c2 can now only grab a-2, and that's all - verifyAcquire(queue, c2, dequeMeC2, "a", 2 ); - - // now C2 can't get any more, since C1 owns "b" and "c" group... - bool gotOne = queue->dispatch(c2); - BOOST_CHECK( !gotOne ); - - // hmmm... what if c1 now dequeues "c-6"? (now only own's b-4) - queue->dequeue( 0, dequeMeC1.front() ); - dequeMeC1.pop_front(); - - // Queue = a-1, a-2, b-4, b-5, c-7, c-8... - // Owners= ^C2, ^C2, ^C1, ^C1, ---, --- - - // c2 can now grab c-7 - verifyAcquire(queue, c2, dequeMeC2, "c", 7 ); - - // Queue = a-1, a-2, b-4, b-5, c-7, c-8... - // Owners= ^C2, ^C2, ^C1, ^C1, ^C2, ^C2 - - // what happens if C-2 "requeues" a-1 and a-2? - queue->requeue( dequeMeC2.front() ); - dequeMeC2.pop_front(); - queue->requeue( dequeMeC2.front() ); - dequeMeC2.pop_front(); // now just has c-7 acquired - - // Queue = a-1, a-2, b-4, b-5, c-7, c-8... - // Owners= ---, ---, ^C1, ^C1, ^C2, ^C2 - - // now c1 will grab a-1 and a-2... - verifyAcquire(queue, c1, dequeMeC1, "a", 1 ); - verifyAcquire(queue, c1, dequeMeC1, "a", 2 ); - - // Queue = a-1, a-2, b-4, b-5, c-7, c-8... - // Owners= ^C1, ^C1, ^C1, ^C1, ^C2, ^C2 - - // c2 can now acquire c-8 only - verifyAcquire(queue, c2, dequeMeC2, "c", 8 ); - - // and c1 can get b-5 - verifyAcquire(queue, c1, dequeMeC1, "b", 5 ); - - // should be no more acquire-able for anyone now: - gotOne = queue->dispatch(c1); - BOOST_CHECK( !gotOne ); - gotOne = queue->dispatch(c2); - BOOST_CHECK( !gotOne ); - - // requeue all of C1's acquired messages, then cancel C1 - while (!dequeMeC1.empty()) { - queue->requeue(dequeMeC1.front()); - dequeMeC1.pop_front(); - } - queue->cancel(c1); - - // Queue = a-1, a-2, b-4, b-5, c-7, c-8... - // Owners= ---, ---, ---, ---, ^C2, ^C2 - - // b-4, a-1, a-2, b-5 all should be available, right? - verifyAcquire(queue, c2, dequeMeC2, "a", 1 ); - - while (!dequeMeC2.empty()) { - queue->dequeue(0, dequeMeC2.front()); - dequeMeC2.pop_front(); - } - - // Queue = a-2, b-4, b-5 - // Owners= ---, ---, --- - - TestConsumer::shared_ptr c3(new TestConsumer("C3")); - std::deque<QueuedMessage> dequeMeC3; - - verifyAcquire(queue, c3, dequeMeC3, "a", 2 ); - verifyAcquire(queue, c2, dequeMeC2, "b", 4 ); - - // Queue = a-2, b-4, b-5 - // Owners= ^C3, ^C2, ^C2 - - gotOne = queue->dispatch(c3); - BOOST_CHECK( !gotOne ); - - verifyAcquire(queue, c2, dequeMeC2, "b", 5 ); - - while (!dequeMeC2.empty()) { - queue->dequeue(0, dequeMeC2.front()); - dequeMeC2.pop_front(); - } - - // Queue = a-2, - // Owners= ^C3, - - intrusive_ptr<Message> msg = create_message("e", "A"); - msg->insertCustomProperty("GROUP-ID", "a"); - msg->insertCustomProperty("MY-ID", 9); - queue->deliver(msg); - - // Queue = a-2, a-9 - // Owners= ^C3, ^C3 - - gotOne = queue->dispatch(c2); - BOOST_CHECK( !gotOne ); - - msg = create_message("e", "A"); - msg->insertCustomProperty("GROUP-ID", "b"); - msg->insertCustomProperty("MY-ID", 10); - queue->deliver(msg); - - // Queue = a-2, a-9, b-10 - // Owners= ^C3, ^C3, ---- - - verifyAcquire(queue, c2, dequeMeC2, "b", 10 ); - verifyAcquire(queue, c3, dequeMeC3, "a", 9 ); - - gotOne = queue->dispatch(c3); - BOOST_CHECK( !gotOne ); - - queue->cancel(c2); - queue->cancel(c3); -} - - -QPID_AUTO_TEST_CASE(testGroupsMultiConsumerDefaults) { - // - // Verify that the same default group name is automatically applied to messages that - // do not specify a group name. - // - FieldTable args; - Queue::shared_ptr queue(new Queue("my_queue", true)); - args.setString("qpid.group_header_key", "GROUP-ID"); - args.setInt("qpid.shared_msg_group", 1); - queue->configure(args); - - for (int i = 0; i < 3; ++i) { - intrusive_ptr<Message> msg = create_message("e", "A"); - // no "GROUP-ID" header - msg->insertCustomProperty("MY-ID", i); - queue->deliver(msg); - } - - // Queue = 0, 1, 2 - - BOOST_CHECK_EQUAL(uint32_t(3), queue->getMessageCount()); - - TestConsumer::shared_ptr c1(new TestConsumer("C1")); - TestConsumer::shared_ptr c2(new TestConsumer("C2")); - - queue->consume(c1); - queue->consume(c2); - - std::deque<QueuedMessage> dequeMeC1; - std::deque<QueuedMessage> dequeMeC2; - - queue->dispatch(c1); // c1 now owns default group (acquired 0) - dequeMeC1.push_back(c1->last); - int id = c1->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID"); - BOOST_CHECK_EQUAL( id, 0 ); - - bool gotOne = queue->dispatch(c2); // c2 should get nothing - BOOST_CHECK( !gotOne ); - - queue->dispatch(c1); // c1 now acquires 1 - dequeMeC1.push_back(c1->last); - id = c1->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID"); - BOOST_CHECK_EQUAL( id, 1 ); - - gotOne = queue->dispatch(c2); // c2 should still get nothing - BOOST_CHECK( !gotOne ); - - while (!dequeMeC1.empty()) { - queue->dequeue(0, dequeMeC1.front()); - dequeMeC1.pop_front(); - } - - // now default group should be available... - queue->dispatch(c2); // c2 now owns default group (acquired 2) - id = c2->last.payload->getProperties<MessageProperties>()->getApplicationHeaders().getAsInt("MY-ID"); - BOOST_CHECK_EQUAL( id, 2 ); - - gotOne = queue->dispatch(c1); // c1 should get nothing - BOOST_CHECK( !gotOne ); - - queue->cancel(c1); - queue->cancel(c2); -} - QPID_AUTO_TEST_CASE(testMultiQueueLastNode){ TestMessageStoreOC testStore; @@ -982,9 +702,9 @@ QPID_AUTO_TEST_CASE(testMultiQueueLastNode){ args.setPersistLastNode(); Queue::shared_ptr queue1(new Queue("queue1", true, &testStore )); - queue1->create(args); + queue1->configure(args); Queue::shared_ptr queue2(new Queue("queue2", true, &testStore )); - queue2->create(args); + queue2->configure(args); intrusive_ptr<Message> msg1 = create_message("e", "A"); @@ -1070,7 +790,7 @@ not requeued to the store. Queue::shared_ptr queue1(new Queue("my-queue", true, &testStore)); intrusive_ptr<Message> received; - queue1->create(args); + queue1->configure(args); // check requeue 1 intrusive_ptr<Message> msg1 = create_message("e", "C"); @@ -1150,40 +870,28 @@ QPID_AUTO_TEST_CASE(testFlowToDiskBlocking){ intrusive_ptr<Message> msg02 = mkMsg(testStore, std::string(5, 'X')); // transient w/ content DeliverableMessage dmsg02(msg02); - { - ScopedSuppressLogging sl; // suppress expected error messages. - BOOST_CHECK_THROW(sbtFanout1.route(dmsg02, "", 0), ResourceLimitExceededException); - } + BOOST_CHECK_THROW(sbtFanout1.route(dmsg02, "", 0), ResourceLimitExceededException); msg02->tryReleaseContent(); BOOST_CHECK_EQUAL(msg02->isContentReleased(), false); BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); intrusive_ptr<Message> msg03 = mkMsg(testStore, std::string(5, 'X'), true); // durable w/ content DeliverableMessage dmsg03(msg03); - { - ScopedSuppressLogging sl; // suppress expected error messages. - BOOST_CHECK_THROW(sbtFanout1.route(dmsg03, "", 0), ResourceLimitExceededException); - } + BOOST_CHECK_THROW(sbtFanout1.route(dmsg03, "", 0), ResourceLimitExceededException); msg03->tryReleaseContent(); BOOST_CHECK_EQUAL(msg03->isContentReleased(), false); BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); intrusive_ptr<Message> msg04 = mkMsg(testStore); // transient no content DeliverableMessage dmsg04(msg04); - { - ScopedSuppressLogging sl; // suppress expected error messages. - BOOST_CHECK_THROW(sbtFanout1.route(dmsg04, "", 0), ResourceLimitExceededException); - } + BOOST_CHECK_THROW(sbtFanout1.route(dmsg04, "", 0), ResourceLimitExceededException); msg04->tryReleaseContent(); BOOST_CHECK_EQUAL(msg04->isContentReleased(), false); BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); intrusive_ptr<Message> msg05 = mkMsg(testStore, "", true); // durable no content DeliverableMessage dmsg05(msg05); - { - ScopedSuppressLogging sl; // suppress expected error messages. - BOOST_CHECK_THROW(sbtFanout1.route(dmsg05, "", 0), ResourceLimitExceededException); - } + BOOST_CHECK_THROW(sbtFanout1.route(dmsg05, "", 0), ResourceLimitExceededException); msg05->tryReleaseContent(); BOOST_CHECK_EQUAL(msg05->isContentReleased(), false); BOOST_CHECK_EQUAL(1u, tq1->getMessageCount()); diff --git a/cpp/src/tests/ReplicationTest.cpp b/cpp/src/tests/ReplicationTest.cpp index 1219a6b59e..7310a3fe20 100644 --- a/cpp/src/tests/ReplicationTest.cpp +++ b/cpp/src/tests/ReplicationTest.cpp @@ -74,7 +74,7 @@ QPID_AUTO_TEST_CASE(testReplicationExchange) { qpid::broker::Broker::Options brokerOpts(getBrokerOpts(list_of<string>("qpidd") ("--replication-exchange-name=qpid.replication"))); - SessionFixture f(brokerOpts); + ProxySessionFixture f(brokerOpts); std::string dataQ("queue-1"); diff --git a/cpp/src/tests/SessionState.cpp b/cpp/src/tests/SessionState.cpp index 3be9bb0cbc..157cabfb63 100644 --- a/cpp/src/tests/SessionState.cpp +++ b/cpp/src/tests/SessionState.cpp @@ -43,7 +43,7 @@ using namespace qpid::framing; // Apply f to [begin, end) and accumulate the result template <class Iter, class T, class F> T applyAccumulate(Iter begin, Iter end, T seed, const F& f) { - return std::accumulate(begin, end, seed, boost::bind(std::plus<T>(), _1, boost::bind(f, _2))); + return std::accumulate(begin, end, seed, bind(std::plus<T>(), _1, bind(f, _2))); } // Create a frame with a one-char string. @@ -105,8 +105,8 @@ size_t transferN(qpid::SessionState& s, string content) { char last = content[content.size()-1]; content.resize(content.size()-1); size += applyAccumulate(content.begin(), content.end(), 0, - boost::bind(&send, boost::ref(s), - boost::bind(contentFrameChar, _1, false))); + bind(&send, ref(s), + bind(contentFrameChar, _1, false))); size += send(s, contentFrameChar(last, true)); } return size; @@ -115,7 +115,7 @@ size_t transferN(qpid::SessionState& s, string content) { // Send multiple transfers with single-byte content. size_t transfers(qpid::SessionState& s, string content) { return applyAccumulate(content.begin(), content.end(), 0, - boost::bind(transfer1Char, boost::ref(s), _1)); + bind(transfer1Char, ref(s), _1)); } size_t contentFrameSize(size_t n=1) { return AMQFrame(( AMQContentBody())).encodedSize() + n; } diff --git a/cpp/src/tests/SocketProxy.h b/cpp/src/tests/SocketProxy.h new file mode 100644 index 0000000000..0c6f39d62e --- /dev/null +++ b/cpp/src/tests/SocketProxy.h @@ -0,0 +1,181 @@ +#ifndef SOCKETPROXY_H +#define SOCKETPROXY_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/IOHandle.h" +#ifdef _WIN32 +# include "qpid/sys/windows/IoHandlePrivate.h" + typedef SOCKET FdType; +#else +# include "qpid/sys/posix/PrivatePosix.h" + typedef int FdType; +#endif +#include "qpid/sys/Socket.h" +#include "qpid/sys/Runnable.h" +#include "qpid/sys/Thread.h" +#include "qpid/sys/Mutex.h" +#include "qpid/log/Statement.h" + +namespace qpid { +namespace tests { + +/** + * A simple socket proxy that forwards to another socket. + * Used between client & local broker to simulate network failures. + */ +class SocketProxy : private qpid::sys::Runnable +{ + // Need a Socket we can get the fd from + class LowSocket : public qpid::sys::Socket { + public: +#ifdef _WIN32 + FdType getFd() { return toSocketHandle(*this); } +#else + FdType getFd() { return toFd(impl); } +#endif + }; + + public: + /** Connect to connectPort on host, start a forwarding thread. + * Listen for connection on getPort(). + */ + SocketProxy(int connectPort, const std::string host="localhost") + : closed(false), joined(true), + port(listener.listen()), dropClient(), dropServer() + { + client.connect(host, connectPort); + joined = false; + thread = qpid::sys::Thread(static_cast<qpid::sys::Runnable*>(this)); + } + + ~SocketProxy() { close(); if (!joined) thread.join(); } + + /** Simulate a network disconnect. */ + void close() { + { + qpid::sys::Mutex::ScopedLock l(lock); + if (closed) { return; } + closed=true; + } + if (thread && thread != qpid::sys::Thread::current()) { + thread.join(); + joined = true; + } + client.close(); + } + + /** Simulate lost packets, drop data from client */ + void dropClientData(bool drop=true) { dropClient=drop; } + + /** Simulate lost packets, drop data from server */ + void dropServerData(bool drop=true) { dropServer=drop; } + + bool isClosed() const { + qpid::sys::Mutex::ScopedLock l(lock); + return closed; + } + + uint16_t getPort() const { return port; } + + private: + static void throwErrno(const std::string& msg) { + throw qpid::Exception(msg+":"+qpid::sys::strError(errno)); + } + static void throwIf(bool condition, const std::string& msg) { + if (condition) throw qpid::Exception(msg); + } + + void run() { + std::auto_ptr<LowSocket> server; + try { + fd_set socks; + FdType maxFd = listener.getFd(); + struct timeval tmo; + for (;;) { + FD_ZERO(&socks); + FD_SET(maxFd, &socks); + tmo.tv_sec = 0; + tmo.tv_usec = 500 * 1000; + if (select(maxFd+1, &socks, 0, 0, &tmo) == 0) { + qpid::sys::Mutex::ScopedLock l(lock); + throwIf(closed, "SocketProxy: Closed by close()"); + continue; + } + throwIf(!FD_ISSET(maxFd, &socks), "SocketProxy: Accept failed"); + break; // Accept ready... go to next step + } + server.reset(reinterpret_cast<LowSocket *>(listener.accept())); + maxFd = server->getFd(); + if (client.getFd() > maxFd) + maxFd = client.getFd(); + char buffer[1024]; + for (;;) { + FD_ZERO(&socks); + tmo.tv_sec = 0; + tmo.tv_usec = 500 * 1000; + FD_SET(client.getFd(), &socks); + FD_SET(server->getFd(), &socks); + if (select(maxFd+1, &socks, 0, 0, &tmo) == 0) { + qpid::sys::Mutex::ScopedLock l(lock); + throwIf(closed, "SocketProxy: Closed by close()"); + continue; + } + // Something is set; relay data as needed until something closes + if (FD_ISSET(server->getFd(), &socks)) { + int n = server->read(buffer, sizeof(buffer)); + throwIf(n <= 0, "SocketProxy: server disconnected"); + if (!dropServer) client.write(buffer, n); + } + if (FD_ISSET(client.getFd(), &socks)) { + int n = client.read(buffer, sizeof(buffer)); + throwIf(n <= 0, "SocketProxy: client disconnected"); + if (!dropServer) server->write(buffer, n); + } + if (!FD_ISSET(client.getFd(), &socks) && + !FD_ISSET(server->getFd(), &socks)) + throwIf(true, "SocketProxy: No handle ready"); + } + } + catch (const std::exception& e) { + QPID_LOG(debug, "SocketProxy::run exception: " << e.what()); + } + try { + if (server.get()) server->close(); + close(); + } + catch (const std::exception& e) { + QPID_LOG(debug, "SocketProxy::run exception in client/server close()" << e.what()); + } + } + + mutable qpid::sys::Mutex lock; + mutable bool closed; + bool joined; + LowSocket client, listener; + uint16_t port; + qpid::sys::Thread thread; + bool dropClient, dropServer; +}; + +}} // namespace qpid::tests + +#endif diff --git a/cpp/src/tests/TimerTest.cpp b/cpp/src/tests/TimerTest.cpp index 6a0a196f4e..7df94164e0 100644 --- a/cpp/src/tests/TimerTest.cpp +++ b/cpp/src/tests/TimerTest.cpp @@ -77,10 +77,8 @@ class TestTask : public TimerTask BOOST_CHECK(fired); BOOST_CHECK_EQUAL(expected_position, position); Duration actual(start, end); -#ifdef _MSC_VER +#ifdef _WIN32 uint64_t difference = _abs64(expected - actual); -#elif defined(_WIN32) - uint64_t difference = labs(expected - actual); #else uint64_t difference = abs(expected - actual); #endif diff --git a/cpp/src/tests/TxPublishTest.cpp b/cpp/src/tests/TxPublishTest.cpp index 152581e4ba..6b44d95baa 100644 --- a/cpp/src/tests/TxPublishTest.cpp +++ b/cpp/src/tests/TxPublishTest.cpp @@ -50,9 +50,10 @@ struct TxPublishTest TxPublishTest() : queue1(new Queue("queue1", false, &store, 0)), queue2(new Queue("queue2", false, &store, 0)), - msg(MessageUtils::createMessage("exchange", "routing_key", true)), + msg(MessageUtils::createMessage("exchange", "routing_key", false, "id")), op(msg) { + msg->getProperties<DeliveryProperties>()->setDeliveryMode(PERSISTENT); op.deliverTo(queue1); op.deliverTo(queue2); } @@ -73,7 +74,7 @@ QPID_AUTO_TEST_CASE(testPrepare) BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[0].second); BOOST_CHECK_EQUAL(string("queue2"), t.store.enqueued[1].first); BOOST_CHECK_EQUAL(pmsg, t.store.enqueued[1].second); - BOOST_CHECK_EQUAL( true, ( boost::static_pointer_cast<PersistableMessage>(t.msg))->isIngressComplete()); + BOOST_CHECK_EQUAL( true, ( boost::static_pointer_cast<PersistableMessage>(t.msg))->isEnqueueComplete()); } QPID_AUTO_TEST_CASE(testCommit) @@ -86,7 +87,7 @@ QPID_AUTO_TEST_CASE(testCommit) BOOST_CHECK_EQUAL((uint32_t) 1, t.queue1->getMessageCount()); intrusive_ptr<Message> msg_dequeue = t.queue1->get().payload; - BOOST_CHECK_EQUAL( true, (boost::static_pointer_cast<PersistableMessage>(msg_dequeue))->isIngressComplete()); + BOOST_CHECK_EQUAL( true, (boost::static_pointer_cast<PersistableMessage>(msg_dequeue))->isEnqueueComplete()); BOOST_CHECK_EQUAL(t.msg, msg_dequeue); BOOST_CHECK_EQUAL((uint32_t) 1, t.queue2->getMessageCount()); diff --git a/cpp/src/tests/Url.cpp b/cpp/src/tests/Url.cpp index b30de682bc..234a62ee91 100644 --- a/cpp/src/tests/Url.cpp +++ b/cpp/src/tests/Url.cpp @@ -60,32 +60,6 @@ QPID_AUTO_TEST_CASE(TestParseXyz) { BOOST_CHECK_EQUAL(Url("xyz:host").str(), "amqp:xyz:host:5672"); } -QPID_AUTO_TEST_CASE(TestParseTricky) { - BOOST_CHECK_EQUAL(Url("amqp").str(), "amqp:tcp:amqp:5672"); - BOOST_CHECK_EQUAL(Url("amqp:tcp").str(), "amqp:tcp:tcp:5672"); - // These are ambiguous parses and arguably not the best result - BOOST_CHECK_EQUAL(Url("amqp:876").str(), "amqp:tcp:876:5672"); - BOOST_CHECK_EQUAL(Url("tcp:567").str(), "amqp:tcp:567:5672"); -} - -QPID_AUTO_TEST_CASE(TestParseIPv6) { - Url u1("[::]"); - BOOST_CHECK_EQUAL(u1[0].host, "::"); - BOOST_CHECK_EQUAL(u1[0].port, 5672); - Url u2("[::1]"); - BOOST_CHECK_EQUAL(u2[0].host, "::1"); - BOOST_CHECK_EQUAL(u2[0].port, 5672); - Url u3("[::127.0.0.1]"); - BOOST_CHECK_EQUAL(u3[0].host, "::127.0.0.1"); - BOOST_CHECK_EQUAL(u3[0].port, 5672); - Url u4("[2002::222:68ff:fe0b:e61a]"); - BOOST_CHECK_EQUAL(u4[0].host, "2002::222:68ff:fe0b:e61a"); - BOOST_CHECK_EQUAL(u4[0].port, 5672); - Url u5("[2002::222:68ff:fe0b:e61a]:123"); - BOOST_CHECK_EQUAL(u5[0].host, "2002::222:68ff:fe0b:e61a"); - BOOST_CHECK_EQUAL(u5[0].port, 123); -} - QPID_AUTO_TEST_CASE(TestParseMultiAddress) { Url::addProtocol("xyz"); URL_CHECK_STR("amqp:tcp:host:0,xyz:foo:123,tcp:foo:0,xyz:bar:1"); diff --git a/cpp/src/tests/Variant.cpp b/cpp/src/tests/Variant.cpp index 40f1c0cf75..b4188f524b 100644 --- a/cpp/src/tests/Variant.cpp +++ b/cpp/src/tests/Variant.cpp @@ -86,64 +86,6 @@ QPID_AUTO_TEST_CASE(testConversions) BOOST_CHECK_THROW(value.asBool(), InvalidConversion); } -QPID_AUTO_TEST_CASE(testConversionsFromString) -{ - Variant value; - value = "5"; - BOOST_CHECK_EQUAL(5, value.asInt16()); - BOOST_CHECK_EQUAL(5u, value.asUint16()); - - value = "-5"; - BOOST_CHECK_EQUAL(-5, value.asInt16()); - BOOST_CHECK_THROW(value.asUint16(), InvalidConversion); - - value = "18446744073709551615"; - BOOST_CHECK_EQUAL(18446744073709551615ull, value.asUint64()); - BOOST_CHECK_THROW(value.asInt64(), InvalidConversion); - - value = "9223372036854775808"; - BOOST_CHECK_EQUAL(9223372036854775808ull, value.asUint64()); - BOOST_CHECK_THROW(value.asInt64(), InvalidConversion); - - value = "-9223372036854775809"; - BOOST_CHECK_THROW(value.asUint64(), InvalidConversion); - BOOST_CHECK_THROW(value.asInt64(), InvalidConversion); - - value = "2147483648"; - BOOST_CHECK_EQUAL(2147483648ul, value.asUint32()); - BOOST_CHECK_THROW(value.asInt32(), InvalidConversion); - - value = "-2147483649"; - BOOST_CHECK_THROW(value.asUint32(), InvalidConversion); - BOOST_CHECK_THROW(value.asInt32(), InvalidConversion); - - value = "32768"; - BOOST_CHECK_EQUAL(32768u, value.asUint16()); - BOOST_CHECK_THROW(value.asInt16(), InvalidConversion); - - value = "-32769"; - BOOST_CHECK_THROW(value.asUint16(), InvalidConversion); - BOOST_CHECK_THROW(value.asInt16(), InvalidConversion); - - value = "-2.5"; - BOOST_CHECK_EQUAL(-2.5, value.asFloat()); - - value = "-0.875432e10"; - BOOST_CHECK_EQUAL(-0.875432e10, value.asDouble()); - - value = "-0"; - BOOST_CHECK_EQUAL(0, value.asInt16()); - BOOST_CHECK_EQUAL(0u, value.asUint16()); - - value = "-000"; - BOOST_CHECK_EQUAL(0, value.asInt16()); - BOOST_CHECK_EQUAL(0u, value.asUint16()); - - value = "-0010"; - BOOST_CHECK_EQUAL(-10, value.asInt16()); - BOOST_CHECK_THROW(value.asUint16(), InvalidConversion); -} - QPID_AUTO_TEST_CASE(testSizeConversionsUint) { Variant value; diff --git a/cpp/src/tests/XmlClientSessionTest.cpp b/cpp/src/tests/XmlClientSessionTest.cpp index b94c35ece0..b3b7f12b53 100644 --- a/cpp/src/tests/XmlClientSessionTest.cpp +++ b/cpp/src/tests/XmlClientSessionTest.cpp @@ -90,7 +90,7 @@ struct SimpleListener : public MessageListener } }; -struct ClientSessionFixture : public SessionFixture +struct ClientSessionFixture : public ProxySessionFixture { void declareSubscribe(const string& q="odd_blue", const string& dest="xml") diff --git a/cpp/src/tests/acl.py b/cpp/src/tests/acl.py index 65d5242e51..2d6a5b489d 100755 --- a/cpp/src/tests/acl.py +++ b/cpp/src/tests/acl.py @@ -26,11 +26,10 @@ from qpid.datatypes import uuid4 from qpid.testlib import TestBase010 from qmf.console import Session from qpid.datatypes import Message -import qpid.messaging class ACLFile: - def __init__(self, policy='data_dir/policy.acl'): - self.f = open(policy,'w') + def __init__(self): + self.f = open('data_dir/policy.acl','w'); def write(self,line): self.f.write(line) @@ -51,24 +50,14 @@ class ACLTests(TestBase010): acl = self.qmf.getObjects(_class="acl")[0] return acl.reloadACLFile() - def get_acl_file(self): - return ACLFile(self.config.defines.get("policy-file", "data_dir/policy.acl")) - def setUp(self): - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow all all\n') aclf.close() TestBase010.setUp(self) self.startQmf() self.reload_acl() - - def tearDown(self): - aclf = self.get_acl_file() - aclf.write('acl allow all all\n') - aclf.close() - self.reload_acl() - TestBase010.tearDown(self) - + #===================================== # ACL general tests #===================================== @@ -77,7 +66,7 @@ class ACLTests(TestBase010): """ Test the deny all mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow anonymous all all\n') aclf.write('acl allow bob@QPID create queue\n') aclf.write('acl deny all all') @@ -105,7 +94,7 @@ class ACLTests(TestBase010): """ Test the allow all mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID bind exchange\n') aclf.write('acl allow all all') aclf.close() @@ -137,7 +126,7 @@ class ACLTests(TestBase010): """ Test empty groups """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl group\n') aclf.write('acl group admins bob@QPID joe@QPID\n') aclf.write('acl allow all all') @@ -151,7 +140,7 @@ class ACLTests(TestBase010): """ Test illegal acl formats """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl group admins bob@QPID joe@QPID\n') aclf.write('acl allow all all') aclf.close() @@ -165,7 +154,7 @@ class ACLTests(TestBase010): Test illegal extension lines """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('group admins bob@QPID \n') aclf.write(' \ \n') aclf.write('joe@QPID \n') @@ -183,7 +172,7 @@ class ACLTests(TestBase010): """ Test proper extention lines """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('group test1 joe@EXAMPLE.com \\ \n') # should be allowed aclf.write(' jack@EXAMPLE.com \\ \n') # should be allowed aclf.write('jill@TEST.COM \\ \n') # should be allowed @@ -200,7 +189,7 @@ class ACLTests(TestBase010): Test a user defined without a realm Ex. group admin rajith """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('group admin bob\n') # shouldn't be allowed aclf.write('acl deny admin bind exchange\n') aclf.write('acl allow all all') @@ -215,7 +204,7 @@ class ACLTests(TestBase010): Test a user defined without a realm Ex. group admin rajith """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('group test1 joe@EXAMPLE.com\n') # should be allowed aclf.write('group test2 jack_123-jill@EXAMPLE.com\n') # should be allowed aclf.write('group test4 host/somemachine.example.com@EXAMPLE.COM\n') # should be allowed @@ -226,7 +215,7 @@ class ACLTests(TestBase010): if (result.text.find("ACL format error",0,len(result.text)) != -1): self.fail(result) - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('group test1 joe$H@EXAMPLE.com\n') # shouldn't be allowed aclf.write('acl allow all all') aclf.close() @@ -244,7 +233,7 @@ class ACLTests(TestBase010): Test illegal queue policy """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ding\n') aclf.write('acl allow all all') aclf.close() @@ -260,7 +249,7 @@ class ACLTests(TestBase010): Test illegal queue policy """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q2 maxqueuesize=-1\n') aclf.write('acl allow all all') aclf.close() @@ -271,7 +260,7 @@ class ACLTests(TestBase010): if (result.text != expected): self.fail(result) - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q2 maxqueuesize=9223372036854775808\n') aclf.write('acl allow all all') aclf.close() @@ -288,7 +277,7 @@ class ACLTests(TestBase010): Test illegal queue policy """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q2 maxqueuecount=-1\n') aclf.write('acl allow all all') aclf.close() @@ -299,7 +288,7 @@ class ACLTests(TestBase010): if (result.text != expected): self.fail(result) - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q2 maxqueuecount=9223372036854775808\n') aclf.write('acl allow all all') aclf.close() @@ -319,7 +308,7 @@ class ACLTests(TestBase010): """ Test cases for queue acl in allow mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create queue name=q1 durable=true passive=true\n') aclf.write('acl deny bob@QPID create queue name=q2 exclusive=true policytype=ring\n') aclf.write('acl deny bob@QPID access queue name=q3\n') @@ -422,7 +411,7 @@ class ACLTests(TestBase010): """ Test cases for queue acl in deny mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow bob@QPID create queue name=q1 durable=true passive=true\n') aclf.write('acl allow bob@QPID create queue name=q2 exclusive=true policytype=ring\n') aclf.write('acl allow bob@QPID access queue name=q3\n') @@ -545,7 +534,7 @@ class ACLTests(TestBase010): """ Test cases for exchange acl in allow mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID create exchange name=testEx durable=true passive=true\n') aclf.write('acl deny bob@QPID create exchange name=ex1 type=direct\n') aclf.write('acl deny bob@QPID access exchange name=myEx queuename=q1 routingkey=rk1.*\n') @@ -676,7 +665,7 @@ class ACLTests(TestBase010): """ Test cases for exchange acl in deny mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow bob@QPID create exchange name=myEx durable=true passive=false\n') aclf.write('acl allow bob@QPID bind exchange name=amq.topic queuename=bar routingkey=foo.*\n') aclf.write('acl allow bob@QPID unbind exchange name=amq.topic queuename=bar routingkey=foo.*\n') @@ -783,52 +772,6 @@ class ACLTests(TestBase010): if (403 == e.args[0].error_code): self.fail("ACL should allow exchange delete request for myEx"); - def test_create_and_delete_exchange_via_qmf(self): - """ - Test acl is enforced when creating/deleting via QMF - methods. Note that in order to be able to send the QMF methods - and receive the responses a significant amount of permissions - need to be enabled (TODO: can the set below be narrowed down - at all?) - """ - aclf = self.get_acl_file() - aclf.write('acl allow bob@QPID create exchange\n') - aclf.write('acl allow admin@QPID delete exchange\n') - aclf.write('acl allow all access exchange\n') - aclf.write('acl allow all bind exchange\n') - aclf.write('acl allow all create queue\n') - aclf.write('acl allow all access queue\n') - aclf.write('acl allow all delete queue\n') - aclf.write('acl allow all consume queue\n') - aclf.write('acl allow all access method\n') - aclf.write('acl deny all all') - aclf.close() - - result = self.reload_acl() - if (result.text.find("format error",0,len(result.text)) != -1): - self.fail(result) - - bob = BrokerAdmin(self.config.broker, "bob", "bob") - bob.create_exchange("my-exchange") #should pass - #cleanup by deleting exchange - try: - bob.delete_exchange("my-exchange") #should fail - self.fail("ACL should deny exchange delete request for my-exchange"); - except Exception, e: - self.assertEqual(7,e.args[0]["error_code"]) - assert e.args[0]["error_text"].find("unauthorized-access") == 0 - admin = BrokerAdmin(self.config.broker, "admin", "admin") - admin.delete_exchange("my-exchange") #should pass - - anonymous = BrokerAdmin(self.config.broker) - try: - anonymous.create_exchange("another-exchange") #should fail - self.fail("ACL should deny exchange create request for another-exchange"); - except Exception, e: - self.assertEqual(7,e.args[0]["error_code"]) - assert e.args[0]["error_text"].find("unauthorized-access") == 0 - - #===================================== # ACL consume tests #===================================== @@ -837,7 +780,7 @@ class ACLTests(TestBase010): """ Test cases for consume in allow mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID consume queue name=q1\n') aclf.write('acl deny bob@QPID consume queue name=q2\n') aclf.write('acl allow all all') @@ -883,7 +826,7 @@ class ACLTests(TestBase010): """ Test cases for consume in allow mode """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow bob@QPID consume queue name=q1\n') aclf.write('acl allow bob@QPID consume queue name=q2\n') aclf.write('acl allow bob@QPID create queue\n') @@ -929,7 +872,7 @@ class ACLTests(TestBase010): """ Test various publish acl """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl deny bob@QPID publish exchange name=amq.direct routingkey=rk1\n') aclf.write('acl deny bob@QPID publish exchange name=amq.topic\n') aclf.write('acl deny bob@QPID publish exchange name=myEx routingkey=rk2\n') @@ -978,7 +921,7 @@ class ACLTests(TestBase010): """ Test various publish acl """ - aclf = self.get_acl_file() + aclf = ACLFile() aclf.write('acl allow bob@QPID publish exchange name=amq.direct routingkey=rk1\n') aclf.write('acl allow bob@QPID publish exchange name=amq.topic\n') aclf.write('acl allow bob@QPID publish exchange name=myEx routingkey=rk2\n') @@ -1029,113 +972,3 @@ class ACLTests(TestBase010): except qpid.session.SessionException, e: if (403 == e.args[0].error_code): self.fail("ACL should allow message transfer to exchange amq.direct with routing key rk1"); - - #===================================== - # ACL broker configuration tests - #===================================== - - def test_broker_timestamp_config(self): - """ - Test ACL control of the broker timestamp configuration - """ - aclf = self.get_acl_file() - # enable lots of stuff to allow QMF to work - aclf.write('acl allow all create exchange\n') - aclf.write('acl allow all access exchange\n') - aclf.write('acl allow all bind exchange\n') - aclf.write('acl allow all publish exchange\n') - aclf.write('acl allow all create queue\n') - aclf.write('acl allow all access queue\n') - aclf.write('acl allow all delete queue\n') - aclf.write('acl allow all consume queue\n') - aclf.write('acl allow all access method\n') - # this should let bob access the timestamp configuration - aclf.write('acl allow bob@QPID access broker\n') - aclf.write('acl allow admin@QPID all all\n') - aclf.write('acl deny all all') - aclf.close() - - result = self.reload_acl() - if (result.text.find("format error",0,len(result.text)) != -1): - self.fail(result) - - ts = None - bob = BrokerAdmin(self.config.broker, "bob", "bob") - ts = bob.get_timestamp_cfg() #should work - bob.set_timestamp_cfg(ts); #should work - - obo = BrokerAdmin(self.config.broker, "obo", "obo") - try: - ts = obo.get_timestamp_cfg() #should fail - failed = False - except Exception, e: - failed = True - self.assertEqual(7,e.args[0]["error_code"]) - assert e.args[0]["error_text"].find("unauthorized-access") == 0 - assert(failed) - - try: - obo.set_timestamp_cfg(ts) #should fail - failed = False - except Exception, e: - failed = True - self.assertEqual(7,e.args[0]["error_code"]) - assert e.args[0]["error_text"].find("unauthorized-access") == 0 - assert(failed) - - admin = BrokerAdmin(self.config.broker, "admin", "admin") - ts = admin.get_timestamp_cfg() #should pass - admin.set_timestamp_cfg(ts) #should pass - - -class BrokerAdmin: - def __init__(self, broker, username=None, password=None): - self.connection = qpid.messaging.Connection(broker) - if username: - self.connection.username = username - self.connection.password = password - self.connection.sasl_mechanisms = "PLAIN" - self.connection.open() - self.session = self.connection.session() - self.sender = self.session.sender("qmf.default.direct/broker") - self.reply_to = "responses-#; {create:always}" - self.receiver = self.session.receiver(self.reply_to) - - def invoke(self, method, arguments): - content = { - "_object_id": {"_object_name": "org.apache.qpid.broker:broker:amqp-broker"}, - "_method_name": method, - "_arguments": arguments - } - request = qpid.messaging.Message(reply_to=self.reply_to, content=content) - request.properties["x-amqp-0-10.app-id"] = "qmf2" - request.properties["qmf.opcode"] = "_method_request" - self.sender.send(request) - response = self.receiver.fetch() - self.session.acknowledge() - if response.properties['x-amqp-0-10.app-id'] == 'qmf2': - if response.properties['qmf.opcode'] == '_method_response': - return response.content['_arguments'] - elif response.properties['qmf.opcode'] == '_exception': - raise Exception(response.content['_values']) - else: raise Exception("Invalid response received, unexpected opcode: %s" % response.properties['qmf.opcode']) - else: raise Exception("Invalid response received, not a qmfv2 method: %s" % response.properties['x-amqp-0-10.app-id']) - def create_exchange(self, name, exchange_type=None, options={}): - properties = options - if exchange_type: properties["exchange_type"] = exchange_type - self.invoke("create", {"type": "exchange", "name":name, "properties":properties}) - - def create_queue(self, name, properties={}): - self.invoke("create", {"type": "queue", "name":name, "properties":properties}) - - def delete_exchange(self, name): - self.invoke("delete", {"type": "exchange", "name":name}) - - def delete_queue(self, name): - self.invoke("delete", {"type": "queue", "name":name}) - - def get_timestamp_cfg(self): - return self.invoke("getTimestampConfig", {}) - - def set_timestamp_cfg(self, receive): - return self.invoke("getTimestampConfig", {"receive":receive}) diff --git a/cpp/src/tests/allhosts b/cpp/src/tests/allhosts index 4b4b943156..e43571aed4 100755 --- a/cpp/src/tests/allhosts +++ b/cpp/src/tests/allhosts @@ -29,12 +29,11 @@ Options: -s SECONDS sleep between starting commands. -q don't print banner lines for each host. -o SUFFIX log output of each command to <host>.SUFFIX - -X passed to ssh - forward X connection. " exit 1 } -while getopts "tl:bs:dqo:X" opt; do +while getopts "tl:bs:dqo:" opt; do case $opt in l) SSHOPTS="-l$OPTARG $SSHOPTS" ;; t) SSHOPTS="-t $SSHOPTS" ;; @@ -43,7 +42,6 @@ while getopts "tl:bs:dqo:X" opt; do s) SLEEP="sleep $OPTARG" ;; q) NOBANNER=1 ;; o) SUFFIX=$OPTARG ;; - X) SSHOPTS="-X $SSHOPTS" ;; *) usage;; esac done diff --git a/cpp/src/tests/brokertest.py b/cpp/src/tests/brokertest.py index 16d7fb0b78..98f58ebfdd 100644 --- a/cpp/src/tests/brokertest.py +++ b/cpp/src/tests/brokertest.py @@ -29,7 +29,6 @@ from unittest import TestCase from copy import copy from threading import Thread, Lock, Condition from logging import getLogger -import qmf.console log = getLogger("qpid.brokertest") @@ -62,6 +61,24 @@ def is_running(pid): class BadProcessStatus(Exception): pass +class ExceptionWrapper: + """Proxy object that adds a message to exceptions raised""" + def __init__(self, obj, msg): + self.obj = obj + self.msg = msg + + def __getattr__(self, name): + func = getattr(self.obj, name) + if type(func) != callable: + return func + return lambda *args, **kwargs: self._wrap(func, args, kwargs) + + def _wrap(self, func, args, kwargs): + try: + return func(*args, **kwargs) + except Exception, e: + raise Exception("%s: %s" %(self.msg, str(e))) + def error_line(filename, n=1): """Get the last n line(s) of filename for error messages""" result = [] @@ -71,8 +88,7 @@ def error_line(filename, n=1): for l in f: if len(result) == n: result.pop(0) result.append(" "+l) - finally: - f.close() + finally: f.close() except: return "" return ":\n" + "".join(result) @@ -80,90 +96,111 @@ def retry(function, timeout=10, delay=.01): """Call function until it returns True or timeout expires. Double the delay for each retry. Return True if function returns true, False if timeout expires.""" - deadline = time.time() + timeout while not function(): - remaining = deadline - time.time() - if remaining <= 0: return False - delay = min(delay, remaining) + if delay > timeout: delay = timeout time.sleep(delay) + timeout -= delay + if timeout <= 0: return False delay *= 2 return True -class AtomicCounter: - def __init__(self): - self.count = 0 - self.lock = Lock() - - def next(self): - self.lock.acquire(); - ret = self.count - self.count += 1 - self.lock.release(); - return ret - -_popen_id = AtomicCounter() # Popen identifier for use in output file names. - -# Constants for file descriptor arguments to Popen -FILE = "FILE" # Write to file named after process -PIPE = subprocess.PIPE - class Popen(subprocess.Popen): """ Can set and verify expectation of process status at end of test. Dumps command line, stdout, stderr to data dir for debugging. """ - def __init__(self, cmd, expect=EXPECT_EXIT_OK, stdin=None, stdout=FILE, stderr=FILE): - """Run cmd (should be a list of program and arguments) + class DrainThread(Thread): + """Thread to drain a file object and write the data to a file.""" + def __init__(self, infile, outname): + Thread.__init__(self) + self.infile, self.outname = infile, outname + self.outfile = None + + def run(self): + try: + for line in self.infile: + if self.outfile is None: + self.outfile = open(self.outname, "w") + self.outfile.write(line) + finally: + self.infile.close() + if self.outfile is not None: self.outfile.close() + + class OutStream(ExceptionWrapper): + """Wrapper for output streams, handles exceptions & draining output""" + def __init__(self, infile, outfile, msg): + ExceptionWrapper.__init__(self, infile, msg) + self.infile, self.outfile = infile, outfile + self.thread = None + + def drain(self): + if self.thread is None: + self.thread = Popen.DrainThread(self.infile, self.outfile) + self.thread.start() + + def outfile(self, ext): return "%s.%s" % (self.pname, ext) + + def __init__(self, cmd, expect=EXPECT_EXIT_OK, drain=True): + """Run cmd (should be a list of arguments) expect - if set verify expectation at end of test. - stdout, stderr - can have the same values as for subprocess.Popen as well as - FILE (the default) which means write to a file named after the process. - stdin - like subprocess.Popen but defauts to PIPE + drain - if true (default) drain stdout/stderr to files. """ self._clean = False self._clean_lock = Lock() assert find_exe(cmd[0]), "executable not found: "+cmd[0] if type(cmd) is type(""): cmd = [cmd] # Make it a list. self.cmd = [ str(x) for x in cmd ] + self.returncode = None self.expect = expect - self.id = _popen_id.next() - self.pname = "%s-%d" % (os.path.split(self.cmd[0])[1], self.id) - if stdout == FILE: stdout = open(self.outfile("out"), "w") - if stderr == FILE: stderr = open(self.outfile("err"), "w") try: - subprocess.Popen.__init__(self, self.cmd, bufsize=0, executable=None, - stdin=stdin, stdout=stdout, stderr=stderr, - close_fds=True) - except ValueError: # Windows can't do close_fds - subprocess.Popen.__init__(self, self.cmd, bufsize=0, executable=None, - stdin=stdin, stdout=stdout, stderr=stderr) - + subprocess.Popen.__init__(self, self.cmd, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE, close_fds=True) + except ValueError: # Windows can't do close_fds + subprocess.Popen.__init__(self, self.cmd, 0, None, subprocess.PIPE, subprocess.PIPE, subprocess.PIPE) + self.pname = "%s-%d" % (os.path.split(self.cmd[0])[1], self.pid) + msg = "Process %s" % self.pname + self.stdin = ExceptionWrapper(self.stdin, msg) + self.stdout = Popen.OutStream(self.stdout, self.outfile("out"), msg) + self.stderr = Popen.OutStream(self.stderr, self.outfile("err"), msg) f = open(self.outfile("cmd"), "w") - try: f.write("%s\n%d"%(self.cmd_str(), self.pid)) + try: f.write(self.cmd_str()) finally: f.close() log.debug("Started process %s: %s" % (self.pname, " ".join(self.cmd))) + if drain: self.drain() - def __str__(self): return "Popen<%s>"%(self.pname) + def __str__(self): return "Popen<%s>"%(self.pname) - def outfile(self, ext): return "%s.%s" % (self.pname, ext) + def drain(self): + """Start threads to drain stdout/err""" + self.stdout.drain() + self.stderr.drain() + + def _cleanup(self): + """Close pipes to sub-process""" + self._clean_lock.acquire() + try: + if self._clean: return + self._clean = True + self.stdin.close() + self.drain() # Drain output pipes. + self.stdout.thread.join() # Drain thread closes pipe. + self.stderr.thread.join() + finally: self._clean_lock.release() def unexpected(self,msg): err = error_line(self.outfile("err")) or error_line(self.outfile("out")) raise BadProcessStatus("%s %s%s" % (self.pname, msg, err)) - + def stop(self): # Clean up at end of test. try: if self.expect == EXPECT_UNKNOWN: try: self.kill() # Just make sure its dead except: pass elif self.expect == EXPECT_RUNNING: - if self.poll() != None: - self.unexpected("expected running, exit code %d" % self.returncode) - else: - try: - self.kill() - except Exception,e: - self.unexpected("exception from kill: %s" % str(e)) + try: + self.kill() + except: + self.unexpected("expected running, exit code %d" % self.wait()) else: retry(lambda: self.poll() is not None) if self.returncode is None: # Still haven't stopped @@ -175,21 +212,40 @@ class Popen(subprocess.Popen): self.unexpected("expected error") finally: self.wait() # Clean up the process. - + def communicate(self, input=None): - ret = subprocess.Popen.communicate(self, input) - self.cleanup() - return ret + if input: + self.stdin.write(input) + self.stdin.close() + outerr = (self.stdout.read(), self.stderr.read()) + self.wait() + return outerr - def is_running(self): return self.poll() is None + def is_running(self): + return self.poll() is None def assert_running(self): if not self.is_running(): self.unexpected("Exit code %d" % self.returncode) + def poll(self, _deadstate=None): # _deadstate required by base class in python 2.4 + if self.returncode is None: + # Pass _deadstate only if it has been set, there is no _deadstate + # parameter in Python 2.6 + if _deadstate is None: ret = subprocess.Popen.poll(self) + else: ret = subprocess.Popen.poll(self, _deadstate) + + if (ret != -1): + self.returncode = ret + self._cleanup() + return self.returncode + def wait(self): - ret = subprocess.Popen.wait(self) - self._cleanup() - return ret + if self.returncode is None: + self.drain() + try: self.returncode = subprocess.Popen.wait(self) + except OSError,e: raise OSError("Wait failed %s: %s"%(self.pname, e)) + self._cleanup() + return self.returncode def terminate(self): try: subprocess.Popen.terminate(self) @@ -198,8 +254,7 @@ class Popen(subprocess.Popen): os.kill( self.pid , signal.SIGTERM) except AttributeError: # no os.kill, using taskkill.. (Windows only) os.popen('TASKKILL /PID ' +str(self.pid) + ' /F') - self._cleanup() - + def kill(self): try: subprocess.Popen.kill(self) except AttributeError: # No terminate method @@ -207,20 +262,6 @@ class Popen(subprocess.Popen): os.kill( self.pid , signal.SIGKILL) except AttributeError: # no os.kill, using taskkill.. (Windows only) os.popen('TASKKILL /PID ' +str(self.pid) + ' /F') - self._cleanup() - - def _cleanup(self): - """Clean up after a dead process""" - self._clean_lock.acquire() - if not self._clean: - self._clean = True - try: self.stdin.close() - except: pass - try: self.stdout.close() - except: pass - try: self.stderr.close() - except: pass - self._clean_lock.release() def cmd_str(self): return " ".join([str(s) for s in self.cmd]) @@ -247,11 +288,11 @@ class Broker(Popen): while (os.path.exists(self.log)): self.log = "%s-%d.log" % (self.name, i) i += 1 - + def get_log(self): return os.path.abspath(self.log) - def __init__(self, test, args=[], name=None, expect=EXPECT_RUNNING, port=0, log_level=None, wait=None, show_cmd=False): + def __init__(self, test, args=[], name=None, expect=EXPECT_RUNNING, port=0, log_level=None, wait=None): """Start a broker daemon. name determines the data-dir and log file names.""" @@ -277,20 +318,15 @@ class Broker(Popen): cmd += ["--log-to-file", self.log] cmd += ["--log-to-stderr=no"] if log_level != None: - cmd += ["--log-enable=%s" % log_level] + cmd += ["--log-enable=%s" % log_level] self.datadir = self.name cmd += ["--data-dir", self.datadir] - if show_cmd: print cmd - Popen.__init__(self, cmd, expect, stdout=PIPE) + Popen.__init__(self, cmd, expect, drain=False) test.cleanup_stop(self) self._host = "127.0.0.1" log.debug("Started broker %s (%s, %s)" % (self.name, self.pname, self.log)) self._log_ready = False - def startQmf(self, handler=None): - self.qmf_session = qmf.console.Session(handler) - self.qmf_broker = self.qmf_session.addBroker("%s:%s" % (self.host(), self.port())) - def host(self): return self._host def port(self): @@ -321,7 +357,7 @@ class Broker(Popen): s = c.session(str(qpid.datatypes.uuid4())) s.queue_declare(queue=queue) c.close() - + def _prep_sender(self, queue, durable, xprops): s = queue + "; {create:always, node:{durable:" + str(durable) if xprops != None: s += ", x-declare:{" + xprops + "}" @@ -365,14 +401,13 @@ class Broker(Popen): def log_ready(self): """Return true if the log file exists and contains a broker ready message""" - if not self._log_ready: - self._log_ready = find_in_file("notice Broker running", self.log) - return self._log_ready + if self._log_ready: return True + self._log_ready = find_in_file("notice Broker running", self.log) def ready(self, **kwargs): """Wait till broker is ready to serve clients""" # First make sure the broker is listening by checking the log. - if not retry(self.log_ready, timeout=60): + if not retry(self.log_ready, timeout=30): raise Exception( "Timed out waiting for broker %s%s"%(self.name, error_line(self.log,5))) # Create a connection and a session. For a cluster broker this will @@ -381,27 +416,23 @@ class Broker(Popen): c = self.connect(**kwargs) try: c.session() finally: c.close() - except Exception,e: raise RethrownException( - "Broker %s not responding: (%s)%s"%(self.name,e,error_line(self.log, 5))) + except: raise RethrownException( + "Broker %s failed ready test%s"%(self.name,error_line(self.log, 5))) def store_state(self): - f = open(os.path.join(self.datadir, "cluster", "store.status")) - try: uuids = f.readlines() - finally: f.close() + uuids = open(os.path.join(self.datadir, "cluster", "store.status")).readlines() null_uuid="00000000-0000-0000-0000-000000000000\n" if len(uuids) < 2: return "unknown" # we looked while the file was being updated. if uuids[0] == null_uuid: return "empty" if uuids[1] == null_uuid: return "dirty" return "clean" - + class Cluster: """A cluster of brokers in a test.""" - # Client connection options for use in failover tests. - CONNECTION_OPTIONS = "reconnect:true,reconnect-timeout:10,reconnect-urls-replace:true" _cluster_count = 0 - def __init__(self, test, count=0, args=[], expect=EXPECT_RUNNING, wait=True, show_cmd=False): + def __init__(self, test, count=0, args=[], expect=EXPECT_RUNNING, wait=True): self.test = test self._brokers=[] self.name = "cluster%d" % Cluster._cluster_count @@ -412,19 +443,16 @@ class Cluster: self.args += [ "--log-enable=info+", "--log-enable=debug+:cluster"] assert BrokerTest.cluster_lib, "Cannot locate cluster plug-in" self.args += [ "--load-module", BrokerTest.cluster_lib ] - self.start_n(count, expect=expect, wait=wait, show_cmd=show_cmd) + self.start_n(count, expect=expect, wait=wait) - def start(self, name=None, expect=EXPECT_RUNNING, wait=True, args=[], port=0, show_cmd=False): + def start(self, name=None, expect=EXPECT_RUNNING, wait=True, args=[], port=0): """Add a broker to the cluster. Returns the index of the new broker.""" if not name: name="%s-%d" % (self.name, len(self._brokers)) - self._brokers.append(self.test.broker(self.args+args, name, expect, wait, port=port, show_cmd=show_cmd)) + self._brokers.append(self.test.broker(self.args+args, name, expect, wait, port=port)) return self._brokers[-1] - def ready(self): - for b in self: b.ready() - - def start_n(self, count, expect=EXPECT_RUNNING, wait=True, args=[], show_cmd=False): - for i in range(count): self.start(expect=expect, wait=wait, args=args, show_cmd=show_cmd) + def start_n(self, count, expect=EXPECT_RUNNING, wait=True, args=[]): + for i in range(count): self.start(expect=expect, wait=wait, args=args) # Behave like a list of brokers. def __len__(self): return len(self._brokers) @@ -453,7 +481,7 @@ class BrokerTest(TestCase): rootdir = os.getcwd() def configure(self, config): self.config=config - + def setUp(self): outdir = self.config.defines.get("OUTDIR") or "brokertest.tmp" self.dir = os.path.join(self.rootdir, outdir, self.id()) @@ -474,49 +502,40 @@ class BrokerTest(TestCase): """Call thing.stop at end of test""" self.stopem.append(stopable) - def popen(self, cmd, expect=EXPECT_EXIT_OK, stdin=None, stdout=FILE, stderr=FILE): + def popen(self, cmd, expect=EXPECT_EXIT_OK, drain=True): """Start a process that will be killed at end of test, in the test dir.""" os.chdir(self.dir) - p = Popen(cmd, expect, stdin=stdin, stdout=stdout, stderr=stderr) + p = Popen(cmd, expect, drain) self.cleanup_stop(p) return p - def broker(self, args=[], name=None, expect=EXPECT_RUNNING, wait=True, port=0, log_level=None, show_cmd=False): + def broker(self, args=[], name=None, expect=EXPECT_RUNNING, wait=True, port=0, log_level=None): """Create and return a broker ready for use""" - b = Broker(self, args=args, name=name, expect=expect, port=port, log_level=log_level, show_cmd=show_cmd) + b = Broker(self, args=args, name=name, expect=expect, port=port, log_level=log_level) if (wait): try: b.ready() except Exception, e: raise RethrownException("Failed to start broker %s(%s): %s" % (b.name, b.log, e)) return b - def cluster(self, count=0, args=[], expect=EXPECT_RUNNING, wait=True, show_cmd=False): + def cluster(self, count=0, args=[], expect=EXPECT_RUNNING, wait=True): """Create and return a cluster ready for use""" - cluster = Cluster(self, count, args, expect=expect, wait=wait, show_cmd=show_cmd) + cluster = Cluster(self, count, args, expect=expect, wait=wait) return cluster - def browse(self, session, queue, timeout=0): - """Return a list with the contents of each message on queue.""" - r = session.receiver("%s;{mode:browse}"%(queue)) - r.capacity = 100 - try: - contents = [] - try: - while True: contents.append(r.fetch(timeout=timeout).content) - except messaging.Empty: pass - finally: r.close() - return contents - def assert_browse(self, session, queue, expect_contents, timeout=0): """Assert that the contents of messages on queue (as retrieved using session and timeout) exactly match the strings in expect_contents""" - actual_contents = self.browse(session, queue, timeout) - self.assertEqual(expect_contents, actual_contents) -def join(thread, timeout=10): - thread.join(timeout) - if thread.isAlive(): raise Exception("Timed out joining thread %s"%thread) + r = session.receiver("%s;{mode:browse}"%(queue)) + actual_contents = [] + try: + for c in expect_contents: actual_contents.append(r.fetch(timeout=timeout).content) + while True: actual_contents.append(r.fetch(timeout=0).content) # Check for extra messages. + except messaging.Empty: pass + r.close() + self.assertEqual(expect_contents, actual_contents) class RethrownException(Exception): """Captures the stack trace of the current exception to be thrown later""" @@ -535,16 +554,15 @@ class StoppableThread(Thread): def stop(self): self.stopped = True - join(self) + self.join() if self.error: raise self.error - + class NumberedSender(Thread): """ Thread to run a sender client and send numbered messages until stopped. """ - def __init__(self, broker, max_depth=None, queue="test-queue", - connection_options=Cluster.CONNECTION_OPTIONS): + def __init__(self, broker, max_depth=None, queue="test-queue"): """ max_depth: enable flow control, ensure sent - received <= max_depth. Requires self.notify_received(n) to be called each time messages are received. @@ -555,11 +573,9 @@ class NumberedSender(Thread): "--broker", "localhost:%s"%broker.port(), "--address", "%s;{create:always}"%queue, "--failover-updates", - "--connection-options", "{%s}"%(connection_options), "--content-stdin" ], - expect=EXPECT_RUNNING, - stdin=PIPE) + expect=EXPECT_RUNNING) self.condition = Condition() self.max = max_depth self.received = 0 @@ -574,7 +590,6 @@ class NumberedSender(Thread): try: self.sent = 0 while not self.stopped: - self.sender.assert_running() if self.max: self.condition.acquire() while not self.stopped and self.sent - self.received > self.max: @@ -597,17 +612,16 @@ class NumberedSender(Thread): self.stopped = True self.condition.notify() finally: self.condition.release() - join(self) + self.join() self.write_message(-1) # end-of-messages marker. if self.error: raise self.error - + class NumberedReceiver(Thread): """ Thread to run a receiver client and verify it receives sequentially numbered messages. """ - def __init__(self, broker, sender = None, queue="test-queue", - connection_options=Cluster.CONNECTION_OPTIONS): + def __init__(self, broker, sender = None, queue="test-queue"): """ sender: enable flow control. Call sender.received(n) for each message received. """ @@ -618,24 +632,22 @@ class NumberedReceiver(Thread): "--broker", "localhost:%s"%broker.port(), "--address", "%s;{create:always}"%queue, "--failover-updates", - "--connection-options", "{%s}"%(connection_options), "--forever" ], expect=EXPECT_RUNNING, - stdout=PIPE) + drain=False) self.lock = Lock() self.error = None self.sender = sender - self.received = 0 def read_message(self): return int(self.receiver.stdout.readline()) - + def run(self): try: + self.received = 0 m = self.read_message() while m != -1: - self.receiver.assert_running() assert(m <= self.received) # Check for missing messages if (m == self.received): # Ignore duplicates self.received += 1 @@ -647,7 +659,7 @@ class NumberedReceiver(Thread): def stop(self): """Returns when termination message is received""" - join(self) + self.join() if self.error: raise self.error class ErrorGenerator(StoppableThread): @@ -662,7 +674,7 @@ class ErrorGenerator(StoppableThread): self.broker=broker broker.test.cleanup_stop(self) self.start() - + def run(self): c = self.broker.connect_old() try: diff --git a/cpp/src/tests/cli_tests.py b/cpp/src/tests/cli_tests.py index 6c75927461..deef03279d 100755 --- a/cpp/src/tests/cli_tests.py +++ b/cpp/src/tests/cli_tests.py @@ -365,26 +365,6 @@ class CliTests(TestBase010): self.assertEqual(queue._altExchange_.name, altName) self.assertEqual(found, True) - def test_qpid_config_list_queues_arguments(self): - """ - Test to verify that when the type of a policy limit is - actually a string (though still a valid value), it does not - upset qpid-config - """ - self.startQmf(); - qmf = self.qmf - - names = ["queue_capacity%s" % (i) for i in range(1, 6)] - for name in names: - self.session.queue_declare(queue=name, exclusive=True, - arguments={'qpid.max_count' : str(i), 'qpid.max_size': '100'}) - - output = os.popen(self.qpid_config_command(" queues")).readlines() - queues = [line.split()[0] for line in output[2:len(output)]] #ignore first two lines (header) - - for name in names: - assert name in queues, "%s not in %s" % (name, queues) - def test_qpid_route(self): self.startQmf(); qmf = self.qmf @@ -425,7 +405,7 @@ class CliTests(TestBase010): qmf = self.qmf ret = self.qpid_route_api("dynamic add " - + " --client-sasl-mechanism PLAIN " + + " --sasl-mechanism PLAIN " + "guest/guest@localhost:"+str(self.broker.port) + " " + str(self.remote_host())+":"+str(self.remote_port()) + " " +"amq.direct") @@ -444,7 +424,7 @@ class CliTests(TestBase010): qmf = self.qmf ret = self.qpid_route_api("dynamic add " - + " --client-sasl-mechanism PLAIN " + + " --sasl-mechanism PLAIN " + "localhost:"+str(self.broker.port) + " " + str(self.remote_host())+":"+str(self.remote_port()) + " " +"amq.direct") diff --git a/cpp/src/tests/cluster_python_tests_failing.txt b/cpp/src/tests/cluster_python_tests_failing.txt index f8639d7b59..7ba8089946 100644 --- a/cpp/src/tests/cluster_python_tests_failing.txt +++ b/cpp/src/tests/cluster_python_tests_failing.txt @@ -1,4 +1,32 @@ qpid_tests.broker_0_10.management.ManagementTest.test_purge_queue qpid_tests.broker_0_10.management.ManagementTest.test_connection_close +qpid_tests.broker_0_10.dtx.DtxTests.test_bad_resume +qpid_tests.broker_0_10.dtx.DtxTests.test_commit_unknown +qpid_tests.broker_0_10.dtx.DtxTests.test_end +qpid_tests.broker_0_10.dtx.DtxTests.test_end_suspend_and_fail +qpid_tests.broker_0_10.dtx.DtxTests.test_end_unknown_xid +qpid_tests.broker_0_10.dtx.DtxTests.test_forget_xid_on_completion +qpid_tests.broker_0_10.dtx.DtxTests.test_get_timeout +qpid_tests.broker_0_10.dtx.DtxTests.test_get_timeout_unknown +qpid_tests.broker_0_10.dtx.DtxTests.test_implicit_end +qpid_tests.broker_0_10.dtx.DtxTests.test_invalid_commit_not_ended +qpid_tests.broker_0_10.dtx.DtxTests.test_invalid_commit_one_phase_false +qpid_tests.broker_0_10.dtx.DtxTests.test_invalid_commit_one_phase_true +qpid_tests.broker_0_10.dtx.DtxTests.test_invalid_prepare_not_ended +qpid_tests.broker_0_10.dtx.DtxTests.test_invalid_rollback_not_ended +qpid_tests.broker_0_10.dtx.DtxTests.test_prepare_unknown +qpid_tests.broker_0_10.dtx.DtxTests.test_recover +qpid_tests.broker_0_10.dtx.DtxTests.test_rollback_unknown +qpid_tests.broker_0_10.dtx.DtxTests.test_select_required +qpid_tests.broker_0_10.dtx.DtxTests.test_set_timeout +qpid_tests.broker_0_10.dtx.DtxTests.test_simple_commit +qpid_tests.broker_0_10.dtx.DtxTests.test_simple_prepare_commit +qpid_tests.broker_0_10.dtx.DtxTests.test_simple_prepare_rollback +qpid_tests.broker_0_10.dtx.DtxTests.test_simple_rollback +qpid_tests.broker_0_10.dtx.DtxTests.test_start_already_known +qpid_tests.broker_0_10.dtx.DtxTests.test_start_join +qpid_tests.broker_0_10.dtx.DtxTests.test_start_join_and_resume +qpid_tests.broker_0_10.dtx.DtxTests.test_suspend_resume +qpid_tests.broker_0_10.dtx.DtxTests.test_suspend_start_end_resume qpid_tests.broker_0_10.message.MessageTests.test_ttl qpid_tests.broker_0_10.management.ManagementTest.test_broker_connectivity_oldAPI diff --git a/cpp/src/tests/cluster_test_logs.py b/cpp/src/tests/cluster_test_logs.py index 3c7e8e8020..1fa9014d11 100755 --- a/cpp/src/tests/cluster_test_logs.py +++ b/cpp/src/tests/cluster_test_logs.py @@ -53,19 +53,16 @@ def filter_log(log): 'stall for update|unstall, ignore update|cancelled offer .* unstall', 'caught up', 'active for links|Passivating links|Activating links', - 'info Connecting: .*', # UpdateClient connection 'info Connection.* connected to', # UpdateClient connection - 'warning Connection \\[[-0-9.: ]+\\] closed', # UpdateClient connection + 'warning Connection [\d+ [0-9.:]+] closed', # UpdateClient connection 'warning Broker closed connection: 200, OK', 'task late', 'task overran', 'warning CLOSING .* unsent data', 'Inter-broker link ', - 'Running in a cluster, marking store', - 'debug Sending keepalive signal to watchdog', # Watchdog timer thread - 'last broker standing joined by 1 replicas, updating queue policies.', - 'Connection .* timed out: closing' # heartbeat connection close + 'Running in a cluster, marking store' ]) + skip_re = re.compile(skip) # Regex to match a UUID uuid='\w\w\w\w\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w-\w\w\w\w\w\w\w\w\w\w\w\w' # Substitutions to remove expected differences @@ -83,13 +80,6 @@ def filter_log(log): (r' map={.*_object_name:([^,}]*)[,}].*', r' \1'), # V2 map - just keep name (r'\d+-\d+-\d+--\d+', 'X-X-X--X'), # V1 Object IDs ] - # Substitutions to mask known issue: durable test shows inconsistent "changed stats for com.redhat.rhm.store:journal" messages. - skip += '|Changed V[12] statistics com.redhat.rhm.store:journal' - subs += [(r'to=console.obj.1.0.com.redhat.rhm.store.journal props=\d+ stats=\d+', - 'to=console.obj.1.0.com.redhat.rhm.store.journal props=NN stats=NN')] - - skip_re = re.compile(skip) - subs = [(re.compile(pattern), subst) for pattern, subst in subs] for l in open(log): if skip_re.search(l): continue for pattern,subst in subs: l = re.sub(pattern,subst,l) diff --git a/cpp/src/tests/cluster_tests.py b/cpp/src/tests/cluster_tests.py index 0e80e06d34..cbad4010b4 100755 --- a/cpp/src/tests/cluster_tests.py +++ b/cpp/src/tests/cluster_tests.py @@ -18,13 +18,12 @@ # under the License. # -import os, signal, sys, time, imp, re, subprocess, glob, random, logging -import cluster_test_logs +import os, signal, sys, time, imp, re, subprocess, glob, cluster_test_logs from qpid import datatypes, messaging from brokertest import * from qpid.harness import Skipped -from qpid.messaging import Message, Empty, Disposition, REJECTED, util -from threading import Thread, Lock, Condition +from qpid.messaging import Message, Empty +from threading import Thread, Lock from logging import getLogger from itertools import chain from tempfile import NamedTemporaryFile @@ -97,15 +96,9 @@ class ShortTests(BrokerTest): destination="amq.direct", message=qpid.datatypes.Message(props, "content")) - # Try message with TTL and differnet headers/properties - cluster[0].send_message("q", Message(durable=True, ttl=100000)) - cluster[0].send_message("q", Message(durable=True, properties={}, ttl=100000)) - cluster[0].send_message("q", Message(durable=True, properties={"x":10}, ttl=100000)) - # Now update a new member and compare their dumps. cluster.start(args=["--test-store-dump", "updatee.dump"]) assert readfile("direct.dump") == readfile("updatee.dump") - os.remove("direct.dump") os.remove("updatee.dump") @@ -115,22 +108,19 @@ class ShortTests(BrokerTest): acl=os.path.join(os.getcwd(), "policy.acl") aclf=file(acl,"w") aclf.write(""" -acl allow zig@QPID all all -acl deny all all +acl deny zag@QPID create queue +acl allow all all """) aclf.close() - cluster = self.cluster(1, args=["--auth", "yes", + cluster = self.cluster(2, args=["--auth", "yes", "--sasl-config", sasl_config, "--load-module", os.getenv("ACL_LIB"), "--acl-file", acl]) # Valid user/password, ensure queue is created. c = cluster[0].connect(username="zig", password="zig") - c.session().sender("ziggy;{create:always,node:{x-declare:{exclusive:true}}}") + c.session().sender("ziggy;{create:always}") c.close() - cluster.start() # Start second node. - - # Check queue is created on second node. c = cluster[1].connect(username="zig", password="zig") c.session().receiver("ziggy;{assert:always}") c.close() @@ -159,7 +149,7 @@ acl deny all all self.fail("Expected exception") except messaging.exceptions.UnauthorizedAccess: pass # make sure the queue was not created at the other node. - c = cluster[1].connect(username="zig", password="zig") + c = cluster[0].connect(username="zag", password="zag") try: s = c.session() s.sender("zaggy;{assert:always}") @@ -167,35 +157,6 @@ acl deny all all self.fail("Expected exception") except messaging.exceptions.NotFound: pass - def test_sasl_join(self): - """Verify SASL authentication between brokers when joining a cluster.""" - sasl_config=os.path.join(self.rootdir, "sasl_config") - # Test with a valid username/password - cluster = self.cluster(1, args=["--auth", "yes", - "--sasl-config", sasl_config, - "--load-module", os.getenv("ACL_LIB"), - "--cluster-username=zig", - "--cluster-password=zig", - "--cluster-mechanism=PLAIN" - ]) - cluster.start() - cluster.ready() - c = cluster[1].connect(username="zag", password="zag") - - # Test with an invalid username/password - cluster = self.cluster(1, args=["--auth", "yes", - "--sasl-config", sasl_config, - "--load-module", os.getenv("ACL_LIB"), - "--cluster-username=x", - "--cluster-password=y", - "--cluster-mechanism=PLAIN" - ]) - try: - cluster.start(expect=EXPECT_EXIT_OK) - cluster[1].ready() - self.fail("Expected exception") - except: pass - def test_user_id_update(self): """Ensure that user-id of an open session is updated to new cluster members""" sasl_config=os.path.join(self.rootdir, "sasl_config") @@ -285,6 +246,25 @@ acl deny all all session1 = cluster[1].connect().session() for q in queues: self.assert_browse(session1, "q1", ["foo"]) + def test_dr_no_message(self): + """Regression test for https://bugzilla.redhat.com/show_bug.cgi?id=655141 + Joining broker crashes with 'error deliveryRecord no update message' + """ + + cluster = self.cluster(1) + session0 = cluster[0].connect().session() + s = session0.sender("q1;{create:always}") + s.send(Message("a", ttl=0.05), sync=False) + s.send(Message("b", ttl=0.05), sync=False) + r1 = session0.receiver("q1") + self.assertEqual("a", r1.fetch(timeout=0).content) + r2 = session0.receiver("q1;{mode:browse}") + self.assertEqual("b", r2.fetch(timeout=0).content) + # Leave messages un-acknowledged, let the expire, then start new broker. + time.sleep(.1) + cluster.start() + self.assertRaises(Empty, cluster[1].connect().session().receiver("q1").fetch,0) + def test_route_update(self): """Regression test for https://issues.apache.org/jira/browse/QPID-2982 Links and bridges associated with routes were not replicated on update. @@ -292,7 +272,6 @@ acl deny all all client was attached. """ args=["--mgmt-pub-interval=1","--log-enable=trace+:management"] - # First broker will be killed. cluster0 = self.cluster(1, args=args) cluster1 = self.cluster(1, args=args) assert 0 == subprocess.call( @@ -322,695 +301,9 @@ acl deny all all qpid_tool.wait() scanner.join() assert scanner.found - # Regression test for https://issues.apache.org/jira/browse/QPID-3235 - # Inconsistent stats when changing elder. - - # Force a change of elder - cluster0.start() - cluster0[0].expect=EXPECT_EXIT_FAIL # About to die. - cluster0[0].kill() - time.sleep(2) # Allow a management interval to pass. # Verify logs are consistent cluster_test_logs.verify_logs() - def test_redelivered(self): - """Verify that redelivered flag is set correctly on replayed messages""" - cluster = self.cluster(2, expect=EXPECT_EXIT_FAIL) - url = "amqp:tcp:%s,tcp:%s" % (cluster[0].host_port(), cluster[1].host_port()) - queue = "my-queue" - cluster[0].declare_queue(queue) - self.sender = self.popen( - ["qpid-send", - "--broker", url, - "--address", queue, - "--sequence=true", - "--send-eos=1", - "--messages=100000", - "--connection-options={%s}"%(Cluster.CONNECTION_OPTIONS) - ]) - self.receiver = self.popen( - ["qpid-receive", - "--broker", url, - "--address", queue, - "--ignore-duplicates", - "--check-redelivered", - "--connection-options={%s}"%(Cluster.CONNECTION_OPTIONS), - "--forever" - ]) - time.sleep(1)#give sender enough time to have some messages to replay - cluster[0].kill() - self.sender.wait() - self.receiver.wait() - cluster[1].kill() - - class BlockedSend(Thread): - """Send a message, send is expected to block. - Verify that it does block (for a given timeout), then allow - waiting till it unblocks when it is expected to do so.""" - def __init__(self, sender, msg): - self.sender, self.msg = sender, msg - self.blocked = True - self.condition = Condition() - self.timeout = 0.1 # Time to wait for expected results. - Thread.__init__(self) - def run(self): - try: - self.sender.send(self.msg, sync=True) - self.condition.acquire() - try: - self.blocked = False - self.condition.notify() - finally: self.condition.release() - except Exception,e: print "BlockedSend exception: %s"%e - def start(self): - Thread.start(self) - time.sleep(self.timeout) - assert self.blocked # Expected to block - def assert_blocked(self): assert self.blocked - def wait(self): # Now expecting to unblock - self.condition.acquire() - try: - while self.blocked: - self.condition.wait(self.timeout) - if self.blocked: raise Exception("Timed out waiting for send to unblock") - finally: self.condition.release() - self.join() - - def queue_flowlimit_test(self, brokers): - """Verify that the queue's flowlimit configuration and state are - correctly replicated. - The brokers argument allows this test to run on single broker, - cluster of 2 pre-startd brokers or cluster where second broker - starts after queue is in flow control. - """ - # configure a queue with a specific flow limit on first broker - ssn0 = brokers.first().connect().session() - s0 = ssn0.sender("flq; {create:always, node:{type:queue, x-declare:{arguments:{'qpid.flow_stop_count':5, 'qpid.flow_resume_count':3}}}}") - brokers.first().startQmf() - q1 = [q for q in brokers.first().qmf_session.getObjects(_class="queue") if q.name == "flq"][0] - oid = q1.getObjectId() - self.assertEqual(q1.name, "flq") - self.assertEqual(q1.arguments, {u'qpid.flow_stop_count': 5L, u'qpid.flow_resume_count': 3L}) - assert not q1.flowStopped - self.assertEqual(q1.flowStoppedCount, 0) - - # fill the queue on one broker until flow control is active - for x in range(5): s0.send(Message(str(x))) - sender = ShortTests.BlockedSend(s0, Message(str(6))) - sender.start() # Tests that sender does block - # Verify the broker queue goes into a flowStopped state - deadline = time.time() + 1 - while not q1.flowStopped and time.time() < deadline: q1.update() - assert q1.flowStopped - self.assertEqual(q1.flowStoppedCount, 1) - sender.assert_blocked() # Still blocked - - # Now verify the both brokers in cluster have same configuration - brokers.second().startQmf() - qs = brokers.second().qmf_session.getObjects(_objectId=oid) - self.assertEqual(len(qs), 1) - q2 = qs[0] - self.assertEqual(q2.name, "flq") - self.assertEqual(q2.arguments, {u'qpid.flow_stop_count': 5L, u'qpid.flow_resume_count': 3L}) - assert q2.flowStopped - self.assertEqual(q2.flowStoppedCount, 1) - - # now drain the queue using a session to the other broker - ssn1 = brokers.second().connect().session() - r1 = ssn1.receiver("flq", capacity=6) - for x in range(4): - r1.fetch(timeout=0) - ssn1.acknowledge() - sender.wait() # Verify no longer blocked. - - # and re-verify state of queue on both brokers - q1.update() - assert not q1.flowStopped - q2.update() - assert not q2.flowStopped - - ssn0.connection.close() - ssn1.connection.close() - cluster_test_logs.verify_logs() - - def test_queue_flowlimit(self): - """Test flow limits on a standalone broker""" - broker = self.broker() - class Brokers: - def first(self): return broker - def second(self): return broker - self.queue_flowlimit_test(Brokers()) - - def test_queue_flowlimit_cluster(self): - cluster = self.cluster(2) - class Brokers: - def first(self): return cluster[0] - def second(self): return cluster[1] - self.queue_flowlimit_test(Brokers()) - - def test_queue_flowlimit_cluster_join(self): - cluster = self.cluster(1) - class Brokers: - def first(self): return cluster[0] - def second(self): - if len(cluster) == 1: cluster.start() - return cluster[1] - self.queue_flowlimit_test(Brokers()) - - def test_queue_flowlimit_replicate(self): - """ Verify that a queue which is in flow control BUT has drained BELOW - the flow control 'stop' threshold, is correctly replicated when a new - broker is added to the cluster. - """ - - class AsyncSender(Thread): - """Send a fixed number of msgs from a sender in a separate thread - so it may block without blocking the test. - """ - def __init__(self, broker, address, count=1, size=4): - Thread.__init__(self) - self.daemon = True - self.broker = broker - self.queue = address - self.count = count - self.size = size - self.done = False - - def run(self): - self.sender = subprocess.Popen(["qpid-send", - "--capacity=1", - "--content-size=%s" % self.size, - "--messages=%s" % self.count, - "--failover-updates", - "--connection-options={%s}"%(Cluster.CONNECTION_OPTIONS), - "--address=%s" % self.queue, - "--broker=%s" % self.broker.host_port()]) - self.sender.wait() - self.done = True - - cluster = self.cluster(2) - # create a queue with rather draconian flow control settings - ssn0 = cluster[0].connect().session() - s0 = ssn0.sender("flq; {create:always, node:{type:queue, x-declare:{arguments:{'qpid.flow_stop_count':100, 'qpid.flow_resume_count':20}}}}") - - # fire off the sending thread to broker[0], and wait until the queue - # hits flow control on broker[1] - sender = AsyncSender(cluster[0], "flq", count=110); - sender.start(); - - cluster[1].startQmf() - q_obj = [q for q in cluster[1].qmf_session.getObjects(_class="queue") if q.name == "flq"][0] - deadline = time.time() + 10 - while not q_obj.flowStopped and time.time() < deadline: - q_obj.update() - assert q_obj.flowStopped - assert not sender.done - assert q_obj.msgDepth < 110 - - # Now drain enough messages on broker[1] to drop below the flow stop - # threshold, but not relieve flow control... - receiver = subprocess.Popen(["qpid-receive", - "--messages=15", - "--timeout=1", - "--print-content=no", - "--failover-updates", - "--connection-options={%s}"%(Cluster.CONNECTION_OPTIONS), - "--ack-frequency=1", - "--address=flq", - "--broker=%s" % cluster[1].host_port()]) - receiver.wait() - q_obj.update() - assert q_obj.flowStopped - assert not sender.done - current_depth = q_obj.msgDepth - - # add a new broker to the cluster, and verify that the queue is in flow - # control on that broker - cluster.start() - cluster[2].startQmf() - q_obj = [q for q in cluster[2].qmf_session.getObjects(_class="queue") if q.name == "flq"][0] - assert q_obj.flowStopped - assert q_obj.msgDepth == current_depth - - # now drain the queue on broker[2], and verify that the sender becomes - # unblocked - receiver = subprocess.Popen(["qpid-receive", - "--messages=95", - "--timeout=1", - "--print-content=no", - "--failover-updates", - "--connection-options={%s}"%(Cluster.CONNECTION_OPTIONS), - "--ack-frequency=1", - "--address=flq", - "--broker=%s" % cluster[2].host_port()]) - receiver.wait() - q_obj.update() - assert not q_obj.flowStopped - self.assertEqual(q_obj.msgDepth, 0) - - # verify that the sender has become unblocked - sender.join(timeout=5) - assert not sender.isAlive() - assert sender.done - - def test_blocked_queue_delete(self): - """Verify that producers which are blocked on a queue due to flow - control are unblocked when that queue is deleted. - """ - - cluster = self.cluster(2) - cluster[0].startQmf() - cluster[1].startQmf() - - # configure a queue with a specific flow limit on first broker - ssn0 = cluster[0].connect().session() - s0 = ssn0.sender("flq; {create:always, node:{type:queue, x-declare:{arguments:{'qpid.flow_stop_count':5, 'qpid.flow_resume_count':3}}}}") - q1 = [q for q in cluster[0].qmf_session.getObjects(_class="queue") if q.name == "flq"][0] - oid = q1.getObjectId() - self.assertEqual(q1.name, "flq") - self.assertEqual(q1.arguments, {u'qpid.flow_stop_count': 5L, u'qpid.flow_resume_count': 3L}) - assert not q1.flowStopped - self.assertEqual(q1.flowStoppedCount, 0) - - # fill the queue on one broker until flow control is active - for x in range(5): s0.send(Message(str(x))) - sender = ShortTests.BlockedSend(s0, Message(str(6))) - sender.start() # Tests that sender does block - # Verify the broker queue goes into a flowStopped state - deadline = time.time() + 1 - while not q1.flowStopped and time.time() < deadline: q1.update() - assert q1.flowStopped - self.assertEqual(q1.flowStoppedCount, 1) - sender.assert_blocked() # Still blocked - - # Now verify the both brokers in cluster have same configuration - qs = cluster[1].qmf_session.getObjects(_objectId=oid) - self.assertEqual(len(qs), 1) - q2 = qs[0] - self.assertEqual(q2.name, "flq") - self.assertEqual(q2.arguments, {u'qpid.flow_stop_count': 5L, u'qpid.flow_resume_count': 3L}) - assert q2.flowStopped - self.assertEqual(q2.flowStoppedCount, 1) - - # now delete the blocked queue from other broker - ssn1 = cluster[1].connect().session() - self.evaluate_address(ssn1, "flq;{delete:always}") - sender.wait() # Verify no longer blocked. - - ssn0.connection.close() - ssn1.connection.close() - cluster_test_logs.verify_logs() - - - def test_alternate_exchange_update(self): - """Verify that alternate-exchange on exchanges and queues is propagated to new members of a cluster. """ - cluster = self.cluster(1) - s0 = cluster[0].connect().session() - # create alt queue bound to amq.fanout exchange, will be destination for alternate exchanges - self.evaluate_address(s0, "alt;{create:always,node:{x-bindings:[{exchange:'amq.fanout',queue:alt}]}}") - # create direct exchange ex with alternate-exchange amq.fanout and no queues bound - self.evaluate_address(s0, "ex;{create:always,node:{type:topic, x-declare:{type:'direct', alternate-exchange:'amq.fanout'}}}") - # create queue q with alternate-exchange amq.fanout - self.evaluate_address(s0, "q;{create:always,node:{type:queue, x-declare:{alternate-exchange:'amq.fanout'}}}") - - def verify(broker): - s = broker.connect().session() - # Verify unmatched message goes to ex's alternate. - s.sender("ex").send("foo") - self.assertEqual("foo", s.receiver("alt").fetch(timeout=0).content) - # Verify rejected message goes to q's alternate. - s.sender("q").send("bar") - msg = s.receiver("q").fetch(timeout=0) - self.assertEqual("bar", msg.content) - s.acknowledge(msg, Disposition(REJECTED)) # Reject the message - self.assertEqual("bar", s.receiver("alt").fetch(timeout=0).content) - - verify(cluster[0]) - cluster.start() - verify(cluster[1]) - - def test_binding_order(self): - """Regression test for binding order inconsistency in cluster""" - cluster = self.cluster(1) - c0 = cluster[0].connect() - s0 = c0.session() - # Declare multiple queues bound to same key on amq.topic - def declare(q,max=0): - if max: declare = 'x-declare:{arguments:{"qpid.max_count":%d, "qpid.flow_stop_count":0}}'%max - else: declare = 'x-declare:{}' - bind='x-bindings:[{queue:%s,key:key,exchange:"amq.topic"}]'%(q) - s0.sender("%s;{create:always,node:{%s,%s}}" % (q,declare,bind)) - declare('d',max=4) # Only one with a limit - for q in ['c', 'b','a']: declare(q) - # Add a cluster member, send enough messages to exceed the max count - cluster.start() - try: - s = s0.sender('amq.topic/key') - for m in xrange(1,6): s.send(Message(str(m))) - self.fail("Expected capacity exceeded exception") - except messaging.exceptions.TargetCapacityExceeded: pass - c1 = cluster[1].connect() - s1 = c1.session() - s0 = c0.session() # Old session s0 is broken by exception. - # Verify queue contents are consistent. - for q in ['a','b','c','d']: - self.assertEqual(self.browse(s0, q), self.browse(s1, q)) - # Verify queue contents are "best effort" - for q in ['a','b','c']: self.assert_browse(s1,q,[str(n) for n in xrange(1,6)]) - self.assert_browse(s1,'d',[str(n) for n in xrange(1,5)]) - - def test_deleted_exchange(self): - """QPID-3215: cached exchange reference can cause cluster inconsistencies - if exchange is deleted/recreated - Verify stand-alone case - """ - cluster = self.cluster() - # Verify we do not route message via an exchange that has been destroyed. - cluster.start() - s0 = cluster[0].connect().session() - self.evaluate_address(s0, "ex;{create:always,node:{type:topic}}") - self.evaluate_address(s0, "q;{create:always,node:{x-bindings:[{exchange:'ex',queue:q,key:foo}]}}") - send0 = s0.sender("ex/foo") - send0.send("foo") - self.assert_browse(s0, "q", ["foo"]) - self.evaluate_address(s0, "ex;{delete:always}") - try: - send0.send("bar") # Should fail, exchange is deleted. - self.fail("Expected not-found exception") - except qpid.messaging.NotFound: pass - self.assert_browse(cluster[0].connect().session(), "q", ["foo"]) - - def test_deleted_exchange_inconsistent(self): - """QPID-3215: cached exchange reference can cause cluster inconsistencies - if exchange is deleted/recreated - - Verify cluster inconsistency. - """ - cluster = self.cluster() - cluster.start() - s0 = cluster[0].connect().session() - self.evaluate_address(s0, "ex;{create:always,node:{type:topic}}") - self.evaluate_address(s0, "q;{create:always,node:{x-bindings:[{exchange:'ex',queue:q,key:foo}]}}") - send0 = s0.sender("ex/foo") - send0.send("foo") - self.assert_browse(s0, "q", ["foo"]) - - cluster.start() - s1 = cluster[1].connect().session() - self.evaluate_address(s0, "ex;{delete:always}") - try: - send0.send("bar") - self.fail("Expected not-found exception") - except qpid.messaging.NotFound: pass - - self.assert_browse(s1, "q", ["foo"]) - - - def test_ttl_consistent(self): - """Ensure we don't get inconsistent errors with message that have TTL very close together""" - messages = [ Message(str(i), ttl=i/1000.0) for i in xrange(0,1000)] - messages.append(Message("x")) - cluster = self.cluster(2) - sender = cluster[0].connect().session().sender("q;{create:always}") - - def fetch(b): - receiver = b.connect().session().receiver("q;{create:always}") - while receiver.fetch().content != "x": pass - - for m in messages: sender.send(m, sync=False) - for m in messages: sender.send(m, sync=False) - fetch(cluster[0]) - fetch(cluster[1]) - for m in messages: sender.send(m, sync=False) - cluster.start() - fetch(cluster[2]) - -# Some utility code for transaction tests -XA_RBROLLBACK = 1 -XA_RBTIMEOUT = 2 -XA_OK = 0 -dtx_branch_counter = 0 - -class DtxStatusException(Exception): - def __init__(self, expect, actual): - self.expect = expect - self.actual = actual - - def str(self): - return "DtxStatusException(expect=%s, actual=%s)"%(self.expect, self.actual) - -class DtxTestFixture: - """Bundle together some common requirements for dtx tests.""" - def __init__(self, test, broker, name, exclusive=False): - self.test = test - self.broker = broker - self.name = name - # Use old API. DTX is not supported in messaging API. - self.connection = broker.connect_old() - self.session = self.connection.session(name, 1) # 1 second timeout - self.queue = self.session.queue_declare(name, exclusive=exclusive) - self.session.dtx_select() - self.consumer = None - - def xid(self, id=None): - if id is None: id = self.name - return self.session.xid(format=0, global_id=id) - - def check_status(self, expect, actual): - if expect != actual: raise DtxStatusException(expect, actual) - - def start(self, id=None, resume=False): - self.check_status(XA_OK, self.session.dtx_start(xid=self.xid(id), resume=resume).status) - - def end(self, id=None, suspend=False): - self.check_status(XA_OK, self.session.dtx_end(xid=self.xid(id), suspend=suspend).status) - - def prepare(self, id=None): - self.check_status(XA_OK, self.session.dtx_prepare(xid=self.xid(id)).status) - - def commit(self, id=None, one_phase=True): - self.check_status( - XA_OK, self.session.dtx_commit(xid=self.xid(id), one_phase=one_phase).status) - - def rollback(self, id=None): - self.check_status(XA_OK, self.session.dtx_rollback(xid=self.xid(id)).status) - - def set_timeout(self, timeout, id=None): - self.session.dtx_set_timeout(xid=self.xid(id),timeout=timeout) - - def send(self, messages): - for m in messages: - dp=self.session.delivery_properties(routing_key=self.name) - mp=self.session.message_properties() - self.session.message_transfer(message=qpid.datatypes.Message(dp, mp, m)) - - def accept(self): - """Accept 1 message from queue""" - consumer_tag="%s-consumer"%(self.name) - self.session.message_subscribe(queue=self.name, destination=consumer_tag) - self.session.message_flow(unit = self.session.credit_unit.message, value = 1, destination = consumer_tag) - self.session.message_flow(unit = self.session.credit_unit.byte, value = 0xFFFFFFFFL, destination = consumer_tag) - msg = self.session.incoming(consumer_tag).get(timeout=1) - self.session.message_cancel(destination=consumer_tag) - self.session.message_accept(qpid.datatypes.RangedSet(msg.id)) - return msg - - - def verify(self, sessions, messages): - for s in sessions: - self.test.assert_browse(s, self.name, messages) - -class DtxTests(BrokerTest): - - def test_dtx_update(self): - """Verify that DTX transaction state is updated to a new broker. - Start a collection of transactions, then add a new cluster member, - then verify they commit/rollback correctly on the new broker.""" - - # Note: multiple test have been bundled into one to avoid the need to start/stop - # multiple brokers per test. - - cluster=self.cluster(1) - sessions = [cluster[0].connect().session()] # For verify - - # Transaction that will be open when new member joins, then committed. - t1 = DtxTestFixture(self, cluster[0], "t1") - t1.start() - t1.send(["1", "2"]) - t1.verify(sessions, []) # Not visible outside of transaction - - # Transaction that will be open when new member joins, then rolled back. - t2 = DtxTestFixture(self, cluster[0], "t2") - t2.start() - t2.send(["1", "2"]) - - # Transaction that will be prepared when new member joins, then committed. - t3 = DtxTestFixture(self, cluster[0], "t3") - t3.start() - t3.send(["1", "2"]) - t3.end() - t3.prepare() - t1.verify(sessions, []) # Not visible outside of transaction - - # Transaction that will be prepared when new member joins, then rolled back. - t4 = DtxTestFixture(self, cluster[0], "t4") - t4.start() - t4.send(["1", "2"]) - t4.end() - t4.prepare() - - # Transaction using an exclusive queue - t5 = DtxTestFixture(self, cluster[0], "t5", exclusive=True) - t5.start() - t5.send(["1", "2"]) - - # Accept messages in a transaction before/after join then commit - t6 = DtxTestFixture(self, cluster[0], "t6") - t6.send(["a","b","c"]) - t6.start() - self.assertEqual(t6.accept().body, "a"); - - # Accept messages in a transaction before/after join then roll back - t7 = DtxTestFixture(self, cluster[0], "t7") - t7.send(["a","b","c"]) - t7.start() - self.assertEqual(t7.accept().body, "a"); - - # Ended, suspended transactions across join. - t8 = DtxTestFixture(self, cluster[0], "t8") - t8.start(id="1") - t8.send(["x"]) - t8.end(id="1", suspend=True) - t8.start(id="2") - t8.send(["y"]) - t8.end(id="2") - t8.start() - t8.send("z") - - - # Start new cluster member - cluster.start() - sessions.append(cluster[1].connect().session()) - - # Commit t1 - t1.send(["3","4"]) - t1.verify(sessions, []) - t1.end() - t1.commit(one_phase=True) - t1.verify(sessions, ["1","2","3","4"]) - - # Rollback t2 - t2.send(["3","4"]) - t2.end() - t2.rollback() - t2.verify(sessions, []) - - # Commit t3 - t3.commit(one_phase=False) - t3.verify(sessions, ["1","2"]) - - # Rollback t4 - t4.rollback() - t4.verify(sessions, []) - - # Commit t5 - t5.send(["3","4"]) - t5.verify(sessions, []) - t5.end() - t5.commit(one_phase=True) - t5.verify(sessions, ["1","2","3","4"]) - - # Commit t6 - self.assertEqual(t6.accept().body, "b"); - t6.verify(sessions, ["c"]) - t6.end() - t6.commit(one_phase=True) - t6.session.close() # Make sure they're not requeued by the session. - t6.verify(sessions, ["c"]) - - # Rollback t7 - self.assertEqual(t7.accept().body, "b"); - t7.end() - t7.rollback() - t7.verify(sessions, ["a", "b", "c"]) - - # Resume t8 - t8.end() - t8.commit(one_phase=True) - t8.start("1", resume=True) - t8.end("1") - t8.commit("1", one_phase=True) - t8.commit("2", one_phase=True) - t8.verify(sessions, ["z", "x","y"]) - - - def test_dtx_failover_rollback(self): - """Kill a broker during a transaction, verify we roll back correctly""" - cluster=self.cluster(1, expect=EXPECT_EXIT_FAIL) - cluster.start(expect=EXPECT_RUNNING) - - # Test unprepared at crash - t1 = DtxTestFixture(self, cluster[0], "t1") - t1.send(["a"]) # Not in transaction - t1.start() - t1.send(["b"]) # In transaction - - # Test prepared at crash - t2 = DtxTestFixture(self, cluster[0], "t2") - t2.send(["a"]) # Not in transaction - t2.start() - t2.send(["b"]) # In transaction - t2.end() - t2.prepare() - - # Crash the broker - cluster[0].kill() - - # Transactional changes should not appear - s = cluster[1].connect().session(); - self.assert_browse(s, "t1", ["a"]) - self.assert_browse(s, "t2", ["a"]) - - def test_dtx_timeout(self): - """Verify that dtx timeout works""" - cluster = self.cluster(1) - t1 = DtxTestFixture(self, cluster[0], "t1") - t1.start() - t1.set_timeout(1) - time.sleep(1.1) - try: - t1.end() - self.fail("Expected rollback timeout.") - except DtxStatusException, e: - self.assertEqual(e.actual, XA_RBTIMEOUT) - -class TxTests(BrokerTest): - - def test_tx_update(self): - """Verify that transaction state is updated to a new broker""" - - def make_message(session, body=None, key=None, id=None): - dp=session.delivery_properties(routing_key=key) - mp=session.message_properties(correlation_id=id) - return qpid.datatypes.Message(dp, mp, body) - - cluster=self.cluster(1) - # Use old API. TX is not supported in messaging API. - c = cluster[0].connect_old() - s = c.session("tx-session", 1) - s.queue_declare(queue="q") - # Start transaction - s.tx_select() - s.message_transfer(message=make_message(s, "1", "q")) - # Start new member mid-transaction - cluster.start() - # Do more work - s.message_transfer(message=make_message(s, "2", "q")) - # Commit the transaction and verify the results. - s.tx_commit() - for b in cluster: self.assert_browse(b.connect().session(), "q", ["1","2"]) - - class LongTests(BrokerTest): """Tests that can run for a long time if -DDURATION=<minutes> is set""" def duration(self): @@ -1023,28 +316,22 @@ class LongTests(BrokerTest): # Original cluster will all be killed so expect exit with failure cluster = self.cluster(3, expect=EXPECT_EXIT_FAIL) - for b in cluster: b.ready() # Wait for brokers to be ready for b in cluster: ErrorGenerator(b) # Start sender and receiver threads cluster[0].declare_queue("test-queue") - sender = NumberedSender(cluster[0], 1000) # Max queue depth - receiver = NumberedReceiver(cluster[0], sender) + sender = NumberedSender(cluster[1], 1000) # Max queue depth + receiver = NumberedReceiver(cluster[2], sender) receiver.start() sender.start() - # Wait for sender & receiver to get up and running - retry(lambda: receiver.received > 0) # Kill original brokers, start new ones for the duration. endtime = time.time() + self.duration() i = 0 while time.time() < endtime: - sender.sender.assert_running() - receiver.receiver.assert_running() cluster[i].kill() i += 1 b = cluster.start(expect=EXPECT_EXIT_FAIL) - for b in cluster[i:]: b.ready() ErrorGenerator(b) time.sleep(5) sender.stop() @@ -1075,24 +362,24 @@ class LongTests(BrokerTest): if self.stopped: break self.process = self.broker.test.popen( self.cmd, expect=EXPECT_UNKNOWN) - finally: - self.lock.release() - try: - exit = self.process.wait() + finally: self.lock.release() + try: exit = self.process.wait() except OSError, e: - # Process may already have been killed by self.stop() - break + # Seems to be a race in wait(), it throws + # "no such process" during test shutdown. + # Doesn't indicate a test error, ignore. + return except Exception, e: self.process.unexpected( "client of %s: %s"%(self.broker.name, e)) self.lock.acquire() try: + # Quit and ignore errors if stopped or expecting failure. if self.stopped: break if exit != 0: self.process.unexpected( "client of %s exit code %s"%(self.broker.name, exit)) - finally: - self.lock.release() + finally: self.lock.release() except Exception, e: self.error = RethrownException("Error in ClientLoop.run") @@ -1114,7 +401,7 @@ class LongTests(BrokerTest): args += ["--log-enable=trace+:management"] # Use store if present. if BrokerTest.store_lib: args +=["--load-module", BrokerTest.store_lib] - cluster = self.cluster(3, args, expect=EXPECT_EXIT_FAIL) # brokers will be killed + cluster = self.cluster(3, args) clients = [] # Per-broker list of clients that only connect to one broker. mclients = [] # Management clients that connect to every broker in the cluster. @@ -1123,12 +410,10 @@ class LongTests(BrokerTest): """Start ordinary clients for a broker.""" cmds=[ ["qpid-tool", "localhost:%s"%(broker.port())], - ["qpid-perftest", "--count=5000", "--durable=yes", + ["qpid-perftest", "--count", 50000, "--base-name", str(qpid.datatypes.uuid4()), "--port", broker.port()], - ["qpid-txtest", "--queue-base-name", "tx-%s"%str(qpid.datatypes.uuid4()), - "--port", broker.port()], - ["qpid-queue-stats", "-a", "localhost:%s" %(broker.port())] - ] + ["qpid-queue-stats", "-a", "localhost:%s" %(broker.port())], + ["testagent", "localhost", str(broker.port())] ] clients.append([ClientLoop(broker, cmd) for cmd in cmds]) def start_mclients(broker): @@ -1137,8 +422,7 @@ class LongTests(BrokerTest): mclients.append(ClientLoop(broker, cmd)) endtime = time.time() + self.duration() - # For long duration, first run is a quarter of the duration. - runtime = min(5.0, self.duration() / 3.0) + runtime = self.duration() / 4 # First run is longer, use quarter of duration. alive = 0 # First live cluster member for i in range(len(cluster)): start_clients(cluster[i]) start_mclients(cluster[alive]) @@ -1149,7 +433,7 @@ class LongTests(BrokerTest): for b in cluster[alive:]: b.ready() # Check if a broker crashed. # Kill the first broker, expect the clients to fail. b = cluster[alive] - b.ready() + b.expect = EXPECT_EXIT_FAIL b.kill() # Stop the brokers clients and all the mclients. for c in clients[alive] + mclients: @@ -1159,251 +443,26 @@ class LongTests(BrokerTest): mclients = [] # Start another broker and clients alive += 1 - cluster.start(expect=EXPECT_EXIT_FAIL) - cluster[-1].ready() # Wait till its ready + cluster.start() start_clients(cluster[-1]) start_mclients(cluster[alive]) for c in chain(mclients, *clients): c.stop() - for b in cluster[alive:]: - b.ready() # Verify still alive - b.kill() + # Verify that logs are consistent cluster_test_logs.verify_logs() def test_management_qmf2(self): self.test_management(args=["--mgmt-qmf2=yes"]) - def test_connect_consistent(self): + def test_connect_consistent(self): # FIXME aconway 2011-01-18: args=["--mgmt-pub-interval=1","--log-enable=trace+:management"] cluster = self.cluster(2, args=args) end = time.time() + self.duration() while (time.time() < end): # Get a management interval for i in xrange(1000): cluster[0].connect().close() - cluster_test_logs.verify_logs() - - def test_flowlimit_failover(self): - """Test fail-over during continuous send-receive with flow control - active. - """ - - # Original cluster will all be killed so expect exit with failure - cluster = self.cluster(3, expect=EXPECT_EXIT_FAIL) - for b in cluster: b.ready() # Wait for brokers to be ready - - # create a queue with rather draconian flow control settings - ssn0 = cluster[0].connect().session() - s0 = ssn0.sender("test-queue; {create:always, node:{type:queue, x-declare:{arguments:{'qpid.flow_stop_count':2000, 'qpid.flow_resume_count':100}}}}") - - receiver = NumberedReceiver(cluster[0]) - receiver.start() - senders = [NumberedSender(cluster[0]) for i in range(1,3)] - for s in senders: - s.start() - # Wait for senders & receiver to get up and running - retry(lambda: receiver.received > 2*senders) - - # Kill original brokers, start new ones for the duration. - endtime = time.time() + self.duration(); - i = 0 - while time.time() < endtime: - for s in senders: s.sender.assert_running() - receiver.receiver.assert_running() - for b in cluster[i:]: b.ready() # Check if any broker crashed. - cluster[i].kill() - i += 1 - b = cluster.start(expect=EXPECT_EXIT_FAIL) - time.sleep(5) - for s in senders: - s.stop() - receiver.stop() - for i in range(i, len(cluster)): cluster[i].kill() - - def test_ttl_failover(self): - """Test that messages with TTL don't cause problems in a cluster with failover""" - - class Client(StoppableThread): - - def __init__(self, broker): - StoppableThread.__init__(self) - self.connection = broker.connect(reconnect=True) - self.auto_fetch_reconnect_urls(self.connection) - self.session = self.connection.session() - - def auto_fetch_reconnect_urls(self, conn): - """Replacment for qpid.messaging.util version which is noisy""" - ssn = conn.session("auto-fetch-reconnect-urls") - rcv = ssn.receiver("amq.failover") - rcv.capacity = 10 - - def main(): - while True: - try: - msg = rcv.fetch() - qpid.messaging.util.set_reconnect_urls(conn, msg) - ssn.acknowledge(msg, sync=False) - except messaging.exceptions.LinkClosed: return - except messaging.exceptions.ConnectionError: return - - thread = Thread(name="auto-fetch-reconnect-urls", target=main) - thread.setDaemon(True) - thread.start() - - def stop(self): - StoppableThread.stop(self) - self.connection.detach() - - class Sender(Client): - def __init__(self, broker, address): - Client.__init__(self, broker) - self.sent = 0 # Number of messages _reliably_ sent. - self.sender = self.session.sender(address, capacity=1000) - - def send_counted(self, ttl): - self.sender.send(Message(str(self.sent), ttl=ttl)) - self.sent += 1 - - def run(self): - while not self.stopped: - choice = random.randint(0,4) - if choice == 0: self.send_counted(None) # No ttl - elif choice == 1: self.send_counted(100000) # Large ttl - else: # Small ttl, might expire - self.sender.send(Message("", ttl=random.random()/10)) - self.sender.send(Message("z"), sync=True) # Chaser. - - class Receiver(Client): - - def __init__(self, broker, address): - Client.__init__(self, broker) - self.received = 0 # Number of non-empty (reliable) messages received. - self.receiver = self.session.receiver(address, capacity=1000) - def run(self): - try: - while True: - m = self.receiver.fetch(1) - if m.content == "z": break - if m.content: # Ignore unreliable messages - # Ignore duplicates - if int(m.content) == self.received: self.received += 1 - except Exception,e: self.error = e - - # def test_ttl_failover - - # Original cluster will all be killed so expect exit with failure - # Set small purge interval. - cluster = self.cluster(3, expect=EXPECT_EXIT_FAIL, args=["--queue-purge-interval=1"]) - for b in cluster: b.ready() # Wait for brokers to be ready - - # Python client failover produces noisy WARN logs, disable temporarily - logger = logging.getLogger() - log_level = logger.getEffectiveLevel() - logger.setLevel(logging.ERROR) - sender = None - receiver = None - try: - # Start sender and receiver threads - receiver = Receiver(cluster[0], "q;{create:always}") - receiver.start() - sender = Sender(cluster[0], "q;{create:always}") - sender.start() - # Wait for sender & receiver to get up and running - retry(lambda: receiver.received > 0) - - # Kill brokers in a cycle. - endtime = time.time() + self.duration() - runtime = min(5.0, self.duration() / 4.0) - i = 0 - while time.time() < endtime: - for b in cluster[i:]: b.ready() # Check if any broker crashed. - cluster[i].kill() - i += 1 - b = cluster.start(expect=EXPECT_EXIT_FAIL) - b.ready() - time.sleep(runtime) - sender.stop() - receiver.stop() - for b in cluster[i:]: - b.ready() # Check it didn't crash - b.kill() - self.assertEqual(sender.sent, receiver.received) cluster_test_logs.verify_logs() - finally: - # Detach to avoid slow reconnect attempts during shut-down if test fails. - if sender: sender.connection.detach() - if receiver: receiver.connection.detach() - logger.setLevel(log_level) - - def test_msg_group_failover(self): - """Test fail-over during continuous send-receive of grouped messages. - """ - - class GroupedTrafficGenerator(Thread): - def __init__(self, url, queue, group_key): - Thread.__init__(self) - self.url = url - self.queue = queue - self.group_key = group_key - self.status = -1 - - def run(self): - # generate traffic for approx 10 seconds (2011msgs / 200 per-sec) - cmd = ["msg_group_test", - "--broker=%s" % self.url, - "--address=%s" % self.queue, - "--connection-options={%s}" % (Cluster.CONNECTION_OPTIONS), - "--group-key=%s" % self.group_key, - "--receivers=2", - "--senders=3", - "--messages=2011", - "--send-rate=200", - "--capacity=11", - "--ack-frequency=23", - "--allow-duplicates", - "--group-size=37", - "--randomize-group-size", - "--interleave=13"] - # "--trace"] - self.generator = Popen( cmd ); - self.status = self.generator.wait() - return self.status - - def results(self): - self.join(timeout=30) # 3x assumed duration - if self.isAlive(): return -1 - return self.status - - # Original cluster will all be killed so expect exit with failure - cluster = self.cluster(3, expect=EXPECT_EXIT_FAIL, args=["-t"]) - for b in cluster: b.ready() # Wait for brokers to be ready - - # create a queue with rather draconian flow control settings - ssn0 = cluster[0].connect().session() - q_args = "{'qpid.group_header_key':'group-id', 'qpid.shared_msg_group':1}" - s0 = ssn0.sender("test-group-q; {create:always, node:{type:queue, x-declare:{arguments:%s}}}" % q_args) - - # Kill original brokers, start new ones for the duration. - endtime = time.time() + self.duration(); - i = 0 - while time.time() < endtime: - traffic = GroupedTrafficGenerator( cluster[i].host_port(), - "test-group-q", "group-id" ) - traffic.start() - time.sleep(1) - - for x in range(2): - for b in cluster[i:]: b.ready() # Check if any broker crashed. - cluster[i].kill() - i += 1 - b = cluster.start(expect=EXPECT_EXIT_FAIL) - time.sleep(1) - - # wait for traffic to finish, verify success - self.assertEqual(0, traffic.results()) - - for i in range(i, len(cluster)): cluster[i].kill() - class StoreTests(BrokerTest): """ diff --git a/cpp/src/tests/exception_test.cpp b/cpp/src/tests/exception_test.cpp index 3e844b4e58..3536ffddbe 100644 --- a/cpp/src/tests/exception_test.cpp +++ b/cpp/src/tests/exception_test.cpp @@ -92,30 +92,32 @@ QPID_AUTO_TEST_CASE(TestSessionBusy) { } QPID_AUTO_TEST_CASE(DisconnectedPop) { - SessionFixture fix; + ProxySessionFixture fix; + ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT)); fix.session.queueDeclare(arg::queue="q"); fix.subs.subscribe(fix.lq, "q"); Catcher<TransportFailure> pop(bind(&LocalQueue::pop, &fix.lq, sys::TIME_SEC)); - fix.shutdownBroker(); + fix.connection.proxy.close(); BOOST_CHECK(pop.join()); } QPID_AUTO_TEST_CASE(DisconnectedListen) { - SessionFixture fix; + ProxySessionFixture fix; struct NullListener : public MessageListener { void received(Message&) { BOOST_FAIL("Unexpected message"); } } l; + ProxyConnection c(fix.broker->getPort(Broker::TCP_TRANSPORT)); fix.session.queueDeclare(arg::queue="q"); fix.subs.subscribe(l, "q"); Catcher<TransportFailure> runner(bind(&SubscriptionManager::run, boost::ref(fix.subs))); - fix.shutdownBroker(); - runner.join(); + fix.connection.proxy.close(); + runner.join(); BOOST_CHECK_THROW(fix.session.queueDeclare(arg::queue="x"), TransportFailure); } QPID_AUTO_TEST_CASE(NoSuchQueueTest) { - SessionFixture fix; + ProxySessionFixture fix; ScopedSuppressLogging sl; // Suppress messages for expected errors. BOOST_CHECK_THROW(fix.subs.subscribe(fix.lq, "no such queue"), NotFoundException); } diff --git a/cpp/src/tests/federated_topic_test b/cpp/src/tests/federated_topic_test index 2e55ddcfaa..b1063c7e8c 100755 --- a/cpp/src/tests/federated_topic_test +++ b/cpp/src/tests/federated_topic_test @@ -42,12 +42,13 @@ while getopts "s:m:b:" opt ; do esac done +MY_DIR=$(dirname $(which $0)) source ./test_env.sh trap stop_brokers EXIT start_broker() { - $QPIDD_EXEC --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port + ${MY_DIR}/../qpidd --daemon --port 0 --no-module-dir --no-data-dir --auth no > qpidd.port } start_brokers() { @@ -75,39 +76,39 @@ subscribe() { echo Subscriber $1 connecting on $MY_PORT LOG="subscriber_$1.log" - ./qpid-topic-listener -p $MY_PORT > $LOG 2>&1 && rm -f $LOG + ${MY_DIR}/topic_listener -p $MY_PORT > $LOG 2>&1 && rm -f $LOG } publish() { - ./qpid-topic-publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS -p $PORT_A + ${MY_DIR}/topic_publisher --messages $MESSAGES --batches $BATCHES --subscribers $SUBSCRIBERS -p $PORT_A } setup_routes() { - BROKER_A="daffodil:$PORT_A" - BROKER_B="daffodil:$PORT_B" - BROKER_C="daffodil:$PORT_C" + BROKER_A="localhost:$PORT_A" + BROKER_B="localhost:$PORT_B" + BROKER_C="localhost:$PORT_C" if (($VERBOSE)); then echo "Establishing routes for topic..." fi - $QPID_ROUTE_EXEC route add $BROKER_B $BROKER_A amq.topic topic_control B B - $QPID_ROUTE_EXEC route add $BROKER_C $BROKER_B amq.topic topic_control C C + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_A amq.topic topic_control B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_C $BROKER_B amq.topic topic_control C C if (($VERBOSE)); then echo "linked A->B->C" fi - $QPID_ROUTE_EXEC route add $BROKER_B $BROKER_C amq.topic topic_control B B - $QPID_ROUTE_EXEC route add $BROKER_A $BROKER_B amq.topic topic_control A A + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.topic topic_control B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.topic topic_control A A if (($VERBOSE)); then echo "linked C->B->A" echo "Establishing routes for response queue..." fi - $QPID_ROUTE_EXEC route add $BROKER_B $BROKER_C amq.direct response B B - $QPID_ROUTE_EXEC route add $BROKER_A $BROKER_B amq.direct response A A + $PYTHON_COMMANDS/qpid-route route add $BROKER_B $BROKER_C amq.direct response B B + $PYTHON_COMMANDS/qpid-route route add $BROKER_A $BROKER_B amq.direct response A A if (($VERBOSE)); then echo "linked C->B->A" for b in $BROKER_A $BROKER_B $BROKER_C; do echo "Routes for $b" - $QPID_ROUTE_EXEC route list $b + $PYTHON_COMMANDS/qpid-route route list $b done fi } diff --git a/cpp/src/tests/federation.py b/cpp/src/tests/federation.py index 7d613b98ce..973a1d366c 100755 --- a/cpp/src/tests/federation.py +++ b/cpp/src/tests/federation.py @@ -23,7 +23,7 @@ from qpid.testlib import TestBase010 from qpid.datatypes import Message from qpid.queue import Empty from qpid.util import URL -from time import sleep, time +from time import sleep class _FedBroker(object): @@ -111,18 +111,18 @@ class FederationTests(TestBase010): broker = qmf.getObjects(_class="broker")[0] result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) link = qmf.getObjects(_class="link")[0] result = link.bridge(False, "amq.direct", "amq.direct", "my-key", "", "", False, False, False, 0) - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) bridge = qmf.getObjects(_class="bridge")[0] result = bridge.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) result = link.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) self.verify_cleanup() @@ -133,11 +133,11 @@ class FederationTests(TestBase010): qmf = self.qmf broker = qmf.getObjects(_class="broker")[0] result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) link = qmf.getObjects(_class="link")[0] result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, False, False, 0) - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) bridge = qmf.getObjects(_class="bridge")[0] @@ -165,9 +165,9 @@ class FederationTests(TestBase010): except Empty: None result = bridge.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) result = link.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) self.verify_cleanup() @@ -178,11 +178,11 @@ class FederationTests(TestBase010): qmf = self.qmf broker = qmf.getObjects(_class="broker")[0] result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) link = qmf.getObjects(_class="link")[0] result = link.bridge(False, "amq.direct", "amq.fanout", "my-key", "", "", False, True, False, 0) - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) bridge = qmf.getObjects(_class="bridge")[0] @@ -209,9 +209,9 @@ class FederationTests(TestBase010): except Empty: None result = bridge.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) result = link.close() - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) self.verify_cleanup() @@ -236,11 +236,11 @@ class FederationTests(TestBase010): qmf = self.qmf broker = qmf.getObjects(_class="broker")[0] result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) link = qmf.getObjects(_class="link")[0] result = link.bridge(False, "my-bridge-queue", "amq.fanout", "my-key", "", "", True, False, False, 1) - self.assertEqual(result.status, 0, result) + self.assertEqual(result.status, 0) bridge = qmf.getObjects(_class="bridge")[0] sleep(3) @@ -262,63 +262,6 @@ class FederationTests(TestBase010): except Empty: None result = bridge.close() - self.assertEqual(result.status, 0, result) - result = link.close() - self.assertEqual(result.status, 0, result) - - self.verify_cleanup() - - def test_pull_from_queue_recovery(self): - session = self.session - - #setup queue on remote broker and add some messages - r_conn = self.connect(host=self.remote_host(), port=self.remote_port()) - r_session = r_conn.session("test_pull_from_queue_recovery") - r_session.queue_declare(queue="my-bridge-queue", auto_delete=True) - for i in range(1, 6): - dp = r_session.delivery_properties(routing_key="my-bridge-queue") - r_session.message_transfer(message=Message(dp, "Message %d" % i)) - - #setup queue to receive messages from local broker - session.queue_declare(queue="fed1", exclusive=True, auto_delete=True) - session.exchange_bind(queue="fed1", exchange="amq.fanout") - self.subscribe(queue="fed1", destination="f1") - queue = session.incoming("f1") - - self.startQmf() - qmf = self.qmf - broker = qmf.getObjects(_class="broker")[0] - result = broker.connect(self.remote_host(), self.remote_port(), False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0, result) - - link = qmf.getObjects(_class="link")[0] - result = link.bridge(False, "my-bridge-queue", "amq.fanout", "my-key", "", "", True, False, False, 1) - self.assertEqual(result.status, 0, result) - - bridge = qmf.getObjects(_class="bridge")[0] - sleep(5) - - #recreate the remote bridge queue to invalidate the bridge session - r_session.queue_delete (queue="my-bridge-queue", if_empty=False, if_unused=False) - r_session.queue_declare(queue="my-bridge-queue", auto_delete=True) - - #add some more messages (i.e. after bridge was created) - for i in range(6, 11): - dp = r_session.delivery_properties(routing_key="my-bridge-queue") - r_session.message_transfer(message=Message(dp, "Message %d" % i)) - - for i in range(1, 11): - try: - msg = queue.get(timeout=5) - self.assertEqual("Message %d" % i, msg.body) - except Empty: - self.fail("Failed to find expected message containing 'Message %d'" % i) - try: - extra = queue.get(timeout=1) - self.fail("Got unexpected message in queue: " + extra.body) - except Empty: None - - result = bridge.close() self.assertEqual(result.status, 0) result = link.close() self.assertEqual(result.status, 0) @@ -706,17 +649,10 @@ class FederationTests(TestBase010): self.verify_cleanup() - def test_dynamic_headers_any(self): - self.do_test_dynamic_headers('any') - - def test_dynamic_headers_all(self): - self.do_test_dynamic_headers('all') - - - def do_test_dynamic_headers(self, match_mode): + def test_dynamic_headers(self): session = self.session r_conn = self.connect(host=self.remote_host(), port=self.remote_port()) - r_session = r_conn.session("test_dynamic_headers_%s" % match_mode) + r_session = r_conn.session("test_dynamic_headers") session.exchange_declare(exchange="fed.headers", type="headers") r_session.exchange_declare(exchange="fed.headers", type="headers") @@ -735,7 +671,7 @@ class FederationTests(TestBase010): sleep(5) session.queue_declare(queue="fed1", exclusive=True, auto_delete=True) - session.exchange_bind(queue="fed1", exchange="fed.headers", binding_key="key1", arguments={'x-match':match_mode, 'class':'first'}) + session.exchange_bind(queue="fed1", exchange="fed.headers", binding_key="key1", arguments={'x-match':'any', 'class':'first'}) self.subscribe(queue="fed1", destination="f1") queue = session.incoming("f1") @@ -1855,301 +1791,3 @@ class FederationTests(TestBase010): if headers: return headers[name] return None - - def test_dynamic_topic_bounce(self): - """ Bounce the connection between federated Topic Exchanges. - """ - class Params: - def exchange_type(self): return "topic" - def bind_queue(self, ssn, qname, ename): - ssn.exchange_bind(queue=qname, exchange=ename, - binding_key="spud.*") - def unbind_queue(self, ssn, qname, ename): - ssn.exchange_unbind(queue=qname, exchange=ename, binding_key="spud.*") - def delivery_properties(self, ssn): - return ssn.delivery_properties(routing_key="spud.boy") - - self.generic_dynamic_bounce_test(Params()) - - def test_dynamic_direct_bounce(self): - """ Bounce the connection between federated Direct Exchanges. - """ - class Params: - def exchange_type(self): return "direct" - def bind_queue(self, ssn, qname, ename): - ssn.exchange_bind(queue=qname, exchange=ename, binding_key="spud") - def unbind_queue(self, ssn, qname, ename): - ssn.exchange_unbind(queue=qname, exchange=ename, binding_key="spud") - def delivery_properties(self, ssn): - return ssn.delivery_properties(routing_key="spud") - self.generic_dynamic_bounce_test(Params()) - - def test_dynamic_fanout_bounce(self): - """ Bounce the connection between federated Fanout Exchanges. - """ - class Params: - def exchange_type(self): return "fanout" - def bind_queue(self, ssn, qname, ename): - ssn.exchange_bind(queue=qname, exchange=ename) - def unbind_queue(self, ssn, qname, ename): - ssn.exchange_unbind(queue=qname, exchange=ename) - def delivery_properties(self, ssn): - return ssn.delivery_properties(routing_key="spud") - self.generic_dynamic_bounce_test(Params()) - - def test_dynamic_headers_bounce(self): - """ Bounce the connection between federated Headers Exchanges. - """ - class Params: - def exchange_type(self): return "headers" - def bind_queue(self, ssn, qname, ename): - ssn.exchange_bind(queue=qname, exchange=ename, - binding_key="spud", arguments={'x-match':'any', 'class':'first'}) - def unbind_queue(self, ssn, qname, ename): - ssn.exchange_unbind(queue=qname, exchange=ename, binding_key="spud") - def delivery_properties(self, ssn): - return ssn.message_properties(application_headers={'class':'first'}) - ## @todo KAG - re-enable once federation bugs with headers exchanges - ## are fixed. - #self.generic_dynamic_bounce_test(Params()) - return - - - def generic_dynamic_bounce_test(self, params): - """ Verify that a federated broker can maintain a binding to a local - queue using the same key as a remote binding. Destroy and reconnect - the federation link, and verify routes are restored correctly. - See QPID-3170. - Topology: - - Queue1 <---"Key"---B0<==[Federated Exchange]==>B1---"Key"--->Queue2 - """ - session = self.session - - # create the federation - - self.startQmf() - qmf = self.qmf - - self._setup_brokers() - - # create exchange on each broker, and retrieve the corresponding - # management object for that exchange - - exchanges=[] - for _b in self._brokers[0:2]: - _b.client_session.exchange_declare(exchange="fedX", type=params.exchange_type()) - self.assertEqual(_b.client_session.exchange_query(name="fedX").type, - params.exchange_type(), "exchange_declare failed!") - # pull the exchange out of qmf... - retries = 0 - my_exchange = None - timeout = time() + 10 - while my_exchange is None and time() <= timeout: - objs = qmf.getObjects(_broker=_b.qmf_broker, _class="exchange") - for ooo in objs: - if ooo.name == "fedX": - my_exchange = ooo - break - if my_exchange is None: - self.fail("QMF failed to find new exchange!") - exchanges.append(my_exchange) - - # - # on each broker, create a local queue bound to the exchange with the - # same key value. - # - - self._brokers[0].client_session.queue_declare(queue="fedX1", exclusive=True, auto_delete=True) - params.bind_queue(self._brokers[0].client_session, "fedX1", "fedX") - self.subscribe(self._brokers[0].client_session, queue="fedX1", destination="f1") - queue_0 = self._brokers[0].client_session.incoming("f1") - - self._brokers[1].client_session.queue_declare(queue="fedX1", exclusive=True, auto_delete=True) - params.bind_queue(self._brokers[1].client_session, "fedX1", "fedX") - self.subscribe(self._brokers[1].client_session, queue="fedX1", destination="f1") - queue_1 = self._brokers[1].client_session.incoming("f1") - - # now federate the two brokers - - # connect B0 --> B1 - result = self._brokers[1].qmf_object.connect(self._brokers[0].host, - self._brokers[0].port, - False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0) - - # connect B1 --> B0 - result = self._brokers[0].qmf_object.connect(self._brokers[1].host, - self._brokers[1].port, - False, "PLAIN", "guest", "guest", "tcp") - self.assertEqual(result.status, 0) - - # for each link, bridge the "fedX" exchanges: - - for _l in qmf.getObjects(_class="link"): - # print("Link=%s:%s %s" % (_l.host, _l.port, str(_l.getBroker()))) - result = _l.bridge(False, # durable - "fedX", # src - "fedX", # dst - "", # key - "", # tag - "", # excludes - False, # srcIsQueue - False, # srcIsLocal - True, # dynamic - 0) # sync - self.assertEqual(result.status, 0) - - # wait for all the inter-broker links to become operational - operational = False - timeout = time() + 10 - while not operational and time() <= timeout: - operational = True - for _l in qmf.getObjects(_class="link"): - #print("Link=%s:%s %s" % (_l.host, _l.port, str(_l.state))) - if _l.state != "Operational": - operational = False - self.failUnless(operational, "inter-broker links failed to become operational.") - - # @todo - There is no way to determine when the bridge objects become - # active. - - # wait until the binding key has propagated to each broker - each - # broker should see 2 bindings (1 local, 1 remote) - - binding_counts = [2, 2] - self.assertEqual(len(binding_counts), len(exchanges), "Update Test!") - for i in range(2): - exchanges[i].update() - timeout = time() + 10 - while exchanges[i].bindingCount < binding_counts[i] and time() <= timeout: - exchanges[i].update() - self.failUnless(exchanges[i].bindingCount == binding_counts[i]) - - # send 10 msgs to B0 - for i in range(1, 11): - # dp = self._brokers[0].client_session.delivery_properties(routing_key=params.routing_key()) - dp = params.delivery_properties(self._brokers[0].client_session) - self._brokers[0].client_session.message_transfer(destination="fedX", message=Message(dp, "Message_trp %d" % i)) - - # get exactly 10 msgs on B0's local queue and B1's queue - for i in range(1, 11): - try: - msg = queue_0.get(timeout=5) - self.assertEqual("Message_trp %d" % i, msg.body) - msg = queue_1.get(timeout=5) - self.assertEqual("Message_trp %d" % i, msg.body) - except Empty: - self.fail("Only got %d msgs - expected 10" % i) - try: - extra = queue_0.get(timeout=1) - self.fail("Got unexpected message in queue_0: " + extra.body) - except Empty: None - - try: - extra = queue_1.get(timeout=1) - self.fail("Got unexpected message in queue_1: " + extra.body) - except Empty: None - - # - # Tear down the bridges between the two exchanges, then wait - # for the bindings to be cleaned up - # - - for _b in qmf.getObjects(_class="bridge"): - result = _b.close() - self.assertEqual(result.status, 0) - - binding_counts = [1, 1] - self.assertEqual(len(binding_counts), len(exchanges), "Update Test!") - for i in range(2): - exchanges[i].update() - timeout = time() + 10 - while exchanges[i].bindingCount != binding_counts[i] and time() <= timeout: - exchanges[i].update() - self.failUnless(exchanges[i].bindingCount == binding_counts[i]) - - # - # restore the bridges between the two exchanges, and wait for the - # bindings to propagate. - # - - for _l in qmf.getObjects(_class="link"): - # print("Link=%s:%s %s" % (_l.host, _l.port, str(_l.getBroker()))) - result = _l.bridge(False, # durable - "fedX", # src - "fedX", # dst - "", # key - "", # tag - "", # excludes - False, # srcIsQueue - False, # srcIsLocal - True, # dynamic - 0) # sync - self.assertEqual(result.status, 0) - - binding_counts = [2, 2] - self.assertEqual(len(binding_counts), len(exchanges), "Update Test!") - for i in range(2): - exchanges[i].update() - timeout = time() + 10 - while exchanges[i].bindingCount != binding_counts[i] and time() <= timeout: - exchanges[i].update() - self.failUnless(exchanges[i].bindingCount == binding_counts[i]) - - # - # verify traffic flows correctly - # - - for i in range(1, 11): - #dp = self._brokers[1].client_session.delivery_properties(routing_key=params.routing_key()) - dp = params.delivery_properties(self._brokers[1].client_session) - self._brokers[1].client_session.message_transfer(destination="fedX", message=Message(dp, "Message_trp %d" % i)) - - # get exactly 10 msgs on B0's queue and B1's queue - for i in range(1, 11): - try: - msg = queue_0.get(timeout=5) - self.assertEqual("Message_trp %d" % i, msg.body) - msg = queue_1.get(timeout=5) - self.assertEqual("Message_trp %d" % i, msg.body) - except Empty: - self.fail("Only got %d msgs - expected 10" % i) - try: - extra = queue_0.get(timeout=1) - self.fail("Got unexpected message in queue_0: " + extra.body) - except Empty: None - - try: - extra = queue_1.get(timeout=1) - self.fail("Got unexpected message in queue_1: " + extra.body) - except Empty: None - - - # - # cleanup - # - params.unbind_queue(self._brokers[0].client_session, "fedX1", "fedX") - self._brokers[0].client_session.message_cancel(destination="f1") - self._brokers[0].client_session.queue_delete(queue="fedX1") - - params.unbind_queue(self._brokers[1].client_session, "fedX1", "fedX") - self._brokers[1].client_session.message_cancel(destination="f1") - self._brokers[1].client_session.queue_delete(queue="fedX1") - - for _b in qmf.getObjects(_class="bridge"): - result = _b.close() - self.assertEqual(result.status, 0) - - for _l in qmf.getObjects(_class="link"): - result = _l.close() - self.assertEqual(result.status, 0) - - for _b in self._brokers[0:2]: - _b.client_session.exchange_delete(exchange="fedX") - - self._teardown_brokers() - - self.verify_cleanup() - - diff --git a/cpp/src/tests/federation_sys.py b/cpp/src/tests/federation_sys.py deleted file mode 100755 index 11590f684e..0000000000 --- a/cpp/src/tests/federation_sys.py +++ /dev/null @@ -1,1900 +0,0 @@ -#!/usr/bin/env python -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -from inspect import stack -from qpid import messaging -from qpid.messaging import Message -from qpid.messaging.exceptions import Empty -from qpid.testlib import TestBase010 -from random import randint -from sys import stdout -from time import sleep - - -class Enum(object): - def __init__(self, **entries): - self.__dict__.update(entries) - def __repr__(self): - args = ['%s=%s' % (k, repr(v)) for (k,v) in vars(self).items()] - return 'Enum(%s)' % ', '.join(args) - - -class QmfTestBase010(TestBase010): - - _brokers = [] - _links = [] - _bridges = [] - _alt_exch_ops = Enum(none=0, create=1, delete=2) - - class _Broker(object): - """ - This broker proxy object holds the Qmf proxy to a broker of known address as well as the QMF broker - object, connection and sessions to the broker. - """ - def __init__(self, url): - self.url = url # format: "host:port" - url_parts = url.split(':') - self.host = url_parts[0] - self.port = int(url_parts[1]) - self.qmf_broker = None - self.connection = messaging.Connection.establish(self.url) - self.sessions = [] - def __str__(self): - return "_Broker %s:%s (%d open sessions)" % (self.host, self.port, len(self.sessions)) - def destroy(self, qmf = None): - if qmf is not None: - qmf.delBroker(self.qmf_broker.getBroker()) - for session in self.sessions: - try: # Session may have been closed by broker error - session.close() - except Exception, e: print "WARNING: %s: Unable to close session %s (%s): %s %s" % (self, session, hex(id(session)), type(e), e) - try: # Connection may have been closed by broker error - self.connection.close() - except Exception, e: print "WARNING: %s: Unable to close connection %s (%s): %s %s" % (self, self.connection, hex(id(self.connection)), type(e), e) - def session(self, name, transactional_flag = False): - session = self.connection.session(name, transactional_flag) - self.sessions.append(session) - return session - - def setUp(self): - """ - Called one before each test starts - """ - TestBase010.setUp(self) - self.startQmf(); - - def tearDown(self): - """ - Called once after each test competes. Close all Qmf objects (bridges, links and brokers) - """ - while len(self._bridges): - self._bridges.pop().close() - while len(self._links): - self._links.pop().close() - while len(self._brokers): - b = self._brokers.pop() - if len(self._brokers) <= 1: - b.destroy(None) - else: - b.destroy(self.qmf) - TestBase010.tearDown(self) - self.qmf.close() - - #--- General test utility functions - - def _get_name(self): - """ - Return the name of method which called this method stripped of "test_" prefix. Used for naming - queues and exchanges on a per-test basis. - """ - return stack()[1][3][5:] - - def _get_broker_port(self, key): - """ - Get the port of a broker defined in the environment using -D<key>=portno - """ - return int(self.defines[key]) - - def _get_cluster_ports(self, key): - """ - Get the cluster ports from the parameters of the test which place it in the environment using - -D<key>="port0 port1 ... portN" (space-separated) - """ - ports = [] - ports_str = self.defines[key] - if ports_str: - for p in ports_str.split(): - ports.append(int(p)) - return ports - - def _get_send_address(self, exch_name, queue_name): - """ - Get an address to which to send messages based on the exchange name and queue name, but taking into account - that the exchange name may be "" (the default exchange), in whcih case the format changes slightly. - """ - if len(exch_name) == 0: # Default exchange - return queue_name - return "%s/%s" % (exch_name, queue_name) - - def _get_broker(self, cluster_flag, broker_port_key, cluster_ports_key): - """ - Read the port numbers for pre-started brokers from the environment using keys, then find or create and return - the Qmf broker proxy for the appropriate broker - """ - if cluster_flag: - port = self._get_cluster_ports(cluster_ports_key)[0] # Always use the first node in the cluster - else: - port = self._get_broker_port(broker_port_key) - return self._find_create_broker("localhost:%s" % port) - - def _get_msg_subject(self, topic_key): - """ - Return an appropriate subject for sending a message to a known topic. Return None if there is no topic. - """ - if len(topic_key) == 0: return None - if "*" in topic_key: return topic_key.replace("*", "test") - if "#" in topic_key: return topic_key.replace("#", "multipart.test") - return topic_key - - def _send_msgs(self, session_name, broker, addr, msg_count, msg_content = "Message_%03d", topic_key = "", - msg_durable_flag = False, enq_txn_size = 0): - """ - Send messages to a broker using address addr - """ - send_session = broker.session(session_name, transactional_flag = enq_txn_size > 0) - sender = send_session.sender(addr) - txn_cnt = 0 - for i in range(0, msg_count): - sender.send(Message(msg_content % (i + 1), subject = self._get_msg_subject(topic_key), durable = msg_durable_flag)) - if enq_txn_size > 0: - txn_cnt += 1 - if txn_cnt >= enq_txn_size: - send_session.commit() - txn_cnt = 0 - if enq_txn_size > 0 and txn_cnt > 0: - send_session.commit() - sender.close() - send_session.close() - - def _receive_msgs(self, session_name, broker, addr, msg_count, msg_content = "Message_%03d", deq_txn_size = 0, - timeout = 0): - """ - Receive messages from a broker - """ - receive_session = broker.session(session_name, transactional_flag = deq_txn_size > 0) - receiver = receive_session.receiver(addr) - txn_cnt = 0 - for i in range(0, msg_count): - try: - msg = receiver.fetch(timeout = timeout) - if deq_txn_size > 0: - txn_cnt += 1 - if txn_cnt >= deq_txn_size: - receive_session.commit() - txn_cnt = 0 - receive_session.acknowledge() - except Empty: - if deq_txn_size > 0: receive_session.rollback() - receiver.close() - receive_session.close() - if i == 0: - self.fail("Broker %s queue \"%s\" is empty" % (broker.qmf_broker.getBroker().getUrl(), addr)) - else: - self.fail("Unable to receive message %d from broker %s queue \"%s\"" % (i, broker.qmf_broker.getBroker().getUrl(), addr)) - if msg.content != msg_content % (i + 1): - receiver.close() - receive_session.close() - self.fail("Unexpected message \"%s\", was expecting \"%s\"." % (msg.content, msg_content % (i + 1))) - try: - msg = receiver.fetch(timeout = 0) - if deq_txn_size > 0: receive_session.rollback() - receiver.close() - receive_session.close() - self.fail("Extra message \"%s\" found on broker %s address \"%s\"" % (msg.content, broker.qmf_broker.getBroker().getUrl(), addr)) - except Empty: - pass - if deq_txn_size > 0 and txn_cnt > 0: - receive_session.commit() - receiver.close() - receive_session.close() - - #--- QMF-specific utility functions - - def _get_qmf_property(self, props, key): - """ - Get the value of a named property key kj from a property list [(k0, v0), (k1, v1), ... (kn, vn)]. - """ - for k,v in props: - if k.name == key: - return v - return None - - def _check_qmf_return(self, method_result): - """ - Check the result of a Qmf-defined method call - """ - self.assertTrue(method_result.status == 0, method_result.text) - - def _check_optional_qmf_property(self, qmf_broker, type, qmf_object, key, expected_val, obj_ref_flag): - """ - Optional Qmf properties don't show up in the properties list when they are not specified. Checks for - these property types involve searching the properties list and making sure it is present or not as - expected. - """ - val = self._get_qmf_property(qmf_object.getProperties(), key) - if val is None: - if len(expected_val) > 0: - self.fail("%s %s exists, but has does not have %s property. Expected value: \"%s\"" % - (type, qmf_object.name, key, expected_val)) - else: - if len(expected_val) > 0: - if obj_ref_flag: - obj = self.qmf.getObjects(_objectId = val, _broker = qmf_broker.getBroker()) - self.assertEqual(len(obj), 1, "More than one object with the same objectId: %s" % obj) - val = obj[0].name - self.assertEqual(val, expected_val, "%s %s exists, but has incorrect %s property. Found \"%s\", expected \"%s\"" % - (type, qmf_object.name, key, val, expected_val)) - else: - self.fail("%s %s exists, but has an unexpected %s property \"%s\" set." % (type, qmf_object.name, key, val)) - - #--- Find/create Qmf broker objects - - def _find_qmf_broker(self, url): - """ - Find the Qmf broker object for the given broker URL. The broker must have been previously added to Qmf through - addBroker() - """ - for b in self.qmf.getObjects(_class="broker"): - if b.getBroker().getUrl() == url: - return b - return None - - def _find_create_broker(self, url): - """ - Find a running broker through Qmf. If it does not exist, add it (assuming the broker is already running). - """ - broker = self._Broker(url) - self._brokers.append(broker) - if self.qmf is not None: - qmf_broker = self._find_qmf_broker(broker.url) - if qmf_broker is None: - self.qmf.addBroker(broker.url) - broker.qmf_broker = self._find_qmf_broker(broker.url) - else: - broker.qmf_broker = qmf_broker - return broker - - #--- Find/create/delete exchanges - - def _find_qmf_exchange(self, qmf_broker, name, type, alternate, durable, auto_delete): - """ - Find Qmf exchange object - """ - for e in self.qmf.getObjects(_class="exchange", _broker = qmf_broker.getBroker()): - if e.name == name: - if len(name) == 0 or (len(name) >= 4 and name[:4] == "amq."): return e # skip checks for special exchanges - self.assertEqual(e.type, type, - "Exchange \"%s\" exists, but is of unexpected type %s; expected type %s." % - (name, e.type, type)) - self._check_optional_qmf_property(qmf_broker, "Exchange", e, "altExchange", alternate, True) - self.assertEqual(e.durable, durable, - "Exchange \"%s\" exists, but has incorrect durability. Found durable=%s, expected durable=%s" % - (name, e.durable, durable)) - self.assertEqual(e.autoDelete, auto_delete, - "Exchange \"%s\" exists, but has incorrect auto-delete property. Found %s, expected %s" % - (name, e.autoDelete, auto_delete)) - return e - return None - - def _find_create_qmf_exchange(self, qmf_broker, name, type, alternate, durable, auto_delete, args): - """ - Find Qmf exchange object if exchange exists, create exchange and return its Qmf object if not - """ - e = self._find_qmf_exchange(qmf_broker, name, type, alternate, durable, auto_delete) - if e is not None: return e - # Does not exist, so create it - props = dict({"exchange-type": type, "type": type, "durable": durable, "auto-delete": auto_delete, "alternate-exchange": alternate}, **args) - self._check_qmf_return(qmf_broker.create(type="exchange", name=name, properties=props, strict=True)) - e = self._find_qmf_exchange(qmf_broker, name, type, alternate, durable, auto_delete) - self.assertNotEqual(e, None, "Creation of exchange %s on broker %s failed" % (name, qmf_broker.getBroker().getUrl())) - return e - - def _find_delete_qmf_exchange(self, qmf_broker, name, type, alternate, durable, auto_delete): - """ - Find and delete Qmf exchange object if it exists - """ - e = self._find_qmf_exchange(qmf_broker, name, type, alternate, durable, auto_delete) - if e is not None and not auto_delete: - self._check_qmf_return(qmf_broker.delete(type="exchange", name=name, options={})) - - #--- Find/create/delete queues - - def _find_qmf_queue(self, qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete): - """ - Find a Qmf queue object - """ - for q in self.qmf.getObjects(_class="queue", _broker = qmf_broker.getBroker()): - if q.name == name: - self._check_optional_qmf_property(qmf_broker, "Queue", q, "altExchange", alternate_exchange, True) - self.assertEqual(q.durable, durable, - "Queue \"%s\" exists, but has incorrect durable property. Found %s, expected %s" % - (name, q.durable, durable)) - self.assertEqual(q.exclusive, exclusive, - "Queue \"%s\" exists, but has incorrect exclusive property. Found %s, expected %s" % - (name, q.exclusive, exclusive)) - self.assertEqual(q.autoDelete, auto_delete, - "Queue \"%s\" exists, but has incorrect auto-delete property. Found %s, expected %s" % - (name, q.autoDelete, auto_delete)) - return q - return None - - def _find_create_qmf_queue(self, qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete, args): - """ - Find Qmf queue object if queue exists, create queue and return its Qmf object if not - """ - q = self._find_qmf_queue(qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete) - if q is not None: return q - # Queue does not exist, so create it - props = dict({"durable": durable, "auto-delete": auto_delete, "exclusive": exclusive, "alternate-exchange": alternate_exchange}, **args) - self._check_qmf_return(qmf_broker.create(type="queue", name=name, properties=props, strict=True)) - q = self._find_qmf_queue(qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete) - self.assertNotEqual(q, None, "Creation of queue %s on broker %s failed" % (name, qmf_broker.getBroker().getUrl())) - return q - - def _find_delete_qmf_queue(self, qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete, args): - """ - Find and delete Qmf queue object if it exists - """ - q = self._find_qmf_queue(qmf_broker, name, alternate_exchange, durable, exclusive, auto_delete) - if q is not None and not auto_delete: - self._check_qmf_return(qmf_broker.delete(type="queue", name=name, options={})) - - #--- Find/create/delete bindings (between an exchange and a queue) - - def _find_qmf_binding(self, qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args): - """ - Find a Qmf binding object - """ - for b in self.qmf.getObjects(_class="binding", _broker = qmf_broker.getBroker()): - if b.exchangeRef == qmf_exchange.getObjectId() and b.queueRef == qmf_queue.getObjectId(): - if qmf_exchange.type != "fanout": # Fanout ignores the binding key, and always returns "" as the key - self.assertEqual(b.bindingKey, binding_key, - "Binding between exchange %s and queue %s exists, but has mismatching binding key: Found %s, expected %s." % - (qmf_exchange.name, qmf_queue.name, b.bindingKey, binding_key)) - self.assertEqual(b.arguments, binding_args, - "Binding between exchange %s and queue %s exists, but has mismatching arguments: Found %s, expected %s" % - (qmf_exchange.name, qmf_queue.name, b.arguments, binding_args)) - return b - return None - - def _find_create_qmf_binding(self, qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args): - """ - Find Qmf binding object if it exists, create binding and return its Qmf object if not - """ - b = self._find_qmf_binding(qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args) - if b is not None: return b - # Does not exist, so create it - self._check_qmf_return(qmf_broker.create(type="binding", name="%s/%s/%s" % (qmf_exchange.name, qmf_queue.name, binding_key), properties=binding_args, strict=True)) - b = self._find_qmf_binding(qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args) - self.assertNotEqual(b, None, "Creation of binding between exchange %s and queue %s with key %s failed" % - (qmf_exchange.name, qmf_queue.name, binding_key)) - return b - - def _find_delete_qmf_binding(self, qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args): - """ - Find and delete Qmf binding object if it exists - """ - b = self._find_qmf_binding(qmf_broker, qmf_exchange, qmf_queue, binding_key, binding_args) - if b is not None: - if len(qmf_exchange.name) > 0: # not default exchange - self._check_qmf_return(qmf_broker.delete(type="binding", name="%s/%s/%s" % (qmf_exchange.name, qmf_queue.name, binding_key), options={})) - - #--- Find/create a link - - def _find_qmf_link(self, qmf_from_broker_proxy, host, port): - """ - Find a Qmf link object - """ - for l in self.qmf.getObjects(_class="link", _broker=qmf_from_broker_proxy): - if l.host == host and l.port == port: - return l - return None - - def _find_create_qmf_link(self, qmf_from_broker, qmf_to_broker_proxy, link_durable_flag, auth_mechanism, user_id, - password, transport, pause_interval, link_ready_timeout): - """ - Find a Qmf link object if it exists, create it and return its Qmf link object if not - """ - to_broker_host = qmf_to_broker_proxy.host - to_broker_port = qmf_to_broker_proxy.port - l = self._find_qmf_link(qmf_from_broker.getBroker(), to_broker_host, to_broker_port) - if l is not None: return l - # Does not exist, so create it - self._check_qmf_return(qmf_from_broker.connect(to_broker_host, to_broker_port, link_durable_flag, auth_mechanism, user_id, password, transport)) - l = self._find_qmf_link(qmf_from_broker.getBroker(), to_broker_host, to_broker_port) - self.assertNotEqual(l, None, "Creation of link from broker %s to broker %s failed" % - (qmf_from_broker.getBroker().getUrl(), qmf_to_broker_proxy.getUrl())) - self._wait_for_link(l, pause_interval, link_ready_timeout) - return l - - def _wait_for_link(self, link, pause_interval, link_ready_timeout): - """ - Wait for link to become active (state=Operational) - """ - tot_time = 0 - link.update() - if link.state == "": - # Link mgmt updates for the c++ link object are disabled when in a cluster because of inconsistent state: - # one is "Operational", the other "Passive". In this case, wait a bit and hope for the best... - sleep(2*pause_interval) - else: - while link.state != "Operational" and tot_time < link_ready_timeout: - sleep(pause_interval) - tot_time += pause_interval - link.update() - self.assertEqual(link.state, "Operational", "Timeout: Link not operational, state=%s" % link.state) - - #--- Find/create a bridge - - def _find_qmf_bridge(self, qmf_broker_proxy, qmf_link, source, destination, key): - """ - Find a Qmf link object - """ - for b in self.qmf.getObjects(_class="bridge", _broker=qmf_broker_proxy): - if b.linkRef == qmf_link.getObjectId() and b.src == source and b.dest == destination and b.key == key: - return b - return None - - def _find_create_qmf_bridge(self, qmf_broker_proxy, qmf_link, queue_name, exch_name, topic_key, - queue_route_type_flag, bridge_durable_flag): - """ - Find a Qmf bridge object if it exists, create it and return its Qmf object if not - """ - if queue_route_type_flag: - src = queue_name - dest = exch_name - key = "" - else: - src = exch_name - dest = exch_name - if len(topic_key) > 0: - key = topic_key - else: - key = queue_name - b = self._find_qmf_bridge(qmf_broker_proxy, qmf_link, src, dest, key) - if b is not None: - return b - # Does not exist, so create it - self._check_qmf_return(qmf_link.bridge(bridge_durable_flag, src, dest, key, "", "", queue_route_type_flag, False, False, 1)) - b = self._find_qmf_bridge(qmf_broker_proxy, qmf_link, src, dest, key) - self.assertNotEqual(b, None, "Bridge creation failed: src=%s dest=%s key=%s" % (src, dest, key)) - return b - - def _wait_for_bridge(self, bridge, src_broker, dest_broker, exch_name, queue_name, topic_key, pause_interval, - bridge_ready_timeout): - """ - Wait for bridge to become active by sending messages over the bridge at 1 sec intervals until they are - observed at the destination. - """ - tot_time = 0 - active = False - send_session = src_broker.session("tx") - sender = send_session.sender(self._get_send_address(exch_name, queue_name)) - src_receive_session = src_broker.session("src_rx") - src_receiver = src_receive_session.receiver(queue_name) - dest_receive_session = dest_broker.session("dest_rx") - dest_receiver = dest_receive_session.receiver(queue_name) - while not active and tot_time < bridge_ready_timeout: - sender.send(Message("xyz123", subject = self._get_msg_subject(topic_key))) - try: - src_receiver.fetch(timeout = 0) - src_receive_session.acknowledge() - # Keep receiving msgs, as several may have accumulated - while True: - dest_receiver.fetch(timeout = 0) - dest_receive_session.acknowledge() - sleep(1) - active = True - except Empty: - sleep(pause_interval) - tot_time += pause_interval - dest_receiver.close() - dest_receive_session.close() - src_receiver.close() - src_receive_session.close() - sender.close() - send_session.close() - self.assertTrue(active, "Bridge failed to become active after %ds: %s" % (bridge_ready_timeout, bridge)) - - #--- Find/create/delete utility functions - - def _create_and_bind(self, qmf_broker, exchange_args, queue_args, binding_args): - """ - Create a binding between a named exchange and queue on a broker - """ - e = self._find_create_qmf_exchange(qmf_broker, **exchange_args) - q = self._find_create_qmf_queue(qmf_broker, **queue_args) - return self._find_create_qmf_binding(qmf_broker, e, q, **binding_args) - - def _check_alt_exchange(self, qmf_broker, alt_exch_name, alt_exch_type, alt_exch_op): - """ - Check for existence of alternate exchange. Return the Qmf exchange proxy object for the alternate exchange - """ - if len(alt_exch_name) == 0: return None - if alt_exch_op == _alt_exch_ops.create: - return self._find_create_qmf_exchange(qmf_broker=qmf_broker, name=alt_exch_name, type=alt_exch_type, - alternate="", durable=False, auto_delete=False, args={}) - if alt_exch_op == _alt_exch_ops.delete: - return self._find_delete_qmf_exchange(qmf_broker=qmf_broker, name=alt_exch_name, type=alt_exch_type, - alternate="", durable=False, auto_delete=False) - return self._find_qmf_exchange(qmf_broker=qmf_broker, name=alt_exchange_name, type=alt_exchange_type, - alternate="", durable=False, auto_delete=False) - - def _delete_queue_binding(self, qmf_broker, exchange_args, queue_args, binding_args): - """ - Delete a queue and the binding between it and the exchange - """ - e = self._find_qmf_exchange(qmf_broker, exchange_args["name"], exchange_args["type"], exchange_args["alternate"], exchange_args["durable"], exchange_args["auto_delete"]) - q = self._find_qmf_queue(qmf_broker, queue_args["name"], queue_args["alternate_exchange"], queue_args["durable"], queue_args["exclusive"], queue_args["auto_delete"]) - self._find_delete_qmf_binding(qmf_broker, e, q, **binding_args) - self._find_delete_qmf_queue(qmf_broker, **queue_args) - - def _create_route(self, queue_route_type_flag, src_broker, dest_broker, exch_name, queue_name, topic_key, - link_durable_flag, bridge_durable_flag, auth_mechanism, user_id, password, transport, - pause_interval = 1, link_ready_timeout = 20, bridge_ready_timeout = 20): - """ - Create a route from a source broker to a destination broker - """ - l = self._find_create_qmf_link(dest_broker.qmf_broker, src_broker.qmf_broker.getBroker(), link_durable_flag, - auth_mechanism, user_id, password, transport, pause_interval, link_ready_timeout) - self._links.append(l) - b = self._find_create_qmf_bridge(dest_broker.qmf_broker.getBroker(), l, queue_name, exch_name, topic_key, - queue_route_type_flag, bridge_durable_flag) - self._bridges.append(b) - self._wait_for_bridge(b, src_broker, dest_broker, exch_name, queue_name, topic_key, pause_interval, bridge_ready_timeout) - - # Parameterized test - entry point for tests - - def _do_test(self, - test_name, # Name of test - exch_name = "amq.direct", # Remote exchange name - exch_type = "direct", # Remote exchange type - exch_alt_exch = "", # Remote exchange alternate exchange - exch_alt_exch_type = "direct", # Remote exchange alternate exchange type - exch_durable_flag = False, # Remote exchange durability - exch_auto_delete_flag = False, # Remote exchange auto-delete property - exch_x_args = {}, # Remote exchange args - queue_alt_exch = "", # Remote queue alternate exchange - queue_alt_exch_type = "direct", # Remote queue alternate exchange type - queue_durable_flag = False, # Remote queue durability - queue_exclusive_flag = False, # Remote queue exclusive property - queue_auto_delete_flag = False, # Remote queue auto-delete property - queue_x_args = {}, # Remote queue args - binding_durable_flag = False, # Remote binding durability - binding_x_args = {}, # Remote binding args - topic_key = "", # Binding key For remote topic exchanges only - msg_count = 10, # Number of messages to send - msg_durable_flag = False, # Message durability - link_durable_flag = False, # Route link durability - bridge_durable_flag = False, # Route bridge durability - queue_route_type_flag = False, # Route type: false = bridge route, true = queue route - enq_txn_size = 0, # Enqueue transaction size, 0 = no transactions - deq_txn_size = 0, # Dequeue transaction size, 0 = no transactions - local_cluster_flag = False, # Use a node from the local cluster, otherwise use single local broker - remote_cluster_flag = False, # Use a node from the remote cluster, otherwise use single remote broker - alt_exch_op = _alt_exch_ops.create,# Op on alt exch [create (ensure present), delete (ensure not present), none (neither create nor delete)] - auth_mechanism = "", # Authorization mechanism for linked broker - user_id = "", # User ID for authorization on linked broker - password = "", # Password for authorization on linked broker - transport = "tcp" # Transport for route to linked broker - ): - """ - Parameterized federation test. Sets up a federated link between a source broker and a destination broker and - checks that messages correctly pass over the link to the destination. Where appropriate (non-queue-routes), also - checks for the presence of messages on the source broker. - - In these tests, the concept is to create a LOCAL broker, then create a link to a REMOTE broker using federation. - In other words, the messages sent to the LOCAL broker will be replicated on the REMOTE broker, and tests are - performed on the REMOTE broker to check that the required messages are present. In the case of regular routes, - the LOCAL broker will also retain the messages, and a similar test is performed on this broker. - - TODO: There are several items to improve here: - 1. _do_test() is rather general. Rather create a version for each exchange type and test the exchange/queue - interaction in more detail based on the exchange type - 2. Add a headers and an xml exchange type - 3. Restructure the tests to start and stop brokers and clusters directly rather than relying on previously - started brokers. Then persistence can be checked by stopping and restarting the brokers/clusters. In particular, - test the persistence of links and bridges, both of which take a persistence flag. - 4. Test the behavior of the alternate exchanges when messages are sourced through a link. Also check behavior - when the alternate exchange is not present or is deleted after the reference is made. - 5. Test special queue types (eg LVQ) - """ - local_broker = self._get_broker(local_cluster_flag, "local-port", "local-cluster-ports") - remote_broker = self._get_broker(remote_cluster_flag, "remote-port", "remote-cluster-ports") - - # Check alternate exchanges exist (and create them if not) on both local and remote brokers - self._check_alt_exchange(local_broker.qmf_broker, exch_alt_exch, exch_alt_exch_type, alt_exch_op) - self._check_alt_exchange(local_broker.qmf_broker, queue_alt_exch, queue_alt_exch_type, alt_exch_op) - self._check_alt_exchange(remote_broker.qmf_broker, exch_alt_exch, exch_alt_exch_type, alt_exch_op) - self._check_alt_exchange(remote_broker.qmf_broker, queue_alt_exch, queue_alt_exch_type, alt_exch_op) - - queue_name = "queue_%s" % test_name - exchange_args = {"name": exch_name, "type": exch_type, "alternate": exch_alt_exch, - "durable": exch_durable_flag, "auto_delete": exch_auto_delete_flag, "args": exch_x_args} - queue_args = {"name": queue_name, "alternate_exchange": queue_alt_exch, "durable": queue_durable_flag, - "exclusive": queue_exclusive_flag, "auto_delete": queue_auto_delete_flag, "args": queue_x_args} - binding_args = {"binding_args": binding_x_args} - if exch_type == "topic": - self.assertTrue(len(topic_key) > 0, "Topic exchange selected, but no topic key was set.") - binding_args["binding_key"] = topic_key - elif exch_type == "direct": - binding_args["binding_key"] = queue_name - else: - binding_args["binding_key"] = "" - self._create_and_bind(qmf_broker=local_broker.qmf_broker, exchange_args=exchange_args, queue_args=queue_args, binding_args=binding_args) - self._create_and_bind(qmf_broker=remote_broker.qmf_broker, exchange_args=exchange_args, queue_args=queue_args, binding_args=binding_args) - self._create_route(queue_route_type_flag, local_broker, remote_broker, exch_name, queue_name, topic_key, - link_durable_flag, bridge_durable_flag, auth_mechanism, user_id, password, transport) - - self._send_msgs("send_session", local_broker, addr = self._get_send_address(exch_name, queue_name), - msg_count = msg_count, topic_key = topic_key, msg_durable_flag = msg_durable_flag, enq_txn_size = enq_txn_size) - if not queue_route_type_flag: - self._receive_msgs("local_receive_session", local_broker, addr = queue_name, msg_count = msg_count, deq_txn_size = deq_txn_size) - self._receive_msgs("remote_receive_session", remote_broker, addr = queue_name, msg_count = msg_count, deq_txn_size = deq_txn_size, timeout = 5) - - # Clean up - self._delete_queue_binding(qmf_broker=local_broker.qmf_broker, exchange_args=exchange_args, queue_args=queue_args, binding_args=binding_args) - self._delete_queue_binding(qmf_broker=remote_broker.qmf_broker, exchange_args=exchange_args, queue_args=queue_args, binding_args=binding_args) - -class A_ShortTests(QmfTestBase010): - - def test_route_defaultExch(self): - self._do_test(self._get_name()) - - def test_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True) - - -class A_LongTests(QmfTestBase010): - - def test_route_amqDirectExch(self): - self._do_test(self._get_name(), exch_name="amq.direct") - - def test_queueRoute_amqDirectExch(self): - self._do_test(self._get_name(), exch_name="amq.direct", queue_route_type_flag=True) - - - def test_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange") - - def test_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True) - - - def test_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout") - - def test_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True) - - - def test_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#") - - def test_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True) - - -class B_ShortTransactionTests(QmfTestBase010): - - def test_txEnq01_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1) - - def test_txEnq01_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_txDeq01_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - -class B_LongTransactionTests(QmfTestBase010): - - def test_txEnq10_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - - - - def test_txEnq01_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1) - - def test_txEnq01_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - - def test_txEnq01_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1) - - def test_txEnq01_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - - def test_txEnq01_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1) - - def test_txEnq01_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - -class C_ShortClusterTests(QmfTestBase010): - - def test_locCluster_route_defaultExch(self): - self._do_test(self._get_name(), local_cluster_flag=True) - - def test_locCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), remote_cluster_flag=True) - - def test_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - -class C_LongClusterTests(QmfTestBase010): - - def test_locCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", local_cluster_flag=True) - - def test_locCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", remote_cluster_flag=True) - - def test_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_locCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", local_cluster_flag=True) - - def test_locCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", remote_cluster_flag=True) - - def test_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_locCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", local_cluster_flag=True) - - def test_locCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", remote_cluster_flag=True) - - def test_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - -class D_ShortClusterTransactionTests(QmfTestBase010): - - def test_txEnq01_locCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - -class D_LongClusterTransactionTests(QmfTestBase010): - - def test_txEnq10_locCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_defaultExch(self): - self._do_test(self._get_name(), enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_defaultExch(self): - self._do_test(self._get_name(), queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_txEnq01_locCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_txEnq01_locCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_txEnq01_locCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - -class E_ShortPersistenceTests(QmfTestBase010): - - def test_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True) - - def test_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True) - - def test_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True) - - def test_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True) - - -class E_LongPersistenceTests(QmfTestBase010): - - - def test_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True) - - def test_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True) - - def test_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True) - - def test_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True) - - - def test_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True) - - def test_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True) - - def test_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True) - - def test_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True) - - - def test_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True) - - def test_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True) - - def test_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True) - - def test_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True) - - -class F_ShortPersistenceTransactionTests(QmfTestBase010): - - def test_txEnq01_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_txDeq01_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - -class F_LongPersistenceTransactionTests(QmfTestBase010): - - def test_txEnq10_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - - - - def test_txEnq01_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - - def test_txEnq01_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - - def test_txEnq01_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq01_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1) - - def test_txEnq10_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq10_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103) - - def test_txEnq01_txDeq01_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - def test_txEnq01_txDeq01_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1) - - -class G_ShortPersistenceClusterTests(QmfTestBase010): - - def test_locCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - -class G_LongPersistenceClusterTests(QmfTestBase010): - - - - def test_locCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_locCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_locCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_locCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True) - - def test_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - def test_locCluster_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, local_cluster_flag=True, remote_cluster_flag=True) - - -class H_ShortPersistenceClusterTransactionTests(QmfTestBase010): - - def test_txEnq01_locCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - -class H_LongPersistenceClusterTransactionTests(QmfTestBase010): - - def test_txEnq10_locCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durQueue_defaultExch(self): - self._do_test(self._get_name(), queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durMsg_durQueue_defaultExch(self): - self._do_test(self._get_name(), msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - - - - def test_txEnq01_locCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durMsg_durQueue_directExch(self): - self._do_test(self._get_name(), exch_name="testDirectExchange", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_txEnq01_locCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durMsg_durQueue_fanoutExch(self): - self._do_test(self._get_name(), exch_name="testFanoutExchange", exch_type="fanout", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - - def test_txEnq01_locCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_locCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq10_locCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True) - - def test_txEnq01_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq10_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_locCluster_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq10_locCluster_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=10, msg_count = 103, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_route_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - - def test_txEnq01_txDeq01_locCluster_remCluster_queueRoute_durMsg_durQueue_topicExch(self): - self._do_test(self._get_name(), exch_name="testTopicExchange", exch_type="topic", topic_key=self._get_name()+".#", msg_durable_flag=True, queue_durable_flag=True, queue_route_type_flag=True, enq_txn_size=1, deq_txn_size=1, local_cluster_flag=True, remote_cluster_flag=True) - diff --git a/cpp/src/tests/ipv6_test b/cpp/src/tests/ipv6_test deleted file mode 100755 index d75d50fd0a..0000000000 --- a/cpp/src/tests/ipv6_test +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Run a simple test over IPv6 -source ./test_env.sh - -CONFIG=$(dirname $0)/config.null -TEST_HOSTNAME=::1 -COUNT=10 - -trap cleanup EXIT - -error() { echo $*; exit 1; } - -# Don't need --no-module-dir or --no-data-dir as they are set as env vars in test_env.sh -COMMON_OPTS="--daemon --auth no --config $CONFIG" - -# Record all broker ports started -unset PORTS -declare -a PORTS - -# Start new brokers: -# $1 must be integer -# $2 = extra opts -# Append used ports to PORTS variable -start_brokers() { - local -a ports - for (( i=0; $i<$1; i++)) do - ports[$i]=$($QPIDD_EXEC --port 0 $COMMON_OPTS $2) - done - PORTS=( ${PORTS[@]} ${ports[@]} ) -} - -stop_brokers() { - for port in "${PORTS[@]}"; - do - $QPIDD_EXEC -qp $port - done - PORTS=() -} - -cleanup() { - stop_brokers -} - -start_brokers 1 -PORT=${PORTS[0]} -echo "Started IPv6 smoke perftest on broker port $PORT" - -## Test connection via connection settings -./qpid-perftest --count ${COUNT} --port ${PORT} -b $TEST_HOSTNAME --summary - -## Test connection with a URL -URL="amqp:[$TEST_HOSTNAME]:$PORT" - -./qpid-send -b $URL --content-string=hello -a "foo;{create:always}" -MSG=`./qpid-receive -b $URL -a "foo;{create:always}" --messages 1` -test "$MSG" = "hello" || { echo "receive failed '$MSG' != 'hello'"; exit 1; } - -stop_brokers - -# Federation smoke test follows - -# Start 2 brokers - -# In a distribution, the python tools will be absent. -if [ ! -f $QPID_CONFIG_EXEC ] || [ ! -f $QPID_ROUTE_EXEC ] ; then - echo "python tools absent - skipping federation test." -else - - start_brokers 2 - echo "Started Federated brokers on ports ${PORTS[*]}" - # Make broker urls - BROKER0="[::1]:${PORTS[0]}" - BROKER1="[::1]:${PORTS[1]}" - TEST_QUEUE=ipv6-fed-test - - $QPID_CONFIG_EXEC -a $BROKER0 add queue $TEST_QUEUE - $QPID_CONFIG_EXEC -a $BROKER1 add queue $TEST_QUEUE - $QPID_ROUTE_EXEC dynamic add $BROKER1 $BROKER0 amq.direct - $QPID_CONFIG_EXEC -a $BROKER1 bind amq.direct $TEST_QUEUE $TEST_QUEUE - $QPID_ROUTE_EXEC route map $BROKER1 - - ./datagen --count 100 | tee rdata-in | - ./qpid-send -b amqp:$BROKER0 -a amq.direct/$TEST_QUEUE --content-stdin - ./qpid-receive -b amqp:$BROKER1 -a $TEST_QUEUE --print-content yes -m 0 > rdata-out - - cmp rdata-in rdata-out || { echo "Federated data over IPv6 does not compare"; exit 1; } - - stop_brokers - rm rdata-in rdata-out -fi - -# Cluster smoke test follows -test -z $CLUSTER_LIB && exit 0 # Exit if cluster not supported. - -## Test failover in a cluster using IPv6 only -. $srcdir/ais_check # Will exit if clustering not enabled. - -pick_port() { - # We need a fixed port to set --cluster-url. Use qpidd to pick a free port. - # Note this method is racy - PICK=$($QPIDD_EXEC -dp0) - $QPIDD_EXEC -qp $PICK - echo $PICK -} - -ssl_cluster_broker() { # $1 = port - $QPIDD_EXEC $COMMON_OPTS --load-module $CLUSTER_LIB --cluster-name ipv6_test.$HOSTNAME.$$ --cluster-url amqp:[$TEST_HOSTNAME]:$1 --port $1 - # Wait for broker to be ready - ./qpid-ping -b $TEST_HOSTNAME -qp $1 || { echo "Cannot connect to broker on $1"; exit 1; } - echo "Running IPv6 cluster broker on port $1" -} - -PORT1=`pick_port`; ssl_cluster_broker $PORT1 -PORT2=`pick_port`; ssl_cluster_broker $PORT2 - -# Pipe receive output to uniq to remove duplicates -./qpid-receive --connection-options "{reconnect:true, reconnect-timeout:5}" --failover-updates -b amqp:[$TEST_HOSTNAME]:$PORT1 -a "foo;{create:always}" -f | uniq > ssl_test_receive.tmp & - -./qpid-send -b amqp:[$TEST_HOSTNAME]:$PORT2 --content-string=one -a "foo;{create:always}" - -$QPIDD_EXEC -qp $PORT1 # Kill broker 1 receiver should fail-over. -./qpid-send -b amqp:[$TEST_HOSTNAME]:$PORT2 --content-string=two -a "foo;{create:always}" --send-eos 1 -wait # Wait for qpid-receive -{ echo one; echo two; } > ssl_test_receive.cmp -diff ssl_test_receive.tmp ssl_test_receive.cmp || { echo "Failover failed"; exit 1; } - -$QPIDD_EXEC -qp $PORT2 - -rm -f ssl_test_receive.* - diff --git a/cpp/src/tests/msg_group_test.cpp b/cpp/src/tests/msg_group_test.cpp deleted file mode 100644 index 6b9d09b89a..0000000000 --- a/cpp/src/tests/msg_group_test.cpp +++ /dev/null @@ -1,618 +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/messaging/Address.h> -#include <qpid/messaging/Connection.h> -#include <qpid/messaging/Receiver.h> -#include <qpid/messaging/Sender.h> -#include <qpid/messaging/Session.h> -#include <qpid/messaging/Message.h> -#include <qpid/messaging/FailoverUpdates.h> -#include <qpid/Options.h> -#include <qpid/log/Logger.h> -#include <qpid/log/Options.h> -#include "qpid/log/Statement.h" -#include "qpid/sys/Time.h" -#include "qpid/sys/Runnable.h" -#include "qpid/sys/Thread.h" -#include "qpid/sys/SystemInfo.h" - -#include <iostream> -#include <memory> -#include <stdlib.h> - -using namespace qpid::messaging; -using namespace qpid::types; -using namespace std; - -namespace qpid { -namespace tests { - -struct Options : public qpid::Options -{ - bool help; - std::string url; - std::string address; - std::string connectionOptions; - uint messages; - uint capacity; - uint ackFrequency; - bool failoverUpdates; - qpid::log::Options log; - uint senders; - uint receivers; - uint groupSize; - bool printReport; - std::string groupKey; - bool durable; - bool allowDuplicates; - bool randomizeSize; - bool stickyConsumer; - uint timeout; - uint interleave; - std::string prefix; - uint sendRate; - - Options(const std::string& argv0=std::string()) - : qpid::Options("Options"), - help(false), - url("amqp:tcp:127.0.0.1"), - messages(10000), - capacity(1000), - ackFrequency(100), - failoverUpdates(false), - log(argv0), - senders(2), - receivers(2), - groupSize(10), - printReport(false), - groupKey("qpid.no_group"), - durable(false), - allowDuplicates(false), - randomizeSize(false), - stickyConsumer(false), - timeout(10), - interleave(1), - sendRate(0) - { - addOptions() - ("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)") - ("address,a", qpid::optValue(address, "ADDRESS"), "address to send and receive from") - ("allow-duplicates", qpid::optValue(allowDuplicates), "Ignore the delivery of duplicated messages") - ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to") - ("capacity", qpid::optValue(capacity, "N"), "Pre-fetch window (0 implies no pre-fetch)") - ("connection-options", qpid::optValue(connectionOptions, "OPTIONS"), "options for the connection") - ("durable", qpid::optValue(durable, "yes|no"), "Mark messages as durable.") - ("failover-updates", qpid::optValue(failoverUpdates), "Listen for membership updates distributed via amq.failover") - ("group-key", qpid::optValue(groupKey, "KEY"), "Key of the message header containing the group identifier.") - ("group-prefix", qpid::optValue(prefix, "STRING"), "Add 'prefix' to the start of all generated group identifiers.") - ("group-size", qpid::optValue(groupSize, "N"), "Number of messages per a group.") - ("interleave", qpid::optValue(interleave, "N"), "Simultaineously interleave messages from N different groups.") - ("messages,m", qpid::optValue(messages, "N"), "Number of messages to send per each sender.") - ("receivers,r", qpid::optValue(receivers, "N"), "Number of message consumers.") - ("randomize-group-size", qpid::optValue(randomizeSize), "Randomize the number of messages per group to [1...group-size].") - ("send-rate", qpid::optValue(sendRate,"N"), "Send at rate of N messages/second. 0 means send as fast as possible.") - ("senders,s", qpid::optValue(senders, "N"), "Number of message producers.") - ("sticky-consumers", qpid::optValue(stickyConsumer), "If set, verify that all messages in a group are consumed by the same client [TBD].") - ("timeout", qpid::optValue(timeout, "N"), "Fail with a stall error should all consumers remain idle for timeout seconds.") - ("print-report", qpid::optValue(printReport), "Dump message group statistics to stdout.") - ("help", qpid::optValue(help), "print this usage statement"); - add(log); - //("check-redelivered", qpid::optValue(checkRedelivered), "Fails with exception if a duplicate is not marked as redelivered (only relevant when ignore-duplicates is selected)") - //("tx", qpid::optValue(tx, "N"), "batch size for transactions (0 implies transaction are not used)") - //("rollback-frequency", qpid::optValue(rollbackFrequency, "N"), "rollback frequency (0 implies no transaction will be rolledback)") - } - - bool parse(int argc, char** argv) - { - try { - qpid::Options::parse(argc, argv); - if (address.empty()) throw qpid::Exception("Address must be specified!"); - qpid::log::Logger::instance().configure(log); - if (help) { - std::ostringstream msg; - std::cout << msg << *this << std::endl << std::endl - << "Verifies the behavior of grouped messages." << std::endl; - return false; - } else { - return true; - } - } catch (const std::exception& e) { - std::cerr << *this << std::endl << std::endl << e.what() << std::endl; - return false; - } - } -}; - -const string EOS("eos"); -const string SN("sn"); - - -// class that monitors group state across all publishers and consumers. tracks the next -// expected sequence for each group, and total messages consumed. -class GroupChecker -{ - qpid::sys::Mutex lock; - - const uint totalMsgs; - uint totalMsgsConsumed; - uint totalMsgsPublished; - bool allowDuplicates; - uint duplicateMsgs; - - typedef std::map<std::string, uint> SequenceMap; - SequenceMap sequenceMap; - - // Statistics - for each group, store the names of all clients that consumed messages - // from that group, and the number of messages consumed per client. - typedef std::map<std::string, uint> ClientCounter; - typedef std::map<std::string, ClientCounter> GroupStatistics; - GroupStatistics statistics; - -public: - - GroupChecker( uint t, bool d ) : - totalMsgs(t), totalMsgsConsumed(0), totalMsgsPublished(0), allowDuplicates(d), - duplicateMsgs(0) {} - - bool checkSequence( const std::string& groupId, - uint sequence, const std::string& client ) - { - qpid::sys::Mutex::ScopedLock l(lock); - - QPID_LOG(debug, "Client " << client << " has received " << groupId << ":" << sequence); - - GroupStatistics::iterator gs = statistics.find(groupId); - if (gs == statistics.end()) { - statistics[groupId][client] = 1; - } else { - gs->second[client]++; - } - // now verify - SequenceMap::iterator s = sequenceMap.find(groupId); - if (s == sequenceMap.end()) { - QPID_LOG(debug, "Client " << client << " thinks this is the first message from group " << groupId << ":" << sequence); - // if duplication allowed, it is possible that the last msg(s) of an old sequence are redelivered on reconnect. - // in this case, set the sequence from the first msg. - sequenceMap[groupId] = (allowDuplicates) ? sequence : 0; - s = sequenceMap.find(groupId); - } else if (sequence < s->second) { - duplicateMsgs++; - QPID_LOG(debug, "Client " << client << " thinks this message is a duplicate! " << groupId << ":" << sequence); - return allowDuplicates; - } - totalMsgsConsumed++; - return sequence == s->second++; - } - - void sendingSequence( const std::string& groupId, - uint sequence, bool eos, - const std::string& client ) - { - qpid::sys::Mutex::ScopedLock l(lock); - ++totalMsgsPublished; - - QPID_LOG(debug, "Client " << client << " sending " << groupId << ":" << sequence << - ((eos) ? " (last)" : "")); - } - - bool eraseGroup( const std::string& groupId, const std::string& name ) - { - qpid::sys::Mutex::ScopedLock l(lock); - QPID_LOG(debug, "Deleting group " << groupId << " (by client " << name << ")"); - return sequenceMap.erase( groupId ) == 1; - } - - uint getNextExpectedSequence( const std::string& groupId ) - { - qpid::sys::Mutex::ScopedLock l(lock); - return sequenceMap[groupId]; - } - - bool allMsgsConsumed() // true when done processing msgs - { - qpid::sys::Mutex::ScopedLock l(lock); - return (totalMsgsPublished >= totalMsgs) && - (totalMsgsConsumed >= totalMsgsPublished) && - sequenceMap.size() == 0; - } - - uint getConsumedTotal() - { - qpid::sys::Mutex::ScopedLock l(lock); - return totalMsgsConsumed; - } - - uint getPublishedTotal() - { - qpid::sys::Mutex::ScopedLock l(lock); - return totalMsgsPublished; - } - - ostream& print(ostream& out) - { - qpid::sys::Mutex::ScopedLock l(lock); - out << "Total Published: " << totalMsgsPublished << ", Total Consumed: " << totalMsgsConsumed << - ", Duplicates detected: " << duplicateMsgs << std::endl; - out << "Total Groups: " << statistics.size() << std::endl; - unsigned long consumers = 0; - for (GroupStatistics::iterator gs = statistics.begin(); gs != statistics.end(); ++gs) { - out << " GroupId: " << gs->first; - consumers += gs->second.size(); // # of consumers that processed this group - if (gs->second.size() == 1) - out << " completely consumed by a single client." << std::endl; - else - out << " consumed by " << gs->second.size() << " different clients." << std::endl; - - for (ClientCounter::iterator cc = gs->second.begin(); cc != gs->second.end(); ++cc) { - out << " Client: " << cc->first << " consumed " << cc->second << " messages from the group." << std::endl; - } - } - out << "Average # of consumers per group: " << ((statistics.size() != 0) ? (double(consumers)/statistics.size()) : 0) << std::endl; - return out; - } -}; - - -namespace { - // rand() is not thread safe. Create a singleton obj to hold a lock while calling - // rand() so it can be called safely by multiple concurrent clients. - class Randomizer { - qpid::sys::Mutex lock; - public: - uint operator()(uint max) { - qpid::sys::Mutex::ScopedLock l(lock); - return (rand() % max) + 1; - } - }; - - static Randomizer randomizer; -} - - -// tag each generated message with a group identifer -// -class GroupGenerator { - - const std::string groupPrefix; - const uint groupSize; - const bool randomizeSize; - const uint interleave; - - uint groupSuffix; - uint total; - - struct GroupState { - std::string id; - const uint size; - uint count; - GroupState( const std::string& i, const uint s ) - : id(i), size(s), count(0) {} - }; - typedef std::list<GroupState> GroupList; - GroupList groups; - GroupList::iterator current; - - // add a new group identifier to the list - void newGroup() { - std::ostringstream groupId(groupPrefix, ios_base::out|ios_base::ate); - groupId << std::string(":") << groupSuffix++; - uint size = (randomizeSize) ? randomizer(groupSize) : groupSize; - QPID_LOG(trace, "New group: GROUPID=[" << groupId.str() << "] size=" << size << " this=" << this); - GroupState group( groupId.str(), size ); - groups.push_back( group ); - } - -public: - GroupGenerator( const std::string& prefix, - const uint t, - const uint size, - const bool randomize, - const uint i) - : groupPrefix(prefix), groupSize(size), - randomizeSize(randomize), interleave(i), groupSuffix(0), total(t) - { - QPID_LOG(trace, "New group generator: PREFIX=[" << prefix << "] total=" << total << " size=" << size << " rand=" << randomize << " interleave=" << interleave << " this=" << this); - for (uint i = 0; i < 1 || i < interleave; ++i) { - newGroup(); - } - current = groups.begin(); - } - - bool genGroup(std::string& groupId, uint& seq, bool& eos) - { - if (!total) return false; - --total; - if (current == groups.end()) - current = groups.begin(); - groupId = current->id; - seq = current->count++; - if (current->count == current->size) { - QPID_LOG(trace, "Last msg for " << current->id << ", " << current->count << " this=" << this); - eos = true; - if (total >= interleave) { // need a new group to replace this one - newGroup(); - groups.erase(current++); - } else ++current; - } else { - ++current; - eos = total < interleave; // mark eos on the last message of each group - } - QPID_LOG(trace, "SENDING GROUPID=[" << groupId << "] seq=" << seq << " eos=" << eos << " this=" << this); - return true; - } -}; - - - -class Client : public qpid::sys::Runnable -{ -public: - typedef boost::shared_ptr<Client> shared_ptr; - enum State {ACTIVE, DONE, FAILURE}; - Client( const std::string& n, const Options& o ) : name(n), opts(o), state(ACTIVE), stopped(false) {} - virtual ~Client() {} - State getState() { return state; } - void testFailed( const std::string& reason ) { state = FAILURE; error << "Client '" << name << "' failed: " << reason; } - void clientDone() { if (state == ACTIVE) state = DONE; } - qpid::sys::Thread& getThread() { return thread; } - const std::string getErrorMsg() { return error.str(); } - void stop() {stopped = true;} - const std::string& getName() { return name; } - -protected: - const std::string name; - const Options& opts; - qpid::sys::Thread thread; - ostringstream error; - State state; - bool stopped; -}; - - -class Consumer : public Client -{ - GroupChecker& checker; - -public: - Consumer(const std::string& n, const Options& o, GroupChecker& c ) : Client(n, o), checker(c) {}; - virtual ~Consumer() {}; - - void run() - { - Connection connection; - try { - connection = Connection(opts.url, opts.connectionOptions); - connection.open(); - std::auto_ptr<FailoverUpdates> updates(opts.failoverUpdates ? new FailoverUpdates(connection) : 0); - Session session = connection.createSession(); - Receiver receiver = session.createReceiver(opts.address); - receiver.setCapacity(opts.capacity); - Message msg; - uint count = 0; - - while (!stopped) { - if (receiver.fetch(msg, Duration::SECOND)) { // msg retrieved - qpid::types::Variant::Map& properties = msg.getProperties(); - std::string groupId = properties[opts.groupKey]; - uint groupSeq = properties[SN]; - bool eof = properties[EOS]; - - QPID_LOG(trace, "RECVING GROUPID=[" << groupId << "] seq=" << groupSeq << " eos=" << eof << " name=" << name); - - qpid::sys::usleep(10); - - if (!checker.checkSequence( groupId, groupSeq, name )) { - ostringstream msg; - msg << "Check sequence failed. Group=" << groupId << " rcvd seq=" << groupSeq << " expected=" << checker.getNextExpectedSequence( groupId ); - testFailed( msg.str() ); - break; - } else if (eof) { - if (!checker.eraseGroup( groupId, name )) { - ostringstream msg; - msg << "Erase group failed. Group=" << groupId << " rcvd seq=" << groupSeq; - testFailed( msg.str() ); - break; - } - } - - ++count; - if (opts.ackFrequency && (count % opts.ackFrequency == 0)) { - session.acknowledge(); - } - // Clear out message properties & content for next iteration. - msg = Message(); // TODO aconway 2010-12-01: should be done by fetch - } else if (checker.allMsgsConsumed()) // timed out, nothing else to do? - break; - } - session.acknowledge(); - session.close(); - connection.close(); - } catch(const std::exception& error) { - ostringstream msg; - msg << "consumer error: " << error.what(); - testFailed( msg.str() ); - connection.close(); - } - clientDone(); - QPID_LOG(trace, "Consuming client " << name << " completed."); - } -}; - - - -class Producer : public Client -{ - GroupChecker& checker; - GroupGenerator generator; - -public: - Producer(const std::string& n, const Options& o, GroupChecker& c) - : Client(n, o), checker(c), - generator( n, o.messages, o.groupSize, o.randomizeSize, o.interleave ) - {}; - virtual ~Producer() {}; - - void run() - { - Connection connection; - try { - connection = Connection(opts.url, opts.connectionOptions); - connection.open(); - std::auto_ptr<FailoverUpdates> updates(opts.failoverUpdates ? new FailoverUpdates(connection) : 0); - Session session = connection.createSession(); - Sender sender = session.createSender(opts.address); - if (opts.capacity) sender.setCapacity(opts.capacity); - Message msg; - msg.setDurable(opts.durable); - std::string groupId; - uint seq; - bool eos; - uint sent = 0; - - qpid::sys::AbsTime start = qpid::sys::now(); - int64_t interval = 0; - if (opts.sendRate) interval = qpid::sys::TIME_SEC/opts.sendRate; - - while (!stopped && generator.genGroup(groupId, seq, eos)) { - msg.getProperties()[opts.groupKey] = groupId; - msg.getProperties()[SN] = seq; - msg.getProperties()[EOS] = eos; - checker.sendingSequence( groupId, seq, eos, name ); - - sender.send(msg); - ++sent; - - if (opts.sendRate) { - qpid::sys::AbsTime waitTill(start, sent*interval); - int64_t delay = qpid::sys::Duration(qpid::sys::now(), waitTill); - if (delay > 0) qpid::sys::usleep(delay/qpid::sys::TIME_USEC); - } - } - session.sync(); - session.close(); - connection.close(); - } catch(const std::exception& error) { - ostringstream msg; - msg << "producer '" << name << "' error: " << error.what(); - testFailed(msg.str()); - connection.close(); - } - clientDone(); - QPID_LOG(trace, "Producing client " << name << " completed."); - } -}; - - -}} // namespace qpid::tests - -using namespace qpid::tests; - -int main(int argc, char ** argv) -{ - int status = 0; - try { - Options opts; - if (opts.parse(argc, argv)) { - - GroupChecker state( opts.senders * opts.messages, - opts.allowDuplicates); - std::vector<Client::shared_ptr> clients; - - if (opts.randomizeSize) srand((unsigned int)qpid::sys::SystemInfo::getProcessId()); - - // fire off the producers && consumers - for (size_t j = 0; j < opts.senders; ++j) { - ostringstream name; - name << opts.prefix << "P_" << j; - clients.push_back(Client::shared_ptr(new Producer( name.str(), opts, state ))); - clients.back()->getThread() = qpid::sys::Thread(*clients.back()); - } - for (size_t j = 0; j < opts.receivers; ++j) { - ostringstream name; - name << opts.prefix << "C_" << j; - clients.push_back(Client::shared_ptr(new Consumer( name.str(), opts, state ))); - clients.back()->getThread() = qpid::sys::Thread(*clients.back()); - } - - // wait for all pubs/subs to finish.... or for consumers to fail or stall. - uint stalledTime = 0; - bool done; - bool clientFailed = false; - do { - uint lastCount = state.getConsumedTotal(); - qpid::sys::usleep( 1000000 ); - - // check each client for status - done = true; - for (std::vector<Client::shared_ptr>::iterator i = clients.begin(); - i != clients.end(); ++i) { - QPID_LOG(debug, "Client " << (*i)->getName() << " state=" << (*i)->getState()); - if ((*i)->getState() == Client::FAILURE) { - QPID_LOG(error, argv[0] << ": test failed with client error: " << (*i)->getErrorMsg()); - clientFailed = true; - done = true; - break; // exit test. - } else if ((*i)->getState() != Client::DONE) { - done = false; - } - } - - if (!done) { - // check that consumers are still receiving messages - if (lastCount == state.getConsumedTotal()) - stalledTime++; - else { - lastCount = state.getConsumedTotal(); - stalledTime = 0; - } - } - - QPID_LOG(debug, "Consumed to date = " << state.getConsumedTotal() << - " Published to date = " << state.getPublishedTotal() << - " total=" << opts.senders * opts.messages ); - - } while (!done && stalledTime < opts.timeout); - - if (clientFailed) { - status = 1; - } else if (stalledTime >= opts.timeout) { - QPID_LOG(error, argv[0] << ": test failed due to stalled consumer." ); - status = 2; - } - - // Wait for started threads. - for (std::vector<Client::shared_ptr>::iterator i = clients.begin(); - i != clients.end(); ++i) { - (*i)->stop(); - (*i)->getThread().join(); - } - - if (opts.printReport && !status) state.print(std::cout); - } else status = 4; - } catch(const std::exception& error) { - QPID_LOG(error, argv[0] << ": " << error.what()); - status = 3; - } - QPID_LOG(trace, "TEST DONE [" << status << "]"); - - return status; -} diff --git a/cpp/src/tests/python_tests b/cpp/src/tests/python_tests index 0216b5ca7b..e367004a71 100755 --- a/cpp/src/tests/python_tests +++ b/cpp/src/tests/python_tests @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/cpp/src/tests/qpid-cluster-benchmark b/cpp/src/tests/qpid-cluster-benchmark index ff787a46dd..4408e63866 100755 --- a/cpp/src/tests/qpid-cluster-benchmark +++ b/cpp/src/tests/qpid-cluster-benchmark @@ -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,40 +19,21 @@ # # Benchmark script for comparing cluster performance. +#PORT=":5555" +BROKER=`echo $HOSTS | awk '{print $1}'` # Single broker +BROKERS=`echo $HOSTS | sed "s/\>/$PORT/g;s/ /,/g"` # Broker URL list +COUNT=100000 +RATE=20000 # Rate to throttle senders for latency results +run_test() { echo $*; "$@"; echo; echo; echo; } -# Default values -PORT="5672" -COUNT=10000 -FLOW=100 # Flow control limit on queue depth for latency. -REPEAT=10 -QUEUES=4 -CLIENTS=3 - -while getopts "p:c:f:r:t:b:q:c" opt; do - case $opt in - p) PORT=$OPTARG;; - c) COUNT=$OPTARG;; - f) FLOW=$OPTARG;; - r) REPEAT=$OPTARG;; - s) SCALE=$OPTARG;; - b) BROKERS=$OPTARG;; - q) QUEUES=$OPTARG;; - c) CLIENTS=$OPTARG;; - *) echo "Unknown option"; exit 1;; - esac -done - -BROKERS=${BROKERS:-$(echo $HOSTS | sed "s/\>/:$PORT/g;s/ /,/g")} # Broker URL list -BROKER=`echo $BROKERS | awk -F, '{print $1}'` # First broker +# Thruput, unshared queue +run_test qpid-cpp-benchmark --repeat 10 -b $BROKER --no-timestamp -m $COUNT -run_test() { echo $*; shift; "$@"; echo; echo; echo; } +# Latency +run_test qpid-cpp-benchmark --repeat 10 -b $BROKER --connection-options '{tcp-nodelay:true}' -m `expr $COUNT / 2` --send-rate $RATE # Multiple pubs/subs connect via multiple brokers (active-active) -run_test "multi-host-thruput" qpid-cpp-benchmark --repeat $REPEAT -b $BROKERS --no-timestamp --summarize -q$QUEUES -s$CLIENTS -r$CLIENTS -m $COUNT +run_test qpid-cpp-benchmark --repeat 10 -b $BROKERS --no-timestamp --summarize -s10 -r10 -m `expr $COUNT / 10` # Multiple pubs/subs connect via single broker (active-passive) -run_test "single-host-thruput" qpid-cpp-benchmark --repeat $REPEAT -b $BROKER --no-timestamp --summarize -q$QUEUES -s$CLIENTS -r$CLIENTS -m $COUNT - -# Latency -run_test "latency" qpid-cpp-benchmark --repeat $REPEAT -b $BROKER --connection-options '{tcp-nodelay:true}' -m $COUNT --flow-control $FLOW - +run_test qpid-cpp-benchmark --repeat 10 -b $BROKER --no-timestamp --summarize -s10 -r10 -m `expr $COUNT / 10` diff --git a/cpp/src/tests/qpid-cpp-benchmark b/cpp/src/tests/qpid-cpp-benchmark index 300d34774f..1f77226b4d 100755 --- a/cpp/src/tests/qpid-cpp-benchmark +++ b/cpp/src/tests/qpid-cpp-benchmark @@ -77,20 +77,6 @@ def ssh_command(host, command): """Convert command into an ssh command on host with quoting""" return ["ssh", host] + [posix_quote(arg) for arg in command] -class Clients: - def __init__(self): self.clients=[] - - def add(self, client): - self.clients.append(client) - return client - - def kill(self): - for c in self.clients: - try: c.kill() - except: pass - -clients = Clients() - def start_receive(queue, index, opts, ready_queue, broker, host): address_opts=["create:receiver"] + opts.receive_option if opts.durable: address_opts += ["node:{durable:true}"] @@ -115,7 +101,7 @@ def start_receive(queue, index, opts, ready_queue, broker, host): if opts.connection_options: command += ["--connection-options",opts.connection_options] if host: command = ssh_command(host, command) - return clients.add(Popen(command, stdout=PIPE)) + return Popen(command, stdout=PIPE) def start_send(queue, opts, broker, host): address="%s;{%s}"%(queue,",".join(opts.send_option)) @@ -136,7 +122,7 @@ def start_send(queue, opts, broker, host): if opts.connection_options: command += ["--connection-options",opts.connection_options] if host: command = ssh_command(host, command) - return clients.add(Popen(command, stdout=PIPE)) + return Popen(command, stdout=PIPE) def first_line(p): out,err=p.communicate() @@ -147,11 +133,7 @@ def delete_queues(queues, broker): c = qpid.messaging.Connection(broker) c.open() for q in queues: - try: - s = c.session() - snd = s.sender("%s;{delete:always}"%(q)) - snd.close() - s.sync() + try: s = c.session().sender("%s;{delete:always}"%(q)) except qpid.messaging.exceptions.NotFound: pass # Ignore "no such queue" c.close() @@ -163,6 +145,7 @@ def print_header(timestamp): def parse(parser, lines): # Parse sender/receiver output for l in lines: fn_val = zip(parser, l) + return [map(lambda p: p[0](p[1]), zip(parser,line.split())) for line in lines] def parse_senders(senders): @@ -173,12 +156,11 @@ def parse_receivers(receivers): def print_data(send_stats, recv_stats): for send,recv in map(None, send_stats, recv_stats): - line="" - if send: line += "%d"%send[0] + if send: print send[0], if recv: - line += "\t\t%d"%recv[0] - if len(recv) == 4: line += "\t%.2f\t%.2f\t%.2f"%tuple(recv[1:]) - print line + print "\t\t%d"%recv[0], + if len(recv) == 4: print "\t%.2f\t%.2f\t%.2f"%tuple(recv[1:]), + print def print_summary(send_stats, recv_stats): def avg(s): sum(s) / len(s) @@ -202,11 +184,11 @@ class ReadyReceiver: self.receiver = self.connection.session().receiver( "%s;{create:receiver,delete:receiver,node:{durable:false}}"%(queue)) self.receiver.session.sync() - self.timeout=10 + self.timeout=2 def wait(self, receivers): try: - for i in receivers: self.receiver.fetch(self.timeout) + for i in xrange(len(receivers)): self.receiver.fetch(self.timeout) self.connection.close() except qpid.messaging.Empty: for r in receivers: @@ -215,8 +197,7 @@ class ReadyReceiver: raise Exception("Receiver error: %s"%(out)) raise Exception("Timed out waiting for receivers to be ready") -def flatten(l): - return sum(map(lambda s: re.split(re.compile("\s*,\s*|\s+"), s), l), []) +def flatten(l): return sum(map(lambda s: s.split(","), l),[]) class RoundRobin: def __init__(self,items): @@ -240,22 +221,20 @@ def main(): receive_out = "" ready_queue="%s-ready"%(opts.queue_name) queues = ["%s-%s"%(opts.queue_name, i) for i in xrange(opts.queues)] - try: - for i in xrange(opts.repeat): - delete_queues(queues, opts.broker[0]) - ready_receiver = ReadyReceiver(ready_queue, opts.broker[0]) - receivers = [start_receive(q, j, opts, ready_queue, brokers.next(), client_hosts.next()) - for q in queues for j in xrange(opts.receivers)] - ready_receiver.wait(filter(None, receivers)) # Wait for receivers to be ready. - senders = [start_send(q, opts,brokers.next(), client_hosts.next()) - for q in queues for j in xrange(opts.senders)] - if opts.report_header and i == 0: print_header(opts.timestamp) - send_stats=parse_senders(senders) - recv_stats=parse_receivers(receivers) - if opts.summarize: print_summary(send_stats, recv_stats) - else: print_data(send_stats, recv_stats) - delete_queues(queues, opts.broker[0]) - finally: clients.kill() # No strays + for i in xrange(opts.repeat): + delete_queues(queues, opts.broker[0]) + ready_receiver = ReadyReceiver(ready_queue, opts.broker[0]) + receivers = [start_receive(q, j, opts, ready_queue, brokers.next(), client_hosts.next()) + for q in queues for j in xrange(opts.receivers)] + ready_receiver.wait(filter(None, receivers)) # Wait for receivers to be ready. + senders = [start_send(q, opts,brokers.next(), client_hosts.next()) + for q in queues for j in xrange(opts.senders)] + if opts.report_header and i == 0: print_header(opts.timestamp) + send_stats=parse_senders(senders) + recv_stats=parse_receivers(receivers) + if opts.summarize: print_summary(send_stats, recv_stats) + else: print_data(send_stats, recv_stats) + delete_queues(queues, opts.broker[0]) if __name__ == "__main__": main() diff --git a/cpp/src/tests/qpid-ctrl b/cpp/src/tests/qpid-ctrl index 4246c57898..7b46c190fb 100755 --- a/cpp/src/tests/qpid-ctrl +++ b/cpp/src/tests/qpid-ctrl @@ -92,10 +92,7 @@ try: arguments = {} for a in args: name, val = nameval(a) - if val[0] == '{' or val[0] == '[': - arguments[name] = eval(val) - else: - arguments[name] = val + arguments[name] = val content = { "_object_id": {"_object_name": object_name}, "_method_name": method_name, diff --git a/cpp/src/tests/qpid-perftest.cpp b/cpp/src/tests/qpid-perftest.cpp index dd81354adb..4d7b563c8c 100644 --- a/cpp/src/tests/qpid-perftest.cpp +++ b/cpp/src/tests/qpid-perftest.cpp @@ -396,7 +396,7 @@ struct Controller : public Client { void run() { // Controller try { // Wait for subscribers to be ready. - process(opts.totalSubs, fqn("sub_ready"), boost::bind(expect, _1, "ready")); + process(opts.totalSubs, fqn("sub_ready"), bind(expect, _1, "ready")); LocalQueue pubDone; LocalQueue subDone; @@ -423,10 +423,8 @@ struct Controller : public Client { process(opts.totalSubs, subDone, fqn("sub_done"), boost::ref(subRates)); AbsTime end=now(); + double time=secs(start, end); - if (time <= 0.0) { - throw Exception("ERROR: Test completed in zero seconds. Try again with a larger message count."); - } double txrate=opts.transfers/time; double mbytes=(txrate*opts.size)/(1024*1024); @@ -510,11 +508,10 @@ struct PublishThread : public Client { } SubscriptionManager subs(session); LocalQueue lq; - subs.setFlowControl(0, SubscriptionManager::UNLIMITED, false); - Subscription cs = subs.subscribe(lq, fqn("pub_start")); + subs.setFlowControl(1, SubscriptionManager::UNLIMITED, true); + subs.subscribe(lq, fqn("pub_start")); for (size_t j = 0; j < opts.iterations; ++j) { - cs.grantMessageCredit(1); expect(lq.pop().getData(), "start"); AbsTime start=now(); for (size_t i=0; i<opts.count; i++) { @@ -546,9 +543,6 @@ struct PublishThread : public Client { if (opts.confirm) session.sync(); AbsTime end=now(); double time=secs(start,end); - if (time <= 0.0) { - throw Exception("ERROR: Test completed in zero seconds. Try again with a larger message count."); - } // Send result to controller. Message report(lexical_cast<string>(opts.count/time), fqn("pub_done")); @@ -644,9 +638,7 @@ struct SubscribeThread : public Client { // // For now verify order only for a single publisher. size_t offset = opts.uniqueData ? 5 /*marker is 'data:'*/ : 0; - size_t n; - memcpy (&n, reinterpret_cast<const char*>(msg.getData().data() + offset), - sizeof(n)); + size_t n = *reinterpret_cast<const size_t*>(msg.getData().data() + offset); if (opts.pubs == 1) { if (opts.subs == 1 || opts.mode == FANOUT) verify(n==expect, "==", expect, n); else verify(n>=expect, ">=", expect, n); diff --git a/cpp/src/tests/qpid-receive.cpp b/cpp/src/tests/qpid-receive.cpp index 9c713e872a..012d544a2e 100644 --- a/cpp/src/tests/qpid-receive.cpp +++ b/cpp/src/tests/qpid-receive.cpp @@ -53,7 +53,6 @@ struct Options : public qpid::Options bool forever; uint messages; bool ignoreDuplicates; - bool checkRedelivered; uint capacity; uint ackFrequency; uint tx; @@ -76,7 +75,6 @@ struct Options : public qpid::Options forever(false), messages(0), ignoreDuplicates(false), - checkRedelivered(false), capacity(1000), ackFrequency(100), tx(0), @@ -94,11 +92,10 @@ struct Options : public qpid::Options ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to") ("address,a", qpid::optValue(address, "ADDRESS"), "address to receive from") ("connection-options", qpid::optValue(connectionOptions, "OPTIONS"), "options for the connection") - ("timeout", qpid::optValue(timeout, "TIMEOUT"), "timeout in seconds to wait before exiting") + ("timeout,t", qpid::optValue(timeout, "TIMEOUT"), "timeout in seconds to wait before exiting") ("forever,f", qpid::optValue(forever), "ignore timeout and wait forever") ("messages,m", qpid::optValue(messages, "N"), "Number of messages to receive; 0 means receive indefinitely") ("ignore-duplicates", qpid::optValue(ignoreDuplicates), "Detect and ignore duplicates (by checking 'sn' header)") - ("check-redelivered", qpid::optValue(checkRedelivered), "Fails with exception if a duplicate is not marked as redelivered (only relevant when ignore-duplicates is selected)") ("capacity", qpid::optValue(capacity, "N"), "Pre-fetch window (0 implies no pre-fetch)") ("ack-frequency", qpid::optValue(ackFrequency, "N"), "Ack frequency (0 implies none of the messages will get accepted)") ("tx", qpid::optValue(tx, "N"), "batch size for transactions (0 implies transaction are not used)") @@ -219,8 +216,6 @@ int main(int argc, char ** argv) std::cout << msg.getContent() << std::endl;//TODO: handle map or list messages if (opts.messages && count >= opts.messages) done = true; } - } else if (opts.checkRedelivered && !msg.getRedelivered()) { - throw qpid::Exception("duplicate sequence number received, message not marked as redelivered!"); } if (opts.tx && (count % opts.tx == 0)) { if (opts.rollbackFrequency && (++txCount % opts.rollbackFrequency == 0)) { @@ -262,7 +257,7 @@ int main(int argc, char ** argv) return 0; } } catch(const std::exception& error) { - std::cerr << "qpid-receive: " << error.what() << std::endl; + std::cerr << "Failure: " << error.what() << std::endl; connection.close(); return 1; } diff --git a/cpp/src/tests/qpid-send.cpp b/cpp/src/tests/qpid-send.cpp index b1213a484f..6a7e7838ce 100644 --- a/cpp/src/tests/qpid-send.cpp +++ b/cpp/src/tests/qpid-send.cpp @@ -28,7 +28,6 @@ #include <qpid/messaging/FailoverUpdates.h> #include <qpid/sys/Time.h> #include <qpid/sys/Monitor.h> -#include <qpid/sys/SystemInfo.h> #include "TestOptions.h" #include "Statistics.h" @@ -77,11 +76,6 @@ struct Options : public qpid::Options uint flowControl; bool sequence; bool timestamp; - std::string groupKey; - std::string groupPrefix; - uint groupSize; - bool groupRandSize; - uint groupInterleave; Options(const std::string& argv0=std::string()) : qpid::Options("Options"), @@ -106,23 +100,19 @@ struct Options : public qpid::Options sendRate(0), flowControl(0), sequence(true), - timestamp(true), - groupPrefix("GROUP-"), - groupSize(10), - groupRandSize(false), - groupInterleave(1) + timestamp(true) { addOptions() ("broker,b", qpid::optValue(url, "URL"), "url of broker to connect to") - ("address,a", qpid::optValue(address, "ADDRESS"), "address to send to") + ("address,a", qpid::optValue(address, "ADDRESS"), "address to drain from") ("connection-options", qpid::optValue(connectionOptions, "OPTIONS"), "options for the connection") ("messages,m", qpid::optValue(messages, "N"), "stop after N messages have been sent, 0 means no limit") ("id,i", qpid::optValue(id, "ID"), "use the supplied id instead of generating one") ("reply-to", qpid::optValue(replyto, "REPLY-TO"), "specify reply-to address") ("send-eos", qpid::optValue(sendEos, "N"), "Send N EOS messages to mark end of input") ("durable", qpid::optValue(durable, "yes|no"), "Mark messages as durable.") - ("ttl", qpid::optValue(ttl, "msecs"), "Time-to-live for messages, in milliseconds") - ("priority", qpid::optValue(priority, "PRIORITY"), "Priority for messages (higher value implies higher priority)") + ("ttl", qpid::optValue(ttl, "msecs"), "Time-to-live for messages, in milliseconds") + ("priority", qpid::optValue(priority, "PRIORITY"), "Priority for messages (higher value implies higher priority)") ("property,P", qpid::optValue(properties, "NAME=VALUE"), "specify message property") ("correlation-id", qpid::optValue(correlationid, "ID"), "correlation-id for message") ("user-id", qpid::optValue(userid, "USERID"), "userid for message") @@ -141,11 +131,6 @@ struct Options : public qpid::Options ("flow-control", qpid::optValue(flowControl,"N"), "Do end to end flow control to limit queue depth to 2*N. 0 means no flow control.") ("sequence", qpid::optValue(sequence, "yes|no"), "Add a sequence number messages property (required for duplicate/lost message detection)") ("timestamp", qpid::optValue(timestamp, "yes|no"), "Add a time stamp messages property (required for latency measurement)") - ("group-key", qpid::optValue(groupKey, "KEY"), "Generate groups of messages using message header 'KEY' to hold the group identifier") - ("group-prefix", qpid::optValue(groupPrefix, "STRING"), "Generate group identifers with 'STRING' prefix (if group-key specified)") - ("group-size", qpid::optValue(groupSize, "N"), "Number of messages per a group (if group-key specified)") - ("group-randomize-size", qpid::optValue(groupRandSize), "Randomize the number of messages per group to [1...group-size] (if group-key specified)") - ("group-interleave", qpid::optValue(groupInterleave, "N"), "Simultaineously interleave messages from N different groups (if group-key specified)") ("help", qpid::optValue(help), "print this usage statement"); add(log); } @@ -267,68 +252,6 @@ class MapContentGenerator : public ContentGenerator { const Options& opts; }; -// tag each generated message with a group identifer -// -class GroupGenerator { -public: - GroupGenerator(const std::string& key, - const std::string& prefix, - const uint size, - const bool randomize, - const uint interleave) - : groupKey(key), groupPrefix(prefix), groupSize(size), - randomizeSize(randomize), groupSuffix(0) - { - if (randomize) srand((unsigned int)qpid::sys::SystemInfo::getProcessId()); - - for (uint i = 0; i < 1 || i < interleave; ++i) { - newGroup(); - } - current = groups.begin(); - } - - void setGroupInfo(Message &msg) - { - if (current == groups.end()) - current = groups.begin(); - msg.getProperties()[groupKey] = current->id; - // std::cout << "SENDING GROUPID=[" << current->id << "]" << std::endl; - if (++(current->count) == current->size) { - newGroup(); - groups.erase(current++); - } else - ++current; - } - - private: - const std::string& groupKey; - const std::string& groupPrefix; - const uint groupSize; - const bool randomizeSize; - - uint groupSuffix; - - struct GroupState { - std::string id; - const uint size; - uint count; - GroupState( const std::string& i, const uint s ) - : id(i), size(s), count(0) {} - }; - typedef std::list<GroupState> GroupList; - GroupList groups; - GroupList::iterator current; - - void newGroup() { - std::ostringstream groupId(groupPrefix, ios_base::out|ios_base::ate); - groupId << groupSuffix++; - uint size = (randomizeSize) ? (rand() % groupSize) + 1 : groupSize; - // std::cout << "New group: GROUPID=[" << groupId.str() << "] size=" << size << std::endl; - GroupState group( groupId.str(), size ); - groups.push_back( group ); - } -}; - int main(int argc, char ** argv) { Connection connection; @@ -373,14 +296,6 @@ int main(int argc, char ** argv) else contentGen.reset(new FixedContentGenerator(opts.contentString)); - std::auto_ptr<GroupGenerator> groupGen; - if (!opts.groupKey.empty()) - groupGen.reset(new GroupGenerator(opts.groupKey, - opts.groupPrefix, - opts.groupSize, - opts.groupRandSize, - opts.groupInterleave)); - qpid::sys::AbsTime start = qpid::sys::now(); int64_t interval = 0; if (opts.sendRate) interval = qpid::sys::TIME_SEC/opts.sendRate; @@ -397,6 +312,9 @@ int main(int argc, char ** argv) ++sent; if (opts.sequence) msg.getProperties()[SN] = sent; + if (opts.timestamp) + msg.getProperties()[TS] = int64_t( + qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now())); if (opts.flowControl) { if ((sent % opts.flowControl) == 0) { msg.setReplyTo(flowControlAddress); @@ -405,12 +323,6 @@ int main(int argc, char ** argv) else msg.setReplyTo(Address()); // Clear the reply address. } - if (groupGen.get()) - groupGen->setGroupInfo(msg); - - if (opts.timestamp) - msg.getProperties()[TS] = int64_t( - qpid::sys::Duration(qpid::sys::EPOCH, qpid::sys::now())); sender.send(msg); reporter.message(msg); @@ -456,7 +368,7 @@ int main(int argc, char ** argv) return 0; } } catch(const std::exception& error) { - std::cerr << "qpid-send: " << error.what() << std::endl; + std::cout << "Failed: " << error.what() << std::endl; connection.close(); return 1; } diff --git a/cpp/src/tests/qrsh.cpp b/cpp/src/tests/qrsh.cpp new file mode 100644 index 0000000000..0cb52b6b05 --- /dev/null +++ b/cpp/src/tests/qrsh.cpp @@ -0,0 +1,169 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <qpid/client/Connection.h> +#include <qpid/client/Session.h> +#include <qpid/client/AsyncSession.h> +#include <qpid/client/Message.h> +#include <qpid/client/MessageListener.h> +#include <qpid/client/SubscriptionManager.h> + +#include <stdio.h> +#include <cstdlib> +#include <iostream> + +#include <sstream> + +using namespace qpid::client; +using namespace qpid::framing; + +using namespace std; + +namespace qpid { +namespace tests { + +class ResponseListener : public MessageListener +{ + public : + + int exitCode; + + ResponseListener ( SubscriptionManager & subscriptions ) + : exitCode(-1), + subscriptions ( subscriptions ) + { + } + + virtual void + received ( Message & message ) + { + char first_word[1000]; + sscanf ( message.getData().c_str(), "%s", first_word ); + + if ( ! strcmp ( first_word, "wait_response" ) ) + { + // If we receive a message here, parse out the exit code. + sscanf ( message.getData().c_str(), "%*s%d", & exitCode ); + subscriptions.cancel(message.getDestination()); + } + else + if ( ! strcmp ( first_word, "get_response" ) ) + { + // The remainder of the message is the file we requested. + fprintf ( stdout, + "%s", + message.getData().c_str() + strlen("get_response" ) + ); + subscriptions.cancel(message.getDestination()); + } + } + + + private : + + SubscriptionManager & subscriptions; +}; + +}} // namespace qpid::tests + +using namespace qpid::tests; + +/* + * argv[1] host + * argv[2] port + * argv[3] server name + * argv[4] command name + * argv[5..N] args to the command + */ +int +main ( int argc, char ** argv ) +{ + const char* host = argv[1]; + int port = atoi(argv[2]); + + + Connection connection; + + try + { + connection.open ( host, port ); + Session session = connection.newSession ( ); + + // Make a queue and bind it to fanout. + string myQueue = session.getId().getName(); + + session.queueDeclare ( arg::queue=myQueue, + arg::exclusive=true, + arg::autoDelete=true + ); + + session.exchangeBind ( arg::exchange="amq.fanout", + arg::queue=myQueue, + arg::bindingKey="my-key" + ); + + // Get ready to listen for the wait-response. + // or maybe a get-response. + // ( Although this may not be one of those types + // of command, get ready anyway. + SubscriptionManager subscriptions ( session ); + ResponseListener responseListener ( subscriptions ); + subscriptions.subscribe ( responseListener, myQueue ); + + bool response_command = false; + if(! strcmp("exec_wait", argv[4] )) + response_command = true; + else + if(! strcmp("exited", argv[4] )) + response_command = true; + else + if(! strcmp("get", argv[4] )) + response_command = true; + + // Send the payload message. + // Skip "qrsh host_name port" + Message message; + stringstream ss; + for ( int i = 3; i < argc; ++ i ) + ss << argv[i] << ' '; + + message.setData ( ss.str() ); + + session.messageTransfer(arg::content=message, + arg::destination="amq.fanout"); + + if ( response_command ) + subscriptions.run(); + + session.close(); + connection.close(); + return responseListener.exitCode; + } + catch ( exception const & e) + { + cerr << e.what() << endl; + } + + return 1; +} + + + diff --git a/cpp/src/tests/qrsh_run.cpp b/cpp/src/tests/qrsh_run.cpp new file mode 100644 index 0000000000..cfdd0cef80 --- /dev/null +++ b/cpp/src/tests/qrsh_run.cpp @@ -0,0 +1,321 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#include <iostream> +#include <sstream> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + + +using namespace std; + + + +int +main ( int argc, char ** argv ) +{ + int exit_code = -1; + int fd[2]; + int my_pid = getpid(); + int child_pid; + + pipe(fd); + + char const * root_dir = argv[1]; // This arg is prepended by qrsh_server. + char const * child_name = argv[2]; // This arg comes from qrsh. + char const * child_path = argv[3]; // This arg comes from qrsh. + + // This is the problem.. + fprintf ( stderr, "MDEBUG qrsh_run: root_dir: |%s|\n", root_dir ); + fprintf ( stderr, "MDEBUG qrsh_run: child_name: |%s|\n", child_name ); + fprintf ( stderr, "MDEBUG qrsh_run: child_path: |%s|\n", child_path ); + + /* + * A named child is one for whom we will create a directory and + * store information. There are some magic names that are not + * real symbolic names -- but are instead the names of actions. + */ + + bool named_child = true; + + if ( ! strcmp ( child_name, "exec" ) ) + named_child = false; + else + if ( ! strcmp ( child_name, "exec_wait" ) ) + named_child = false; + else + if ( ! strcmp ( child_name, "exited" ) ) + named_child = false; + else + named_child = true; + + stringstream child_dir_name; + + if ( named_child ) + { + child_dir_name << root_dir + << '/' + << child_name; + + /* + * Make the child directory before forking, or there is + * a race in which the child might be trying to make its + * stdout and stderr files while we are tring to make + * the directory. + */ + if ( -1 == mkdir ( child_dir_name.str().c_str(), 0777 ) ) + { + fprintf ( stderr, + "qrsh_run error: Can't mkdir |%s|\n", + child_dir_name.str().c_str() + ); + exit ( 1 ); + } + + } + else + /* + * If this is an 'exited' command that means we are + * waiting for a pre-existing child. + */ + if ( ! strcmp ( child_name, "exited" ) ) + { + int wait_pid = atoi(child_path); + + // Find the child's symbolic name. + stringstream pid_to_name_file_name; + pid_to_name_file_name << root_dir + << '/' + << wait_pid; + FILE * fp = fopen ( pid_to_name_file_name.str().c_str(), "r" ); + if (! fp) + { + fprintf ( stderr, + "qrsh_run %d error: Can't open pid2name file |%s|.\n", + my_pid, + pid_to_name_file_name.str().c_str() + ); + exit(1); + } + char symbolic_name[1000]; + strcpy ( symbolic_name, "qrsh_no_name" ); + fscanf ( fp, "%s", symbolic_name ); + fclose ( fp ); + + // Make the name of the child's exit code file. + stringstream exit_code_file_name; + exit_code_file_name << root_dir + << '/' + << symbolic_name + << "/exit_code"; + + struct stat stat_buf; + int file_does_not_exist = stat ( exit_code_file_name.str().c_str(), & stat_buf ); + + /* + * If the result of stat is zero, the file exists, which means that + * the command has exited. The question we are being asked here is + * "has it exited yet?" + */ + if ( ! file_does_not_exist ) + return 1; + else + if ( errno == ENOENT ) + return 0; + else + return 2 ; + } + + + // We are not waiting on a pre-wxiting child: we have a + // new child to create. + + child_pid = fork(); + + if ( child_pid == 0 ) + { + // This code is executed in the child process. + + // If it's a *named* child, then redirect its stdout and stderr. + if ( named_child ) + { + stringstream stdout_path, + stderr_path; + + // Redirect the child's stdout. ----------------- + stdout_path << root_dir + << '/' + << child_name + << '/' + << "stdout"; + + int redirected_stdout = open ( stdout_path.str().c_str(), + O_WRONLY|O_CREAT|O_TRUNC, + S_IRWXU|S_IRWXG|S_IRWXO + ); + if ( redirected_stdout < 0 ) + { + perror ( "qrsh_run: error opening redirected_stdout: " ); + fprintf ( stderr, "stdout path: |%s|\n", stdout_path.str().c_str() ); + exit ( 1 ); + } + if ( -1 == dup2 ( redirected_stdout, 1 ) ) + { + perror ( "qrsh_run: dup2 (stdout) error: " ); + exit(1); + } + + // Redirect the child's stderr. ----------------- + stderr_path << root_dir + << '/' + << child_name + << '/' + << "stderr"; + + int redirected_stderr = open ( stderr_path.str().c_str(), + O_WRONLY|O_CREAT|O_TRUNC, + S_IRWXU|S_IRWXG|S_IRWXO + ); + if ( redirected_stderr < 0 ) + { + perror ( "qrsh_run: error opening redirected_stderr: " ); + fprintf ( stderr, "stderr path: |%s|\n", stderr_path.str().c_str() ); + exit ( 1 ); + } + if(-1 == dup2 ( redirected_stderr, 2 ) ) + { + perror ( "qrsh_run: dup2 (stderr) error: " ); + exit(1); + } + } + + fprintf ( stderr, "MDEBUG ------------- qrsh_run argv -------------\n" ); + for ( int i = 0; i < argc; ++ i ) + fprintf ( stderr, "MDEBUG argv[%d] : |%s|\n", i, argv[i] ); + + execv ( child_path, argv + 2 ); + perror ( "qrsh_run: execv error: " ); + fprintf ( stderr, "on path |%s|\n", child_path ); + exit ( 1 ); + } + else + { + // This code is executed in the parent process. + + if ( named_child ) + { + // Write the name-to-pid mapping. + stringstream pid_file_name; + pid_file_name << child_dir_name.str() + << "/pid"; + + FILE * fp; + if ( ! (fp = fopen ( pid_file_name.str().c_str(), "w") ) ) + { + fprintf ( stderr, + "qrsh_run %d error: Can't open file |%s|\n", + my_pid, + pid_file_name.str().c_str() + ); + exit(1); + } + fprintf ( fp, "%d\n", child_pid ); + fclose ( fp ); + + + // Write the pid-to-name mapping. + stringstream name_to_pid_file_name; + name_to_pid_file_name << root_dir + << '/' + << child_pid; + if(! (fp = fopen ( name_to_pid_file_name.str().c_str(), "w"))) + { + fprintf ( stderr, + "qrsh_run %d error: Can't open file |%s|\n", + my_pid, + name_to_pid_file_name.str().c_str() + ); + exit(1); + } + fprintf ( fp, "%s\n", child_name ); + fclose(fp); + } + + pid_t awaited_pid; + while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) ) + { + fprintf ( stderr, + "qrsh_run %d info: parent: waiting for child %d...\n", + my_pid, + child_pid + ); + sleep(1); + } + + if ( -1 == awaited_pid ) + { + fprintf ( stderr, "qrsh_run error awaiting child!\n" ); + exit ( 1 ); + } + + /* + * Write the exit code. + */ + exit_code >>= 8; + + if ( named_child ) + { + if ( child_pid == awaited_pid ) + { + stringstream exit_code_file_name; + exit_code_file_name << child_dir_name.str() + << "/exit_code"; + + FILE * fp; + if ( ! (fp = fopen ( exit_code_file_name.str().c_str(), "w") ) ) + { + fprintf ( stderr, + "qrsh_run error: Can't open file |%s|\n", + exit_code_file_name.str().c_str() + ); + exit(1); + } + fprintf ( fp, "%d\n", exit_code ); + fclose ( fp ); + } + } + } + + fprintf ( stderr, "MDEBUG qrsh_run returning exit code %d\n", exit_code ); + return exit_code; +} + + + + diff --git a/cpp/src/tests/qrsh_server.cpp b/cpp/src/tests/qrsh_server.cpp new file mode 100644 index 0000000000..782f1e6c7c --- /dev/null +++ b/cpp/src/tests/qrsh_server.cpp @@ -0,0 +1,1068 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 <stdio.h> +#include <set> +#include <string> +#include <sstream> +#include <unistd.h> +#include <cstdlib> +#include <iostream> +#include <map> +#include <dirent.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <qpid/client/Connection.h> +#include <qpid/client/Session.h> +#include <qpid/client/AsyncSession.h> +#include <qpid/client/Message.h> +#include <qpid/client/MessageListener.h> +#include <qpid/client/SubscriptionManager.h> + + +using namespace qpid::client; +using namespace qpid::framing; +using namespace std; + + +namespace qpid { +namespace tests { + +int +mrand ( int max_desired_val ) +{ + double zero_to_one = (double) rand() / (double) RAND_MAX; + return (int) (zero_to_one * (double) max_desired_val); +} + + + +char * +file2str ( char const * file_name ) +{ + FILE * fp = fopen ( file_name, "r" ); + if(! fp) + { + fprintf ( stderr, "file2str error: can't open file |%s|.\n", file_name ); + return 0; + } + + fseek ( fp, 0, SEEK_END ); + size_t file_len = (size_t) ftell ( fp ); + rewind ( fp ); + char * content = (char *) malloc ( file_len + 1 ); + + if ( ! content ) + { + fprintf ( stderr, + "file2str error: can't malloc %d bytes.\n", + (int)file_len + ); + return 0; + } + + size_t items_read = fread ( content, file_len, 1, fp ); + + if ( 1 != items_read ) + { + fprintf ( stderr, "file2str error: read failed.\n" ); + free ( content ); + return 0; + } + + fclose ( fp ); + content[file_len] = 0; + + return content; +} + + + + + +class QrshServer : public MessageListener +{ + public: + + QrshServer ( SubscriptionManager & subscriptions, + char const * name, + char const * qrsh_run_path, + char const * host, + int port + ); + + virtual void received ( Message & message); + + + private: + + set<string> all_server_names; + + stringstream data_dir; + + SubscriptionManager & subscriptions; + + // Is this message addressed to me? + bool myMessage ( Message const & message ); + + /* ---------------------------------------------- + * Special Commands + * These are commands that the qrsh_server executes + * directly, rather than through a child process + * instance of qrsh_run. + */ + void runCommand ( Message const & message ); + void execute ( Message const & message ); + void wait ( Message const & message ); + void exited ( Message const & message ); + void get ( Message const & message ); + void rememberIntroduction ( Message const & message ); + void getStraw ( Message const & message ); + void addAlias ( Message const & message ); + + void start ( ); + void sayHello ( ); + void sayName ( ); + // end Special Commands ------------------------ + + + void saveCommand ( Message const & message ); + + void send ( string const & content ); + + void drawStraws ( ); + void getNames ( ); + void runSavedCommand ( ); + + char ** getArgs ( char const * s ); + bool isProcessName ( char const * s ); + int string_countWords ( char const * s ); + char const * skipWord ( char const * s ); + + + void string_replaceAll ( string & str, + string & target, + string & replacement + ); + + + string name, + qrsh_run_path, + host; + + vector<string *> aliases; + + int port; + + map < char *, int > abstract_name_map; + + set < string > myFellowBrokers; + + bool saidHello; + + Message savedCommand; + + vector < int > straws; + int myStraw; + +}; + + + +QrshServer::QrshServer ( SubscriptionManager & subs, + char const * name, + char const * qrsh_run_path, + char const * host, + int port + ) + : subscriptions ( subs ), + name ( name ), + qrsh_run_path ( qrsh_run_path ), + host ( host ), + port ( port ), + saidHello ( false ), + myStraw ( 0 ) +{ + data_dir << "/tmp/qrsh_" + << getpid(); + + if(mkdir ( data_dir.str().c_str(), 0777 ) ) + { + fprintf ( stderr, + "QrshServer::QrshServer error: can't mkdir |%s|\n", + data_dir.str().c_str() + ); + exit ( 1 ); + } +} + + + +void +QrshServer::saveCommand ( Message const & message ) +{ + savedCommand = message; +} + + + +void +QrshServer::runSavedCommand ( ) +{ + runCommand ( savedCommand ); +} + + + +void +QrshServer::start ( ) +{ + stringstream announcement_data; + announcement_data << "hello_my_name_is " + << name; + + send ( announcement_data.str() ); + + saidHello = true; +} + + + + +void +QrshServer::send ( string const & content ) +{ + try + { + Message message; + message.setData ( content ); + + Connection connection; + connection.open ( host, port ); + Session session = connection.newSession ( ); + session.messageTransfer ( arg::content = message, + arg::destination = "amq.fanout" + ); + session.close(); + connection.close(); + } + catch ( exception const & e ) + { + fprintf ( stderr, "QrshServer::send error: |%s|\n", e.what() ); + } +} + + + + +void +QrshServer::sayHello ( ) +{ + if ( saidHello ) + return; + + stringstream ss; + + ss << "hello_my_name_is " + << name; + + send ( ss.str() ); + saidHello = true; +} + + + +void +QrshServer::sayName ( ) +{ + fprintf ( stderr, "My name is: |%s|\n", name.c_str() ); +} + + + + +void +QrshServer::drawStraws ( ) +{ + myStraw = mrand ( 1000000000 ); + stringstream ss; + ss << "straw " + << name + << ' ' + << myStraw; + send ( ss.str() ); +} + + + +void +QrshServer::getStraw ( Message const & message ) +{ + int straw; + + char brokerName[1000]; + sscanf ( message.getData().c_str(), "%*s%s", brokerName ); + + if ( ! strcmp ( brokerName, name.c_str() ) ) + return; + + sscanf ( message.getData().c_str(), "%*s%*s%d", & straw ); + straws.push_back ( straw ); + + bool i_win = true; + int ties = 0; + + if ( straws.size() >= myFellowBrokers.size() ) + { + // All votes are in! Let's see if I win! + for ( unsigned int i = 0; i < straws.size(); ++ i ) + { + if ( straws[i] == myStraw ) + ++ ties; + else + if ( straws[i] > myStraw ) + { + i_win = false; + break; + } + } + + if ( i_win && (ties <= 0) ) + { + myStraw = 0; + straws.clear(); + runSavedCommand ( ); + } + else + if ( i_win && (ties > 0) ) + { + fprintf ( stderr, "MDEBUG oh no! drawStraws error: server %s tied with straw %d!\n", name.c_str(), straw ); + } + } +} + + + + +/* + * "APB" command (all-points-bullitens (commands that are not addressed + * specifically to any server)) are handled directly, here. + * Because if I return simply "true", the normal command processing code + * will misinterpret the command. + */ +bool +QrshServer::myMessage ( Message const & message ) +{ + int const maxlen = 100; + char head[maxlen]; + char first_word [ maxlen + 1 ]; + strncpy ( head, message.getData().c_str(), maxlen ); + sscanf ( head, "%s", first_word ); + + if ( ! strcmp ( name.c_str(), first_word ) ) + { + return true; + } + else + { + // Is the given name one of my aliases? + char possibleAlias[1000]; + if(1 == sscanf ( message.getData().c_str(), "%s", possibleAlias )) + { + for ( unsigned int i = 0; i < aliases.size(); ++ i ) + { + + if ( ! strcmp ( possibleAlias, aliases[i]->c_str() )) + { + return true; + } + } + } + } + + if ( ! strcmp ( first_word, "hello_my_name_is" ) ) + { + rememberIntroduction ( message ); + sayHello ( ); + return false; + } + else + if ( ! strcmp ( first_word, "straw" ) ) + { + getStraw ( message ); + return false; + } + else + if ( ! strcmp ( first_word, "all" ) ) + { + return true; + } + else + if ( ! strcmp ( first_word, "any" ) ) + { + straws.clear(); + usleep ( 200000 ); + saveCommand ( message ); + drawStraws ( ); + return false; + } + else + return false; +} + + + + +void +QrshServer::rememberIntroduction ( Message const & message ) +{ + char brokerName [ 1000 ]; + sscanf ( message.getData().c_str(), "%*s%s", brokerName ); + + if ( strcmp ( brokerName, name.c_str() ) ) + myFellowBrokers.insert ( string ( brokerName ) ); +} + + + + +void +QrshServer::addAlias ( Message const & message ) +{ + char alias[1000]; + sscanf ( message.getData().c_str(), "%*s%*s%s", alias ); + aliases.push_back ( new string(alias) ); +} + + + + +void +QrshServer::getNames ( ) +{ + abstract_name_map.clear(); + + DIR * dir = opendir ( data_dir.str().c_str() ); + + if ( ! dir ) + { + fprintf ( stderr, + "QrshServer::getNames error: could not open dir |%s|.\n", + data_dir.str().c_str() + ); + return; + } + + struct dirent * file; + while ( (file = readdir ( dir ) ) ) + { + if ( '.' != file->d_name[0] ) + { + stringstream pid_file_name; + pid_file_name << data_dir.str() + << '/' + << file->d_name + << "/pid"; + + int pid = 0; + FILE * fp; + if ( (fp = fopen ( pid_file_name.str().c_str(), "r" ) ) ) + { + fscanf ( fp, "%d", & pid ); + fclose ( fp ); + abstract_name_map.insert(pair<char*, int>(strdup(file->d_name), pid)); + } + else + { + /* + * Fail silently. The non-existence of this file + * is not necessarily an error. + */ + } + } + } + closedir ( dir ); +} + + + +void +QrshServer::string_replaceAll ( string & str, + string & target, + string & replacement + ) +{ + int target_size = target.size(); + int found_pos = 0; + + while ( 0 <= (found_pos = str.find ( target ) ) ) + str.replace ( found_pos, target_size, replacement ); +} + + + + +bool +QrshServer::isProcessName ( char const * str ) +{ + getNames(); + map<char *, int>::iterator it; + for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it ) + { + if ( ! strcmp ( str, it->first ) ) + return true; + } + + return false; +} + + + + + +int +QrshServer::string_countWords ( char const * s1 ) +{ + int count = 0; + char const * s2 = s1 + 1; + + if ( ! isspace(* s1) ) + { + ++ count; + } + + for ( ; * s2; ++ s1, ++ s2 ) + { + // count space-to-word transitions. + if ( isspace(*s1) && (! isspace(*s2)) ) + ++ count; + } + + return count; +} + + + + +void +QrshServer::execute ( Message const & message ) +{ + // First, gather all the symbolic names we know. + getNames(); + + // Now make a copy of the command, that I can alter. + string command ( message.getData() ); + + + // Replace each occurrence of every abstract name with its pid. + char pid_str[100]; + map<char *, int>::iterator it; + for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it ) + { + sprintf ( pid_str, "%d", it->second ); + string target ( it->first ), + replacement ( pid_str ); + string_replaceAll ( command, target, replacement ); + } + + + char const * truncated_command = skipWord(skipWord(command.c_str())); + + if ( truncated_command ) + system ( truncated_command ); +} + + + + + +void +QrshServer::get ( Message const & request_message ) +{ + char * file_content; + + /* + * Get the contents of the requested file. + */ + char file_or_process_name[1000]; + sscanf ( request_message.getData().c_str(), "%*s%*s%s", file_or_process_name ); + + if ( isProcessName ( file_or_process_name ) ) + { + stringstream desired_file_name; + desired_file_name << data_dir.str() + << '/' + << file_or_process_name + << '/'; + char requested_output_stream[1000]; + if(1 != sscanf ( request_message.getData().c_str(), + "%*s%*s%*s%s", + requested_output_stream + ) + ) + { + fprintf ( stderr, + "QrshServer::get error: Can't read requested data file name from this message: |%s|\n", + request_message.getData().c_str() + ); + return; + } + desired_file_name << requested_output_stream; + file_content = file2str ( desired_file_name.str().c_str() ); + } + else + { + file_content = file2str ( file_or_process_name ); + } + + stringstream reply_data ; + reply_data << "get_response " + << file_content; + /* + * Send a response-message to the server who is waiting. + */ + send ( reply_data.str() ); +} + + + + + + +void +QrshServer::exited ( Message const & message ) +{ + int exit_code = -1; + + // First, gather all the symbolic names we know. + getNames(); + + // Now make a copy of the command, that I can alter. + string edited_command ( message.getData() ); + + // Replace each occurrence of every abstract name with its pid. + char pid_str[100]; + map<char *, int>::iterator it; + for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it ) + { + sprintf ( pid_str, "%d", it->second ); + string target ( it->first ), + replacement ( pid_str ); + string_replaceAll ( edited_command, target, replacement ); + } + + // Skip the service name. That is not used by the child. + char const * truncated_command = skipWord(edited_command.c_str()); + + if ( truncated_command ) + { + stringstream ss; + ss << qrsh_run_path + << ' ' + << data_dir.str() + << ' ' + << truncated_command; + + int child_pid; + if ( ! (child_pid = fork() ) ) + { + // This is the child. + + char ** argv = getArgs ( ss.str().c_str() ); + execv ( qrsh_run_path.c_str(), argv ); + + perror ( "qrsh_server: execv error: " ); + exit ( 1 ); + } + else + { + // This is the parent. + pid_t awaited_pid; + while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) ) + { + fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" ); + sleep(1); + } + + if ( -1 == awaited_pid ) + { + fprintf ( stderr, "qrsh_server error awaiting child!\n" ); + exit ( 1 ); + } + + exit_code >>= 8; + + stringstream data; + data << "wait_response " + << exit_code; + + send ( data.str() ); + } + } +} + + + + +void +QrshServer::wait ( Message const & message ) +{ + bool pre_existing = false; + if ( 3 == string_countWords ( message.getData().c_str() ) ) + { + // The first word is the name of this service. + // The second word is "exec_wait". + // The third word is the symbolic name of the command to wait for. + // The fact that there are exactly three words means that this + // must be a command that has already been named and started -- + // we just need to find its pid and wait on it. + pre_existing = true; + } + + + int exit_code = -1; + + // First, gather all the symbolic names we know. + getNames(); + + // Now make a copy of the command, that I can alter. + string edited_command ( message.getData() ); + + // Replace each occurrence of every abstract name with its pid. + char pid_str[100]; + map<char *, int>::iterator it; + for ( it = abstract_name_map.begin(); it != abstract_name_map.end(); ++ it ) + { + sprintf ( pid_str, "%d", it->second ); + string target ( it->first ), + replacement ( pid_str ); + string_replaceAll ( edited_command, target, replacement ); + } + + // Skip the service name. That is not used by the child. + char const * truncated_command = skipWord(edited_command.c_str()); + + if ( truncated_command ) + { + stringstream ss; + ss << qrsh_run_path + << ' ' + << data_dir.str() + << ' ' + << truncated_command; + + int child_pid; + if ( ! (child_pid = fork() ) ) + { + // This is the child. + + char ** argv = getArgs ( ss.str().c_str() ); + execv ( qrsh_run_path.c_str(), argv ); + + perror ( "qrsh_server: execv error: " ); + exit ( 1 ); + } + else + { + // This is the parent. + pid_t awaited_pid; + while ( 0 == (awaited_pid = waitpid ( child_pid, & exit_code, WNOHANG)) ) + { + fprintf ( stderr, "qrsh_server info: parent: waiting for child...\n" ); + sleep(1); + } + + if ( -1 == awaited_pid ) + { + fprintf ( stderr, "qrsh_server error awaiting child!\n" ); + exit ( 1 ); + } + } + + exit_code >>= 8; + + stringstream data; + data << "wait_response " + << exit_code; + + send ( data.str() ); + } +} + + + + + +char const * +QrshServer::skipWord ( char const * s ) +{ + if(! (s && *s) ) + return 0; + + // skip past initial white space + while ( isspace(*s) ) + { + ++ s; + if(! *s) + return 0; + } + + // skip past first word + while ( ! isspace(*s) ) + { + ++ s; + if(! *s) + return 0; + } + + return s; +} + + + + + +char ** +QrshServer::getArgs ( char const * str ) +{ + char const * s = str; + + char ** argv = 0; + vector<int> start_positions, + lengths; + + int pos = 0; + int arg_len = 0; + + int n_args = 0; + while ( 1 ) + { + // advance over whitespace. + while ( isspace ( *s ) ) + { + ++ s; ++ pos; + if(! *s) + { + goto done; + } + } + + ++ n_args; + start_positions.push_back ( pos ); + arg_len = 0; + + // advance over non-whitespace. + while ( ! isspace ( *s ) ) + { + ++ s; ++ pos; ++ arg_len; + if(! *s) + { + lengths.push_back ( arg_len ); + arg_len = 0; + goto done; + } + } + + lengths.push_back ( arg_len ); + arg_len = 0; + } + + done: + + if ( arg_len > 0 ) + lengths.push_back ( arg_len ); + + // Alloc the array. + argv = (char **) malloc ( sizeof(char *) * ( n_args + 1 ) ); + argv[n_args] = 0; // mull-term the array. + + for ( int i = 0; i < n_args; ++ i ) + { + argv[i] = ( char *) malloc ( lengths[i] + 1 ); + strncpy ( argv[i], + str + start_positions[i], + lengths[i] + ); + argv[i][lengths[i]] = 0; + } + + return argv; +} + + + +void +QrshServer::runCommand ( Message const & message ) +{ + char const * s = message.getData().c_str(); + + /* + * Skip the first word, which is this server's name. + */ + while ( isspace(*s) ) // go to start of first word. + ++ s; + + while ( ! isspace(*s) ) // go to end of first word. + ++ s; + + while ( isspace(*s) ) // go to start of second word. + ++ s; + + char command_name[1000]; + sscanf ( s, "%s", command_name ); + + if ( ! strcmp ( "get", command_name ) ) + { + get ( message ); + } + else + if ( ! strcmp ( "exited", command_name ) ) + { + exited ( message ); + } + else + if ( ! strcmp ( "exec_wait", command_name ) ) + { + wait ( message ); + } + else + if ( ! strcmp ( "exec", command_name ) ) + { + execute ( message ); + } + else + if ( ! strcmp ( "start", command_name ) ) + { + start ( ); + } + else + if ( ! strcmp ( "alias", command_name ) ) + { + addAlias ( message ); + } + else + if ( ! strcmp ( "sayName", command_name ) ) + { + sayName ( ); + } + else + { + /* + * If the command is not any of the "special" commands + * above, then it's a "normal" command. + * That means we run it with a child process instance of + * qrsh_run, which will save all its data in the qrsh dir. + */ + stringstream ss; + ss << qrsh_run_path + << ' ' + << data_dir.str() + << ' ' + << s; + + if ( ! fork() ) + { + char ** argv = getArgs ( ss.str().c_str() ); + execv ( qrsh_run_path.c_str(), argv ); + perror ( "qrsh_server: execv error: " ); + } + } +} + + + +void +QrshServer::received ( Message & message ) +{ + if ( myMessage ( message ) ) + runCommand ( message ); +} + + + +}} // namespace qpid::tests + +using namespace qpid::tests; + +/* + * fixme mick Mon Aug 3 10:29:26 EDT 2009 + * argv[1] server name + * argv[2] qrsh exe path + * argv[3] host + * argv[4] port + */ +int +main ( int /*argc*/, char** argv ) +{ + const char* host = argv[3]; + int port = atoi(argv[4]); + Connection connection; + Message msg; + + srand ( getpid() ); + + try + { + connection.open ( host, port ); + Session session = connection.newSession(); + + + // Declare queues. + string myQueue = session.getId().getName(); + session.queueDeclare ( arg::queue=myQueue, + arg::exclusive=true, + arg::autoDelete=true); + + session.exchangeBind ( arg::exchange="amq.fanout", + arg::queue=myQueue, + arg::bindingKey="my-key"); + + // Create a server and subscribe it to my queue. + SubscriptionManager subscriptions ( session ); + QrshServer server ( subscriptions, + argv[1], // server name + argv[2], // qrsh exe path + host, + port + ); + subscriptions.subscribe ( server, myQueue ); + + // Receive messages until the subscription is cancelled + // by QrshServer::received() + subscriptions.run(); + + connection.close(); + } + catch(const exception& error) + { + cout << error.what() << endl; + return 1; + } + + return 0; +} + + + + diff --git a/cpp/src/qpid/sys/windows/mingw32_compat.h b/cpp/src/tests/qrsh_utils/10_all index 51f613cc25..7b486ea672 100644..100755 --- a/cpp/src/qpid/sys/windows/mingw32_compat.h +++ b/cpp/src/tests/qrsh_utils/10_all @@ -1,5 +1,3 @@ -#ifndef _sys_windows_mingw32_compat -#define _sys_windows_mingw32_compat /* * * Licensed to the Apache Software Foundation (ASF) under one @@ -11,7 +9,7 @@ * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable 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,21 +17,14 @@ * specific language governing permissions and limitations * under the License. * - */ + */ + +#! /bin/bash -#ifdef WIN32 -#ifndef _MSC_VER +echo "Asking all servers to say their names... " +qrsh 127.0.0.1 5813 \ + all sayName -// -// 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. -// -#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); -#endif -#endif -#endif diff --git a/cpp/src/tests/qrsh_utils/1_remote_run b/cpp/src/tests/qrsh_utils/1_remote_run new file mode 100755 index 0000000000..5b9b307bba --- /dev/null +++ b/cpp/src/tests/qrsh_utils/1_remote_run @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + + +./qrsh 127.0.0.1 5813 \ + mrg23 command_1 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz diff --git a/cpp/src/tests/qrsh_utils/2_forever b/cpp/src/tests/qrsh_utils/2_forever new file mode 100755 index 0000000000..5528b0e4d8 --- /dev/null +++ b/cpp/src/tests/qrsh_utils/2_forever @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + + +./qrsh 127.0.0.1 5813 \ + mrg23 command_2 /home/mick/redhat/qrsh/qrsh_run/forever foo bar baz diff --git a/cpp/src/tests/qrsh_utils/3_kill_it b/cpp/src/tests/qrsh_utils/3_kill_it new file mode 100755 index 0000000000..afc7a03c9d --- /dev/null +++ b/cpp/src/tests/qrsh_utils/3_kill_it @@ -0,0 +1,27 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +echo "Killing command 2... " +./qrsh 127.0.0.1 5813 \ + mrg23 exec kill -9 command_2 + diff --git a/cpp/src/tests/qrsh_utils/4_wait_for_it b/cpp/src/tests/qrsh_utils/4_wait_for_it new file mode 100755 index 0000000000..a4dc0da1ce --- /dev/null +++ b/cpp/src/tests/qrsh_utils/4_wait_for_it @@ -0,0 +1,26 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +./qrsh 127.0.0.1 5813 \ + mrg23 exec_wait /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz +echo "my_command returned an exit code of $?" diff --git a/cpp/src/tests/qrsh_utils/5_exited b/cpp/src/tests/qrsh_utils/5_exited new file mode 100755 index 0000000000..4fec1dcc79 --- /dev/null +++ b/cpp/src/tests/qrsh_utils/5_exited @@ -0,0 +1,64 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +path=/home/mick/redhat/qrsh/qrsh_run + +echo "Running command_3 ..." +./qrsh 127.0.0.1 5813 \ + mrg23 command_3 $path/my_command foo bar baz + +echo "Now I do some other stuff..." +sleep 1 +echo "And then some more stuff..." +sleep 1 +echo "and so on..." +sleep 1 + +echo "Now I'm waiting for command_3 ..." +./qrsh 127.0.0.1 5813 \ + mrg23 exited command_3 +echo "has command_3 exited: $? ." +sleep 5 + +./qrsh 127.0.0.1 5813 \ + mrg23 exited command_3 +echo "has command_3 exited: $? ." +sleep 5 + +./qrsh 127.0.0.1 5813 \ + mrg23 exited command_3 +echo "has command_3 exited: $? ." +sleep 5 + +./qrsh 127.0.0.1 5813 \ + mrg23 exited command_3 +echo "has command_3 exited: $? ." +sleep 5 + +./qrsh 127.0.0.1 5813 \ + mrg23 exited command_3 +echo "has command_3 exited: $? ." +sleep 5 + + + diff --git a/cpp/src/tests/qrsh_utils/6_get b/cpp/src/tests/qrsh_utils/6_get new file mode 100755 index 0000000000..4b35ca98e6 --- /dev/null +++ b/cpp/src/tests/qrsh_utils/6_get @@ -0,0 +1,29 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +echo "getting /tmp/foo ..." +./qrsh 127.0.0.1 5813 \ + mrg23 get /tmp/foo + + + diff --git a/cpp/src/tests/qrsh_utils/7_get_output b/cpp/src/tests/qrsh_utils/7_get_output new file mode 100755 index 0000000000..59911089ec --- /dev/null +++ b/cpp/src/tests/qrsh_utils/7_get_output @@ -0,0 +1,44 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +echo "Run a command..." +./qrsh 127.0.0.1 5813 \ + mrg23 command_4 /home/mick/redhat/qrsh/qrsh_run/my_command foo bar baz + +echo "Wait for a while..." +sleep 20 + +echo "Get stderr output:" +echo "------------- begin stderr ---------------" +./qrsh 127.0.0.1 5813 \ + mrg23 get command_4 stderr +echo "------------- end stderr ---------------" +echo " " +echo " " +echo " " +echo "Get stdout output:" +echo "------------- begin stdout ---------------" +./qrsh 127.0.0.1 5813 \ + mrg23 get command_4 stdout +echo "------------- end stdout ---------------" + diff --git a/cpp/src/tests/qrsh_utils/8_any b/cpp/src/tests/qrsh_utils/8_any new file mode 100755 index 0000000000..2a922ea0e0 --- /dev/null +++ b/cpp/src/tests/qrsh_utils/8_any @@ -0,0 +1,43 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +echo "asking any server to say his name ..." +./qrsh 127.0.0.1 5813 \ + any sayName +sleep 1 +echo "asking any server to say his name ..." +./qrsh 127.0.0.1 5813 \ + any sayName +sleep 1 +echo "asking any server to say his name ..." +./qrsh 127.0.0.1 5813 \ + any sayName +sleep 1 +echo "asking any server to say his name ..." +./qrsh 127.0.0.1 5813 \ + any sayName +sleep 1 + + + + diff --git a/cpp/src/tests/qrsh_utils/9_alias b/cpp/src/tests/qrsh_utils/9_alias new file mode 100755 index 0000000000..a4cfdfdf9a --- /dev/null +++ b/cpp/src/tests/qrsh_utils/9_alias @@ -0,0 +1,38 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +#! /bin/bash + +# Make a group of two of the servers, using "alias", +# and send the group a command. + +qrsh 127.0.0.1 5813 \ + mrg22 alias group_1 +qrsh 127.0.0.1 5813 \ + mrg23 alias group_1 + +echo "Asking group_1 to say their names... " +qrsh 127.0.0.1 5813 \ + group_1 sayName + + + + diff --git a/cpp/src/qmf/EventNotifierImpl.h b/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp index d85f9979d2..386e2f73f0 100644 --- a/cpp/src/qmf/EventNotifierImpl.h +++ b/cpp/src/tests/qrsh_utils/qrsh_example_command.cpp @@ -1,7 +1,5 @@ -#ifndef __QMF_EVENT_NOTIFIER_IMPL_H -#define __QMF_EVENT_NOTIFIER_IMPL_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 @@ -9,40 +7,46 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 <stdio.h> +#include <unistd.h> + -#include "qmf/AgentSession.h" -#include "qmf/ConsoleSession.h" -namespace qmf +main ( int argc, char ** argv ) { - class EventNotifierImpl { - private: - bool readable; - AgentSession agent; - ConsoleSession console; - - public: - EventNotifierImpl(AgentSession& agentSession); - EventNotifierImpl(ConsoleSession& consoleSession); - virtual ~EventNotifierImpl(); - - void setReadable(bool readable); - bool isReadable() const; - - protected: - virtual void update(bool readable) = 0; - }; + fprintf ( stderr, "Hello, I am the Example Child!\n"); + fprintf ( stderr, "my arguments %d are:\n", argc - 1 ); + fprintf ( stdout, "And hello to stdout, too!\n"); + + int i; + for ( i = 1; i < argc; ++ i ) + { + fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] ); + } + + for ( i = 0; i < 15; ++ i ) + { + fprintf ( stderr, "child sleeping...\n" ); + sleep ( 1 ); + } + + fprintf ( stderr, "child exiting with code 13.\n" ); + + return 13; } -#endif + + diff --git a/cpp/src/tests/qrsh_utils/qrsh_forever.cpp b/cpp/src/tests/qrsh_utils/qrsh_forever.cpp new file mode 100644 index 0000000000..191a9bca11 --- /dev/null +++ b/cpp/src/tests/qrsh_utils/qrsh_forever.cpp @@ -0,0 +1,50 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT 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 <stdio.h> +#include <unistd.h> + + + +main ( int argc, char ** argv ) +{ + fprintf ( stderr, "Hello, I am the Forever Example Child!\n"); + fprintf ( stderr, "my %d arguments are:\n", argc - 1 ); + + int i; + for ( i = 1; i < argc; ++ i ) + fprintf ( stderr, "arg %d: |%s|\n", i, argv[i] ); + + for ( i = 0; i >= 0; ++ i ) + { + fprintf ( stderr, "child sleeping forever %d ...\n" , i); + sleep ( 1 ); + } + + fprintf ( stderr, "child exiting with code 12.\n" ); + + return 12; +} + + + + diff --git a/cpp/src/tests/qrsh_utils/qsh_doc.txt b/cpp/src/tests/qrsh_utils/qsh_doc.txt new file mode 100644 index 0000000000..ad5990b38b --- /dev/null +++ b/cpp/src/tests/qrsh_utils/qsh_doc.txt @@ -0,0 +1,309 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +############################################## + qrsh: a Qpid-based remote shell utility + + Last updated: 3 Aug 09 Mick Goulish +############################################## + + + +============================= +Overview +============================= + + You're writing a multi-box test, and you want to write a + shell script in which you start processes on other boxes + and kill them (or send arbitrary signals to them). + + But ssh doesn't let you signal them, and bash isn't the + greatest language in the world for creating data structures + (like you need to associate the PIDs with box names and + executable names.) + + Qsh is a utility implemented on Qpid that you can use from + within your bash script, or any other scripting language. + With it, you can: + + 1. run any executable on any box in your cluster. + + 2. don't worry about PIDs and box-names. You associate + your own abstract names with the executable instances, + and then use those names in the rest of your script. + I.e. "broker_1" "sender_3" etc. + + 3. Launch the executable and wait until it returns, and + get its exit code. + + 4. Launch your executable and do other stuff, then come + back later and see if it has exited. + + 5. Get whatever it sent to stdout or stderr. + + 6. Get the contents of any other file. + + 7. send a command to all your boxes at once + + 8. send a command to a randomly selected box. + + 9. define groups of boxes, and send a command simultaneously + to all boxes in a given group. + + + + +============================= +Using It +============================= + + 1. You need to run a Qpid broker. + + 2. You start a Qpid client ( which is called a qrsh_server ) + on all the boxes you care about. And you give them all + names like "mrg13", "mrg14" etc. The names can be anything + you want, but I've always used one qrsh_server per box, + and given it the box name. ( However, you can run two on + one box, they won't collide. ) + + 3. After you start all servers, send a "start" command to any + one of them: + + 4. The qrsh_servers use the fanout exchange to talk to each + other. + + 5. In your script, you run an executable called "qrsh". It knows + how to talk to the servers, do what you want, and retrieve + the data you want. + + + example start script: (this does 4 servers on the same box) + ------------------------------------------------------------- + + echo "Starting server mrg22 ..." + ./qrsh_server mrg22 ./qrsh_run 127.0.0.1 5813 & + + echo "Starting server mrg23 ..." + ./qrsh_server mrg23 ./qrsh_run 127.0.0.1 5813 & + + echo "Starting server mrg24 ..." + ./qrsh_server mrg24 ./qrsh_run 127.0.0.1 5813 & + + echo "Starting server mrg25 ..." + ./qrsh_server mrg25 ./qrsh_run 127.0.0.1 5813 & + + echo "Issuing start command..." + sleep 2 + ./qrsh 127.0.0.1 5813 mrg22 start + sleep 1 + + echo "Ready." + + # end of script. + + + + + + +============================= +Qrsh Syntax +============================= + + qrsh host port server_name command_name arg* + + + "host" and "port" specify the Qpid server to connect to. + + "server_name" can be anything you want. I always use the name + of the box that the server is running on. + + "command_name" is the name that you choose to assign to + the process you are running. Each process that you decide + to name must have a unique name within this script. + + Or it could be a reserved command name, that Qsh + interprets in a special way. + + Reserved command names are: + + exec + exec_wait + exited + get + + "exec" means "interpret the rest of the command line as a + command to be executed by the designated server. + + "exec_wait" means same as "exec", but wait for the command + to terminate, and return its exit code. + + "exited" -- you provide 1 arg, which is an abstract + process name. qrsh returns 1 if that process has exited, + else 0. + + "get" -- you provide one arg which is a path. qrsh returns + (by printing to stdout) the contents of that file. + + "arg*" is zero or more arguments. They are interpreted + differently depending on whether you are using one of + the above reserved command names, or making up your own + abstract name for a command. + + + + +============================= +Examples +============================= + + 1. Run a process on a remote box. + + qrsh mrg23 command_1 /usr/sbin/whatever foo bar baz + + Returns immediately. + + + + 2. Kill a process that you started earlier: + + qrsh mrg23 exec kill -9 command_1 + + After the word "exec" put any command line you want. + The server you're sending this to will replace all abstract + names in the command with process IDs. ( In this example, + just the word "command_1" will be replaced. ) Then it will + execute the command. + + + + 3. Execute a command, and wait for it to finish + + qrsh mrg23 exec_wait command_name args + + + + 4. Check on whether a command you issude earlier has exited. + + ./qrsh mrg23 exited command_3 + + Returns 1 if it has exited, else 0. + + + + 5. Get the contents of a file from the remote system: + + ./qrsh mrg23 get /tmp/foo + + Prints the contents to stdout. + + + + 6. Send a command to all servers at once: + + # This example causes them all to print thir names to stderr. + ./qrsh all sayName + + + 7. Define a group of servers and send a command to that group. + + #! /bin/bash + + # Make a group of two of the servers, using "alias", + # and send the group a command. + + qrsh 127.0.0.1 5813 \ + mrg22 alias group_1 + + qrsh 127.0.0.1 5813 \ + mrg23 alias group_1 + + echo "Asking group_1 to say their names... " + qrsh 127.0.0.1 5813 \ + group_1 sayName + + # end of script. + + + + + 8. Execute a command and get its stdout and stderr contents. + + #! /bin/bash + + echo "Run a command..." + ./qrsh 127.0.0.1 5813 \ + mrg23 command_4 my_command foo bar baz + + echo "Wait for a while..." + sleep 10 + + echo "Get stderr output:" + echo "------------- begin stderr ---------------" + ./qrsh 127.0.0.1 5813 \ + mrg23 get command_4 stderr + echo "------------- end stderr ---------------" + echo " " + + echo " " + echo "Get stdout output:" + echo "------------- begin stdout ---------------" + ./qrsh 127.0.0.1 5813 \ + mrg23 get command_4 stdout + echo "------------- end stdout ---------------" + + # end of script. + + + + + 9. Send a command to one of your servers, selected + at random. + + #! /bin/bash + + # I do it multiple times here, so I can see + # that it really is selecting randomly. + + echo "asking any server to say his name ..." + ./qrsh 127.0.0.1 5813 \ + any sayName + sleep 1 + + echo "asking any server to say his name ..." + ./qrsh 127.0.0.1 5813 \ + any sayName + sleep 1 + + echo "asking any server to say his name ..." + ./qrsh 127.0.0.1 5813 \ + any sayName + sleep 1 + + echo "asking any server to say his name ..." + ./qrsh 127.0.0.1 5813 \ + any sayName + + # end of script. + + + + diff --git a/cpp/src/tests/queue_flow_limit_tests.py b/cpp/src/tests/queue_flow_limit_tests.py deleted file mode 100644 index dec7cfb3af..0000000000 --- a/cpp/src/tests/queue_flow_limit_tests.py +++ /dev/null @@ -1,371 +0,0 @@ -#!/usr/bin/env python -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -import sys -from qpid.testlib import TestBase010 -from qpid import datatypes, messaging -from qpid.messaging import Message, Empty -from threading import Thread, Lock -from logging import getLogger -from time import sleep, time -from os import environ, popen - -class QueueFlowLimitTests(TestBase010): - - def __getattr__(self, name): - if name == "assertGreater": - return lambda a, b: self.failUnless(a > b) - else: - raise AttributeError - - def _create_queue(self, name, - stop_count=None, resume_count=None, - stop_size=None, resume_size=None, - max_size=None, max_count=None): - """ Create a queue with the given flow settings via the queue.declare - command. - """ - args={} - if (stop_count is not None): - args["qpid.flow_stop_count"] = stop_count; - if (resume_count is not None): - args["qpid.flow_resume_count"] = resume_count; - if (stop_size is not None): - args["qpid.flow_stop_size"] = stop_size; - if (resume_size is not None): - args["qpid.flow_resume_size"] = resume_size; - if (max_size is not None): - args["qpid.max_size"] = max_size; - if (max_count is not None): - args["qpid.max_count"] = max_count; - - - self.session.queue_declare(queue=name, arguments=args) - - qs = self.qmf.getObjects(_class="queue") - for i in qs: - if i.name == name: - # verify flow settings - if (stop_count is not None): - self.assertEqual(i.arguments.get("qpid.flow_stop_count"), stop_count) - if (resume_count is not None): - self.assertEqual(i.arguments.get("qpid.flow_resume_count"), resume_count) - if (stop_size is not None): - self.assertEqual(i.arguments.get("qpid.flow_stop_size"), stop_size) - if (resume_size is not None): - self.assertEqual(i.arguments.get("qpid.flow_resume_size"), resume_size) - if (max_size is not None): - self.assertEqual(i.arguments.get("qpid.max_size"), max_size) - if (max_count is not None): - self.assertEqual(i.arguments.get("qpid.max_count"), max_count) - self.failIf(i.flowStopped) - return i.getObjectId() - self.fail("Unable to create queue '%s'" % name) - return None - - - def _delete_queue(self, name): - """ Delete a named queue - """ - self.session.queue_delete(queue=name) - - - def _start_qpid_send(self, queue, count, content="X", capacity=100): - """ Use the qpid-send client to generate traffic to a queue. - """ - command = "qpid-send" + \ - " -b" + " %s:%s" % (self.broker.host, self.broker.port) \ - + " -a " + str(queue) \ - + " --messages " + str(count) \ - + " --content-string " + str(content) \ - + " --capacity " + str(capacity) - return popen(command) - - def _start_qpid_receive(self, queue, count, timeout=5): - """ Use the qpid-receive client to consume from a queue. - Note well: prints one line of text to stdout for each consumed msg. - """ - command = "qpid-receive" + \ - " -b " + "%s:%s" % (self.broker.host, self.broker.port) \ - + " -a " + str(queue) \ - + " --messages " + str(count) \ - + " --timeout " + str(timeout) \ - + " --print-content yes" - return popen(command) - - def test_qpid_config_cmd(self): - """ Test the qpid-config command's ability to configure a queue's flow - control thresholds. - """ - tool = environ.get("QPID_CONFIG_EXEC") - if tool: - command = tool + \ - " --broker-addr=%s:%s " % (self.broker.host, self.broker.port) \ - + "add queue test01 --flow-stop-count=999" \ - + " --flow-resume-count=55 --flow-stop-size=5000000" \ - + " --flow-resume-size=100000" - cmd = popen(command) - rc = cmd.close() - self.assertEqual(rc, None) - - # now verify the settings - self.startQmf(); - qs = self.qmf.getObjects(_class="queue") - for i in qs: - if i.name == "test01": - self.assertEqual(i.arguments.get("qpid.flow_stop_count"), 999) - self.assertEqual(i.arguments.get("qpid.flow_resume_count"), 55) - self.assertEqual(i.arguments.get("qpid.flow_stop_size"), 5000000) - self.assertEqual(i.arguments.get("qpid.flow_resume_size"), 100000) - self.failIf(i.flowStopped) - break; - self.assertEqual(i.name, "test01") - self._delete_queue("test01") - - - def test_flow_count(self): - """ Create a queue with count-based flow limit. Spawn several - producers which will exceed the limit. Verify limit exceeded. Consume - all messages. Verify flow control released. - """ - self.startQmf(); - oid = self._create_queue("test-q", stop_count=373, resume_count=229) - self.assertEqual(self.qmf.getObjects(_objectId=oid)[0].flowStoppedCount, 0) - - sndr1 = self._start_qpid_send("test-q", count=1213, content="XXX", capacity=50); - sndr2 = self._start_qpid_send("test-q", count=797, content="Y", capacity=13); - sndr3 = self._start_qpid_send("test-q", count=331, content="ZZZZZ", capacity=149); - totalMsgs = 1213 + 797 + 331 - - # wait until flow control is active - deadline = time() + 10 - while (not self.qmf.getObjects(_objectId=oid)[0].flowStopped) and \ - time() < deadline: - pass - self.failUnless(self.qmf.getObjects(_objectId=oid)[0].flowStopped) - depth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - self.assertGreater(depth, 373) - - # now wait until the enqueues stop happening - ensure that - # not all msgs have been sent (senders are blocked) - sleep(1) - newDepth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - while depth != newDepth: - depth = newDepth; - sleep(1) - newDepth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - self.assertGreater(totalMsgs, depth) - - # drain the queue - rcvr = self._start_qpid_receive("test-q", - count=totalMsgs) - count = 0; - x = rcvr.readline() # prints a line for each received msg - while x: - count += 1; - x = rcvr.readline() - - sndr1.close(); - sndr2.close(); - sndr3.close(); - rcvr.close(); - - self.assertEqual(count, totalMsgs) - self.failIf(self.qmf.getObjects(_objectId=oid)[0].flowStopped) - self.failUnless(self.qmf.getObjects(_objectId=oid)[0].flowStoppedCount) - - self._delete_queue("test-q") - - - def test_flow_size(self): - """ Create a queue with size-based flow limit. Spawn several - producers which will exceed the limit. Verify limit exceeded. Consume - all messages. Verify flow control released. - """ - self.startQmf(); - oid = self._create_queue("test-q", stop_size=351133, resume_size=251143) - - sndr1 = self._start_qpid_send("test-q", count=1699, content="X"*439, capacity=53); - sndr2 = self._start_qpid_send("test-q", count=1129, content="Y"*631, capacity=13); - sndr3 = self._start_qpid_send("test-q", count=881, content="Z"*823, capacity=149); - totalMsgs = 1699 + 1129 + 881 - - # wait until flow control is active - deadline = time() + 10 - while (not self.qmf.getObjects(_objectId=oid)[0].flowStopped) and \ - time() < deadline: - pass - self.failUnless(self.qmf.getObjects(_objectId=oid)[0].flowStopped) - self.assertGreater(self.qmf.getObjects(_objectId=oid)[0].byteDepth, 351133) - - # now wait until the enqueues stop happening - ensure that - # not all msgs have been sent (senders are blocked) - depth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - sleep(1) - newDepth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - while depth != newDepth: - depth = newDepth; - sleep(1) - newDepth = self.qmf.getObjects(_objectId=oid)[0].msgDepth - self.assertGreater(totalMsgs, depth) - - # drain the queue - rcvr = self._start_qpid_receive("test-q", - count=totalMsgs) - count = 0; - x = rcvr.readline() # prints a line for each received msg - while x: - count += 1; - x = rcvr.readline() - - sndr1.close(); - sndr2.close(); - sndr3.close(); - rcvr.close(); - - self.assertEqual(count, totalMsgs) - self.failIf(self.qmf.getObjects(_objectId=oid)[0].flowStopped) - - self._delete_queue("test-q") - - - def verify_limit(self, testq): - """ run a limit check against the testq object - """ - - testq.mgmt = self.qmf.getObjects(_objectId=testq.oid)[0] - - # fill up the queue, waiting until flow control is active - sndr1 = self._start_qpid_send(testq.mgmt.name, count=testq.sendCount, content=testq.content) - deadline = time() + 10 - while (not testq.mgmt.flowStopped) and time() < deadline: - testq.mgmt.update() - - self.failUnless(testq.verifyStopped()) - - # now consume enough messages to drop below the flow resume point, and - # verify flow control is released. - rcvr = self._start_qpid_receive(testq.mgmt.name, count=testq.consumeCount) - rcvr.readlines() # prints a line for each received msg - rcvr.close(); - - # we should now be below the resume threshold - self.failUnless(testq.verifyResumed()) - - self._delete_queue(testq.mgmt.name) - sndr1.close(); - - - def test_default_flow_count(self): - """ Create a queue with count-based size limit, and verify the computed - thresholds using the broker's default ratios. - """ - class TestQ: - def __init__(self, oid): - # Use the broker-wide default flow thresholds of 80%/70% (see - # run_queue_flow_limit_tests) to base the thresholds off the - # queue's max_count configuration parameter - # max_count == 1000 -> stop == 800, resume == 700 - self.oid = oid - self.sendCount = 1000 - self.consumeCount = 301 # (send - resume) + 1 to reenable flow - self.content = "X" - def verifyStopped(self): - self.mgmt.update() - return self.mgmt.flowStopped and (self.mgmt.msgDepth > 800) - def verifyResumed(self): - self.mgmt.update() - return (not self.mgmt.flowStopped) and (self.mgmt.msgDepth < 700) - - self.startQmf(); - oid = self._create_queue("test-X", max_count=1000) - self.verify_limit(TestQ(oid)) - - - def test_default_flow_size(self): - """ Create a queue with byte-based size limit, and verify the computed - thresholds using the broker's default ratios. - """ - class TestQ: - def __init__(self, oid): - # Use the broker-wide default flow thresholds of 80%/70% (see - # run_queue_flow_limit_tests) to base the thresholds off the - # queue's max_count configuration parameter - # max_size == 10000 -> stop == 8000 bytes, resume == 7000 bytes - self.oid = oid - self.sendCount = 2000 - self.consumeCount = 601 # (send - resume) + 1 to reenable flow - self.content = "XXXXX" # 5 bytes per message sent. - def verifyStopped(self): - self.mgmt.update() - return self.mgmt.flowStopped and (self.mgmt.byteDepth > 8000) - def verifyResumed(self): - self.mgmt.update() - return (not self.mgmt.flowStopped) and (self.mgmt.byteDepth < 7000) - - self.startQmf(); - oid = self._create_queue("test-Y", max_size=10000) - self.verify_limit(TestQ(oid)) - - - def test_blocked_queue_delete(self): - """ Verify that blocked senders are unblocked when a queue that is flow - controlled is deleted. - """ - - class BlockedSender(Thread): - def __init__(self, tester, queue, count, capacity=10): - self.tester = tester - self.queue = queue - self.count = count - self.capacity = capacity - Thread.__init__(self) - self.done = False - self.start() - def run(self): - # spawn qpid-send - p = self.tester._start_qpid_send(self.queue, - self.count, - self.capacity) - p.close() # waits for qpid-send to complete - self.done = True - - self.startQmf(); - oid = self._create_queue("kill-q", stop_size=10, resume_size=2) - q = self.qmf.getObjects(_objectId=oid)[0] - self.failIf(q.flowStopped) - - sender = BlockedSender(self, "kill-q", count=100) - # wait for flow control - deadline = time() + 10 - while (not q.flowStopped) and time() < deadline: - q.update() - - self.failUnless(q.flowStopped) - self.failIf(sender.done) # sender blocked - - self._delete_queue("kill-q") - sender.join(5) - self.failIf(sender.isAlive()) - self.failUnless(sender.done) - - - - diff --git a/cpp/src/tests/replication_test b/cpp/src/tests/replication_test index 8c37568875..691fd20b0c 100755 --- a/cpp/src/tests/replication_test +++ b/cpp/src/tests/replication_test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/cpp/src/tests/run_acl_tests b/cpp/src/tests/run_acl_tests index 41f41e20e1..aff13408ed 100755 --- a/cpp/src/tests/run_acl_tests +++ b/cpp/src/tests/run_acl_tests @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/cpp/src/tests/run_cli_tests b/cpp/src/tests/run_cli_tests index ec5c71b646..3f1388b9f5 100755 --- a/cpp/src/tests/run_cli_tests +++ b/cpp/src/tests/run_cli_tests @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one @@ -70,8 +70,7 @@ stop_brokers() { if test -d ${PYTHON_DIR} ; then start_brokers echo "Running CLI tests using brokers on ports $LOCAL_PORT $REMOTE_PORT" - PYTHON_TESTS=${PYTHON_TESTS:-$*} - $QPID_PYTHON_TEST -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $targs $PYTHON_TESTS $@ + $QPID_PYTHON_TEST -m cli_tests -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dcli-dir=$CLI_DIR $targs $@ RETCODE=$? stop_brokers if test x$RETCODE != x0; then diff --git a/cpp/src/tests/run_federation_sys_tests b/cpp/src/tests/run_federation_sys_tests deleted file mode 100755 index f5f772d72e..0000000000 --- a/cpp/src/tests/run_federation_sys_tests +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Run the federation system tests. - -source ./test_env.sh - -MODULENAME=federation_sys - -# Test for clustering -ps -u root | grep 'aisexec\|corosync' > /dev/null -if (( $? == 0 )); then - CLUSTERING_ENABLED=1 -else - echo "WARNING: No clustering detected; tests using it will be ignored." -fi - -# Test for long test -if [[ "$1" == "LONG_TEST" ]]; then - USE_LONG_TEST=1 - shift # get rid of this param so it is not treated as a test name -fi - -trap stop_brokers INT TERM QUIT - -SKIPTESTS="-i federation_sys.E_* -i federation_sys.F_* -i federation_sys.G_* -i federation_sys.H_*" -if [ -z ${USE_LONG_TEST} ]; then - SKIPTESTS="-i federation_sys.A_Long* -i federation_sys.B_Long* ${SKIPTESTS}" -fi -echo "WARNING: Tests using persistence will be ignored." -if [ -z ${CLUSTERING_ENABLED} ]; then - SKIPTESTS="${SKIPTESTS} -i federation_sys.C_* -i federation_sys.D_*" -elif [ -z ${USE_LONG_TEST} ]; then - SKIPTESTS="${SKIPTESTS} -i federation_sys.C_Long* -i federation_sys.D_Long*" -fi - -start_brokers() { - start_broker() { - ${QPIDD_EXEC} --daemon --port 0 --auth no --no-data-dir $1 > qpidd.port - PORT=`cat qpidd.port` - eval "$2=${PORT}" - } - start_broker "" LOCAL_PORT - start_broker "" REMOTE_PORT - if [ -n "${CLUSTERING_ENABLED}" ]; then - start_broker "--load-module ${CLUSTER_LIB} --cluster-name test-cluster-1" CLUSTER_C1_1 - start_broker "--load-module ${CLUSTER_LIB} --cluster-name test-cluster-1" CLUSTER_C1_2 - start_broker "--load-module ${CLUSTER_LIB} --cluster-name test-cluster-2" CLUSTER_C2_1 - start_broker "--load-module ${CLUSTER_LIB} --cluster-name test-cluster-2" CLUSTER_C2_2 - fi - rm qpidd.port -} - -stop_brokers() { - ${QPIDD_EXEC} -q --port ${LOCAL_PORT} - ${QPIDD_EXEC} -q --port ${REMOTE_PORT} - if [ -n "${CLUSTERING_ENABLED}" ]; then - ${QPID_CLUSTER_EXEC} --all-stop --force localhost:${CLUSTER_C1_1} - ${QPID_CLUSTER_EXEC} --all-stop --force localhost:${CLUSTER_C2_1} - fi -} - -if test -d ${PYTHON_DIR} ; then - start_brokers - if [ -z ${CLUSTERING_ENABLED} ]; then - echo "Running federation tests using brokers on local port ${LOCAL_PORT}, remote port ${REMOTE_PORT} (NOTE: clustering is DISABLED)" - else - echo "Running federation tests using brokers on local port ${LOCAL_PORT}, remote port ${REMOTE_PORT}, local cluster nodes ${CLUSTER_C1_1} ${CLUSTER_C1_2}, remote cluster nodes ${CLUSTER_C2_1} ${CLUSTER_C2_2}" - fi - if [ -z ${USE_LONG_TEST} ]; then - echo "NOTE: To run a full set of federation system tests, use \"make check-long\". To test with persistence, run the store version of this script." - fi - ${QPID_PYTHON_TEST} -m ${MODULENAME} ${SKIPTESTS} -b localhost:${REMOTE_PORT} -Dlocal-port=${LOCAL_PORT} -Dremote-port=${REMOTE_PORT} -Dlocal-cluster-ports="${CLUSTER_C1_1} ${CLUSTER_C1_2}" -Dremote-cluster-ports="${CLUSTER_C2_1} ${CLUSTER_C2_2}" $@ - RETCODE=$? - stop_brokers - if test x${RETCODE} != x0; then - echo "FAIL federation tests"; exit 1; - fi -fi diff --git a/cpp/src/tests/run_federation_tests b/cpp/src/tests/run_federation_tests index 14af4807ba..4be27a2e85 100755 --- a/cpp/src/tests/run_federation_tests +++ b/cpp/src/tests/run_federation_tests @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one @@ -55,7 +55,7 @@ stop_brokers() { if test -d ${PYTHON_DIR} ; then start_brokers echo "Running federation tests using brokers on ports $LOCAL_PORT $REMOTE_PORT $REMOTE_B1 $REMOTE_B2" - $QPID_PYTHON_TEST -m federation "$SKIPTESTS" -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dextra-brokers="$REMOTE_B1 $REMOTE_B2" $@ + $QPID_PYTHON_TEST -m federation $SKIPTESTS -b localhost:$LOCAL_PORT -Dremote-port=$REMOTE_PORT -Dextra-brokers="$REMOTE_B1 $REMOTE_B2" $@ RETCODE=$? stop_brokers if test x$RETCODE != x0; then diff --git a/cpp/src/tests/run_header_test b/cpp/src/tests/run_header_test index 34008132cc..07658343e7 100755 --- a/cpp/src/tests/run_header_test +++ b/cpp/src/tests/run_header_test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one diff --git a/cpp/src/tests/run_long_federation_sys_tests b/cpp/src/tests/run_long_federation_sys_tests deleted file mode 100644 index 69dc08d11c..0000000000 --- a/cpp/src/tests/run_long_federation_sys_tests +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Run the federation system tests (long version). - -./run_federation_sys_tests LONG_TEST $@ diff --git a/cpp/src/tests/run_msg_group_tests b/cpp/src/tests/run_msg_group_tests deleted file mode 100755 index 8423022521..0000000000 --- a/cpp/src/tests/run_msg_group_tests +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -#script to run a sequence of message group queue tests via make - -#setup path to find qpid-config and msg_group_test progs -source ./test_env.sh - -export PATH=$PWD:$srcdir:$PYTHON_COMMANDS:$PATH - -#set port to connect to via env var -test -s qpidd.port && QPID_PORT=`cat qpidd.port` - -#trap cleanup INT TERM QUIT - -QUEUE_NAME="group-queue" -GROUP_KEY="My-Group-Id" - -BROKER_URL="${QPID_BROKER:-localhost}:${QPID_PORT:-5672}" - -run_test() { - $@ -} - -##set -x - -declare -i i=0 -declare -a tests -tests=("qpid-config -a $BROKER_URL add queue $QUEUE_NAME --group-header=${GROUP_KEY} --shared-groups" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 3 --ack-frequency 7 --randomize-group-size --interleave 3" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 7 --ack-frequency 7 --randomize-group-size" - "qpid-config -a $BROKER_URL add queue ${QUEUE_NAME}-two --group-header=${GROUP_KEY} --shared-groups" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 7 --ack-frequency 3 --randomize-group-size" - "msg_group_test -b $BROKER_URL -a ${QUEUE_NAME}-two --group-key $GROUP_KEY --messages 103 --group-size 13 --receivers 2 --senders 3 --capacity 3 --ack-frequency 7 --randomize-group-size --interleave 5" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 59 --group-size 5 --receivers 2 --senders 3 --capacity 1 --ack-frequency 3 --randomize-group-size" - "qpid-config -a $BROKER_URL del queue ${QUEUE_NAME}-two --force" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 59 --group-size 3 --receivers 2 --senders 3 --capacity 1 --ack-frequency 1 --randomize-group-size" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 211 --group-size 13 --receivers 2 --senders 3 --capacity 47 --ack-frequency 79 --interleave 53" - "qpid-config -a $BROKER_URL del queue $QUEUE_NAME --force") - -while [ -n "${tests[i]}" ]; do - run_test ${tests[i]} - RETCODE=$? - if test x$RETCODE != x0; then - echo "FAILED message group test. Failed command: \"${tests[i]}\""; - exit 1; - fi - i+=1 -done diff --git a/cpp/src/tests/run_msg_group_tests_soak b/cpp/src/tests/run_msg_group_tests_soak deleted file mode 100755 index 5231f74755..0000000000 --- a/cpp/src/tests/run_msg_group_tests_soak +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -#script to run a sequence of long-running message group tests via make - -#setup path to find qpid-config and msg_group_test test progs -source ./test_env.sh - -export PATH=$PWD:$srcdir:$PYTHON_COMMANDS:$PATH - -#set port to connect to via env var -test -s qpidd.port && QPID_PORT=`cat qpidd.port` - -#trap cleanup INT TERM QUIT - -QUEUE_NAME="group-queue" -GROUP_KEY="My-Group-Id" - -BROKER_URL="${QPID_BROKER:-localhost}:${QPID_PORT:-5672}" - -run_test() { - $@ -} - -##set -x - -declare -i i=0 -declare -a tests -tests=("qpid-config -a $BROKER_URL add queue $QUEUE_NAME --group-header=${GROUP_KEY} --shared-groups" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 10007 --receivers 3 --senders 5 --group-size 211 --randomize-group-size --capacity 47 --ack-frequency 97" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 10007 --receivers 3 --senders 5 --group-size 211 --randomize-group-size --capacity 79 --ack-frequency 79" - "msg_group_test -b $BROKER_URL -a $QUEUE_NAME --group-key $GROUP_KEY --messages 10007 --receivers 3 --senders 5 --group-size 211 --randomize-group-size --capacity 97 --ack-frequency 47" - "qpid-config -a $BROKER_URL del queue $QUEUE_NAME --force") - -while [ -n "${tests[i]}" ]; do - run_test ${tests[i]} - RETCODE=$? - if test x$RETCODE != x0; then - echo "FAILED message group test. Failed command: \"${tests[i]}\""; - exit 1; - fi - i+=1 -done diff --git a/cpp/src/tests/run_queue_flow_limit_tests b/cpp/src/tests/run_queue_flow_limit_tests deleted file mode 100755 index f921cf5e7e..0000000000 --- a/cpp/src/tests/run_queue_flow_limit_tests +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -# Run tests against Queue producer flow control. - -source ./test_env.sh -test -d $PYTHON_DIR || { echo "Skipping queue flow control tests, no python dir."; exit 0; } - -LOG_FILE=queue_flow_limit_test.log -PORT="" - -trap stop_broker INT TERM QUIT - -error() { - echo $* - exit 1; -} - -start_broker() { - # Note: if you change the DEFAULT_THRESHOLDS, you will need to update queue_flow_limit_tests.py - DEFAULT_THRESHOLDS="--default-flow-stop-threshold=80 --default-flow-resume-threshold=70" - rm -rf $LOG_FILE - PORT=$($QPIDD_EXEC $DEFAULT_THRESHOLDS --auth=no --no-module-dir --daemon --port=0 -t --log-to-file $LOG_FILE) || error "Could not start broker" -} - -stop_broker() { - test -n "$PORT" && $QPIDD_EXEC --no-module-dir --quit --port $PORT -} - -start_broker -echo "Running Queue flow limit tests using broker on port $PORT" -$QPID_PYTHON_TEST -m queue_flow_limit_tests $SKIPTESTS -b localhost:$PORT $@ -RETCODE=$? -stop_broker -if test x$RETCODE != x0; then - echo "FAIL queue flow limit tests"; exit 1; -fi -rm -rf $LOG_FILE - diff --git a/cpp/src/tests/run_store_tests.ps1 b/cpp/src/tests/run_store_tests.ps1 index b2f0b1ccd8..76b46737f0 100644 --- a/cpp/src/tests/run_store_tests.ps1 +++ b/cpp/src/tests/run_store_tests.ps1 @@ -111,7 +111,7 @@ Invoke-Expression "$prog --quit --port $env:QPID_PORT" | Write-Output # Test 2... store.py starts/stops/restarts its own brokers $tests = "*" -$env:PYTHONPATH="$PYTHON_DIR;$QMF_LIB;$srcdir" +$env:PYTHONPATH="$PYTHON_DIR;$srcdir" $env:QPIDD_EXEC="$prog" $env:STORE_LIB="$store_dir\store$suffix.dll" if ($test_store -eq "MSSQL") { diff --git a/cpp/src/tests/run_test b/cpp/src/tests/run_test index 6ec1fd892b..4b227621bc 100755 --- a/cpp/src/tests/run_test +++ b/cpp/src/tests/run_test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file diff --git a/cpp/src/tests/sasl.mk b/cpp/src/tests/sasl.mk index 69b24c3f8a..5b8419f604 100644 --- a/cpp/src/tests/sasl.mk +++ b/cpp/src/tests/sasl.mk @@ -30,21 +30,9 @@ check_PROGRAMS+=sasl_version sasl_version_SOURCES=sasl_version.cpp sasl_version_LDADD=$(lib_client) -TESTS += run_cluster_authentication_test sasl_fed sasl_fed_ex_dynamic sasl_fed_ex_link sasl_fed_ex_queue sasl_fed_ex_route sasl_fed_ex_route_cluster sasl_fed_ex_link_cluster sasl_fed_ex_queue_cluster sasl_fed_ex_dynamic_cluster sasl_no_dir +TESTS += run_cluster_authentication_test sasl_fed sasl_fed_ex LONG_TESTS += run_cluster_authentication_soak -EXTRA_DIST += run_cluster_authentication_test \ - sasl_fed \ - sasl_fed_ex \ - run_cluster_authentication_soak \ - sasl_fed_ex_dynamic \ - sasl_fed_ex_link \ - sasl_fed_ex_queue \ - sasl_fed_ex_route \ - sasl_fed_ex_dynamic_cluster \ - sasl_fed_ex_link_cluster \ - sasl_fed_ex_queue_cluster \ - sasl_fed_ex_route_cluster \ - sasl_no_dir +EXTRA_DIST += run_cluster_authentication_test sasl_fed sasl_fed_ex run_cluster_authentication_soak endif # HAVE_SASL diff --git a/cpp/src/tests/sasl_fed b/cpp/src/tests/sasl_fed index 884c44177c..9845a20838 100755 --- a/cpp/src/tests/sasl_fed +++ b/cpp/src/tests/sasl_fed @@ -123,7 +123,7 @@ n_messages=100 #-------------------------------------------------- #echo " Sending 100 messages to $broker_1_port " #-------------------------------------------------- -$builddir/datagen --count $n_messages | $SENDER_EXEC --mechanism DIGEST-MD5 --username zag --password zag --exchange $EXCHANGE_NAME --routing-key $ROUTING_KEY --port $broker_1_port +$builddir/datagen --count $n_messages | $SENDER_EXEC --username zag --password zag --exchange $EXCHANGE_NAME --routing-key $ROUTING_KEY --port $broker_1_port sleep 5 diff --git a/cpp/src/tests/sasl_fed_ex b/cpp/src/tests/sasl_fed_ex index 716a806874..0740650d6c 100755 --- a/cpp/src/tests/sasl_fed_ex +++ b/cpp/src/tests/sasl_fed_ex @@ -19,52 +19,22 @@ # under the License. # + #=============================================================================== -# These tests create federated links between two brokers using SASL security. +# This test creates a federated link between two brokers using SASL security. # The SASL mechanism used is EXTERNAL, which is satisfied by SSL # transport-layer security. #=============================================================================== source ./test_env.sh -script_name=`basename $0` - -if [ $# -lt 1 ] || [ $# -gt 2 ] -then - echo - # These are the four different ways of creating links ( or routes+links ) - # that the qpid-route command provides. - echo "Usage: ${script_name} dynamic|link|queue|route [cluster]" - echo - exit 1 -fi - -# Has the user told us to do clustering ? ----------- -clustering_flag= -if [ $# -eq "2" ] && [ "$2" == "cluster" ]; then - clustering_flag=true -fi - -qpid_route_method=$1 - -# Debugging print. -------------------------- -debug= -function print { - if [ "$debug" ]; then - echo "${script_name}: $1" - fi -} - -print "=========== start sasl_fed_ex $* ============" - - # This minimum value corresponds to sasl version 2.1.22 minimum_sasl_version=131350 sasl_version=`$QPID_TEST_EXEC_DIR/sasl_version` -# This test is necessary because this sasl version is the first one that permits +# This test is necessary becasue this sasl version is the first one that permits # redirection of the sasl config file path. if [ "$sasl_version" -lt "$minimum_sasl_version" ]; then echo "sasl_fed: must have sasl version 2.1.22 or greater. ( Integer value: $minimum_sasl_version ) Version is: $sasl_version" @@ -90,7 +60,6 @@ create_certs() { delete_certs() { if [[ -e ${CERT_DIR} ]] ; then - print "removing cert dir ${CERT_DIR}" rm -rf ${CERT_DIR} fi } @@ -103,40 +72,22 @@ if [[ !(-x $CERTUTIL) ]] ; then fi delete_certs -create_certs 2> /dev/null -if [ ! $? ]; then - error "Could not create test certificate" - exit 1 -fi +create_certs || error "Could not create test certificate" -sasl_config_dir=$builddir/sasl_config -tmp_root=${builddir}/sasl_fed_ex_temp -print "results dir is ${tmp_root}" -rm -rf ${tmp_root} +sasl_config_file=$builddir/sasl_config + +my_random_number=$RANDOM +tmp_root=/tmp/sasl_fed_$my_random_number mkdir -p $tmp_root SRC_SSL_PORT=6667 DST_SSL_PORT=6666 -SRC_SSL_PORT_2=6668 -DST_SSL_PORT_2=6669 - SRC_TCP_PORT=5801 DST_TCP_PORT=5807 -SRC_TCP_PORT_2=5802 -DST_TCP_PORT_2=5803 - -CLUSTER_NAME_SUFFIX=`hostname | tr '.' ' ' | awk '{print $1}'` -CLUSTER_1_NAME=sasl_fed_ex_cluster_1_${CLUSTER_NAME_SUFFIX} -CLUSTER_2_NAME=sasl_fed_ex_cluster_2_${CLUSTER_NAME_SUFFIX} - -print "CLUSTER_1_NAME == ${CLUSTER_1_NAME}" -print "CLUSTER_2_NAME == ${CLUSTER_2_NAME}" - -SSL_LIB=${moduledir}/ssl.so -CLUSTER_LIB=${moduledir}/cluster.so +SSL_LIB=../.libs/ssl.so export QPID_SSL_CERT_NAME=${TEST_HOSTNAME} @@ -165,112 +116,52 @@ export QPID_SSL_CERT_NAME=${TEST_HOSTNAME} # 5. DST pulls messages off the temp queue on SRC to itself. # -COMMON_BROKER_OPTIONS=" \ - --ssl-sasl-no-dict \ - --sasl-config=$sasl_config_dir \ - --ssl-require-client-authentication \ - --auth yes \ - --ssl-cert-db $CERT_DIR \ - --ssl-cert-password-file $CERT_PW_FILE \ - --ssl-cert-name $TEST_HOSTNAME \ - --no-data-dir \ - --no-module-dir \ - --load-module ${SSL_LIB} \ - --mgmt-enable=yes \ - --log-enable info+ \ - --log-source yes \ - --daemon " - - -function start_brokers { - if [ $1 ]; then - # clustered ---------------------------------------- - print "Starting SRC cluster" - - print " src broker 1" - $QPIDD_EXEC \ - --port=${SRC_TCP_PORT} \ - --ssl-port ${SRC_SSL_PORT} \ - ${COMMON_BROKER_OPTIONS} \ - --load-module ${CLUSTER_LIB} \ - --cluster-name ${CLUSTER_1_NAME} \ - --log-to-file $tmp_root/qpidd_src.log 2> /dev/null - - broker_ports[0]=${SRC_TCP_PORT} - - print " src broker 2" - $QPIDD_EXEC \ - --port=${SRC_TCP_PORT_2} \ - --ssl-port ${SRC_SSL_PORT_2} \ - ${COMMON_BROKER_OPTIONS} \ - --load-module ${CLUSTER_LIB} \ - --cluster-name ${CLUSTER_1_NAME} \ - --log-to-file $tmp_root/qpidd_src_2.log 2> /dev/null - - broker_ports[1]=${SRC_TCP_PORT_2} - - - print "Starting DST cluster" - - print " dst broker 1" - $QPIDD_EXEC \ - --port=${DST_TCP_PORT} \ - --ssl-port ${DST_SSL_PORT} \ - ${COMMON_BROKER_OPTIONS} \ - --load-module ${CLUSTER_LIB} \ - --cluster-name ${CLUSTER_2_NAME} \ - --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null - - broker_ports[2]=${DST_TCP_PORT} - - print " dst broker 2" - $QPIDD_EXEC \ - --port=${DST_TCP_PORT_2} \ - --ssl-port ${DST_SSL_PORT_2} \ - ${COMMON_BROKER_OPTIONS} \ - --load-module ${CLUSTER_LIB} \ - --cluster-name ${CLUSTER_2_NAME} \ - --log-to-file $tmp_root/qpidd_dst_2.log 2> /dev/null - - broker_ports[3]=${DST_TCP_PORT_2} - - else - # vanilla brokers -------------------------------- - print "Starting SRC broker" - $QPIDD_EXEC \ - --port=${SRC_TCP_PORT} \ - --ssl-port ${SRC_SSL_PORT} \ - ${COMMON_BROKER_OPTIONS} \ - --log-to-file $tmp_root/qpidd_src.log 2> /dev/null - - broker_ports[0]=${SRC_TCP_PORT} - - print "Starting DST broker" - $QPIDD_EXEC \ - --port=${DST_TCP_PORT} \ - --ssl-port ${DST_SSL_PORT} \ - ${COMMON_BROKER_OPTIONS} \ - --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null - - broker_ports[1]=${DST_TCP_PORT} - fi -} - -function halt_brokers { - n_brokers=${#broker_ports[@]} - print "Halting ${n_brokers} brokers." - for i in $(seq 0 $((${n_brokers} - 1))) - do - halt_port=${broker_ports[$i]} - print "Halting broker $i on port ${halt_port}" - $QPIDD_EXEC --port ${halt_port} --quit - done - -} - -start_brokers $clustering_flag +#echo "-----------------------" +#echo "Starting SRC broker" +#echo "-----------------------" +$QPIDD_EXEC \ + --port=${SRC_TCP_PORT} \ + --ssl-port ${SRC_SSL_PORT} \ + --ssl-sasl-no-dict \ + --sasl-config=$sasl_config_file \ + --ssl-require-client-authentication \ + --auth yes \ + --ssl-cert-db $CERT_DIR \ + --ssl-cert-password-file $CERT_PW_FILE \ + --ssl-cert-name $TEST_HOSTNAME \ + --no-data-dir \ + --no-module-dir \ + --load-module ${SSL_LIB} \ + --mgmt-enable=yes \ + --log-enable info+ \ + --log-source yes \ + --daemon \ + --log-to-file $tmp_root/qpidd_src.log 2> /dev/null + + +#echo "-----------------------" +#echo "Starting DST broker" +#echo "-----------------------" +$QPIDD_EXEC \ + --port=${DST_TCP_PORT} \ + --ssl-port ${DST_SSL_PORT} \ + --ssl-cert-db $CERT_DIR \ + --ssl-cert-password-file $CERT_PW_FILE \ + --ssl-cert-name $TEST_HOSTNAME \ + --ssl-sasl-no-dict \ + --ssl-require-client-authentication \ + --sasl-config=$sasl_config_file \ + --no-data-dir \ + --no-module-dir \ + --load-module ${SSL_LIB} \ + --mgmt-enable=yes \ + --log-enable info+ \ + --log-source yes \ + --daemon \ + $COMMON_BROKER_OPTIONS \ + --log-to-file $tmp_root/qpidd_dst.log 2> /dev/null # I am not randomizing these names, because this test creates its own brokers. @@ -279,83 +170,76 @@ ROUTING_KEY=sasl_fed_queue EXCHANGE_NAME=sasl_fedex -print "add exchanges" +#echo "-----------------------" +#echo "add exchanges" +#echo "-----------------------" $QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} add exchange direct $EXCHANGE_NAME $QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} add exchange direct $EXCHANGE_NAME -print "add queues" +#echo "-----------------------" +#echo "add queues" +#echo "-----------------------" $QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} add queue $QUEUE_NAME $QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} add queue $QUEUE_NAME -print "create bindings" +#echo "-----------------------" +#echo "create bindings" +#echo "-----------------------" $QPID_CONFIG_EXEC -a localhost:${SRC_TCP_PORT} bind $EXCHANGE_NAME $QUEUE_NAME $ROUTING_KEY $QPID_CONFIG_EXEC -a localhost:${DST_TCP_PORT} bind $EXCHANGE_NAME $QUEUE_NAME $ROUTING_KEY -# +#echo "-----------------------" +#echo "qpid-route route add" +#echo "-----------------------" # NOTE: The SRC broker *must* be referred to as $TEST_HOSTNAME, and not as "localhost". # It must be referred to by the exact string given as the Common Name (CN) in the cert, # which was created in the function create_certs, above. +$QPID_ROUTE_EXEC route add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} -t ssl $EXCHANGE_NAME $ROUTING_KEY "" "" EXTERNAL +#echo "-----------------------" +#echo "view the route :" +#echo "-----------------------" +#$PYTHON_COMMANDS/qpid-route route list localhost:${DST_TCP_PORT} +# I don't know how to avoid this sleep yet. It has to come after route-creation. +sleep 5 -#---------------------------------------------------------------- -# Use qpid-route to create the link, or the link+route, depending -# on which of its several methods was requested. -#---------------------------------------------------------------- -if [ ${qpid_route_method} == "dynamic" ]; then - print "dynamic add" - $QPID_ROUTE_EXEC -t ssl dynamic add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME "" "" EXTERNAL -elif [ ${qpid_route_method} == "link" ]; then - print "link add" - $QPID_ROUTE_EXEC -t ssl link add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} EXTERNAL -elif [ ${qpid_route_method} == "queue" ]; then - print "queue add" - $QPID_ROUTE_EXEC -t ssl queue add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME $ROUTING_KEY EXTERNAL -elif [ ${qpid_route_method} == "route" ]; then - print "route add" - $QPID_ROUTE_EXEC -t ssl route add localhost:${DST_TCP_PORT} $TEST_HOSTNAME:${SRC_SSL_PORT} $EXCHANGE_NAME $ROUTING_KEY "" "" EXTERNAL -else - echo "unknown method: |${qpid_route_method}|" - echo " choices are: dynamic|link|queue|route " - halt_brokers - exit 1 -fi +n_messages=100 +./datagen --count ${n_messages} | ./sender --broker localhost --port ${SRC_TCP_PORT} --exchange ${EXCHANGE_NAME} --routing-key ${ROUTING_KEY} --mechanism ANONYMOUS -# I don't know how to avoid this sleep yet. It has to come after route-creation -# to avoid false negatives. -sleep 5 -# This should work the same whether or not we are running a clustered test. -# In the case of clustered tests, the status is not printed by qpid_route. -# So in either case, I will look only at the transport field, which should be "ssl". -print "check the link" -link_status=$($QPID_ROUTE_EXEC link list localhost:${DST_TCP_PORT} | tail -1 | awk '{print $3}') +#echo "-----------------------" +#echo "Examine DST Broker" +#echo "-----------------------" +dst_message_count=`qpid-stat -q localhost:${DST_TCP_PORT} | grep sasl_fed_queue | awk '{print $2}'` -halt_brokers -sleep 1 +#echo "-----------------------" +#echo "Asking brokers to quit." +#echo "-----------------------" +$QPIDD_EXEC --port ${SRC_TCP_PORT} --quit +$QPIDD_EXEC --port ${DST_TCP_PORT} --quit -if [ ! ${link_status} ]; then - print "link_status is empty" - print "result: fail" - exit 2 -fi -if [ ${link_status} == "ssl" ]; then - print "result: good" - # Only remove the tmp_root on success, to permit debugging. - print "Removing temporary directory $tmp_root" - rm -rf $tmp_root +#echo "-----------------------" +#echo "Removing temporary directory $tmp_root" +#echo "-----------------------" +rm -rf $tmp_root + +if [ "$dst_message_count" -eq "$n_messages" ]; then + #echo "good: |$dst_message_count| == |$n_messages|" exit 0 +else + #echo "not ideal: |$dst_message_count| != |$n_messages|" + exit 1 fi -print "link_status has a bad value: ${link_status}" -print "result: fail" -exit 3 + + diff --git a/cpp/src/tests/sasl_fed_ex_dynamic b/cpp/src/tests/sasl_fed_ex_dynamic deleted file mode 100755 index c20b8d69a0..0000000000 --- a/cpp/src/tests/sasl_fed_ex_dynamic +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh - -${srcdir}/sasl_fed_ex dynamic - - diff --git a/cpp/src/tests/sasl_fed_ex_dynamic_cluster b/cpp/src/tests/sasl_fed_ex_dynamic_cluster deleted file mode 100755 index b0cceccecb..0000000000 --- a/cpp/src/tests/sasl_fed_ex_dynamic_cluster +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh -source $srcdir/ais_check - -with_ais_group ${srcdir}/sasl_fed_ex dynamic cluster - - diff --git a/cpp/src/tests/sasl_fed_ex_link b/cpp/src/tests/sasl_fed_ex_link deleted file mode 100755 index 7b232d4874..0000000000 --- a/cpp/src/tests/sasl_fed_ex_link +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh - -${srcdir}/sasl_fed_ex link - - diff --git a/cpp/src/tests/sasl_fed_ex_link_cluster b/cpp/src/tests/sasl_fed_ex_link_cluster deleted file mode 100755 index 4139300b12..0000000000 --- a/cpp/src/tests/sasl_fed_ex_link_cluster +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh -source $srcdir/ais_check - -with_ais_group ${srcdir}/sasl_fed_ex link cluster - - diff --git a/cpp/src/tests/sasl_fed_ex_queue b/cpp/src/tests/sasl_fed_ex_queue deleted file mode 100755 index be0c10cf63..0000000000 --- a/cpp/src/tests/sasl_fed_ex_queue +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh - -${srcdir}/sasl_fed_ex queue - - diff --git a/cpp/src/tests/sasl_fed_ex_queue_cluster b/cpp/src/tests/sasl_fed_ex_queue_cluster deleted file mode 100755 index f251420e08..0000000000 --- a/cpp/src/tests/sasl_fed_ex_queue_cluster +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh -source ${srcdir}/ais_check - -with_ais_group ${srcdir}/sasl_fed_ex queue cluster - - diff --git a/cpp/src/tests/sasl_fed_ex_route b/cpp/src/tests/sasl_fed_ex_route deleted file mode 100755 index dd5c4f3cac..0000000000 --- a/cpp/src/tests/sasl_fed_ex_route +++ /dev/null @@ -1,27 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh - -${srcdir}/sasl_fed_ex route - - diff --git a/cpp/src/tests/sasl_fed_ex_route_cluster b/cpp/src/tests/sasl_fed_ex_route_cluster deleted file mode 100755 index a5d1542def..0000000000 --- a/cpp/src/tests/sasl_fed_ex_route_cluster +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -source ./test_env.sh -source ${srcdir}/ais_check - -with_ais_group ${srcdir}/sasl_fed_ex route cluster - - diff --git a/cpp/src/tests/sasl_no_dir b/cpp/src/tests/sasl_no_dir deleted file mode 100755 index 15a36014bb..0000000000 --- a/cpp/src/tests/sasl_no_dir +++ /dev/null @@ -1,218 +0,0 @@ -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -source ./test_env.sh - -script_name=`basename $0` - -# This minimum value corresponds to sasl version 2.1.22 -minimum_sasl_version=131350 - -sasl_version=`$QPID_TEST_EXEC_DIR/sasl_version` - -# This test is necessary because this sasl version is the first one that permits -# redirection of the sasl config file path. -if [ "$sasl_version" -lt "$minimum_sasl_version" ]; then - echo "sasl_fed: must have sasl version 2.1.22 or greater. ( Integer value: $minimum_sasl_version ) Version is: $sasl_version" - exit 0 -fi - - -sasl_config_dir=$builddir/sasl_config - - -# Debugging print. -------------------------- -debug= -function print { - if [ "$debug" ]; then - echo "${script_name}: $1" - fi -} - - -my_random_number=$RANDOM -tmp_root=/tmp/sasl_fed_$my_random_number -mkdir -p $tmp_root - - -LOG_FILE=$tmp_root/qpidd.log - -# If you want to see this test fail, just comment out this 'mv' command. -print "Moving sasl configuration dir." -mv ${sasl_config_dir} ${sasl_config_dir}- - - -#-------------------------------------------------- -print " Starting broker" -#-------------------------------------------------- -$QPIDD_EXEC \ - -p 0 \ - --no-data-dir \ - --auth=yes \ - --mgmt-enable=yes \ - --log-enable info+ \ - --log-source yes \ - --log-to-file ${LOG_FILE} \ - --sasl-config=$sasl_config_dir \ - -d 2> /dev/null 1> $tmp_root/broker_port - - - -# If it works right, the output will look something like this: ( two lines long ) -# Daemon startup failed: SASL: sasl_set_path failed: no such directory: /home/mick/trunk/qpid/cpp/src/tests/sasl_config (qpid/broker/SaslAuthenticator.cpp:112) -# 2011-10-13 14:07:00 critical qpidd.cpp:83: Unexpected error: Daemon startup failed: SASL: sasl_set_path failed: no such directory: /home/mick/trunk/qpid/cpp/src/tests/sasl_config (qpid/broker/SaslAuthenticator.cpp:112) - -result=`cat ${LOG_FILE} | grep "sasl_set_path failed: no such directory" | wc -l ` - -#-------------------------------------------------- -print "Restore the Sasl config dir to its original place." -#-------------------------------------------------- -mv ${sasl_config_dir}- ${sasl_config_dir} - -if [ "2" -eq ${result} ]; then - print "result: success" - rm -rf $tmp_root - exit 0 -fi - - -# If this test fails, the broker is still alive. -# Kill it. -broker_port=`cat $tmp_root/broker_port` -#-------------------------------------------------- -print "Asking broker to quit." -#-------------------------------------------------- -$QPIDD_EXEC --port $broker_port --quit - -rm -rf $tmp_root - -print "result: fail" -exit 1 - -#! /bin/bash - -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -source ./test_env.sh - -script_name=`basename $0` - -# This minimum value corresponds to sasl version 2.1.22 -minimum_sasl_version=131350 - -sasl_version=`$QPID_TEST_EXEC_DIR/sasl_version` - -# This test is necessary because this sasl version is the first one that permits -# redirection of the sasl config file path. -if [ "$sasl_version" -lt "$minimum_sasl_version" ]; then - echo "sasl_fed: must have sasl version 2.1.22 or greater. ( Integer value: $minimum_sasl_version ) Version is: $sasl_version" - exit 0 -fi - - -sasl_config_dir=$builddir/sasl_config - - -# Debugging print. -------------------------- -debug= -function print { - if [ "$debug" ]; then - echo "${script_name}: $1" - fi -} - - -my_random_number=$RANDOM -tmp_root=/tmp/sasl_fed_$my_random_number -mkdir -p $tmp_root - - -LOG_FILE=$tmp_root/qpidd.log - -# If you want to see this test fail, just comment out this 'mv' command. -print "Moving sasl configuration dir." -mv ${sasl_config_dir} ${sasl_config_dir}- - - -#-------------------------------------------------- -print " Starting broker" -#-------------------------------------------------- -$QPIDD_EXEC \ - -p 0 \ - --no-data-dir \ - --auth=yes \ - --mgmt-enable=yes \ - --log-enable info+ \ - --log-source yes \ - --log-to-file ${LOG_FILE} \ - --sasl-config=$sasl_config_dir \ - -d 2> /dev/null 1> $tmp_root/broker_port - - - -# If it works right, the output will look something like this: ( two lines long ) -# Daemon startup failed: SASL: sasl_set_path failed: no such directory: /home/mick/trunk/qpid/cpp/src/tests/sasl_config (qpid/broker/SaslAuthenticator.cpp:112) -# 2011-10-13 14:07:00 critical qpidd.cpp:83: Unexpected error: Daemon startup failed: SASL: sasl_set_path failed: no such directory: /home/mick/trunk/qpid/cpp/src/tests/sasl_config (qpid/broker/SaslAuthenticator.cpp:112) - -result=`cat ${LOG_FILE} | grep "sasl_set_path failed: no such directory" | wc -l ` - -#-------------------------------------------------- -print "Restore the Sasl config dir to its original place." -#-------------------------------------------------- -mv ${sasl_config_dir}- ${sasl_config_dir} - -if [ "2" -eq ${result} ]; then - print "result: success" - rm -rf $tmp_root - exit 0 -fi - - -# If this test fails, the broker is still alive. -# Kill it. -broker_port=`cat $tmp_root/broker_port` -#-------------------------------------------------- -print "Asking broker to quit." -#-------------------------------------------------- -$QPIDD_EXEC --port $broker_port --quit - -rm -rf $tmp_root - -print "result: fail" -exit 1 - diff --git a/cpp/src/tests/sasl_test_setup.sh b/cpp/src/tests/sasl_test_setup.sh index 3e69c0f02b..6395ba6ec3 100755 --- a/cpp/src/tests/sasl_test_setup.sh +++ b/cpp/src/tests/sasl_test_setup.sh @@ -30,7 +30,6 @@ pwcheck_method: auxprop auxprop_plugin: sasldb sasldb_path: $PWD/sasl_config/qpidd.sasldb sql_select: dummy select -mech_list: ANONYMOUS PLAIN DIGEST-MD5 EXTERNAL EOF # Populate temporary sasl db. diff --git a/cpp/src/tests/sender.cpp b/cpp/src/tests/sender.cpp index 063b5e87dc..9850e851da 100644 --- a/cpp/src/tests/sender.cpp +++ b/cpp/src/tests/sender.cpp @@ -120,7 +120,7 @@ void Sender::execute(AsyncSession& session, bool isRetry) string data; while (getline(std::cin, data)) { message.setData(data); - //message.getHeaders().setInt("SN", ++sent); + message.getHeaders().setInt("SN", ++sent); string matchKey; if (lvqMatchValues && getline(lvqMatchValues, matchKey)) { message.getHeaders().setString(QueueOptions::strLVQMatchProperty, matchKey); diff --git a/cpp/src/tests/ssl_test b/cpp/src/tests/ssl_test index 2a56c0b80e..04584f169d 100755 --- a/cpp/src/tests/ssl_test +++ b/cpp/src/tests/ssl_test @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # # Licensed to the Apache Software Foundation (ASF) under one @@ -47,13 +47,9 @@ delete_certs() { fi } -COMMON_OPTS="--daemon --no-data-dir --no-module-dir --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME --require-encryption" +COMMON_OPTS="--daemon --no-data-dir --no-module-dir --auth no --config $CONFIG --load-module $SSL_LIB --ssl-cert-db $CERT_DIR --ssl-cert-password-file $CERT_PW_FILE --ssl-cert-name $TEST_HOSTNAME --require-encryption" start_broker() { # $1 = extra opts - ../qpidd --transport ssl --port 0 --ssl-port 0 $COMMON_OPTS --auth no $1; -} - -start_authenticating_broker() { - ../qpidd --transport ssl --port 0 --ssl-port 0 $COMMON_OPTS --ssl-sasl-no-dict --ssl-require-client-authentication --auth yes; + ../qpidd --transport ssl --port 0 --ssl-port 0 $COMMON_OPTS $1; } stop_brokers() { @@ -97,7 +93,7 @@ test "$MSG" = "hello" || { echo "receive failed '$MSG' != 'hello'"; exit 1; } #### Client Authentication tests -PORT2=`start_authenticating_broker` || error "Could not start broker" +PORT2=`start_broker --ssl-require-client-authentication` || error "Could not start broker" echo "Running SSL client authentication test on port $PORT2" URL=amqp:ssl:$TEST_HOSTNAME:$PORT2 @@ -125,7 +121,7 @@ pick_port() { echo $PICK } ssl_cluster_broker() { # $1 = port - ../qpidd $COMMON_OPTS --auth no --load-module $CLUSTER_LIB --cluster-name ssl_test.$HOSTNAME.$$ --cluster-url amqp:ssl:$TEST_HOSTNAME:$1 --port 0 --ssl-port $1 --transport ssl > /dev/null + ../qpidd $COMMON_OPTS --load-module $CLUSTER_LIB --cluster-name ssl_test.$HOSTNAME.$$ --cluster-url amqp:ssl:$TEST_HOSTNAME:$1 --port 0 --ssl-port $1 --transport ssl > /dev/null # Wait for broker to be ready qpid-ping -Pssl -b $TEST_HOSTNAME -qp $1 || { echo "Cannot connect to broker on $1"; exit 1; } echo "Running SSL cluster broker on port $1" diff --git a/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp b/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp index 024f20b147..a0b665db73 100644 --- a/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp +++ b/cpp/src/tests/windows/DisableWin32ErrorWindows.cpp @@ -26,9 +26,7 @@ // include this file with the executable being built. If the default // behaviors are desired, don't include this file in the build. -#if defined(_MSC_VER) #include <crtdbg.h> -#endif #include <windows.h> #include <iostream> @@ -55,14 +53,12 @@ static redirect_errors_to_stderr block; redirect_errors_to_stderr::redirect_errors_to_stderr() { -#if defined(_MSC_VER) _CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportFile (_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportFile (_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_FILE); _CrtSetReportFile (_CRT_ASSERT, _CRTDBG_FILE_STDERR); -#endif // Prevent the system from displaying the critical-error-handler // and can't-open-file message boxes. diff --git a/cpp/src/windows/QpiddBroker.cpp b/cpp/src/windows/QpiddBroker.cpp index 60a31901bd..884cdc366b 100644 --- a/cpp/src/windows/QpiddBroker.cpp +++ b/cpp/src/windows/QpiddBroker.cpp @@ -21,12 +21,12 @@ #include "config.h" #include "qpidd.h" +#include "SCM.h" #include "qpid/Exception.h" #include "qpid/Options.h" #include "qpid/Plugin.h" #include "qpid/sys/IntegerTypes.h" #include "qpid/sys/windows/check.h" -#include "qpid/sys/windows/SCM.h" #include "qpid/broker/Broker.h" #include <iostream> @@ -147,7 +147,7 @@ NamedSharedMemory<T>::NamedSharedMemory(const std::string& n) : name(n), memory(NULL), data(0) -{} +{}; template <typename T> NamedSharedMemory<T>::~NamedSharedMemory() { @@ -155,7 +155,7 @@ NamedSharedMemory<T>::~NamedSharedMemory() { ::UnmapViewOfFile(data); if (memory != NULL) ::CloseHandle(memory); -} +}; template <typename T> T& NamedSharedMemory<T>::create() { @@ -291,12 +291,12 @@ struct ServiceOptions : public qpid::Options { depends("") { addOptions() - ("install", qpid::optValue(install), "Install as service.") - ("start-type", qpid::optValue(startType, "auto|demand|disabled"), "Service start type.\nApplied at install time only.") + ("install", qpid::optValue(install), "Install as service") + ("start-type", qpid::optValue(startType, "auto|demand|disabled"), "Service start type\nApplied at install time only.") ("arguments", qpid::optValue(startArgs, "COMMAND LINE ARGS"), "Arguments to pass when service auto-starts") - ("account", qpid::optValue(account, "ACCOUNT"), "Account to run as.\nApplied at install time only.") - ("password", qpid::optValue(password, "PASSWORD"), "Account password, if needed.\nApplied at install time only.") - ("depends", qpid::optValue(depends, "(comma delimited list)"), "Names of services that must start before this service.\nApplied at install time only.") + ("account", qpid::optValue(account, "(LocalService)"), "Account to run as, default is LocalService\nApplied at install time only.") + ("password", qpid::optValue(password, "PASSWORD"), "Account password, if needed\nApplied at install time only.") + ("depends", qpid::optValue(depends, "(comma delimited list)"), "Names of services that must start before this service\nApplied at install time only.") ("start", qpid::optValue(start), "Start the service.") ("stop", qpid::optValue(stop), "Stop the service.") ("uninstall", qpid::optValue(uninstall), "Uninstall the service."); diff --git a/cpp/src/qpid/sys/windows/SCM.cpp b/cpp/src/windows/SCM.cpp index 4d2c74d4b9..232bb04c17 100644 --- a/cpp/src/qpid/sys/windows/SCM.cpp +++ b/cpp/src/windows/SCM.cpp @@ -1,332 +1,332 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT 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 +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT 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/windows/SCM.h index 8e94ef83c7..bdc73bc210 100644 --- a/cpp/src/qpid/sys/windows/SCM.h +++ b/cpp/src/windows/SCM.h @@ -1,111 +1,109 @@ -#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 */ +#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>
+
+namespace qpid {
+namespace windows {
+
+/**
+ * @class SCM
+ *
+ * Access the Windows Service Control Manager.
+ */
+class SCM
+{
+public:
+ SCM();
+ ~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
+ */
+ 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
+ */
+ void uninstall(const string& serviceName);
+
+ /**
+ * Start the specified service
+ *
+ * @param serviceName the name of the service
+ */
+ void start(const string& serviceName);
+
+ /**
+ * Stop the specified service
+ *
+ * @param serviceName the name of the service
+ */
+ 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/windows/resources/template-resource.rc b/cpp/src/windows/resources/template-resource.rc index 8ca0a90890..725d1c9391 100644 --- a/cpp/src/windows/resources/template-resource.rc +++ b/cpp/src/windows/resources/template-resource.rc @@ -24,7 +24,7 @@ //
// Generated from the TEXTINCLUDE 2 resource.
//
-#include "windows.h"
+#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
diff --git a/cpp/src/xml.mk b/cpp/src/xml.mk index baf3803647..0d700fcc03 100644 --- a/cpp/src/xml.mk +++ b/cpp/src/xml.mk @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -dmoduleexec_LTLIBRARIES += xml.la +dmodule_LTLIBRARIES += xml.la xml_la_SOURCES = \ qpid/xml/XmlExchange.cpp \ diff --git a/cpp/xml/cluster.xml b/cpp/xml/cluster.xml index 899625f5ec..be1c1f868c 100644 --- a/cpp/xml/cluster.xml +++ b/cpp/xml/cluster.xml @@ -8,9 +8,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 @@ -78,6 +78,10 @@ <field name="left" type="vbin16"/> <!-- packed member-id array --> </control> + <control name="message-expired" code="0x12"> + <field name="id" type="uint64"/> + </control> + <domain name="error-type" type="uint8" label="Types of error"> <enum> <choice name="none" value="0"/> @@ -85,7 +89,7 @@ <choice name="connection" value="2"/> </enum> </domain> - + <!-- Check for error consistency across the cluster --> <control name="error-check" code="0x14"> <field name="type" type="error-type"/> @@ -112,11 +116,6 @@ <field name="message" type="vbin32"/> </control> - <!-- Update the cluster time --> - <control name="clock" code="0x22"> - <field name="time" type="uint64"/> - </control> - </class> <!-- Controls associated with a specific connection. --> @@ -150,7 +149,7 @@ <!-- Abort a connection that is sending invalid data. --> <control name="abort" code="0x4"/> - + <!-- Update controls. Sent to a new broker in joining mode. A connection is updated as followed: - send the shadow's management ID in shadow-perpare on the update connection @@ -184,7 +183,7 @@ <field name="position" type="sequence-no"/> <field name="tag" type="str8"/> <field name="id" type="sequence-no"/> - <field name="acquired" type="bit"/> <!--If not set, message is on update queue. --> + <field name="acquired" type="bit"/> <!--If not set, message follows. --> <field name="accepted" type="bit"/> <field name="cancelled" type="bit"/> <field name="completed" type="bit"/> @@ -193,9 +192,9 @@ <field name="enqueued" type="bit"/> <field name="credit" type="uint32"/> </control> - + <!-- Tx transaction state. --> - <control name="tx-start" code="0x12"/> + <control name="tx-start" code="0x12"/> <control name="tx-accept" code="0x13"> <field name="commands" type="sequence-set"/> </control> <control name="tx-dequeue" code="0x14"> <field name="queue" type="str8"/> </control> <control name="tx-enqueue" code="0x15"> <field name="queue" type="str8"/> </control> @@ -205,37 +204,13 @@ </control> <control name="tx-end" code="0x17"/> <control name="accumulated-ack" code="0x18"> <field name="commands" type="sequence-set"/> </control> - + <!-- Consumers in the connection's output task --> <control name="output-task" code="0x19"> <field name="channel" type="uint16"/> <field name="name" type="str8"/> </control> - <!-- Dtx transaction state. --> - <control name="dtx-start" code="0x1A"> - <field name="xid" type="str16"/> - <field name="ended" type="bit"/> - <field name="suspended" type="bit"/> - <field name="failed" type="bit"/> - <field name="expired" type="bit"/> - </control> - <control name="dtx-end" code="0x1B"/> - - <control name="dtx-ack" code="0x1C"/> - - <control name="dtx-buffer-ref" code="0x1D"> - <field name="xid" type="str16"/> - <field name="index" type="uint32"/> - <field name="suspended" type="bit"/> - </control> - - <control name="dtx-work-record" code="0x1E"> - <field name="xid" type="str16"/> - <field name="prepared" type="bit"/> - <field name="timeout" type="uint32"/> - </control> - <!-- Complete a session state update. --> <control name="session-state" code="0x1F"> <!-- Target session deduced from channel number. --> @@ -247,7 +222,6 @@ <field name="received" type="sequence-no"/> <!-- Received up to here (>= expected) --> <field name="unknown-completed" type="sequence-set"/> <!-- Completed but not known to peer. --> <field name="received-incomplete" type="sequence-set"/> <!-- Received and incomplete --> - <field name="dtx-selected" type="bit"/> </control> <!-- Complete a shadow connection update. --> @@ -278,6 +252,10 @@ <!-- Replicate encoded exchanges/queues. --> <control name="exchange" code="0x31"><field name="encoded" type="str32"/></control> + <control name="queue" code="0x32"><field name="encoded" type="str32"/></control> + + <!-- Set expiry-id for subsequent messages. --> + <control name="expiry-id" code="0x33"><field name="expiry-id" type="uint64"/></control> <!-- Add a listener to a queue --> <control name="add-queue-listener" code="0x34"> @@ -304,26 +282,6 @@ <field name="position" type="uint8"/> <field name="count" type="uint8"/> </control> - - <!-- Replicate a QueueObserver for a given queue. --> - <control name="queue-observer-state" code="0x39"> - <field name="queue" type="str8"/> - <field name="observer-id" type="str8"/> - <field name="state" type="map"/> <!-- "name"=value --> - </control> - - <!-- Update the cluster time --> - <control name="clock" code="0x40"> - <field name="time" type="uint64"/> - </control> - - <!-- Update a queue's dequeue rate --> - <control name="queue-dequeue-since-purge-state" code="0x41"> - <field name="queue" type="str8"/> - <field name="dequeueSincePurge" type="uint32"/> - </control> - - </class> </amqp> |