Moving from govendor to dep, updated dependencies (#48)

* Moving from govendor to dep.

* Making the pull request template more friendly.

* Fixing akward space in PR template.

* goimports run on whole project using ` goimports -w $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./gen-go/*")`

source of command: https://gist.github.com/bgentry/fd1ffef7dbde01857f66
This commit is contained in:
Renan DelValle 2018-01-07 13:13:47 -08:00 committed by GitHub
parent 9631aa3aab
commit 8d445c1c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2186 changed files with 400410 additions and 352 deletions

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<BOOST_ROOT>$(THIRD_PARTY)\boost\boost_1_47_0</BOOST_ROOT>
<OPENSSL_ROOT_DIR>$(THIRD_PARTY)\openssl\OpenSSL-Win32</OPENSSL_ROOT_DIR>
<LIBEVENT_ROOT>$(THIRD_PARTY)\libevent-2.0.21-stable</LIBEVENT_ROOT>
</PropertyGroup>
<PropertyGroup />
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="BOOST_ROOT">
<Value>$(BOOST_ROOT)</Value>
<EnvironmentVariable>true</EnvironmentVariable>
</BuildMacro>
<BuildMacro Include="OPENSSL_ROOT_DIR">
<Value>$(OPENSSL_ROOT_DIR)</Value>
<EnvironmentVariable>true</EnvironmentVariable>
</BuildMacro>
<BuildMacro Include="LIBEVENT_ROOT">
<Value>$(LIBEVENT_ROOT)</Value>
<EnvironmentVariable>true</EnvironmentVariable>
</BuildMacro>
</ItemGroup>
</Project>

217
vendor/git.apache.org/thrift.git/lib/cpp/CMakeLists.txt generated vendored Executable file
View file

@ -0,0 +1,217 @@
#
# 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_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
include_directories(src)
# SYSLIBS contains libraries that need to be linked to all lib targets
set(SYSLIBS "")
# Create the thrift C++ library
set( thriftcpp_SOURCES
src/thrift/TApplicationException.cpp
src/thrift/TOutput.cpp
src/thrift/async/TAsyncChannel.cpp
src/thrift/async/TConcurrentClientSyncInfo.h
src/thrift/async/TConcurrentClientSyncInfo.cpp
src/thrift/concurrency/ThreadManager.cpp
src/thrift/concurrency/TimerManager.cpp
src/thrift/concurrency/Util.cpp
src/thrift/processor/PeekProcessor.cpp
src/thrift/protocol/TBase64Utils.cpp
src/thrift/protocol/TDebugProtocol.cpp
src/thrift/protocol/TJSONProtocol.cpp
src/thrift/protocol/TMultiplexedProtocol.cpp
src/thrift/protocol/TProtocol.cpp
src/thrift/transport/TTransportException.cpp
src/thrift/transport/TFDTransport.cpp
src/thrift/transport/TSimpleFileTransport.cpp
src/thrift/transport/THttpTransport.cpp
src/thrift/transport/THttpClient.cpp
src/thrift/transport/THttpServer.cpp
src/thrift/transport/TSocket.cpp
src/thrift/transport/TSocketPool.cpp
src/thrift/transport/TServerSocket.cpp
src/thrift/transport/TTransportUtils.cpp
src/thrift/transport/TBufferTransports.cpp
src/thrift/server/TConnectedClient.cpp
src/thrift/server/TServerFramework.cpp
src/thrift/server/TSimpleServer.cpp
src/thrift/server/TThreadPoolServer.cpp
src/thrift/server/TThreadedServer.cpp
)
# This files don't work on Windows CE as there is no pipe support
# TODO: These files won't work with UNICODE support on windows. If fixed this can be re-added.
if (NOT WINCE)
list(APPEND thriftcpp_SOURCES
src/thrift/transport/TPipe.cpp
src/thrift/transport/TPipeServer.cpp
src/thrift/transport/TFileTransport.cpp
)
endif()
if (WIN32)
list(APPEND thriftcpp_SOURCES
src/thrift/windows/TWinsockSingleton.cpp
src/thrift/windows/SocketPair.cpp
src/thrift/windows/GetTimeOfDay.cpp
src/thrift/windows/WinFcntl.cpp
)
if(NOT WINCE)
# This file uses pipes so it currently won't work on Windows CE
list(APPEND thriftcpp_SOURCES
src/thrift/windows/OverlappedSubmissionThread.cpp
)
endif()
else()
# These files evaluate to nothing on Windows, so omit them from the
# Windows build
list(APPEND thriftcpp_SOURCES
src/thrift/VirtualProfiling.cpp
src/thrift/server/TServer.cpp
)
endif()
# If OpenSSL is not found just ignore the OpenSSL stuff
find_package(OpenSSL)
if(OPENSSL_FOUND AND WITH_OPENSSL)
list( APPEND thriftcpp_SOURCES
src/thrift/transport/TSSLSocket.cpp
src/thrift/transport/TSSLServerSocket.cpp
)
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
list(APPEND SYSLIBS "${OPENSSL_LIBRARIES}")
endif()
# WITH_*THREADS selects which threading library to use
if(WITH_BOOSTTHREADS)
set( thriftcpp_threads_SOURCES
src/thrift/concurrency/BoostThreadFactory.cpp
src/thrift/concurrency/BoostMonitor.cpp
src/thrift/concurrency/BoostMutex.cpp
)
list(APPEND SYSLIBS "${Boost_LIBRARIES}")
elseif(UNIX AND NOT WITH_STDTHREADS)
if(ANDROID)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
else()
list(APPEND SYSLIBS pthread)
endif()
set( thriftcpp_threads_SOURCES
src/thrift/concurrency/PosixThreadFactory.cpp
src/thrift/concurrency/Mutex.cpp
src/thrift/concurrency/Monitor.cpp
)
else()
if(UNIX)
if(ANDROID)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
else()
list(APPEND SYSLIBS pthread)
endif()
endif()
set( thriftcpp_threads_SOURCES
src/thrift/concurrency/StdThreadFactory.cpp
src/thrift/concurrency/StdMutex.cpp
src/thrift/concurrency/StdMonitor.cpp
)
endif()
# Thrift non blocking server
set( thriftcppnb_SOURCES
src/thrift/server/TNonblockingServer.cpp
src/thrift/async/TAsyncProtocolProcessor.cpp
src/thrift/async/TEvhttpServer.cpp
src/thrift/async/TEvhttpClientChannel.cpp
)
# Thrift zlib server
set( thriftcppz_SOURCES
src/thrift/transport/TZlibTransport.cpp
src/thrift/protocol/THeaderProtocol.cpp
src/thrift/transport/THeaderTransport.cpp
src/thrift/protocol/THeaderProtocol.cpp
src/thrift/transport/THeaderTransport.cpp
)
# Thrift Qt4 server
set( thriftcppqt_SOURCES
src/thrift/qt/TQIODeviceTransport.cpp
src/thrift/qt/TQTcpServer.cpp
)
# Contains the thrift specific ADD_LIBRARY_THRIFT and TARGET_LINK_LIBRARIES_THRIFT
include(ThriftMacros)
ADD_LIBRARY_THRIFT(thrift ${thriftcpp_SOURCES} ${thriftcpp_threads_SOURCES})
if(WIN32)
TARGET_LINK_LIBRARIES_THRIFT(thrift ${SYSLIBS} ws2_32)
else()
TARGET_LINK_LIBRARIES_THRIFT(thrift ${SYSLIBS})
endif()
if(WITH_LIBEVENT)
find_package(Libevent REQUIRED) # Libevent comes with CMake support form upstream
include_directories(SYSTEM ${LIBEVENT_INCLUDE_DIRS})
ADD_LIBRARY_THRIFT(thriftnb ${thriftcppnb_SOURCES})
TARGET_LINK_LIBRARIES_THRIFT(thriftnb ${SYSLIBS} ${LIBEVENT_LIBRARIES})
TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftnb thrift)
endif()
if(WITH_ZLIB)
find_package(ZLIB REQUIRED)
include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
ADD_LIBRARY_THRIFT(thriftz ${thriftcppz_SOURCES})
TARGET_LINK_LIBRARIES_THRIFT(thriftz ${SYSLIBS} ${ZLIB_LIBRARIES})
TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftz thrift)
endif()
if(WITH_QT4)
set(CMAKE_AUTOMOC ON)
find_package(Qt4 REQUIRED COMPONENTS QtCore QtNetwork)
ADD_LIBRARY_THRIFT(thriftqt ${thriftcppqt_SOURCES})
TARGET_LINK_LIBRARIES_THRIFT(thriftqt ${SYSLIBS} Qt4::QtCore Qt4::QtNetwork)
TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftqt thrift)
endif()
if(WITH_QT5)
# Qt5 has its own directory to avoid conflict with Qt4 caused by CMAKE_AUTOMOC
add_subdirectory(src/thrift/qt)
endif()
if(MSVC)
add_definitions("-DUNICODE -D_UNICODE")
endif()
add_definitions("-D__STDC_LIMIT_MACROS")
# Install the headers
install(DIRECTORY "src/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
FILES_MATCHING PATTERN "*.h" PATTERN "*.tcc")
# Copy config.h file
install(DIRECTORY "${CMAKE_BINARY_DIR}/thrift" DESTINATION "${INCLUDE_INSTALL_DIR}"
FILES_MATCHING PATTERN "*.h")
if(BUILD_TESTING)
add_subdirectory(test)
endif()

287
vendor/git.apache.org/thrift.git/lib/cpp/Makefile.am generated vendored Executable file
View file

@ -0,0 +1,287 @@
#
# 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.
#
AUTOMAKE_OPTIONS = subdir-objects
moc_%.cpp: %.h
$(QT_MOC) $(QT_CFLAGS) $< -o $@
moc__%.cpp: %.h
$(QT5_MOC) $(QT5_CFLAGS) $< -o $@
SUBDIRS = .
if WITH_TESTS
# This file is needed by compiler with plugin, while test/Makefile.am needs compiler
# So test directory is directly picked by top level Makefile.am for plugin build
if !WITH_PLUGIN
SUBDIRS += test
endif
endif
pkgconfigdir = $(libdir)/pkgconfig
lib_LTLIBRARIES = libthrift.la
pkgconfig_DATA = thrift.pc
libthrift_la_LDFLAGS = -release $(VERSION)
libthrift_la_LIBADD = $(BOOST_LDFLAGS) $(OPENSSL_LDFLAGS) $(OPENSSL_LIBS)
## We only build the extra libraries if we have the dependencies,
## but we install all of the headers unconditionally.
if AMX_HAVE_LIBEVENT
lib_LTLIBRARIES += libthriftnb.la
pkgconfig_DATA += thrift-nb.pc
endif
if AMX_HAVE_ZLIB
lib_LTLIBRARIES += libthriftz.la
pkgconfig_DATA += thrift-z.pc
endif
if AMX_HAVE_QT
lib_LTLIBRARIES += libthriftqt.la
pkgconfig_DATA += thrift-qt.pc
endif
if AMX_HAVE_QT5
lib_LTLIBRARIES += libthriftqt5.la
pkgconfig_DATA += thrift-qt5.pc
endif
AM_CXXFLAGS = -Wall -Wextra -pedantic
AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(OPENSSL_INCLUDES) -I$(srcdir)/src -D__STDC_LIMIT_MACROS
# Define the source files for the module
libthrift_la_SOURCES = src/thrift/TApplicationException.cpp \
src/thrift/TOutput.cpp \
src/thrift/VirtualProfiling.cpp \
src/thrift/async/TAsyncChannel.cpp \
src/thrift/async/TConcurrentClientSyncInfo.cpp \
src/thrift/concurrency/ThreadManager.cpp \
src/thrift/concurrency/TimerManager.cpp \
src/thrift/concurrency/Util.cpp \
src/thrift/processor/PeekProcessor.cpp \
src/thrift/protocol/TDebugProtocol.cpp \
src/thrift/protocol/TJSONProtocol.cpp \
src/thrift/protocol/TBase64Utils.cpp \
src/thrift/protocol/TMultiplexedProtocol.cpp \
src/thrift/protocol/TProtocol.cpp \
src/thrift/transport/TTransportException.cpp \
src/thrift/transport/TFDTransport.cpp \
src/thrift/transport/TFileTransport.cpp \
src/thrift/transport/TSimpleFileTransport.cpp \
src/thrift/transport/THttpTransport.cpp \
src/thrift/transport/THttpClient.cpp \
src/thrift/transport/THttpServer.cpp \
src/thrift/transport/TSocket.cpp \
src/thrift/transport/TPipe.cpp \
src/thrift/transport/TPipeServer.cpp \
src/thrift/transport/TSSLSocket.cpp \
src/thrift/transport/TSocketPool.cpp \
src/thrift/transport/TServerSocket.cpp \
src/thrift/transport/TSSLServerSocket.cpp \
src/thrift/transport/TTransportUtils.cpp \
src/thrift/transport/TBufferTransports.cpp \
src/thrift/server/TConnectedClient.cpp \
src/thrift/server/TServer.cpp \
src/thrift/server/TServerFramework.cpp \
src/thrift/server/TSimpleServer.cpp \
src/thrift/server/TThreadPoolServer.cpp \
src/thrift/server/TThreadedServer.cpp
if WITH_BOOSTTHREADS
libthrift_la_SOURCES += src/thrift/concurrency/BoostThreadFactory.cpp \
src/thrift/concurrency/BoostMonitor.cpp \
src/thrift/concurrency/BoostMutex.cpp
else
libthrift_la_SOURCES += src/thrift/concurrency/Mutex.cpp \
src/thrift/concurrency/Monitor.cpp \
src/thrift/concurrency/PosixThreadFactory.cpp
endif
libthriftnb_la_SOURCES = src/thrift/server/TNonblockingServer.cpp \
src/thrift/async/TAsyncProtocolProcessor.cpp \
src/thrift/async/TEvhttpServer.cpp \
src/thrift/async/TEvhttpClientChannel.cpp
libthriftz_la_SOURCES = src/thrift/transport/TZlibTransport.cpp \
src/thrift/transport/THeaderTransport.cpp \
src/thrift/protocol/THeaderProtocol.cpp
libthriftqt_la_MOC = src/thrift/qt/moc_TQTcpServer.cpp
nodist_libthriftqt_la_SOURCES = $(libthriftqt_la_MOC)
libthriftqt_la_SOURCES = src/thrift/qt/TQIODeviceTransport.cpp \
src/thrift/qt/TQTcpServer.cpp
CLEANFILES = $(libthriftqt_la_MOC)
libthriftqt5_la_MOC = src/thrift/qt/moc__TQTcpServer.cpp
nodist_libthriftqt5_la_SOURCES = $(libthriftqt5_la_MOC)
libthriftqt5_la_SOURCES = src/thrift/qt/TQIODeviceTransport.cpp \
src/thrift/qt/TQTcpServer.cpp
CLEANFILES += $(libthriftqt5_la_MOC)
# Flags for the various libraries
libthriftnb_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBEVENT_CPPFLAGS)
libthriftz_la_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_CPPFLAGS)
libthriftqt_la_CPPFLAGS = $(AM_CPPFLAGS) $(QT_CFLAGS)
libthriftqt5_la_CPPFLAGS = $(AM_CPPFLAGS) $(QT5_CFLAGS)
if QT5_REDUCE_RELOCATIONS
libthriftqt5_la_CPPFLAGS += -fPIC
endif
libthriftnb_la_CXXFLAGS = $(AM_CXXFLAGS)
libthriftz_la_CXXFLAGS = $(AM_CXXFLAGS)
libthriftqt_la_CXXFLAGS = $(AM_CXXFLAGS)
libthriftqt5_la_CXXFLAGS = $(AM_CXXFLAGS)
libthriftnb_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS)
libthriftz_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS)
libthriftqt_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS) $(QT_LIBS)
libthriftqt5_la_LDFLAGS = -release $(VERSION) $(BOOST_LDFLAGS) $(QT5_LIBS)
include_thriftdir = $(includedir)/thrift
include_thrift_HEADERS = \
$(top_builddir)/config.h \
src/thrift/thrift-config.h \
src/thrift/TDispatchProcessor.h \
src/thrift/Thrift.h \
src/thrift/TOutput.h \
src/thrift/TProcessor.h \
src/thrift/TApplicationException.h \
src/thrift/TLogging.h \
src/thrift/cxxfunctional.h \
src/thrift/TToString.h \
src/thrift/TBase.h
include_concurrencydir = $(include_thriftdir)/concurrency
include_concurrency_HEADERS = \
src/thrift/concurrency/BoostThreadFactory.h \
src/thrift/concurrency/Exception.h \
src/thrift/concurrency/Mutex.h \
src/thrift/concurrency/Monitor.h \
src/thrift/concurrency/PlatformThreadFactory.h \
src/thrift/concurrency/PosixThreadFactory.h \
src/thrift/concurrency/StdMonitor.cpp \
src/thrift/concurrency/StdMutex.cpp \
src/thrift/concurrency/StdThreadFactory.cpp \
src/thrift/concurrency/StdThreadFactory.h \
src/thrift/concurrency/Thread.h \
src/thrift/concurrency/ThreadManager.h \
src/thrift/concurrency/TimerManager.h \
src/thrift/concurrency/FunctionRunner.h \
src/thrift/concurrency/Util.h
include_protocoldir = $(include_thriftdir)/protocol
include_protocol_HEADERS = \
src/thrift/protocol/TBinaryProtocol.h \
src/thrift/protocol/TBinaryProtocol.tcc \
src/thrift/protocol/TCompactProtocol.h \
src/thrift/protocol/TCompactProtocol.tcc \
src/thrift/protocol/TDebugProtocol.h \
src/thrift/protocol/THeaderProtocol.h \
src/thrift/protocol/TBase64Utils.h \
src/thrift/protocol/TJSONProtocol.h \
src/thrift/protocol/TMultiplexedProtocol.h \
src/thrift/protocol/TProtocolDecorator.h \
src/thrift/protocol/TProtocolTap.h \
src/thrift/protocol/TProtocolTypes.h \
src/thrift/protocol/TProtocolException.h \
src/thrift/protocol/TVirtualProtocol.h \
src/thrift/protocol/TProtocol.h
include_transportdir = $(include_thriftdir)/transport
include_transport_HEADERS = \
src/thrift/transport/PlatformSocket.h \
src/thrift/transport/TFDTransport.h \
src/thrift/transport/TFileTransport.h \
src/thrift/transport/THeaderTransport.h \
src/thrift/transport/TSimpleFileTransport.h \
src/thrift/transport/TServerSocket.h \
src/thrift/transport/TSSLServerSocket.h \
src/thrift/transport/TServerTransport.h \
src/thrift/transport/THttpTransport.h \
src/thrift/transport/THttpClient.h \
src/thrift/transport/THttpServer.h \
src/thrift/transport/TSocket.h \
src/thrift/transport/TPipe.h \
src/thrift/transport/TPipeServer.h \
src/thrift/transport/TSSLSocket.h \
src/thrift/transport/TSocketPool.h \
src/thrift/transport/TVirtualTransport.h \
src/thrift/transport/TTransport.h \
src/thrift/transport/TTransportException.h \
src/thrift/transport/TTransportUtils.h \
src/thrift/transport/TBufferTransports.h \
src/thrift/transport/TShortReadTransport.h \
src/thrift/transport/TZlibTransport.h
include_serverdir = $(include_thriftdir)/server
include_server_HEADERS = \
src/thrift/server/TConnectedClient.h \
src/thrift/server/TServer.h \
src/thrift/server/TServerFramework.h \
src/thrift/server/TSimpleServer.h \
src/thrift/server/TThreadPoolServer.h \
src/thrift/server/TThreadedServer.h \
src/thrift/server/TNonblockingServer.h
include_processordir = $(include_thriftdir)/processor
include_processor_HEADERS = \
src/thrift/processor/PeekProcessor.h \
src/thrift/processor/StatsProcessor.h \
src/thrift/processor/TMultiplexedProcessor.h
include_asyncdir = $(include_thriftdir)/async
include_async_HEADERS = \
src/thrift/async/TAsyncChannel.h \
src/thrift/async/TAsyncDispatchProcessor.h \
src/thrift/async/TAsyncProcessor.h \
src/thrift/async/TAsyncBufferProcessor.h \
src/thrift/async/TAsyncProtocolProcessor.h \
src/thrift/async/TConcurrentClientSyncInfo.h \
src/thrift/async/TEvhttpClientChannel.h \
src/thrift/async/TEvhttpServer.h
include_qtdir = $(include_thriftdir)/qt
include_qt_HEADERS = \
src/thrift/qt/TQIODeviceTransport.h \
src/thrift/qt/TQTcpServer.h
THRIFT = $(top_builddir)/compiler/cpp/thrift
WINDOWS_DIST = \
src/thrift/windows \
thrift.sln \
libthrift.vcxproj \
libthrift.vcxproj.filters \
libthriftnb.vcxproj \
libthriftnb.vcxproj.filters \
3rdparty.props
EXTRA_DIST = \
CMakeLists.txt \
coding_standards.md \
README.md \
thrift-nb.pc.in \
thrift.pc.in \
thrift-z.pc.in \
thrift-qt.pc.in \
thrift-qt5.pc.in \
src/thrift/qt/CMakeLists.txt \
$(WINDOWS_DIST)
style-local:
$(CPPSTYLE_CMD)

274
vendor/git.apache.org/thrift.git/lib/cpp/README.md generated vendored Executable file
View file

@ -0,0 +1,274 @@
Thrift C++ Software Library
# License
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.
# Using Thrift with C++
The Thrift C++ libraries are built using the GNU tools. Follow the instructions
in the top-level README.md
In case you do not want to open another README.md file, do this thrift src:
./bootstrap.sh
./configure (--with-boost=/usr/local)
make
sudo make install
Thrift is divided into two libraries.
* libthrift - The core Thrift library contains all the core Thrift code. It requires
boost shared pointers, pthreads, and librt.
* libthriftnb - This library contains the Thrift nonblocking server, which uses libevent.
To link this library you will also need to link libevent.
## Linking Against Thrift
After you build and install Thrift the libraries are installed to
/usr/local/lib by default. Make sure this is in your LDPATH.
On Linux, the best way to do this is to ensure that /usr/local/lib is in
your /etc/ld.so.conf and then run /sbin/ldconfig.
Depending upon whether you are linking dynamically or statically and how
your build environment it set up, you may need to include additional
libraries when linking against thrift, such as librt and/or libpthread. If
you are using libthriftnb you will also need libevent.
## Dependencies
boost shared pointers
http://www.boost.org/libs/smart_ptr/smart_ptr.htm
libevent (for libthriftnb only)
http://monkey.org/~provos/libevent/
# Using Thrift with C++ on Windows
You need to define an environment variables for 3rd party components separately:
BOOST_ROOT : For boost, e.g. D:\boost_1_55_0
OPENSSL_ROOT_DIR : For OpenSSL, e.g. D:\OpenSSL-Win32
only required by libthriftnb:
LIBEVENT_ROOT_DIR : For Libevent e.g. D:\libevent-2.0.21-stable
See /3rdparty.user for more details.
Thrift is divided into two libraries.
* libthrift - The core Thrift library contains all the core Thrift code. It requires
boost shared pointers, pthreads, and librt.
* libthriftnb - This library contains the Thrift nonblocking server, which uses libevent.
To link this library you will also need to link libevent.
## Linking Against Thrift
You need to link your project that uses thrift against all the thrift
dependencies; in the case of libthrift, boost and for
libthriftnb, libevent.
In the project properties you must also set HAVE_CONFIG_H as force include
the config header: "windows/confg.h"
## Dependencies
boost shared pointers
http://www.boost.org/libs/smart_ptr/smart_ptr.htm
boost thread
http://www.boost.org/doc/libs/release/doc/html/thread.html
libevent (for libthriftnb only)
http://monkey.org/~provos/libevent/
## Notes on boost thread (static vs shared):
By default lib/cpp/windows/force_inc.h defines:
#define BOOST_ALL_NO_LIB 1
#define BOOST_THREAD_NO_LIB 1
This has for effect to have the host application linking against Thrift
to have to link with boost thread as a static library.
If you wanted instead to link with boost thread as a shared library,
you'll need to uncomment those two lines, and recompile.
## Windows version compatibility
The Thrift library targets Windows XP for broadest compatbility. A notable
difference is in the Windows-specific implementation of the socket poll
function. To target Vista, Win7 or other versions, comment out the line
#define TARGET_WIN_XP.
## Named Pipes
Named Pipe transport has been added in the TPipe and TPipeServer classes. This
is currently Windows-only. Named pipe transport for *NIX has not been
implemented. Domain sockets are a better choice for local IPC under non-Windows
OS's. *NIX named pipes only support 1:1 client-server connection.
# Thrift/SSL
## Scope
This SSL only supports blocking mode socket I/O. It can only be used with
TSimpleServer, TThreadedServer, and TThreadPoolServer.
## Implementation
There're two main classes TSSLSocketFactory and TSSLSocket. Instances of
TSSLSocket are always created from TSSLSocketFactory.
PosixSSLThreadFactory creates PosixSSLThread. The only difference from the
PthreadThread type is that it cleanups OpenSSL error queue upon exiting
the thread. Ideally, OpenSSL APIs should only be called from PosixSSLThread.
## How to use SSL APIs
This is for demo. In real code, typically only one TSSLSocketFactory
instance is needed.
shared_ptr<TSSLSocketFactory> getSSLSocketFactory() {
shared_ptr<TSSLSocketFactory> factory(new TSSLSocketFactory());
// client: load trusted certificates
factory->loadTrustedCertificates("my-trusted-ca-certificates.pem");
// client: optionally set your own access manager, otherwise,
// the default client access manager will be loaded.
factory->loadCertificate("my-certificate-signed-by-ca.pem");
factory->loadPrivateKey("my-private-key.pem");
// server: optionally setup access manager
// shared_ptr<AccessManager> accessManager(new MyAccessManager);
// factory->access(accessManager);
...
}
client code sample
shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
shared_ptr<TSocket> socket = factory.createSocket(host, port);
shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
...
server code sample
shared_ptr<TSSLSocketFactory> factory = getSSLSocketFactory();
shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, factory));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory));
...
## AccessManager
AccessManager defines a callback interface. It has three callback methods:
(a) Decision verify(const sockaddr_storage& sa);
(b) Decision verify(const string& host, const char* name, int size);
(c) Decision verify(const sockaddr_storage& sa, const char* data, int size);
After SSL handshake completes, additional checks are conducted. Application
is given the chance to decide whether or not to continue the conversation
with the remote. Application is queried through the above three "verify"
method. They are called at different points of the verification process.
Decisions can be one of ALLOW, DENY, and SKIP. ALLOW and DENY means the
conversation should be continued or disconnected, respectively. ALLOW and
DENY decision stops the verification process. SKIP means there's no decision
based on the given input, continue the verification process.
First, (a) is called with the remote IP. It is called once at the beginning.
"sa" is the IP address of the remote peer.
Then, the certificate of remote peer is loaded. SubjectAltName extensions
are extracted and sent to application for verification. When a DNS
subjectAltName field is extracted, (b) is called. When an IP subjectAltName
field is extracted, (c) is called.
The "host" in (b) is the value from TSocket::getHost() if this is a client
side socket, or TSocket::getPeerHost() if this is a server side socket. The
reason is client side socket initiates the connection. TSocket::getHost()
is the remote host name. On server side, the remote host name is unknown
unless it's retrieved through TSocket::getPeerHost(). Either way, "host"
should be the remote host name. Keep in mind, if TSocket::getPeerHost()
failed, it would return the remote host name in numeric format.
If all subjectAltName extensions were "skipped", the common name field would
be checked. It is sent to application through (c), where "sa" is the remote
IP address. "data" is the IP address extracted from subjectAltName IP
extension, and "size" is the length of the extension data.
If any of the above "verify" methods returned a decision ALLOW or DENY, the
verification process would be stopped.
If any of the above "verify" methods returned SKIP, that decision would be
ignored and the verification process would move on till the last item is
examined. At that point, if there's still no decision, the connection is
terminated.
Thread safety, an access manager should not store state information if it's
to be used by many SSL sockets.
## SIGPIPE signal
Applications running OpenSSL over network connections may crash if SIGPIPE
is not ignored. This happens when they receive a connection reset by remote
peer exception, which somehow triggers a SIGPIPE signal. If not handled,
this signal would kill the application.
## How to run test client/server in SSL mode
The server and client expects the followings from the directory /test/
- keys/server.crt
- keys/server.key
- keys/CA.pem
The file names are hard coded in the source code. You need to create these
certificates before you can run the test code in SSL mode. Make sure at least
one of the followings is included in "keys/server.crt",
- subjectAltName, DNS localhost
- subjectAltName, IP 127.0.0.1
- common name, localhost
Run within /test/ folder,
./cpp/TestServer --ssl &
./cpp/TestClient --ssl
If "-h <host>" is used to run client, the above "localhost" in the above
keys/server.crt has to be replaced with that host name.
## TSSLSocketFactory::randomize()
The default implementation of OpenSSLSocketFactory::randomize() simply calls
OpenSSL's RAND_poll() when OpenSSL library is first initialized.
The PRNG seed is key to the application security. This method should be
overridden if it's not strong enough for you.

View file

@ -0,0 +1,4 @@
Please follow [General Coding Standards](/doc/coding_standards.md)
* see .clang-format in root dir for settings of accepted format
* clang-format (3.5 or newer) can be used to automaticaly reformat code ('make style' command)

View file

@ -0,0 +1,363 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug-mt|Win32">
<Configuration>Debug-mt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-mt|x64">
<Configuration>Debug-mt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-mt|Win32">
<Configuration>Release-mt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-mt|x64">
<Configuration>Release-mt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\thrift\async\TAsyncChannel.cpp"/>
<ClCompile Include="src\thrift\async\TConcurrentClientSyncInfo.cpp"/>
<ClCompile Include="src\thrift\concurrency\BoostMonitor.cpp" />
<ClCompile Include="src\thrift\concurrency\BoostMutex.cpp" />
<ClCompile Include="src\thrift\concurrency\BoostThreadFactory.cpp" />
<ClCompile Include="src\thrift\concurrency\StdThreadFactory.cpp" />
<ClCompile Include="src\thrift\concurrency\ThreadManager.cpp"/>
<ClCompile Include="src\thrift\concurrency\TimerManager.cpp"/>
<ClCompile Include="src\thrift\concurrency\Util.cpp"/>
<ClCompile Include="src\thrift\processor\PeekProcessor.cpp"/>
<ClCompile Include="src\thrift\protocol\TBase64Utils.cpp" />
<ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp"/>
<ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp"/>
<ClCompile Include="src\thrift\protocol\TProtocol.cpp"/>
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp"/>
<ClCompile Include="src\thrift\server\TSimpleServer.cpp"/>
<ClCompile Include="src\thrift\server\TThreadPoolServer.cpp"/>
<ClCompile Include="src\thrift\server\TThreadedServer.cpp"/>
<ClCompile Include="src\thrift\TApplicationException.cpp"/>
<ClCompile Include="src\thrift\TOutput.cpp"/>
<ClCompile Include="src\thrift\transport\TBufferTransports.cpp"/>
<ClCompile Include="src\thrift\transport\TFDTransport.cpp" />
<ClCompile Include="src\thrift\transport\THttpClient.cpp" />
<ClCompile Include="src\thrift\transport\THttpServer.cpp" />
<ClCompile Include="src\thrift\transport\THttpTransport.cpp"/>
<ClCompile Include="src\thrift\transport\TPipe.cpp" />
<ClCompile Include="src\thrift\transport\TPipeServer.cpp" />
<ClCompile Include="src\thrift\transport\TServerSocket.cpp"/>
<ClCompile Include="src\thrift\transport\TSimpleFileTransport.cpp" />
<ClCompile Include="src\thrift\transport\TFileTransport.cpp" />
<ClCompile Include="src\thrift\transport\TSocket.cpp"/>
<ClCompile Include="src\thrift\transport\TSSLSocket.cpp"/>
<ClCompile Include="src\thrift\transport\TTransportException.cpp"/>
<ClCompile Include="src\thrift\transport\TTransportUtils.cpp"/>
<ClCompile Include="src\thrift\windows\GetTimeOfDay.cpp" />
<ClCompile Include="src\thrift\windows\OverlappedSubmissionThread.cpp" />
<ClCompile Include="src\thrift\windows\SocketPair.cpp" />
<ClCompile Include="src\thrift\windows\TWinsockSingleton.cpp" />
<ClCompile Include="src\thrift\windows\WinFcntl.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\thrift\async\TAsyncChannel.h" />
<ClInclude Include="src\thrift\async\TConcurrentClientSyncInfo.h" />
<ClInclude Include="src\thrift\concurrency\BoostThreadFactory.h" />
<ClInclude Include="src\thrift\concurrency\StdThreadFactory.h" />
<ClInclude Include="src\thrift\concurrency\Exception.h" />
<ClInclude Include="src\thrift\concurrency\PlatformThreadFactory.h" />
<ClInclude Include="src\thrift\processor\PeekProcessor.h" />
<ClInclude Include="src\thrift\processor\TMultiplexedProcessor.h" />
<ClInclude Include="src\thrift\protocol\TBinaryProtocol.h" />
<ClInclude Include="src\thrift\protocol\TDebugProtocol.h" />
<ClInclude Include="src\thrift\protocol\TJSONProtocol.h" />
<ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h" />
<ClInclude Include="src\thrift\protocol\TProtocol.h" />
<ClInclude Include="src\thrift\protocol\TVirtualProtocol.h" />
<ClInclude Include="src\thrift\server\TServer.h" />
<ClInclude Include="src\thrift\server\TSimpleServer.h" />
<ClInclude Include="src\thrift\server\TThreadPoolServer.h" />
<ClInclude Include="src\thrift\server\TThreadedServer.h" />
<ClInclude Include="src\thrift\TApplicationException.h" />
<ClInclude Include="src\thrift\Thrift.h" />
<ClInclude Include="src\thrift\TOutput.h" />
<ClInclude Include="src\thrift\TProcessor.h" />
<ClInclude Include="src\thrift\transport\TBufferTransports.h" />
<ClInclude Include="src\thrift\transport\TFDTransport.h" />
<ClInclude Include="src\thrift\transport\TFileTransport.h" />
<ClInclude Include="src\thrift\transport\THttpClient.h" />
<ClInclude Include="src\thrift\transport\THttpServer.h" />
<ClInclude Include="src\thrift\transport\TPipe.h" />
<ClInclude Include="src\thrift\transport\TPipeServer.h" />
<ClInclude Include="src\thrift\transport\TServerSocket.h" />
<ClInclude Include="src\thrift\transport\TServerTransport.h" />
<ClInclude Include="src\thrift\transport\TSimpleFileTransport.h" />
<ClInclude Include="src\thrift\transport\TSocket.h" />
<ClInclude Include="src\thrift\transport\TSSLSocket.h" />
<ClInclude Include="src\thrift\transport\TTransport.h" />
<ClInclude Include="src\thrift\transport\TTransportException.h" />
<ClInclude Include="src\thrift\transport\TTransportUtils.h" />
<ClInclude Include="src\thrift\transport\TVirtualTransport.h" />
<ClInclude Include="src\thrift\windows\config.h" />
<ClInclude Include="src\thrift\windows\GetTimeOfDay.h" />
<ClInclude Include="src\thrift\windows\Operators.h" />
<ClInclude Include="src\thrift\windows\OverlappedSubmissionThread.h" />
<ClInclude Include="src\thrift\windows\SocketPair.h" />
<ClInclude Include="src\thrift\windows\TWinsockSingleton.h" />
<ClInclude Include="src\thrift\windows\WinFcntl.h" />
</ItemGroup>
<ItemGroup>
<None Include="src\thrift\protocol\TBinaryProtocol.tcc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{DD26F57E-60F2-4F37-A616-D219A9BF338F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>thrift</RootNamespace>
<ProjectName>libthrift</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(OPENSSL_ROOT_DIR)\include\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthrift.pdb</ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthrift.pdb</ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthrift.pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthrift.pdb</ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,283 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\thrift\transport\TBufferTransports.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\TOutput.cpp" />
<ClCompile Include="src\thrift\TApplicationException.cpp" />
<ClCompile Include="src\thrift\windows\StdAfx.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TTransportException.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\windows\GetTimeOfDay.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\ThreadManager.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\TimerManager.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\Util.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\protocol\TDebugProtocol.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\protocol\TBase64Utils.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\protocol\TJSONProtocol.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\protocol\TMultiplexedProtocol.cpp">
<Filter>protocol</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TFDTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TFileTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TSimpleFileTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\THttpTransport.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\THttpClient.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\THttpServer.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TSSLSocket.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TTransportUtils.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\server\TSimpleServer.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="src\thrift\server\TThreadPoolServer.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="src\thrift\server\TThreadedServer.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="src\thrift\async\TAsyncChannel.cpp">
<Filter>async</Filter>
</ClCompile>
<ClCompile Include="src\thrift\async\TConcurrentClientSyncInfo.cpp">
<Filter>async</Filter>
</ClCompile>
<ClCompile Include="src\thrift\processor\PeekProcessor.cpp">
<Filter>processor</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TServerSocket.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TSocket.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\windows\TWinsockSingleton.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="src\thrift\windows\SocketPair.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\BoostMonitor.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\BoostMutex.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\BoostThreadFactory.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\concurrency\StdThreadFactory.cpp">
<Filter>concurrency</Filter>
</ClCompile>
<ClCompile Include="src\thrift\windows\WinFcntl.cpp">
<Filter>windows</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TPipe.cpp">
<Filter>transport</Filter>
</ClCompile>
<ClCompile Include="src\thrift\transport\TPipeServer.cpp">
<Filter>transport</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\thrift\transport\TBufferTransports.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TSocket.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TBinaryProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\Thrift.h" />
<ClInclude Include="src\thrift\TProcessor.h" />
<ClInclude Include="src\thrift\TApplicationException.h" />
<ClInclude Include="src\thrift\windows\StdAfx.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\TargetVersion.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\concurrency\Exception.h">
<Filter>concurrency</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TVirtualTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TTransportException.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\GetTimeOfDay.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TServerTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\config.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TVirtualProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\server\TServer.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="src\thrift\server\TSimpleServer.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="src\thrift\server\TThreadPoolServer.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="src\thrift\server\TThreadedServer.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="src\thrift\async\TAsyncChannel.h">
<Filter>async</Filter>
</ClInclude>
<ClInclude Include="src\thrift\async\TConcurrentClientSyncInfo.h">
<Filter>async</Filter>
</ClInclude>
<ClInclude Include="src\thrift\processor\PeekProcessor.h">
<Filter>processor</Filter>
</ClInclude>
<ClInclude Include="src\thrift\processor\TMultiplexedProcessor.h">
<Filter>processor</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TFDTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TFileTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\THttpClient.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\THttpServer.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TSSLSocket.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TTransportUtils.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TSimpleFileTransport.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TJSONProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TMultiplexedProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\protocol\TDebugProtocol.h">
<Filter>protocol</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TServerSocket.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\Operators.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\TWinsockSingleton.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\SocketPair.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\force_inc.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\concurrency\BoostThreadFactory.h">
<Filter>concurrency</Filter>
</ClInclude>
<ClInclude Include="src\thrift\concurrency\StdThreadFactory.h">
<Filter>concurrency</Filter>
</ClInclude>
<ClInclude Include="src\thrift\concurrency\PlatformThreadFactory.h">
<Filter>concurrency</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\WinFcntl.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TPipe.h">
<Filter>transport</Filter>
</ClInclude>
<ClInclude Include="src\thrift\transport\TPipeServer.h">
<Filter>transport</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="protocol">
<UniqueIdentifier>{07ced19b-b72a-4105-9ffb-6d2bcf64497e}</UniqueIdentifier>
</Filter>
<Filter Include="transport">
<UniqueIdentifier>{e9f61404-1148-4103-bd6f-e5869d37fa79}</UniqueIdentifier>
</Filter>
<Filter Include="windows">
<UniqueIdentifier>{2814002a-3c68-427e-b0eb-33acd2f406ae}</UniqueIdentifier>
</Filter>
<Filter Include="concurrency">
<UniqueIdentifier>{addd4707-dbaa-4d0c-bef6-fff8be7b495a}</UniqueIdentifier>
</Filter>
<Filter Include="server">
<UniqueIdentifier>{f55a8e9b-6959-487f-a396-c31b4d6c61d6}</UniqueIdentifier>
</Filter>
<Filter Include="async">
<UniqueIdentifier>{d526885b-1b3e-4ee3-8027-e694fe98ad63}</UniqueIdentifier>
</Filter>
<Filter Include="processor">
<UniqueIdentifier>{8f428da8-5a83-44fb-9578-de935fb415e1}</UniqueIdentifier>
</Filter>
<Filter Include="windows\tr1">
<UniqueIdentifier>{eea10406-3380-4f2d-9365-c26fa2875dae}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="src\thrift\protocol\TBinaryProtocol.tcc">
<Filter>protocol</Filter>
</None>
<None Include="src\thrift\windows\tr1\functional">
<Filter>windows\tr1</Filter>
</None>
</ItemGroup>
</Project>

293
vendor/git.apache.org/thrift.git/lib/cpp/libthriftnb.vcxproj generated vendored Executable file
View file

@ -0,0 +1,293 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug-mt|Win32">
<Configuration>Debug-mt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug-mt|x64">
<Configuration>Debug-mt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-mt|Win32">
<Configuration>Release-mt</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release-mt|x64">
<Configuration>Release-mt</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\thrift\async\TAsyncProtocolProcessor.cpp"/>
<ClCompile Include="src\thrift\async\TEvhttpClientChannel.cpp"/>
<ClCompile Include="src\thrift\async\TEvhttpServer.cpp"/>
<ClCompile Include="src\thrift\server\TNonblockingServer.cpp"/>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\thrift\async\TAsyncProtocolProcessor.h" />
<ClInclude Include="src\thrift\async\TEvhttpClientChannel.h" />
<ClInclude Include="src\thrift\async\TEvhttpServer.h" />
<ClInclude Include="src\thrift\server\TNonblockingServer.h" />
<ClInclude Include="src\thrift\windows\config.h" />
<ClInclude Include="src\thrift\windows\force_inc.h" />
<ClInclude Include="src\thrift\windows\TargetVersion.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D8696CCE-7D46-4659-B432-91754A41DEB0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libthriftnb</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="3rdparty.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
<IncludePath>$(ProjectDir)\src\;$(ProjectDir)\src\thrift\windows\;$(BOOST_ROOT)\include;$(BOOST_ROOT)\;$(LIBEVENT_ROOT)\WIN32-Code\;$(LIBEVENT_ROOT)\include;$(LIBEVENT_ROOT)\;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthriftnb.pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthriftnb.pdb</ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-mt|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthriftnb.pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ProgramDataBaseFileName>$(IntDir)libthriftnb.pdb</ProgramDataBaseFileName>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release-mt|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_CONFIG_H=1;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="server">
<UniqueIdentifier>{bf449d92-4be8-4f6f-a010-c536f57c6f13}</UniqueIdentifier>
</Filter>
<Filter Include="async">
<UniqueIdentifier>{0294d0a6-ce46-4be8-a659-826d6e98ae41}</UniqueIdentifier>
</Filter>
<Filter Include="windows">
<UniqueIdentifier>{60fc9e5e-0866-4aba-8662-439bb4a461d3}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\thrift\server\TNonblockingServer.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="src\thrift\async\TEvhttpClientChannel.cpp">
<Filter>async</Filter>
</ClCompile>
<ClCompile Include="src\thrift\async\TEvhttpServer.cpp">
<Filter>async</Filter>
</ClCompile>
<ClCompile Include="src\thrift\async\TAsyncProtocolProcessor.cpp">
<Filter>async</Filter>
</ClCompile>
<ClCompile Include="src\thrift\windows\StdAfx.cpp">
<Filter>windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\thrift\server\TNonblockingServer.h">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="src\thrift\async\TEvhttpClientChannel.h">
<Filter>async</Filter>
</ClInclude>
<ClInclude Include="src\thrift\async\TEvhttpServer.h">
<Filter>async</Filter>
</ClInclude>
<ClInclude Include="src\thrift\async\TAsyncProtocolProcessor.h">
<Filter>async</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\config.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\StdAfx.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\TargetVersion.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="src\thrift\windows\force_inc.h">
<Filter>windows</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -0,0 +1,81 @@
/*
* 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 <thrift/TApplicationException.h>
#include <thrift/protocol/TProtocol.h>
namespace apache {
namespace thrift {
uint32_t TApplicationException::read(apache::thrift::protocol::TProtocol* iprot) {
uint32_t xfer = 0;
std::string fname;
apache::thrift::protocol::TType ftype;
int16_t fid;
xfer += iprot->readStructBegin(fname);
while (true) {
xfer += iprot->readFieldBegin(fname, ftype, fid);
if (ftype == apache::thrift::protocol::T_STOP) {
break;
}
switch (fid) {
case 1:
if (ftype == apache::thrift::protocol::T_STRING) {
xfer += iprot->readString(message_);
} else {
xfer += iprot->skip(ftype);
}
break;
case 2:
if (ftype == apache::thrift::protocol::T_I32) {
int32_t type;
xfer += iprot->readI32(type);
type_ = (TApplicationExceptionType)type;
} else {
xfer += iprot->skip(ftype);
}
break;
default:
xfer += iprot->skip(ftype);
break;
}
xfer += iprot->readFieldEnd();
}
xfer += iprot->readStructEnd();
return xfer;
}
uint32_t TApplicationException::write(apache::thrift::protocol::TProtocol* oprot) const {
uint32_t xfer = 0;
xfer += oprot->writeStructBegin("TApplicationException");
xfer += oprot->writeFieldBegin("message", apache::thrift::protocol::T_STRING, 1);
xfer += oprot->writeString(message_);
xfer += oprot->writeFieldEnd();
xfer += oprot->writeFieldBegin("type", apache::thrift::protocol::T_I32, 2);
xfer += oprot->writeI32(type_);
xfer += oprot->writeFieldEnd();
xfer += oprot->writeFieldStop();
xfer += oprot->writeStructEnd();
return xfer;
}
}
} // apache::thrift

View file

@ -0,0 +1,115 @@
/*
* 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 _THRIFT_TAPPLICATIONEXCEPTION_H_
#define _THRIFT_TAPPLICATIONEXCEPTION_H_ 1
#include <thrift/Thrift.h>
namespace apache {
namespace thrift {
namespace protocol {
class TProtocol;
}
class TApplicationException : public TException {
public:
/**
* Error codes for the various types of exceptions.
*/
enum TApplicationExceptionType {
UNKNOWN = 0,
UNKNOWN_METHOD = 1,
INVALID_MESSAGE_TYPE = 2,
WRONG_METHOD_NAME = 3,
BAD_SEQUENCE_ID = 4,
MISSING_RESULT = 5,
INTERNAL_ERROR = 6,
PROTOCOL_ERROR = 7,
INVALID_TRANSFORM = 8,
INVALID_PROTOCOL = 9,
UNSUPPORTED_CLIENT_TYPE = 10
};
TApplicationException() : TException(), type_(UNKNOWN) {}
TApplicationException(TApplicationExceptionType type) : TException(), type_(type) {}
TApplicationException(const std::string& message) : TException(message), type_(UNKNOWN) {}
TApplicationException(TApplicationExceptionType type, const std::string& message)
: TException(message), type_(type) {}
virtual ~TApplicationException() throw() {}
/**
* Returns an error code that provides information about the type of error
* that has occurred.
*
* @return Error code
*/
TApplicationExceptionType getType() const { return type_; }
virtual const char* what() const throw() {
if (message_.empty()) {
switch (type_) {
case UNKNOWN:
return "TApplicationException: Unknown application exception";
case UNKNOWN_METHOD:
return "TApplicationException: Unknown method";
case INVALID_MESSAGE_TYPE:
return "TApplicationException: Invalid message type";
case WRONG_METHOD_NAME:
return "TApplicationException: Wrong method name";
case BAD_SEQUENCE_ID:
return "TApplicationException: Bad sequence identifier";
case MISSING_RESULT:
return "TApplicationException: Missing result";
case INTERNAL_ERROR:
return "TApplicationException: Internal error";
case PROTOCOL_ERROR:
return "TApplicationException: Protocol error";
case INVALID_TRANSFORM:
return "TApplicationException: Invalid transform";
case INVALID_PROTOCOL:
return "TApplicationException: Invalid protocol";
case UNSUPPORTED_CLIENT_TYPE:
return "TApplicationException: Unsupported client type";
default:
return "TApplicationException: (Invalid exception type)";
};
} else {
return message_.c_str();
}
}
uint32_t read(protocol::TProtocol* iprot);
uint32_t write(protocol::TProtocol* oprot) const;
protected:
/**
* Error code
*/
TApplicationExceptionType type_;
};
}
} // apache::thrift
#endif // #ifndef _THRIFT_TAPPLICATIONEXCEPTION_H_

View file

@ -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.
*/
#ifndef _THRIFT_TBASE_H_
#define _THRIFT_TBASE_H_ 1
#include <thrift/Thrift.h>
#include <thrift/protocol/TProtocol.h>
namespace apache {
namespace thrift {
class TBase {
public:
virtual ~TBase(){};
virtual uint32_t read(protocol::TProtocol* iprot) = 0;
virtual uint32_t write(protocol::TProtocol* oprot) const = 0;
};
}
} // apache::thrift
#endif // #ifndef _THRIFT_TBASE_H_

View file

@ -0,0 +1,141 @@
/*
* 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 _THRIFT_TDISPATCHPROCESSOR_H_
#define _THRIFT_TDISPATCHPROCESSOR_H_ 1
#include <thrift/TProcessor.h>
namespace apache {
namespace thrift {
/**
* TDispatchProcessor is a helper class to parse the message header then call
* another function to dispatch based on the function name.
*
* Subclasses must implement dispatchCall() to dispatch on the function name.
*/
template <class Protocol_>
class TDispatchProcessorT : public TProcessor {
public:
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out,
void* connectionContext) {
protocol::TProtocol* inRaw = in.get();
protocol::TProtocol* outRaw = out.get();
// Try to dynamic cast to the template protocol type
Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
if (specificIn && specificOut) {
return processFast(specificIn, specificOut, connectionContext);
}
// Log the fact that we have to use the slow path
T_GENERIC_PROTOCOL(this, inRaw, specificIn);
T_GENERIC_PROTOCOL(this, outRaw, specificOut);
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
inRaw->readMessageBegin(fname, mtype, seqid);
// If this doesn't look like a valid call, log an error and return false so
// that the server will close the connection.
//
// (The old generated processor code used to try to skip a T_STRUCT and
// continue. However, that seems unsafe.)
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
return false;
}
return this->dispatchCall(inRaw, outRaw, fname, seqid, connectionContext);
}
protected:
bool processFast(Protocol_* in, Protocol_* out, void* connectionContext) {
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
in->readMessageBegin(fname, mtype, seqid);
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
return false;
}
return this->dispatchCallTemplated(in, out, fname, seqid, connectionContext);
}
/**
* dispatchCall() methods must be implemented by subclasses
*/
virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
apache::thrift::protocol::TProtocol* out,
const std::string& fname,
int32_t seqid,
void* callContext) = 0;
virtual bool dispatchCallTemplated(Protocol_* in,
Protocol_* out,
const std::string& fname,
int32_t seqid,
void* callContext) = 0;
};
/**
* Non-templatized version of TDispatchProcessor, that doesn't bother trying to
* perform a dynamic_cast.
*/
class TDispatchProcessor : public TProcessor {
public:
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out,
void* connectionContext) {
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
in->readMessageBegin(fname, mtype, seqid);
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
return false;
}
return dispatchCall(in.get(), out.get(), fname, seqid, connectionContext);
}
protected:
virtual bool dispatchCall(apache::thrift::protocol::TProtocol* in,
apache::thrift::protocol::TProtocol* out,
const std::string& fname,
int32_t seqid,
void* callContext) = 0;
};
// Specialize TDispatchProcessorT for TProtocol and TDummyProtocol just to use
// the generic TDispatchProcessor.
template <>
class TDispatchProcessorT<protocol::TDummyProtocol> : public TDispatchProcessor {};
template <>
class TDispatchProcessorT<protocol::TProtocol> : public TDispatchProcessor {};
}
} // apache::thrift
#endif // _THRIFT_TDISPATCHPROCESSOR_H_

View file

@ -0,0 +1,195 @@
/*
* 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 _THRIFT_TLOGGING_H_
#define _THRIFT_TLOGGING_H_ 1
#include <thrift/thrift-config.h>
/**
* Contains utility macros for debugging and logging.
*
*/
#include <time.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
/**
* T_GLOBAL_DEBUGGING_LEVEL = 0: all debugging turned off, debug macros undefined
* T_GLOBAL_DEBUGGING_LEVEL = 1: all debugging turned on
*/
#define T_GLOBAL_DEBUGGING_LEVEL 0
/**
* T_GLOBAL_LOGGING_LEVEL = 0: all logging turned off, logging macros undefined
* T_GLOBAL_LOGGING_LEVEL = 1: all logging turned on
*/
#define T_GLOBAL_LOGGING_LEVEL 1
/**
* Standard wrapper around fprintf what will prefix the file name and line
* number to the line. Uses T_GLOBAL_DEBUGGING_LEVEL to control whether it is
* turned on or off.
*
* @param format_string
*/
#if T_GLOBAL_DEBUGGING_LEVEL > 0
#define T_DEBUG(format_string, ...) \
if (T_GLOBAL_DEBUGGING_LEVEL > 0) { \
fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__); \
}
#else
#define T_DEBUG(format_string, ...)
#endif
/**
* analogous to T_DEBUG but also prints the time
*
* @param string format_string input: printf style format string
*/
#if T_GLOBAL_DEBUGGING_LEVEL > 0
#define T_DEBUG_T(format_string, ...) \
{ \
if (T_GLOBAL_DEBUGGING_LEVEL > 0) { \
time_t now; \
char dbgtime[26]; \
time(&now); \
THRIFT_CTIME_R(&now, dbgtime); \
dbgtime[24] = '\0'; \
fprintf(stderr, \
"[%s,%d] [%s] " format_string " \n", \
__FILE__, \
__LINE__, \
dbgtime, \
##__VA_ARGS__); \
} \
}
#else
#define T_DEBUG_T(format_string, ...)
#endif
/**
* analogous to T_DEBUG but uses input level to determine whether or not the string
* should be logged.
*
* @param int level: specified debug level
* @param string format_string input: format string
*/
#define T_DEBUG_L(level, format_string, ...) \
if ((level) > 0) { \
fprintf(stderr, "[%s,%d] " format_string " \n", __FILE__, __LINE__, ##__VA_ARGS__); \
}
/**
* Explicit error logging. Prints time, file name and line number
*
* @param string format_string input: printf style format string
*/
#define T_ERROR(format_string, ...) \
{ \
time_t now; \
char dbgtime[26]; \
time(&now); \
THRIFT_CTIME_R(&now, dbgtime); \
dbgtime[24] = '\0'; \
fprintf(stderr, \
"[%s,%d] [%s] ERROR: " format_string " \n", \
__FILE__, \
__LINE__, \
dbgtime, \
##__VA_ARGS__); \
}
/**
* Analogous to T_ERROR, additionally aborting the process.
* WARNING: macro calls abort(), ending program execution
*
* @param string format_string input: printf style format string
*/
#define T_ERROR_ABORT(format_string, ...) \
{ \
time_t now; \
char dbgtime[26]; \
time(&now); \
THRIFT_CTIME_R(&now, dbgtime); \
dbgtime[24] = '\0'; \
fprintf(stderr, \
"[%s,%d] [%s] ERROR: Going to abort " format_string " \n", \
__FILE__, \
__LINE__, \
dbgtime, \
##__VA_ARGS__); \
exit(1); \
}
/**
* Log input message
*
* @param string format_string input: printf style format string
*/
#if T_GLOBAL_LOGGING_LEVEL > 0
#define T_LOG_OPER(format_string, ...) \
{ \
if (T_GLOBAL_LOGGING_LEVEL > 0) { \
time_t now; \
char dbgtime[26]; \
time(&now); \
THRIFT_CTIME_R(&now, dbgtime); \
dbgtime[24] = '\0'; \
fprintf(stderr, "[%s] " format_string " \n", dbgtime, ##__VA_ARGS__); \
} \
}
#else
#define T_LOG_OPER(format_string, ...)
#endif
/**
* T_GLOBAL_DEBUG_VIRTUAL = 0 or unset: normal operation,
* virtual call debug messages disabled
* T_GLOBAL_DEBUG_VIRTUAL = 1: log a debug messages whenever an
* avoidable virtual call is made
* T_GLOBAL_DEBUG_VIRTUAL = 2: record detailed info that can be
* printed by calling
* apache::thrift::profile_print_info()
*/
#if T_GLOBAL_DEBUG_VIRTUAL > 1
#define T_VIRTUAL_CALL() ::apache::thrift::profile_virtual_call(typeid(*this))
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
do { \
if (!(specific_prot)) { \
::apache::thrift::profile_generic_protocol(typeid(*template_class), typeid(*generic_prot)); \
} \
} while (0)
#elif T_GLOBAL_DEBUG_VIRTUAL == 1
#define T_VIRTUAL_CALL() fprintf(stderr, "[%s,%d] virtual call\n", __FILE__, __LINE__)
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot) \
do { \
if (!(specific_prot)) { \
fprintf(stderr, "[%s,%d] failed to cast to specific protocol type\n", __FILE__, __LINE__); \
} \
} while (0)
#else
#define T_VIRTUAL_CALL()
#define T_GENERIC_PROTOCOL(template_class, generic_prot, specific_prot)
#endif
#endif // #ifndef _THRIFT_TLOGGING_H_

View file

@ -0,0 +1,126 @@
/*
* 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 <thrift/Thrift.h>
#include <cstring>
#include <cstdlib>
#include <boost/lexical_cast.hpp>
#include <stdarg.h>
#include <stdio.h>
namespace apache {
namespace thrift {
TOutput GlobalOutput;
void TOutput::printf(const char* message, ...) {
#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
// Try to reduce heap usage, even if printf is called rarely.
static const int STACK_BUF_SIZE = 256;
char stack_buf[STACK_BUF_SIZE];
va_list ap;
#ifdef _MSC_VER
va_start(ap, message);
int need = _vscprintf(message, ap);
va_end(ap);
if (need < STACK_BUF_SIZE) {
va_start(ap, message);
vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
va_end(ap);
f_(stack_buf);
return;
}
#else
va_start(ap, message);
int need = vsnprintf(stack_buf, STACK_BUF_SIZE, message, ap);
va_end(ap);
if (need < STACK_BUF_SIZE) {
f_(stack_buf);
return;
}
#endif
char* heap_buf = (char*)malloc((need + 1) * sizeof(char));
if (heap_buf == NULL) {
#ifdef _MSC_VER
va_start(ap, message);
vsnprintf_s(stack_buf, STACK_BUF_SIZE, _TRUNCATE, message, ap);
va_end(ap);
#endif
// Malloc failed. We might as well print the stack buffer.
f_(stack_buf);
return;
}
va_start(ap, message);
int rval = vsnprintf(heap_buf, need + 1, message, ap);
va_end(ap);
// TODO(shigin): inform user
if (rval != -1) {
f_(heap_buf);
}
free(heap_buf);
#endif
}
void TOutput::errorTimeWrapper(const char* msg) {
#ifndef THRIFT_SQUELCH_CONSOLE_OUTPUT
time_t now;
char dbgtime[26];
time(&now);
THRIFT_CTIME_R(&now, dbgtime);
dbgtime[24] = 0;
fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg);
#endif
}
void TOutput::perror(const char* message, int errno_copy) {
std::string out = message + strerror_s(errno_copy);
f_(out.c_str());
}
std::string TOutput::strerror_s(int errno_copy) {
#ifndef HAVE_STRERROR_R
return "errno = " + boost::lexical_cast<std::string>(errno_copy);
#else // HAVE_STRERROR_R
char b_errbuf[1024] = {'\0'};
#ifdef STRERROR_R_CHAR_P
char* b_error = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
#else
char* b_error = b_errbuf;
int rv = strerror_r(errno_copy, b_errbuf, sizeof(b_errbuf));
if (rv == -1) {
// strerror_r failed. omgwtfbbq.
return "XSI-compliant strerror_r() failed with errno = "
+ boost::lexical_cast<std::string>(errno_copy);
}
#endif
// Can anyone prove that explicit cast is probably not necessary
// to ensure that the string object is constructed before
// b_error becomes invalid?
return std::string(b_error);
#endif // HAVE_STRERROR_R
}
}
} // apache::thrift

View file

@ -0,0 +1,58 @@
/*
* 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 _THRIFT_OUTPUT_H_
#define _THRIFT_OUTPUT_H_ 1
namespace apache {
namespace thrift {
class TOutput {
public:
TOutput() : f_(&errorTimeWrapper) {}
inline void setOutputFunction(void (*function)(const char*)) { f_ = function; }
inline void operator()(const char* message) { f_(message); }
// It is important to have a const char* overload here instead of
// just the string version, otherwise errno could be corrupted
// if there is some problem allocating memory when constructing
// the string.
void perror(const char* message, int errno_copy);
inline void perror(const std::string& message, int errno_copy) {
perror(message.c_str(), errno_copy);
}
void printf(const char* message, ...);
static void errorTimeWrapper(const char* msg);
/** Just like strerror_r but returns a C++ string object. */
static std::string strerror_s(int errno_copy);
private:
void (*f_)(const char*);
};
extern TOutput GlobalOutput;
}
} // namespace apache::thrift
#endif //_THRIFT_OUTPUT_H_

View file

@ -0,0 +1,230 @@
/*
* 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 _THRIFT_TPROCESSOR_H_
#define _THRIFT_TPROCESSOR_H_ 1
#include <string>
#include <thrift/protocol/TProtocol.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
/**
* Virtual interface class that can handle events from the processor. To
* use this you should subclass it and implement the methods that you care
* about. Your subclass can also store local data that you may care about,
* such as additional "arguments" to these methods (stored in the object
* instance's state).
*/
class TProcessorEventHandler {
public:
virtual ~TProcessorEventHandler() {}
/**
* Called before calling other callback methods.
* Expected to return some sort of context object.
* The return value is passed to all other callbacks
* for that function invocation.
*/
virtual void* getContext(const char* fn_name, void* serverContext) {
(void)fn_name;
(void)serverContext;
return NULL;
}
/**
* Expected to free resources associated with a context.
*/
virtual void freeContext(void* ctx, const char* fn_name) {
(void)ctx;
(void)fn_name;
}
/**
* Called before reading arguments.
*/
virtual void preRead(void* ctx, const char* fn_name) {
(void)ctx;
(void)fn_name;
}
/**
* Called between reading arguments and calling the handler.
*/
virtual void postRead(void* ctx, const char* fn_name, uint32_t bytes) {
(void)ctx;
(void)fn_name;
(void)bytes;
}
/**
* Called between calling the handler and writing the response.
*/
virtual void preWrite(void* ctx, const char* fn_name) {
(void)ctx;
(void)fn_name;
}
/**
* Called after writing the response.
*/
virtual void postWrite(void* ctx, const char* fn_name, uint32_t bytes) {
(void)ctx;
(void)fn_name;
(void)bytes;
}
/**
* Called when an async function call completes successfully.
*/
virtual void asyncComplete(void* ctx, const char* fn_name) {
(void)ctx;
(void)fn_name;
}
/**
* Called if the handler throws an undeclared exception.
*/
virtual void handlerError(void* ctx, const char* fn_name) {
(void)ctx;
(void)fn_name;
}
protected:
TProcessorEventHandler() {}
};
/**
* A helper class used by the generated code to free each context.
*/
class TProcessorContextFreer {
public:
TProcessorContextFreer(TProcessorEventHandler* handler, void* context, const char* method)
: handler_(handler), context_(context), method_(method) {}
~TProcessorContextFreer() {
if (handler_ != NULL)
handler_->freeContext(context_, method_);
}
void unregister() { handler_ = NULL; }
private:
apache::thrift::TProcessorEventHandler* handler_;
void* context_;
const char* method_;
};
/**
* A processor is a generic object that acts upon two streams of data, one
* an input and the other an output. The definition of this object is loose,
* though the typical case is for some sort of server that either generates
* responses to an input stream or forwards data from one pipe onto another.
*
*/
class TProcessor {
public:
virtual ~TProcessor() {}
virtual bool process(boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out,
void* connectionContext) = 0;
bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> io, void* connectionContext) {
return process(io, io, connectionContext);
}
boost::shared_ptr<TProcessorEventHandler> getEventHandler() const { return eventHandler_; }
void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
eventHandler_ = eventHandler;
}
protected:
TProcessor() {}
boost::shared_ptr<TProcessorEventHandler> eventHandler_;
};
/**
* This is a helper class to allow boost::shared_ptr to be used with handler
* pointers returned by the generated handler factories.
*
* The handler factory classes generated by the thrift compiler return raw
* pointers, and factory->releaseHandler() must be called when the handler is
* no longer needed.
*
* A ReleaseHandler object can be instantiated and passed as the second
* parameter to a shared_ptr, so that factory->releaseHandler() will be called
* when the object is no longer needed, instead of deleting the pointer.
*/
template <typename HandlerFactory_>
class ReleaseHandler {
public:
ReleaseHandler(const boost::shared_ptr<HandlerFactory_>& handlerFactory)
: handlerFactory_(handlerFactory) {}
void operator()(typename HandlerFactory_::Handler* handler) {
if (handler) {
handlerFactory_->releaseHandler(handler);
}
}
private:
boost::shared_ptr<HandlerFactory_> handlerFactory_;
};
struct TConnectionInfo {
// The input and output protocols
boost::shared_ptr<protocol::TProtocol> input;
boost::shared_ptr<protocol::TProtocol> output;
// The underlying transport used for the connection
// This is the transport that was returned by TServerTransport::accept(),
// and it may be different than the transport pointed to by the input and
// output protocols.
boost::shared_ptr<transport::TTransport> transport;
};
class TProcessorFactory {
public:
virtual ~TProcessorFactory() {}
/**
* Get the TProcessor to use for a particular connection.
*
* This method is always invoked in the same thread that the connection was
* accepted on. This generally means that this call does not need to be
* thread safe, as it will always be invoked from a single thread.
*/
virtual boost::shared_ptr<TProcessor> getProcessor(const TConnectionInfo& connInfo) = 0;
};
class TSingletonProcessorFactory : public TProcessorFactory {
public:
TSingletonProcessorFactory(boost::shared_ptr<TProcessor> processor) : processor_(processor) {}
boost::shared_ptr<TProcessor> getProcessor(const TConnectionInfo&) { return processor_; }
private:
boost::shared_ptr<TProcessor> processor_;
};
}
} // apache::thrift
#endif // #ifndef _THRIFT_TPROCESSOR_H_

View file

@ -0,0 +1,89 @@
/*
* 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 _THRIFT_TOSTRING_H_
#define _THRIFT_TOSTRING_H_ 1
#include <boost/lexical_cast.hpp>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <sstream>
namespace apache {
namespace thrift {
template <typename T>
std::string to_string(const T& t) {
return boost::lexical_cast<std::string>(t);
}
template <typename K, typename V>
std::string to_string(const std::map<K, V>& m);
template <typename T>
std::string to_string(const std::set<T>& s);
template <typename T>
std::string to_string(const std::vector<T>& t);
template <typename K, typename V>
std::string to_string(const typename std::pair<K, V>& v) {
std::ostringstream o;
o << to_string(v.first) << ": " << to_string(v.second);
return o.str();
}
template <typename T>
std::string to_string(const T& beg, const T& end) {
std::ostringstream o;
for (T it = beg; it != end; ++it) {
if (it != beg)
o << ", ";
o << to_string(*it);
}
return o.str();
}
template <typename T>
std::string to_string(const std::vector<T>& t) {
std::ostringstream o;
o << "[" << to_string(t.begin(), t.end()) << "]";
return o.str();
}
template <typename K, typename V>
std::string to_string(const std::map<K, V>& m) {
std::ostringstream o;
o << "{" << to_string(m.begin(), m.end()) << "}";
return o.str();
}
template <typename T>
std::string to_string(const std::set<T>& s) {
std::ostringstream o;
o << "{" << to_string(s.begin(), s.end()) << "}";
return o.str();
}
}
} // apache::thrift
#endif // _THRIFT_TOSTRING_H_

View file

@ -0,0 +1,136 @@
/*
* 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 _THRIFT_THRIFT_H_
#define _THRIFT_THRIFT_H_ 1
#include <thrift/transport/PlatformSocket.h>
#include <thrift/thrift-config.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <string>
#include <map>
#include <list>
#include <set>
#include <vector>
#include <exception>
#include <typeinfo>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <thrift/TLogging.h>
#include <thrift/TOutput.h>
#define THRIFT_UNUSED_VARIABLE(x) ((void)(x))
namespace apache {
namespace thrift {
class TEnumIterator
: public std::iterator<std::forward_iterator_tag, std::pair<int, const char*> > {
public:
TEnumIterator(int n, int* enums, const char** names)
: ii_(0), n_(n), enums_(enums), names_(names) {}
int operator++() { return ++ii_; }
bool operator!=(const TEnumIterator& end) {
THRIFT_UNUSED_VARIABLE(end);
assert(end.n_ == -1);
return (ii_ != n_);
}
std::pair<int, const char*> operator*() const { return std::make_pair(enums_[ii_], names_[ii_]); }
private:
int ii_;
const int n_;
int* enums_;
const char** names_;
};
class TException : public std::exception {
public:
TException() : message_() {}
TException(const std::string& message) : message_(message) {}
virtual ~TException() throw() {}
virtual const char* what() const throw() {
if (message_.empty()) {
return "Default TException.";
} else {
return message_.c_str();
}
}
protected:
std::string message_;
};
class TDelayedException {
public:
template <class E>
static TDelayedException* delayException(const E& e);
virtual void throw_it() = 0;
virtual ~TDelayedException(){};
};
template <class E>
class TExceptionWrapper : public TDelayedException {
public:
TExceptionWrapper(const E& e) : e_(e) {}
virtual void throw_it() {
E temp(e_);
delete this;
throw temp;
}
private:
E e_;
};
template <class E>
TDelayedException* TDelayedException::delayException(const E& e) {
return new TExceptionWrapper<E>(e);
}
#if T_GLOBAL_DEBUG_VIRTUAL > 1
void profile_virtual_call(const std::type_info& info);
void profile_generic_protocol(const std::type_info& template_type, const std::type_info& prot_type);
void profile_print_info(FILE* f);
void profile_print_info();
void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f);
#endif
}
} // apache::thrift
#endif // #ifndef _THRIFT_THRIFT_H_

View file

@ -0,0 +1,425 @@
/*
* 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 <thrift/Thrift.h>
// Do nothing if virtual call profiling is not enabled
#if T_GLOBAL_DEBUG_VIRTUAL > 1
// TODO: This code only works with g++ (since we rely on the fact
// that all std::type_info instances referring to a particular type
// always return the exact same pointer value from name().)
#ifndef __GNUG__
#error "Thrift virtual function profiling currently only works with gcc"
#endif // !__GNUG__
// TODO: We also require glibc for the backtrace() and backtrace_symbols()
// functions.
#ifndef __GLIBC__
#error "Thrift virtual function profiling currently requires glibc"
#endif // !__GLIBC__
#include <thrift/concurrency/Mutex.h>
#include <ext/hash_map>
#include <execinfo.h>
#include <stdio.h>
namespace apache {
namespace thrift {
using ::apache::thrift::concurrency::Mutex;
using ::apache::thrift::concurrency::Guard;
static const unsigned int MAX_STACK_DEPTH = 15;
/**
* A stack trace
*/
class Backtrace {
public:
Backtrace(int skip = 0);
Backtrace(Backtrace const& bt);
void operator=(Backtrace const& bt) {
numCallers_ = bt.numCallers_;
if (numCallers_ >= 0) {
memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
}
}
bool operator==(Backtrace const& bt) const { return (cmp(bt) == 0); }
size_t hash() const {
intptr_t ret = 0;
for (int n = 0; n < numCallers_; ++n) {
ret ^= reinterpret_cast<intptr_t>(callers_[n]);
}
return static_cast<size_t>(ret);
}
int cmp(Backtrace const& bt) const {
int depth_diff = (numCallers_ - bt.numCallers_);
if (depth_diff != 0) {
return depth_diff;
}
for (int n = 0; n < numCallers_; ++n) {
int diff = reinterpret_cast<intptr_t>(callers_[n])
- reinterpret_cast<intptr_t>(bt.callers_[n]);
if (diff != 0) {
return diff;
}
}
return 0;
}
void print(FILE* f, int indent = 0, int start = 0) const {
char** strings = backtrace_symbols(callers_, numCallers_);
if (strings) {
start += skip_;
if (start < 0) {
start = 0;
}
for (int n = start; n < numCallers_; ++n) {
fprintf(f, "%*s#%-2d %s\n", indent, "", n, strings[n]);
}
free(strings);
} else {
fprintf(f, "%*s<failed to determine symbols>\n", indent, "");
}
}
int getDepth() const { return numCallers_ - skip_; }
void* getFrame(int index) const {
int adjusted_index = index + skip_;
if (adjusted_index < 0 || adjusted_index >= numCallers_) {
return NULL;
}
return callers_[adjusted_index];
}
private:
void* callers_[MAX_STACK_DEPTH];
int numCallers_;
int skip_;
};
// Define the constructors non-inline, so they consistently add a single
// frame to the stack trace, regardless of whether optimization is enabled
Backtrace::Backtrace(int skip)
: skip_(skip + 1) // ignore the constructor itself
{
numCallers_ = backtrace(callers_, MAX_STACK_DEPTH);
if (skip_ > numCallers_) {
skip_ = numCallers_;
}
}
Backtrace::Backtrace(Backtrace const& bt) : numCallers_(bt.numCallers_), skip_(bt.skip_) {
if (numCallers_ >= 0) {
memcpy(callers_, bt.callers_, numCallers_ * sizeof(void*));
}
}
/**
* A backtrace, plus one or two type names
*/
class Key {
public:
class Hash {
public:
size_t operator()(Key const& k) const { return k.hash(); }
};
Key(const Backtrace* bt, const std::type_info& type_info)
: backtrace_(bt), typeName1_(type_info.name()), typeName2_(NULL) {}
Key(const Backtrace* bt, const std::type_info& type_info1, const std::type_info& type_info2)
: backtrace_(bt), typeName1_(type_info1.name()), typeName2_(type_info2.name()) {}
Key(const Key& k)
: backtrace_(k.backtrace_), typeName1_(k.typeName1_), typeName2_(k.typeName2_) {}
void operator=(const Key& k) {
backtrace_ = k.backtrace_;
typeName1_ = k.typeName1_;
typeName2_ = k.typeName2_;
}
const Backtrace* getBacktrace() const { return backtrace_; }
const char* getTypeName() const { return typeName1_; }
const char* getTypeName2() const { return typeName2_; }
void makePersistent() {
// Copy the Backtrace object
backtrace_ = new Backtrace(*backtrace_);
// NOTE: We don't copy the type name.
// The GNU libstdc++ implementation of type_info::name() returns a value
// that will be valid for the lifetime of the program. (Although the C++
// standard doesn't guarantee this will be true on all implementations.)
}
/**
* Clean up memory allocated by makePersistent()
*
* Should only be invoked if makePersistent() has previously been called.
* The Key should no longer be used after cleanup() is called.
*/
void cleanup() {
delete backtrace_;
backtrace_ = NULL;
}
int cmp(const Key& k) const {
int ret = backtrace_->cmp(*k.backtrace_);
if (ret != 0) {
return ret;
}
// NOTE: We compare just the name pointers.
// With GNU libstdc++, every type_info object for the same type points to
// exactly the same name string. (Although this isn't guaranteed by the
// C++ standard.)
ret = k.typeName1_ - typeName1_;
if (ret != 0) {
return ret;
}
return k.typeName2_ - typeName2_;
}
bool operator==(const Key& k) const { return cmp(k) == 0; }
size_t hash() const {
// NOTE: As above, we just use the name pointer value.
// Works with GNU libstdc++, but not guaranteed to be correct on all
// implementations.
return backtrace_->hash() ^ reinterpret_cast<size_t>(typeName1_)
^ reinterpret_cast<size_t>(typeName2_);
}
private:
const Backtrace* backtrace_;
const char* typeName1_;
const char* typeName2_;
};
/**
* A functor that determines which of two BacktraceMap entries
* has a higher count.
*/
class CountGreater {
public:
bool operator()(std::pair<Key, size_t> bt1, std::pair<Key, size_t> bt2) const {
return bt1.second > bt2.second;
}
};
typedef __gnu_cxx::hash_map<Key, size_t, Key::Hash> BacktraceMap;
/**
* A map describing how many times T_VIRTUAL_CALL() has been invoked.
*/
BacktraceMap virtual_calls;
Mutex virtual_calls_mutex;
/**
* A map describing how many times T_GENERIC_PROTOCOL() has been invoked.
*/
BacktraceMap generic_calls;
Mutex generic_calls_mutex;
void _record_backtrace(BacktraceMap* map, const Mutex& mutex, Key* k) {
Guard guard(mutex);
BacktraceMap::iterator it = map->find(*k);
if (it == map->end()) {
k->makePersistent();
map->insert(std::make_pair(*k, 1));
} else {
// increment the count
// NOTE: we could assert if it->second is 0 afterwards, since that would
// mean we've wrapped.
++(it->second);
}
}
/**
* Record an unnecessary virtual function call.
*
* This method is invoked by the T_VIRTUAL_CALL() macro.
*/
void profile_virtual_call(const std::type_info& type) {
int const skip = 1; // ignore this frame
Backtrace bt(skip);
Key k(&bt, type);
_record_backtrace(&virtual_calls, virtual_calls_mutex, &k);
}
/**
* Record a call to a template processor with a protocol that is not the one
* specified in the template parameter.
*
* This method is invoked by the T_GENERIC_PROTOCOL() macro.
*/
void profile_generic_protocol(const std::type_info& template_type,
const std::type_info& prot_type) {
int const skip = 1; // ignore this frame
Backtrace bt(skip);
Key k(&bt, template_type, prot_type);
_record_backtrace(&generic_calls, generic_calls_mutex, &k);
}
/**
* Print the recorded profiling information to the specified file.
*/
void profile_print_info(FILE* f) {
typedef std::vector<std::pair<Key, size_t> > BacktraceVector;
CountGreater is_greater;
// Grab both locks for the duration of the print operation,
// to ensure the output is a consistent snapshot of a single point in time
Guard generic_calls_guard(generic_calls_mutex);
Guard virtual_calls_guard(virtual_calls_mutex);
// print the info from generic_calls, sorted by frequency
//
// We print the generic_calls info ahead of virtual_calls, since it is more
// useful in some cases. All T_GENERIC_PROTOCOL calls can be eliminated
// from most programs. Not all T_VIRTUAL_CALLs will be eliminated by
// converting to templates.
BacktraceVector gp_sorted(generic_calls.begin(), generic_calls.end());
std::sort(gp_sorted.begin(), gp_sorted.end(), is_greater);
for (BacktraceVector::const_iterator it = gp_sorted.begin(); it != gp_sorted.end(); ++it) {
Key const& key = it->first;
size_t const count = it->second;
fprintf(f,
"T_GENERIC_PROTOCOL: %zu calls to %s with a %s:\n",
count,
key.getTypeName(),
key.getTypeName2());
key.getBacktrace()->print(f, 2);
fprintf(f, "\n");
}
// print the info from virtual_calls, sorted by frequency
BacktraceVector vc_sorted(virtual_calls.begin(), virtual_calls.end());
std::sort(vc_sorted.begin(), vc_sorted.end(), is_greater);
for (BacktraceVector::const_iterator it = vc_sorted.begin(); it != vc_sorted.end(); ++it) {
Key const& key = it->first;
size_t const count = it->second;
fprintf(f, "T_VIRTUAL_CALL: %zu calls on %s:\n", count, key.getTypeName());
key.getBacktrace()->print(f, 2);
fprintf(f, "\n");
}
}
/**
* Print the recorded profiling information to stdout.
*/
void profile_print_info() {
profile_print_info(stdout);
}
/**
* Write a BacktraceMap as Google CPU profiler binary data.
*/
static void profile_write_pprof_file(FILE* f, BacktraceMap const& map) {
// Write the header
uintptr_t header[5] = {0, 3, 0, 0, 0};
fwrite(&header, sizeof(header), 1, f);
// Write the profile records
for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) {
uintptr_t count = it->second;
fwrite(&count, sizeof(count), 1, f);
Backtrace const* bt = it->first.getBacktrace();
uintptr_t num_pcs = bt->getDepth();
fwrite(&num_pcs, sizeof(num_pcs), 1, f);
for (uintptr_t n = 0; n < num_pcs; ++n) {
void* pc = bt->getFrame(n);
fwrite(&pc, sizeof(pc), 1, f);
}
}
// Write the trailer
uintptr_t trailer[3] = {0, 1, 0};
fwrite(&trailer, sizeof(trailer), 1, f);
// Write /proc/self/maps
// TODO(simpkins): This only works on linux
FILE* proc_maps = fopen("/proc/self/maps", "r");
if (proc_maps) {
uint8_t buf[4096];
while (true) {
size_t bytes_read = fread(buf, 1, sizeof(buf), proc_maps);
if (bytes_read == 0) {
break;
}
fwrite(buf, 1, bytes_read, f);
}
fclose(proc_maps);
}
}
/**
* Write the recorded profiling information as pprof files.
*
* This writes the information using the Google CPU profiler binary data
* format, so it can be analyzed with pprof. Note that information about the
* protocol/transport data types cannot be stored in this file format.
*
* See http://code.google.com/p/google-perftools/ for more details.
*
* @param gen_calls_f The information about calls to
* profile_generic_protocol() will be written to this
* file.
* @param virtual_calls_f The information about calls to
* profile_virtual_call() will be written to this file.
*/
void profile_write_pprof(FILE* gen_calls_f, FILE* virtual_calls_f) {
typedef std::vector<std::pair<Key, size_t> > BacktraceVector;
CountGreater is_greater;
// Grab both locks for the duration of the print operation,
// to ensure the output is a consistent snapshot of a single point in time
Guard generic_calls_guard(generic_calls_mutex);
Guard virtual_calls_guard(virtual_calls_mutex);
// write the info from generic_calls
profile_write_pprof_file(gen_calls_f, generic_calls);
// write the info from virtual_calls
profile_write_pprof_file(virtual_calls_f, virtual_calls);
}
}
} // apache::thrift
#endif // T_GLOBAL_PROFILE_VIRTUAL > 0

View file

@ -0,0 +1,48 @@
/*
* 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 _THRIFT_TASYNC_BUFFER_PROCESSOR_H_
#define _THRIFT_TASYNC_BUFFER_PROCESSOR_H_ 1
#include <thrift/cxxfunctional.h>
#include <boost/shared_ptr.hpp>
#include <thrift/transport/TBufferTransports.h>
namespace apache {
namespace thrift {
namespace async {
class TAsyncBufferProcessor {
public:
// Process data in "in", putting the result in "out".
// Call _return(true) when done, or _return(false) to
// forcefully close the connection (if applicable).
// "in" and "out" should be TMemoryBuffer or similar,
// not a wrapper around a socket.
virtual void process(apache::thrift::stdcxx::function<void(bool healthy)> _return,
boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf) = 0;
virtual ~TAsyncBufferProcessor() {}
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_TASYNC_BUFFER_PROCESSOR_H_

View file

@ -0,0 +1,37 @@
/*
* 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 <thrift/async/TAsyncChannel.h>
#include <thrift/cxxfunctional.h>
namespace apache {
namespace thrift {
namespace async {
void TAsyncChannel::sendAndRecvMessage(const VoidCallback& cob,
TMemoryBuffer* sendBuf,
TMemoryBuffer* recvBuf) {
apache::thrift::stdcxx::function<void()> send_done
= apache::thrift::stdcxx::bind(&TAsyncChannel::recvMessage, this, cob, recvBuf);
sendMessage(send_done, sendBuf);
}
}
}
} // apache::thrift::async

View file

@ -0,0 +1,73 @@
/*
* 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 _THRIFT_ASYNC_TASYNCCHANNEL_H_
#define _THRIFT_ASYNC_TASYNCCHANNEL_H_ 1
#include <thrift/cxxfunctional.h>
#include <thrift/Thrift.h>
namespace apache {
namespace thrift {
namespace transport {
class TMemoryBuffer;
}
}
}
namespace apache {
namespace thrift {
namespace async {
using apache::thrift::transport::TMemoryBuffer;
class TAsyncChannel {
public:
typedef apache::thrift::stdcxx::function<void()> VoidCallback;
virtual ~TAsyncChannel() {}
// is the channel in a good state?
virtual bool good() const = 0;
virtual bool error() const = 0;
virtual bool timedOut() const = 0;
/**
* Send a message over the channel.
*/
virtual void sendMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message) = 0;
/**
* Receive a message from the channel.
*/
virtual void recvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message) = 0;
/**
* Send a message over the channel and receive a response.
*/
virtual void sendAndRecvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* sendBuf,
apache::thrift::transport::TMemoryBuffer* recvBuf);
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_ASYNC_TASYNCCHANNEL_H_

View file

@ -0,0 +1,151 @@
/*
* 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 _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_
#define _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_ 1
#include <thrift/async/TAsyncProcessor.h>
namespace apache {
namespace thrift {
namespace async {
/**
* TAsyncDispatchProcessor is a helper class to parse the message header then
* call another function to dispatch based on the function name.
*
* Subclasses must implement dispatchCall() to dispatch on the function name.
*/
template <class Protocol_>
class TAsyncDispatchProcessorT : public TAsyncProcessor {
public:
virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out) {
protocol::TProtocol* inRaw = in.get();
protocol::TProtocol* outRaw = out.get();
// Try to dynamic cast to the template protocol type
Protocol_* specificIn = dynamic_cast<Protocol_*>(inRaw);
Protocol_* specificOut = dynamic_cast<Protocol_*>(outRaw);
if (specificIn && specificOut) {
return processFast(_return, specificIn, specificOut);
}
// Log the fact that we have to use the slow path
T_GENERIC_PROTOCOL(this, inRaw, specificIn);
T_GENERIC_PROTOCOL(this, outRaw, specificOut);
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
inRaw->readMessageBegin(fname, mtype, seqid);
// If this doesn't look like a valid call, log an error and return false so
// that the server will close the connection.
//
// (The old generated processor code used to try to skip a T_STRUCT and
// continue. However, that seems unsafe.)
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
_return(false);
return;
}
return this->dispatchCall(_return, inRaw, outRaw, fname, seqid);
}
void processFast(apache::thrift::stdcxx::function<void(bool success)> _return,
Protocol_* in,
Protocol_* out) {
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
in->readMessageBegin(fname, mtype, seqid);
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
_return(false);
return;
}
return this->dispatchCallTemplated(_return, in, out, fname, seqid);
}
virtual void dispatchCall(apache::thrift::stdcxx::function<void(bool ok)> _return,
apache::thrift::protocol::TProtocol* in,
apache::thrift::protocol::TProtocol* out,
const std::string& fname,
int32_t seqid) = 0;
virtual void dispatchCallTemplated(apache::thrift::stdcxx::function<void(bool ok)> _return,
Protocol_* in,
Protocol_* out,
const std::string& fname,
int32_t seqid) = 0;
};
/**
* Non-templatized version of TAsyncDispatchProcessor,
* that doesn't bother trying to perform a dynamic_cast.
*/
class TAsyncDispatchProcessor : public TAsyncProcessor {
public:
virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out) {
protocol::TProtocol* inRaw = in.get();
protocol::TProtocol* outRaw = out.get();
std::string fname;
protocol::TMessageType mtype;
int32_t seqid;
inRaw->readMessageBegin(fname, mtype, seqid);
// If this doesn't look like a valid call, log an error and return false so
// that the server will close the connection.
//
// (The old generated processor code used to try to skip a T_STRUCT and
// continue. However, that seems unsafe.)
if (mtype != protocol::T_CALL && mtype != protocol::T_ONEWAY) {
GlobalOutput.printf("received invalid message type %d from client", mtype);
_return(false);
return;
}
return dispatchCall(_return, inRaw, outRaw, fname, seqid);
}
virtual void dispatchCall(apache::thrift::stdcxx::function<void(bool ok)> _return,
apache::thrift::protocol::TProtocol* in,
apache::thrift::protocol::TProtocol* out,
const std::string& fname,
int32_t seqid) = 0;
};
// Specialize TAsyncDispatchProcessorT for TProtocol and TDummyProtocol just to
// use the generic TDispatchProcessor.
template <>
class TAsyncDispatchProcessorT<protocol::TDummyProtocol> : public TAsyncDispatchProcessor {};
template <>
class TAsyncDispatchProcessorT<protocol::TProtocol> : public TAsyncDispatchProcessor {};
}
}
} // apache::thrift::async
#endif // _THRIFT_ASYNC_TASYNCDISPATCHPROCESSOR_H_

View file

@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _THRIFT_TASYNCPROCESSOR_H_
#define _THRIFT_TASYNCPROCESSOR_H_ 1
#include <thrift/cxxfunctional.h>
#include <boost/shared_ptr.hpp>
#include <thrift/protocol/TProtocol.h>
#include <thrift/TProcessor.h>
namespace apache {
namespace thrift {
namespace async {
/**
* Async version of a TProcessor. It is not expected to complete by the time
* the call to process returns. Instead, it calls a cob to signal completion.
*/
class TAsyncProcessor {
public:
virtual ~TAsyncProcessor() {}
virtual void process(apache::thrift::stdcxx::function<void(bool success)> _return,
boost::shared_ptr<protocol::TProtocol> in,
boost::shared_ptr<protocol::TProtocol> out) = 0;
void process(apache::thrift::stdcxx::function<void(bool success)> _return,
boost::shared_ptr<apache::thrift::protocol::TProtocol> io) {
return process(_return, io, io);
}
boost::shared_ptr<TProcessorEventHandler> getEventHandler() const { return eventHandler_; }
void setEventHandler(boost::shared_ptr<TProcessorEventHandler> eventHandler) {
eventHandler_ = eventHandler;
}
protected:
TAsyncProcessor() {}
boost::shared_ptr<TProcessorEventHandler> eventHandler_;
};
class TAsyncProcessorFactory {
public:
virtual ~TAsyncProcessorFactory() {}
/**
* Get the TAsyncProcessor to use for a particular connection.
*
* This method is always invoked in the same thread that the connection was
* accepted on. This generally means that this call does not need to be
* thread safe, as it will always be invoked from a single thread.
*/
virtual boost::shared_ptr<TAsyncProcessor> getProcessor(const TConnectionInfo& connInfo) = 0;
};
}
}
} // apache::thrift::async
// XXX I'm lazy for now
namespace apache {
namespace thrift {
using apache::thrift::async::TAsyncProcessor;
}
}
#endif // #ifndef _THRIFT_TASYNCPROCESSOR_H_

View file

@ -0,0 +1,53 @@
/*
* 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 <thrift/async/TAsyncProtocolProcessor.h>
using apache::thrift::transport::TBufferBase;
using apache::thrift::protocol::TProtocol;
namespace apache {
namespace thrift {
namespace async {
void TAsyncProtocolProcessor::process(apache::thrift::stdcxx::function<void(bool healthy)> _return,
boost::shared_ptr<TBufferBase> ibuf,
boost::shared_ptr<TBufferBase> obuf) {
boost::shared_ptr<TProtocol> iprot(pfact_->getProtocol(ibuf));
boost::shared_ptr<TProtocol> oprot(pfact_->getProtocol(obuf));
return underlying_
->process(apache::thrift::stdcxx::bind(&TAsyncProtocolProcessor::finish,
_return,
oprot,
apache::thrift::stdcxx::placeholders::_1),
iprot,
oprot);
}
/* static */ void TAsyncProtocolProcessor::finish(
apache::thrift::stdcxx::function<void(bool healthy)> _return,
boost::shared_ptr<TProtocol> oprot,
bool healthy) {
(void)oprot;
// This is a stub function to hold a reference to oprot.
return _return(healthy);
}
}
}
} // apache::thrift::async

View file

@ -0,0 +1,55 @@
/*
* 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 _THRIFT_TNAME_ME_H_
#define _THRIFT_TNAME_ME_H_ 1
#include <thrift/async/TAsyncProcessor.h>
#include <thrift/async/TAsyncBufferProcessor.h>
#include <thrift/protocol/TProtocol.h>
namespace apache {
namespace thrift {
namespace async {
class TAsyncProtocolProcessor : public TAsyncBufferProcessor {
public:
TAsyncProtocolProcessor(boost::shared_ptr<TAsyncProcessor> underlying,
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact)
: underlying_(underlying), pfact_(pfact) {}
virtual void process(apache::thrift::stdcxx::function<void(bool healthy)> _return,
boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,
boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf);
virtual ~TAsyncProtocolProcessor() {}
private:
static void finish(apache::thrift::stdcxx::function<void(bool healthy)> _return,
boost::shared_ptr<apache::thrift::protocol::TProtocol> oprot,
bool healthy);
boost::shared_ptr<TAsyncProcessor> underlying_;
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_TNAME_ME_H_

View file

@ -0,0 +1,242 @@
/*
* 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 <thrift/async/TConcurrentClientSyncInfo.h>
#include <thrift/TApplicationException.h>
#include <thrift/transport/TTransportException.h>
#include <limits>
namespace apache { namespace thrift { namespace async {
using namespace ::apache::thrift::concurrency;
TConcurrentClientSyncInfo::TConcurrentClientSyncInfo() :
stop_(false),
seqidMutex_(),
// test rollover all the time
nextseqid_((std::numeric_limits<int32_t>::max)()-10),
seqidToMonitorMap_(),
freeMonitors_(),
writeMutex_(),
readMutex_(),
recvPending_(false),
wakeupSomeone_(false),
seqidPending_(0),
fnamePending_(),
mtypePending_(::apache::thrift::protocol::T_CALL)
{
freeMonitors_.reserve(MONITOR_CACHE_SIZE);
}
bool TConcurrentClientSyncInfo::getPending(
std::string &fname,
::apache::thrift::protocol::TMessageType &mtype,
int32_t &rseqid)
{
if(stop_)
throwDeadConnection_();
wakeupSomeone_ = false;
if(recvPending_)
{
recvPending_ = false;
rseqid = seqidPending_;
fname = fnamePending_;
mtype = mtypePending_;
return true;
}
return false;
}
void TConcurrentClientSyncInfo::updatePending(
const std::string &fname,
::apache::thrift::protocol::TMessageType mtype,
int32_t rseqid)
{
recvPending_ = true;
seqidPending_ = rseqid;
fnamePending_ = fname;
mtypePending_ = mtype;
MonitorPtr monitor;
{
Guard seqidGuard(seqidMutex_);
MonitorMap::iterator i = seqidToMonitorMap_.find(rseqid);
if(i == seqidToMonitorMap_.end())
throwBadSeqId_();
monitor = i->second;
}
monitor->notify();
}
void TConcurrentClientSyncInfo::waitForWork(int32_t seqid)
{
MonitorPtr m;
{
Guard seqidGuard(seqidMutex_);
m = seqidToMonitorMap_[seqid];
}
while(true)
{
// be very careful about setting state in this loop that affects waking up. You may exit
// this function, attempt to grab some work, and someone else could have beaten you (or not
// left) the read mutex, and that will put you right back in this loop, with the mangled
// state you left behind.
if(stop_)
throwDeadConnection_();
if(wakeupSomeone_)
return;
if(recvPending_ && seqidPending_ == seqid)
return;
m->waitForever();
}
}
void TConcurrentClientSyncInfo::throwBadSeqId_()
{
throw apache::thrift::TApplicationException(
TApplicationException::BAD_SEQUENCE_ID,
"server sent a bad seqid");
}
void TConcurrentClientSyncInfo::throwDeadConnection_()
{
throw apache::thrift::transport::TTransportException(
apache::thrift::transport::TTransportException::NOT_OPEN,
"this client died on another thread, and is now in an unusable state");
}
void TConcurrentClientSyncInfo::wakeupAnyone_(const Guard &)
{
wakeupSomeone_ = true;
if(!seqidToMonitorMap_.empty())
{
// The monitor map maps integers to monitors. Larger integers are more recent
// messages. Since this is ordered, it means that the last element is the most recent.
// We are trying to guess which thread will have its message complete next, so we are picking
// the most recent. The oldest message is likely to be some polling, long lived message.
// If we guess right, the thread we wake up will handle the message that comes in.
// If we guess wrong, the thread we wake up will hand off the work to the correct thread,
// costing us an extra context switch.
seqidToMonitorMap_.rbegin()->second->notify();
}
}
void TConcurrentClientSyncInfo::markBad_(const Guard &)
{
wakeupSomeone_ = true;
stop_ = true;
for(MonitorMap::iterator i = seqidToMonitorMap_.begin(); i != seqidToMonitorMap_.end(); ++i)
i->second->notify();
}
TConcurrentClientSyncInfo::MonitorPtr
TConcurrentClientSyncInfo::newMonitor_(const Guard &)
{
if(freeMonitors_.empty())
return MonitorPtr(new Monitor(&readMutex_));
MonitorPtr retval;
//swapping to avoid an atomic operation
retval.swap(freeMonitors_.back());
freeMonitors_.pop_back();
return retval;
}
void TConcurrentClientSyncInfo::deleteMonitor_(
const Guard &,
TConcurrentClientSyncInfo::MonitorPtr &m) /*noexcept*/
{
if(freeMonitors_.size() > MONITOR_CACHE_SIZE)
{
m.reset();
return;
}
//freeMonitors_ was reserved up to MONITOR_CACHE_SIZE in the ctor,
//so this shouldn't throw
freeMonitors_.push_back(TConcurrentClientSyncInfo::MonitorPtr());
//swapping to avoid an atomic operation
m.swap(freeMonitors_.back());
}
int32_t TConcurrentClientSyncInfo::generateSeqId()
{
Guard seqidGuard(seqidMutex_);
if(stop_)
throwDeadConnection_();
if(!seqidToMonitorMap_.empty())
if(nextseqid_ == seqidToMonitorMap_.begin()->first)
throw apache::thrift::TApplicationException(
TApplicationException::BAD_SEQUENCE_ID,
"about to repeat a seqid");
int32_t newSeqId = nextseqid_++;
seqidToMonitorMap_[newSeqId] = newMonitor_(seqidGuard);
return newSeqId;
}
TConcurrentRecvSentry::TConcurrentRecvSentry(TConcurrentClientSyncInfo *sync, int32_t seqid) :
sync_(*sync),
seqid_(seqid),
committed_(false)
{
sync_.getReadMutex().lock();
}
TConcurrentRecvSentry::~TConcurrentRecvSentry()
{
{
Guard seqidGuard(sync_.seqidMutex_);
sync_.deleteMonitor_(seqidGuard, sync_.seqidToMonitorMap_[seqid_]);
sync_.seqidToMonitorMap_.erase(seqid_);
if(committed_)
sync_.wakeupAnyone_(seqidGuard);
else
sync_.markBad_(seqidGuard);
}
sync_.getReadMutex().unlock();
}
void TConcurrentRecvSentry::commit()
{
committed_ = true;
}
TConcurrentSendSentry::TConcurrentSendSentry(TConcurrentClientSyncInfo *sync) :
sync_(*sync),
committed_(false)
{
sync_.getWriteMutex().lock();
}
TConcurrentSendSentry::~TConcurrentSendSentry()
{
if(!committed_)
{
Guard seqidGuard(sync_.seqidMutex_);
sync_.markBad_(seqidGuard);
}
sync_.getWriteMutex().unlock();
}
void TConcurrentSendSentry::commit()
{
committed_ = true;
}
}}} // apache::thrift::async

View file

@ -0,0 +1,126 @@
/*
* 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 _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_
#define _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_ 1
#include <thrift/protocol/TProtocol.h>
#include <thrift/concurrency/Mutex.h>
#include <thrift/concurrency/Monitor.h>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
#include <map>
namespace apache {
namespace thrift {
namespace async {
class TConcurrentClientSyncInfo;
class TConcurrentSendSentry {
public:
explicit TConcurrentSendSentry(TConcurrentClientSyncInfo* sync);
~TConcurrentSendSentry();
void commit();
private:
TConcurrentClientSyncInfo& sync_;
bool committed_;
};
class TConcurrentRecvSentry {
public:
TConcurrentRecvSentry(TConcurrentClientSyncInfo* sync, int32_t seqid);
~TConcurrentRecvSentry();
void commit();
private:
TConcurrentClientSyncInfo& sync_;
int32_t seqid_;
bool committed_;
};
class TConcurrentClientSyncInfo {
private: // typedefs
typedef boost::shared_ptr< ::apache::thrift::concurrency::Monitor> MonitorPtr;
typedef std::map<int32_t, MonitorPtr> MonitorMap;
public:
TConcurrentClientSyncInfo();
int32_t generateSeqId();
bool getPending(std::string& fname,
::apache::thrift::protocol::TMessageType& mtype,
int32_t& rseqid); /* requires readMutex_ */
void updatePending(const std::string& fname,
::apache::thrift::protocol::TMessageType mtype,
int32_t rseqid); /* requires readMutex_ */
void waitForWork(int32_t seqid); /* requires readMutex_ */
::apache::thrift::concurrency::Mutex& getReadMutex() { return readMutex_; }
::apache::thrift::concurrency::Mutex& getWriteMutex() { return writeMutex_; }
private: // constants
enum { MONITOR_CACHE_SIZE = 10 };
private: // functions
MonitorPtr newMonitor_(
const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */
void deleteMonitor_(const ::apache::thrift::concurrency::Guard& seqidGuard, MonitorPtr& m);
/*noexcept*/ /* requires seqidMutex_ */
void wakeupAnyone_(
const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */
void markBad_(const ::apache::thrift::concurrency::Guard& seqidGuard); /* requires seqidMutex_ */
void throwBadSeqId_();
void throwDeadConnection_();
private: // data members
volatile bool stop_;
::apache::thrift::concurrency::Mutex seqidMutex_;
// begin seqidMutex_ protected members
int32_t nextseqid_;
MonitorMap seqidToMonitorMap_;
std::vector<MonitorPtr> freeMonitors_;
// end seqidMutex_ protected members
::apache::thrift::concurrency::Mutex writeMutex_;
::apache::thrift::concurrency::Mutex readMutex_;
// begin readMutex_ protected members
bool recvPending_;
bool wakeupSomeone_;
int32_t seqidPending_;
std::string fnamePending_;
::apache::thrift::protocol::TMessageType mtypePending_;
// end readMutex_ protected members
friend class TConcurrentSendSentry;
friend class TConcurrentRecvSentry;
};
}
}
} // apache::thrift::async
#endif // _THRIFT_TCONCURRENTCLIENTSYNCINFO_H_

View file

@ -0,0 +1,155 @@
/*
* 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 <thrift/async/TEvhttpClientChannel.h>
#include <evhttp.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/protocol/TProtocolException.h>
#include <iostream>
#include <sstream>
using namespace apache::thrift::protocol;
using apache::thrift::transport::TTransportException;
namespace apache {
namespace thrift {
namespace async {
TEvhttpClientChannel::TEvhttpClientChannel(const std::string& host,
const std::string& path,
const char* address,
int port,
struct event_base* eb)
: host_(host), path_(path), conn_(NULL) {
conn_ = evhttp_connection_new(address, port);
if (conn_ == NULL) {
throw TException("evhttp_connection_new failed");
}
evhttp_connection_set_base(conn_, eb);
}
TEvhttpClientChannel::~TEvhttpClientChannel() {
if (conn_ != NULL) {
evhttp_connection_free(conn_);
}
}
void TEvhttpClientChannel::sendAndRecvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* sendBuf,
apache::thrift::transport::TMemoryBuffer* recvBuf) {
struct evhttp_request* req = evhttp_request_new(response, this);
if (req == NULL) {
throw TException("evhttp_request_new failed");
}
int rv;
rv = evhttp_add_header(req->output_headers, "Host", host_.c_str());
if (rv != 0) {
throw TException("evhttp_add_header failed");
}
rv = evhttp_add_header(req->output_headers, "Content-Type", "application/x-thrift");
if (rv != 0) {
throw TException("evhttp_add_header failed");
}
uint8_t* obuf;
uint32_t sz;
sendBuf->getBuffer(&obuf, &sz);
rv = evbuffer_add(req->output_buffer, obuf, sz);
if (rv != 0) {
throw TException("evbuffer_add failed");
}
rv = evhttp_make_request(conn_, req, EVHTTP_REQ_POST, path_.c_str());
if (rv != 0) {
throw TException("evhttp_make_request failed");
}
completionQueue_.push(Completion(cob, recvBuf));
}
void TEvhttpClientChannel::sendMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message) {
(void)cob;
(void)message;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"Unexpected call to TEvhttpClientChannel::sendMessage");
}
void TEvhttpClientChannel::recvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message) {
(void)cob;
(void)message;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"Unexpected call to TEvhttpClientChannel::recvMessage");
}
void TEvhttpClientChannel::finish(struct evhttp_request* req) {
assert(!completionQueue_.empty());
Completion completion = completionQueue_.front();
completionQueue_.pop();
if (req == NULL) {
try {
completion.first();
} catch (const TTransportException& e) {
if (e.getType() == TTransportException::END_OF_FILE)
throw TException("connect failed");
else
throw;
}
return;
} else if (req->response_code != 200) {
try {
completion.first();
} catch (const TTransportException& e) {
std::stringstream ss;
ss << "server returned code " << req->response_code;
if (req->response_code_line)
ss << ": " << req->response_code_line;
if (e.getType() == TTransportException::END_OF_FILE)
throw TException(ss.str());
else
throw;
}
return;
}
completion.second->resetBuffer(EVBUFFER_DATA(req->input_buffer),
static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)));
completion.first();
return;
}
/* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) {
TEvhttpClientChannel* self = (TEvhttpClientChannel*)arg;
try {
self->finish(req);
} catch (std::exception& e) {
// don't propagate a C++ exception in C code (e.g. libevent)
std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what()
<< std::endl;
}
}
}
}
} // apache::thrift::async

View file

@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_
#define _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_ 1
#include <queue>
#include <string>
#include <utility>
#include <boost/shared_ptr.hpp>
#include <thrift/async/TAsyncChannel.h>
struct event_base;
struct evhttp_connection;
struct evhttp_request;
namespace apache {
namespace thrift {
namespace transport {
class TMemoryBuffer;
}
}
}
namespace apache {
namespace thrift {
namespace async {
class TEvhttpClientChannel : public TAsyncChannel {
public:
using TAsyncChannel::VoidCallback;
TEvhttpClientChannel(const std::string& host,
const std::string& path,
const char* address,
int port,
struct event_base* eb);
~TEvhttpClientChannel();
virtual void sendAndRecvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* sendBuf,
apache::thrift::transport::TMemoryBuffer* recvBuf);
virtual void sendMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message);
virtual void recvMessage(const VoidCallback& cob,
apache::thrift::transport::TMemoryBuffer* message);
void finish(struct evhttp_request* req);
// XXX
virtual bool good() const { return true; }
virtual bool error() const { return false; }
virtual bool timedOut() const { return false; }
private:
static void response(struct evhttp_request* req, void* arg);
std::string host_;
std::string path_;
typedef std::pair<VoidCallback, apache::thrift::transport::TMemoryBuffer*> Completion;
typedef std::queue<Completion> CompletionQueue;
CompletionQueue completionQueue_;
struct evhttp_connection* conn_;
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_TEVHTTP_CLIENT_CHANNEL_H_

View file

@ -0,0 +1,159 @@
/*
* 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 <thrift/async/TEvhttpServer.h>
#include <thrift/async/TAsyncBufferProcessor.h>
#include <thrift/transport/TBufferTransports.h>
#include <evhttp.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <iostream>
#ifndef HTTP_INTERNAL // libevent < 2
#define HTTP_INTERNAL 500
#endif
using apache::thrift::transport::TMemoryBuffer;
namespace apache {
namespace thrift {
namespace async {
struct TEvhttpServer::RequestContext {
struct evhttp_request* req;
boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> ibuf;
boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> obuf;
RequestContext(struct evhttp_request* req);
};
TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor)
: processor_(processor), eb_(NULL), eh_(NULL) {
}
TEvhttpServer::TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port)
: processor_(processor), eb_(NULL), eh_(NULL) {
// Create event_base and evhttp.
eb_ = event_base_new();
if (eb_ == NULL) {
throw TException("event_base_new failed");
}
eh_ = evhttp_new(eb_);
if (eh_ == NULL) {
event_base_free(eb_);
throw TException("evhttp_new failed");
}
// Bind to port.
int ret = evhttp_bind_socket(eh_, NULL, port);
if (ret < 0) {
evhttp_free(eh_);
event_base_free(eb_);
throw TException("evhttp_bind_socket failed");
}
// Register a handler. If you use the other constructor,
// you will want to do this yourself.
// Don't forget to unregister before destorying this TEvhttpServer.
evhttp_set_cb(eh_, "/", request, (void*)this);
}
TEvhttpServer::~TEvhttpServer() {
if (eh_ != NULL) {
evhttp_free(eh_);
}
if (eb_ != NULL) {
event_base_free(eb_);
}
}
int TEvhttpServer::serve() {
if (eb_ == NULL) {
throw TException("Unexpected call to TEvhttpServer::serve");
}
return event_base_dispatch(eb_);
}
TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req)
: req(req),
ibuf(new TMemoryBuffer(EVBUFFER_DATA(req->input_buffer),
static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)))),
obuf(new TMemoryBuffer()) {
}
void TEvhttpServer::request(struct evhttp_request* req, void* self) {
try {
static_cast<TEvhttpServer*>(self)->process(req);
} catch (std::exception& e) {
evhttp_send_reply(req, HTTP_INTERNAL, e.what(), 0);
}
}
void TEvhttpServer::process(struct evhttp_request* req) {
RequestContext* ctx = new RequestContext(req);
return processor_->process(apache::thrift::stdcxx::bind(&TEvhttpServer::complete,
this,
ctx,
apache::thrift::stdcxx::placeholders::_1),
ctx->ibuf,
ctx->obuf);
}
void TEvhttpServer::complete(RequestContext* ctx, bool success) {
(void)success;
std::auto_ptr<RequestContext> ptr(ctx);
int code = success ? 200 : 400;
const char* reason = success ? "OK" : "Bad Request";
int rv = evhttp_add_header(ctx->req->output_headers, "Content-Type", "application/x-thrift");
if (rv != 0) {
// TODO: Log an error.
std::cerr << "evhttp_add_header failed " << __FILE__ << ":" << __LINE__ << std::endl;
}
struct evbuffer* buf = evbuffer_new();
if (buf == NULL) {
// TODO: Log an error.
std::cerr << "evbuffer_new failed " << __FILE__ << ":" << __LINE__ << std::endl;
} else {
uint8_t* obuf;
uint32_t sz;
ctx->obuf->getBuffer(&obuf, &sz);
int ret = evbuffer_add(buf, obuf, sz);
if (ret != 0) {
// TODO: Log an error.
std::cerr << "evhttp_add failed with " << ret << " " << __FILE__ << ":" << __LINE__
<< std::endl;
}
}
evhttp_send_reply(ctx->req, code, reason, buf);
if (buf != NULL) {
evbuffer_free(buf);
}
}
struct event_base* TEvhttpServer::getEventBase() {
return eb_;
}
}
}
} // apache::thrift::async

View file

@ -0,0 +1,74 @@
/*
* 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 _THRIFT_TEVHTTP_SERVER_H_
#define _THRIFT_TEVHTTP_SERVER_H_ 1
#include <boost/shared_ptr.hpp>
struct event_base;
struct evhttp;
struct evhttp_request;
namespace apache {
namespace thrift {
namespace async {
class TAsyncBufferProcessor;
class TEvhttpServer {
public:
/**
* Create a TEvhttpServer for use with an external evhttp instance.
* Must be manually installed with evhttp_set_cb, using
* TEvhttpServer::request as the callback and the
* address of the server as the extra arg.
* Do not call "serve" on this server.
*/
TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor);
/**
* Create a TEvhttpServer with an embedded event_base and evhttp,
* listening on port and responding on the endpoint "/".
* Call "serve" on this server to serve forever.
*/
TEvhttpServer(boost::shared_ptr<TAsyncBufferProcessor> processor, int port);
~TEvhttpServer();
static void request(struct evhttp_request* req, void* self);
int serve();
struct event_base* getEventBase();
private:
struct RequestContext;
void process(struct evhttp_request* req);
void complete(RequestContext* ctx, bool success);
boost::shared_ptr<TAsyncBufferProcessor> processor_;
struct event_base* eb_;
struct evhttp* eh_;
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_TEVHTTP_SERVER_H_

View file

@ -0,0 +1,214 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <thrift/thrift-config.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Util.h>
#include <thrift/transport/PlatformSocket.h>
#include <assert.h>
#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Monitor implementation using the boost thread library
*
* @version $Id:$
*/
class Monitor::Impl : public boost::condition_variable_any {
public:
Impl() : ownedMutex_(new Mutex()), mutex_(NULL) { init(ownedMutex_.get()); }
Impl(Mutex* mutex) : mutex_(NULL) { init(mutex); }
Impl(Monitor* monitor) : mutex_(NULL) { init(&(monitor->mutex())); }
Mutex& mutex() { return *mutex_; }
void lock() { mutex().lock(); }
void unlock() { mutex().unlock(); }
/**
* Exception-throwing version of waitForTimeRelative(), called simply
* wait(int64) for historical reasons. Timeout is in milliseconds.
*
* If the condition occurs, this function returns cleanly; on timeout or
* error an exception is thrown.
*/
void wait(int64_t timeout_ms) {
int result = waitForTimeRelative(timeout_ms);
if (result == THRIFT_ETIMEDOUT) {
throw TimedOutException();
} else if (result != 0) {
throw TException("Monitor::wait() failed");
}
}
/**
* Waits until the specified timeout in milliseconds for the condition to
* occur, or waits forever if timeout_ms == 0.
*
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTimeRelative(int64_t timeout_ms) {
if (timeout_ms == 0LL) {
return waitForever();
}
assert(mutex_);
boost::timed_mutex* mutexImpl
= reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
int res
= timed_wait(lock, boost::get_system_time() + boost::posix_time::milliseconds(timeout_ms))
? 0
: THRIFT_ETIMEDOUT;
lock.release();
return res;
}
/**
* Waits until the absolute time specified using struct THRIFT_TIMESPEC.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const THRIFT_TIMESPEC* abstime) {
struct timeval temp;
temp.tv_sec = static_cast<long>(abstime->tv_sec);
temp.tv_usec = static_cast<long>(abstime->tv_nsec) / 1000;
return waitForTime(&temp);
}
/**
* Waits until the absolute time specified using struct timeval.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const struct timeval* abstime) {
assert(mutex_);
boost::timed_mutex* mutexImpl = static_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
struct timeval currenttime;
Util::toTimeval(currenttime, Util::currentTime());
long tv_sec = static_cast<long>(abstime->tv_sec - currenttime.tv_sec);
long tv_usec = static_cast<long>(abstime->tv_usec - currenttime.tv_usec);
if (tv_sec < 0)
tv_sec = 0;
if (tv_usec < 0)
tv_usec = 0;
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
int res = timed_wait(lock,
boost::get_system_time() + boost::posix_time::seconds(tv_sec)
+ boost::posix_time::microseconds(tv_usec))
? 0
: THRIFT_ETIMEDOUT;
lock.release();
return res;
}
/**
* Waits forever until the condition occurs.
* Returns 0 if condition occurs, or an error code otherwise.
*/
int waitForever() {
assert(mutex_);
boost::timed_mutex* mutexImpl
= reinterpret_cast<boost::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
boost::timed_mutex::scoped_lock lock(*mutexImpl, boost::adopt_lock);
((boost::condition_variable_any*)this)->wait(lock);
lock.release();
return 0;
}
void notify() { notify_one(); }
void notifyAll() { notify_all(); }
private:
void init(Mutex* mutex) { mutex_ = mutex; }
boost::scoped_ptr<Mutex> ownedMutex_;
Mutex* mutex_;
};
Monitor::Monitor() : impl_(new Monitor::Impl()) {
}
Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {
}
Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {
}
Monitor::~Monitor() {
delete impl_;
}
Mutex& Monitor::mutex() const {
return const_cast<Monitor::Impl*>(impl_)->mutex();
}
void Monitor::lock() const {
const_cast<Monitor::Impl*>(impl_)->lock();
}
void Monitor::unlock() const {
const_cast<Monitor::Impl*>(impl_)->unlock();
}
void Monitor::wait(int64_t timeout) const {
const_cast<Monitor::Impl*>(impl_)->wait(timeout);
}
int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
}
int Monitor::waitForTime(const timeval* abstime) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
}
int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTimeRelative(timeout_ms);
}
int Monitor::waitForever() const {
return const_cast<Monitor::Impl*>(impl_)->waitForever();
}
void Monitor::notify() const {
const_cast<Monitor::Impl*>(impl_)->notify();
}
void Monitor::notifyAll() const {
const_cast<Monitor::Impl*>(impl_)->notifyAll();
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,71 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/Mutex.h>
#include <thrift/concurrency/Util.h>
#include <thrift/Thrift.h>
#include <cassert>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Implementation of Mutex class using boost interprocess mutex
*
* @version $Id:$
*/
class Mutex::impl : public boost::timed_mutex {};
Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {
THRIFT_UNUSED_VARIABLE(init);
}
void* Mutex::getUnderlyingImpl() const {
return impl_.get();
}
void Mutex::lock() const {
impl_->lock();
}
bool Mutex::trylock() const {
return impl_->try_lock();
}
bool Mutex::timedlock(int64_t ms) const {
return impl_->timed_lock(boost::get_system_time() + boost::posix_time::milliseconds(ms));
}
void Mutex::unlock() const {
impl_->unlock();
}
void Mutex::DEFAULT_INITIALIZER(void* arg) {
THRIFT_UNUSED_VARIABLE(arg);
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,147 @@
/*
* 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 <thrift/thrift-config.h>
#if USE_BOOST_THREAD
#include <thrift/concurrency/BoostThreadFactory.h>
#include <thrift/concurrency/Exception.h>
#include <cassert>
#include <boost/weak_ptr.hpp>
#include <boost/thread.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
using boost::shared_ptr;
using boost::weak_ptr;
/**
* The boost thread class.
*
* @version $Id:$
*/
class BoostThread : public Thread {
public:
enum STATE { uninitialized, starting, started, stopping, stopped };
static void* threadMain(void* arg);
private:
std::auto_ptr<boost::thread> thread_;
STATE state_;
weak_ptr<BoostThread> self_;
bool detached_;
public:
BoostThread(bool detached, shared_ptr<Runnable> runnable)
: state_(uninitialized), detached_(detached) {
this->Thread::runnable(runnable);
}
~BoostThread() {
if (!detached_) {
try {
join();
} catch (...) {
// We're really hosed.
}
}
}
void start() {
if (state_ != uninitialized) {
return;
}
// Create reference
shared_ptr<BoostThread>* selfRef = new shared_ptr<BoostThread>();
*selfRef = self_.lock();
state_ = starting;
thread_
= std::auto_ptr<boost::thread>(new boost::thread(boost::bind(threadMain, (void*)selfRef)));
if (detached_)
thread_->detach();
}
void join() {
if (!detached_ && state_ != uninitialized) {
thread_->join();
}
}
Thread::id_t getId() { return thread_.get() ? thread_->get_id() : boost::thread::id(); }
shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
void weakRef(shared_ptr<BoostThread> self) {
assert(self.get() == this);
self_ = weak_ptr<BoostThread>(self);
}
};
void* BoostThread::threadMain(void* arg) {
shared_ptr<BoostThread> thread = *(shared_ptr<BoostThread>*)arg;
delete reinterpret_cast<shared_ptr<BoostThread>*>(arg);
if (!thread) {
return (void*)0;
}
if (thread->state_ != starting) {
return (void*)0;
}
thread->state_ = started;
thread->runnable()->run();
if (thread->state_ != stopping && thread->state_ != stopped) {
thread->state_ = stopping;
}
return (void*)0;
}
BoostThreadFactory::BoostThreadFactory(bool detached)
: ThreadFactory(detached) {
}
shared_ptr<Thread> BoostThreadFactory::newThread(shared_ptr<Runnable> runnable) const {
shared_ptr<BoostThread> result = shared_ptr<BoostThread>(new BoostThread(isDetached(), runnable));
result->weakRef(result);
runnable->thread(result);
return result;
}
Thread::id_t BoostThreadFactory::getCurrentThreadId() const {
return boost::this_thread::get_id();
}
}
}
} // apache::thrift::concurrency
#endif // USE_BOOST_THREAD

View file

@ -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.
*/
#ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_
#define _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_ 1
#include <thrift/concurrency/Thread.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* A thread factory to create posix threads
*
* @version $Id:$
*/
class BoostThreadFactory : public ThreadFactory {
public:
/**
* Boost thread factory. All threads created by a factory are reference-counted
* via boost::shared_ptr and boost::weak_ptr. The factory guarantees that threads and
* the Runnable tasks they host will be properly cleaned up once the last strong reference
* to both is given up.
*
* Threads are created with the specified boost policy, priority, stack-size. A detachable thread
* is not joinable.
*
* By default threads are not joinable.
*/
BoostThreadFactory(bool detached = true);
// From ThreadFactory;
boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
// From ThreadFactory;
Thread::id_t getCurrentThreadId() const;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_BOOSTTHREADFACTORY_H_

View file

@ -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.
*/
#ifndef _THRIFT_CONCURRENCY_EXCEPTION_H_
#define _THRIFT_CONCURRENCY_EXCEPTION_H_ 1
#include <exception>
#include <thrift/Thrift.h>
namespace apache {
namespace thrift {
namespace concurrency {
class NoSuchTaskException : public apache::thrift::TException {};
class UncancellableTaskException : public apache::thrift::TException {};
class InvalidArgumentException : public apache::thrift::TException {};
class IllegalStateException : public apache::thrift::TException {
public:
IllegalStateException() {}
IllegalStateException(const std::string& message) : TException(message) {}
};
class TimedOutException : public apache::thrift::TException {
public:
TimedOutException() : TException("TimedOutException"){};
TimedOutException(const std::string& message) : TException(message) {}
};
class TooManyPendingTasksException : public apache::thrift::TException {
public:
TooManyPendingTasksException() : TException("TooManyPendingTasksException"){};
TooManyPendingTasksException(const std::string& message) : TException(message) {}
};
class SystemResourceException : public apache::thrift::TException {
public:
SystemResourceException() {}
SystemResourceException(const std::string& message) : TException(message) {}
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_EXCEPTION_H_

View file

@ -0,0 +1,118 @@
/*
* 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 _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H
#define _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H 1
#include <thrift/cxxfunctional.h>
#include <thrift/concurrency/Thread.h>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Convenient implementation of Runnable that will execute arbitrary callbacks.
* Interfaces are provided to accept both a generic 'void(void)' callback, and
* a 'void* (void*)' pthread_create-style callback.
*
* Example use:
* void* my_thread_main(void* arg);
* shared_ptr<ThreadFactory> factory = ...;
* // To create a thread that executes my_thread_main once:
* shared_ptr<Thread> thread = factory->newThread(
* FunctionRunner::create(my_thread_main, some_argument));
* thread->start();
*
* bool A::foo();
* A* a = new A();
* // To create a thread that executes a.foo() every 100 milliseconds:
* factory->newThread(FunctionRunner::create(
* apache::thrift::stdcxx::bind(&A::foo, a), 100))->start();
*
*/
class FunctionRunner : public Runnable {
public:
// This is the type of callback 'pthread_create()' expects.
typedef void* (*PthreadFuncPtr)(void* arg);
// This a fully-generic void(void) callback for custom bindings.
typedef apache::thrift::stdcxx::function<void()> VoidFunc;
typedef apache::thrift::stdcxx::function<bool()> BoolFunc;
/**
* Syntactic sugar to make it easier to create new FunctionRunner
* objects wrapped in shared_ptr.
*/
static boost::shared_ptr<FunctionRunner> create(const VoidFunc& cob) {
return boost::shared_ptr<FunctionRunner>(new FunctionRunner(cob));
}
static boost::shared_ptr<FunctionRunner> create(PthreadFuncPtr func, void* arg) {
return boost::shared_ptr<FunctionRunner>(new FunctionRunner(func, arg));
}
private:
static void pthread_func_wrapper(PthreadFuncPtr func, void* arg) {
// discard return value
func(arg);
}
public:
/**
* Given a 'pthread_create' style callback, this FunctionRunner will
* execute the given callback. Note that the 'void*' return value is ignored.
*/
FunctionRunner(PthreadFuncPtr func, void* arg)
: func_(apache::thrift::stdcxx::bind(pthread_func_wrapper, func, arg)), intervalMs_(-1) {}
/**
* Given a generic callback, this FunctionRunner will execute it.
*/
FunctionRunner(const VoidFunc& cob) : func_(cob), intervalMs_(-1) {}
/**
* Given a bool foo(...) type callback, FunctionRunner will execute
* the callback repeatedly with 'intervalMs' milliseconds between the calls,
* until it returns false. Note that the actual interval between calls will
* be intervalMs plus execution time of the callback.
*/
FunctionRunner(const BoolFunc& cob, int intervalMs) : repFunc_(cob), intervalMs_(intervalMs) {}
void run() {
if (repFunc_) {
while (repFunc_()) {
THRIFT_SLEEP_USEC(intervalMs_ * 1000);
}
} else {
func_();
}
}
private:
VoidFunc func_;
BoolFunc repFunc_;
int intervalMs_;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_FUNCTION_RUNNER_H

View file

@ -0,0 +1,224 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Util.h>
#include <thrift/transport/PlatformSocket.h>
#include <boost/scoped_ptr.hpp>
#include <assert.h>
#include <iostream>
#include <pthread.h>
namespace apache {
namespace thrift {
namespace concurrency {
using boost::scoped_ptr;
/**
* Monitor implementation using the POSIX pthread library
*
* @version $Id:$
*/
class Monitor::Impl {
public:
Impl() : ownedMutex_(new Mutex()), mutex_(NULL), condInitialized_(false) {
init(ownedMutex_.get());
}
Impl(Mutex* mutex) : mutex_(NULL), condInitialized_(false) { init(mutex); }
Impl(Monitor* monitor) : mutex_(NULL), condInitialized_(false) { init(&(monitor->mutex())); }
~Impl() { cleanup(); }
Mutex& mutex() { return *mutex_; }
void lock() { mutex().lock(); }
void unlock() { mutex().unlock(); }
/**
* Exception-throwing version of waitForTimeRelative(), called simply
* wait(int64) for historical reasons. Timeout is in milliseconds.
*
* If the condition occurs, this function returns cleanly; on timeout or
* error an exception is thrown.
*/
void wait(int64_t timeout_ms) const {
int result = waitForTimeRelative(timeout_ms);
if (result == THRIFT_ETIMEDOUT) {
// pthread_cond_timedwait has been observed to return early on
// various platforms, so comment out this assert.
// assert(Util::currentTime() >= (now + timeout));
throw TimedOutException();
} else if (result != 0) {
throw TException("pthread_cond_wait() or pthread_cond_timedwait() failed");
}
}
/**
* Waits until the specified timeout in milliseconds for the condition to
* occur, or waits forever if timeout_ms == 0.
*
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTimeRelative(int64_t timeout_ms) const {
if (timeout_ms == 0LL) {
return waitForever();
}
struct THRIFT_TIMESPEC abstime;
Util::toTimespec(abstime, Util::currentTime() + timeout_ms);
return waitForTime(&abstime);
}
/**
* Waits until the absolute time specified using struct THRIFT_TIMESPEC.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const THRIFT_TIMESPEC* abstime) const {
assert(mutex_);
pthread_mutex_t* mutexImpl = reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
// XXX Need to assert that caller owns mutex
return pthread_cond_timedwait(&pthread_cond_, mutexImpl, abstime);
}
int waitForTime(const struct timeval* abstime) const {
struct THRIFT_TIMESPEC temp;
temp.tv_sec = abstime->tv_sec;
temp.tv_nsec = abstime->tv_usec * 1000;
return waitForTime(&temp);
}
/**
* Waits forever until the condition occurs.
* Returns 0 if condition occurs, or an error code otherwise.
*/
int waitForever() const {
assert(mutex_);
pthread_mutex_t* mutexImpl = reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
return pthread_cond_wait(&pthread_cond_, mutexImpl);
}
void notify() {
// XXX Need to assert that caller owns mutex
int iret = pthread_cond_signal(&pthread_cond_);
THRIFT_UNUSED_VARIABLE(iret);
assert(iret == 0);
}
void notifyAll() {
// XXX Need to assert that caller owns mutex
int iret = pthread_cond_broadcast(&pthread_cond_);
THRIFT_UNUSED_VARIABLE(iret);
assert(iret == 0);
}
private:
void init(Mutex* mutex) {
mutex_ = mutex;
if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
condInitialized_ = true;
}
if (!condInitialized_) {
cleanup();
throw SystemResourceException();
}
}
void cleanup() {
if (condInitialized_) {
condInitialized_ = false;
int iret = pthread_cond_destroy(&pthread_cond_);
THRIFT_UNUSED_VARIABLE(iret);
assert(iret == 0);
}
}
scoped_ptr<Mutex> ownedMutex_;
Mutex* mutex_;
mutable pthread_cond_t pthread_cond_;
mutable bool condInitialized_;
};
Monitor::Monitor() : impl_(new Monitor::Impl()) {
}
Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {
}
Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {
}
Monitor::~Monitor() {
delete impl_;
}
Mutex& Monitor::mutex() const {
return impl_->mutex();
}
void Monitor::lock() const {
impl_->lock();
}
void Monitor::unlock() const {
impl_->unlock();
}
void Monitor::wait(int64_t timeout) const {
impl_->wait(timeout);
}
int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
return impl_->waitForTime(abstime);
}
int Monitor::waitForTime(const timeval* abstime) const {
return impl_->waitForTime(abstime);
}
int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
return impl_->waitForTimeRelative(timeout_ms);
}
int Monitor::waitForever() const {
return impl_->waitForever();
}
void Monitor::notify() const {
impl_->notify();
}
void Monitor::notifyAll() const {
impl_->notifyAll();
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,133 @@
/*
* 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 _THRIFT_CONCURRENCY_MONITOR_H_
#define _THRIFT_CONCURRENCY_MONITOR_H_ 1
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Mutex.h>
#include <boost/utility.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* A monitor is a combination mutex and condition-event. Waiting and
* notifying condition events requires that the caller own the mutex. Mutex
* lock and unlock operations can be performed independently of condition
* events. This is more or less analogous to java.lang.Object multi-thread
* operations.
*
* Note the Monitor can create a new, internal mutex; alternatively, a
* separate Mutex can be passed in and the Monitor will re-use it without
* taking ownership. It's the user's responsibility to make sure that the
* Mutex is not deallocated before the Monitor.
*
* Note that all methods are const. Monitors implement logical constness, not
* bit constness. This allows const methods to call monitor methods without
* needing to cast away constness or change to non-const signatures.
*
* @version $Id:$
*/
class Monitor : boost::noncopyable {
public:
/** Creates a new mutex, and takes ownership of it. */
Monitor();
/** Uses the provided mutex without taking ownership. */
explicit Monitor(Mutex* mutex);
/** Uses the mutex inside the provided Monitor without taking ownership. */
explicit Monitor(Monitor* monitor);
/** Deallocates the mutex only if we own it. */
virtual ~Monitor();
Mutex& mutex() const;
virtual void lock() const;
virtual void unlock() const;
/**
* Waits a maximum of the specified timeout in milliseconds for the condition
* to occur, or waits forever if timeout_ms == 0.
*
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTimeRelative(int64_t timeout_ms) const;
/**
* Waits until the absolute time specified using struct THRIFT_TIMESPEC.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const THRIFT_TIMESPEC* abstime) const;
/**
* Waits until the absolute time specified using struct timeval.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const struct timeval* abstime) const;
/**
* Waits forever until the condition occurs.
* Returns 0 if condition occurs, or an error code otherwise.
*/
int waitForever() const;
/**
* Exception-throwing version of waitForTimeRelative(), called simply
* wait(int64) for historical reasons. Timeout is in milliseconds.
*
* If the condition occurs, this function returns cleanly; on timeout or
* error an exception is thrown.
*/
void wait(int64_t timeout_ms = 0LL) const;
/** Wakes up one thread waiting on this monitor. */
virtual void notify() const;
/** Wakes up all waiting threads on this monitor. */
virtual void notifyAll() const;
private:
class Impl;
Impl* impl_;
};
class Synchronized {
public:
Synchronized(const Monitor* monitor) : g(monitor->mutex()) {}
Synchronized(const Monitor& monitor) : g(monitor.mutex()) {}
private:
Guard g;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_MONITOR_H_

View file

@ -0,0 +1,373 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <thrift/thrift-config.h>
#include <thrift/Thrift.h>
#include <thrift/concurrency/Mutex.h>
#include <thrift/concurrency/Util.h>
#include <assert.h>
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#include <signal.h>
using boost::shared_ptr;
namespace apache {
namespace thrift {
namespace concurrency {
#ifndef THRIFT_NO_CONTENTION_PROFILING
static int32_t mutexProfilingCounter = 0;
static int32_t mutexProfilingSampleRate = 0;
static MutexWaitCallback mutexProfilingCallback = 0;
void enableMutexProfiling(int32_t profilingSampleRate, MutexWaitCallback callback) {
mutexProfilingSampleRate = profilingSampleRate;
mutexProfilingCallback = callback;
}
#define PROFILE_MUTEX_START_LOCK() int64_t _lock_startTime = maybeGetProfilingStartTime();
#define PROFILE_MUTEX_NOT_LOCKED() \
do { \
if (_lock_startTime > 0) { \
int64_t endTime = Util::currentTimeUsec(); \
(*mutexProfilingCallback)(this, endTime - _lock_startTime); \
} \
} while (0)
#define PROFILE_MUTEX_LOCKED() \
do { \
profileTime_ = _lock_startTime; \
if (profileTime_ > 0) { \
profileTime_ = Util::currentTimeUsec() - profileTime_; \
} \
} while (0)
#define PROFILE_MUTEX_START_UNLOCK() \
int64_t _temp_profileTime = profileTime_; \
profileTime_ = 0;
#define PROFILE_MUTEX_UNLOCKED() \
do { \
if (_temp_profileTime > 0) { \
(*mutexProfilingCallback)(this, _temp_profileTime); \
} \
} while (0)
static inline int64_t maybeGetProfilingStartTime() {
if (mutexProfilingSampleRate && mutexProfilingCallback) {
// This block is unsynchronized, but should produce a reasonable sampling
// rate on most architectures. The main race conditions are the gap
// between the decrement and the test, the non-atomicity of decrement, and
// potential caching of different values at different CPUs.
//
// - if two decrements race, the likeliest result is that the counter
// decrements slowly (perhaps much more slowly) than intended.
//
// - many threads could potentially decrement before resetting the counter
// to its large value, causing each additional incoming thread to
// profile every call. This situation is unlikely to persist for long
// as the critical gap is quite short, but profiling could be bursty.
sig_atomic_t localValue = --mutexProfilingCounter;
if (localValue <= 0) {
mutexProfilingCounter = mutexProfilingSampleRate;
return Util::currentTimeUsec();
}
}
return 0;
}
#else
#define PROFILE_MUTEX_START_LOCK()
#define PROFILE_MUTEX_NOT_LOCKED()
#define PROFILE_MUTEX_LOCKED()
#define PROFILE_MUTEX_START_UNLOCK()
#define PROFILE_MUTEX_UNLOCKED()
#endif // THRIFT_NO_CONTENTION_PROFILING
/**
* Implementation of Mutex class using POSIX mutex
*
* @version $Id:$
*/
class Mutex::impl {
public:
impl(Initializer init) : initialized_(false) {
#ifndef THRIFT_NO_CONTENTION_PROFILING
profileTime_ = 0;
#endif
init(&pthread_mutex_);
initialized_ = true;
}
~impl() {
if (initialized_) {
initialized_ = false;
int ret = pthread_mutex_destroy(&pthread_mutex_);
THRIFT_UNUSED_VARIABLE(ret);
assert(ret == 0);
}
}
void lock() const {
PROFILE_MUTEX_START_LOCK();
pthread_mutex_lock(&pthread_mutex_);
PROFILE_MUTEX_LOCKED();
}
bool trylock() const { return (0 == pthread_mutex_trylock(&pthread_mutex_)); }
bool timedlock(int64_t milliseconds) const {
#if defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS >= 200112L
PROFILE_MUTEX_START_LOCK();
struct THRIFT_TIMESPEC ts;
Util::toTimespec(ts, milliseconds + Util::currentTime());
int ret = pthread_mutex_timedlock(&pthread_mutex_, &ts);
if (ret == 0) {
PROFILE_MUTEX_LOCKED();
return true;
}
PROFILE_MUTEX_NOT_LOCKED();
return false;
#else
/* Otherwise follow solution used by Mono for Android */
struct THRIFT_TIMESPEC sleepytime, now, to;
/* This is just to avoid a completely busy wait */
sleepytime.tv_sec = 0;
sleepytime.tv_nsec = 10000000L; /* 10ms */
Util::toTimespec(to, milliseconds + Util::currentTime());
while ((trylock()) == false) {
Util::toTimespec(now, Util::currentTime());
if (now.tv_sec >= to.tv_sec && now.tv_nsec >= to.tv_nsec) {
return false;
}
nanosleep(&sleepytime, NULL);
}
return true;
#endif
}
void unlock() const {
PROFILE_MUTEX_START_UNLOCK();
pthread_mutex_unlock(&pthread_mutex_);
PROFILE_MUTEX_UNLOCKED();
}
void* getUnderlyingImpl() const { return (void*)&pthread_mutex_; }
private:
mutable pthread_mutex_t pthread_mutex_;
mutable bool initialized_;
#ifndef THRIFT_NO_CONTENTION_PROFILING
mutable int64_t profileTime_;
#endif
};
Mutex::Mutex(Initializer init) : impl_(new Mutex::impl(init)) {
}
void* Mutex::getUnderlyingImpl() const {
return impl_->getUnderlyingImpl();
}
void Mutex::lock() const {
impl_->lock();
}
bool Mutex::trylock() const {
return impl_->trylock();
}
bool Mutex::timedlock(int64_t ms) const {
return impl_->timedlock(ms);
}
void Mutex::unlock() const {
impl_->unlock();
}
void Mutex::DEFAULT_INITIALIZER(void* arg) {
pthread_mutex_t* pthread_mutex = (pthread_mutex_t*)arg;
int ret = pthread_mutex_init(pthread_mutex, NULL);
THRIFT_UNUSED_VARIABLE(ret);
assert(ret == 0);
}
#if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) \
|| defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
static void init_with_kind(pthread_mutex_t* mutex, int kind) {
pthread_mutexattr_t mutexattr;
int ret = pthread_mutexattr_init(&mutexattr);
assert(ret == 0);
// Apparently, this can fail. Should we really be aborting?
ret = pthread_mutexattr_settype(&mutexattr, kind);
assert(ret == 0);
ret = pthread_mutex_init(mutex, &mutexattr);
assert(ret == 0);
ret = pthread_mutexattr_destroy(&mutexattr);
assert(ret == 0);
THRIFT_UNUSED_VARIABLE(ret);
}
#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
void Mutex::ADAPTIVE_INITIALIZER(void* arg) {
// From mysql source: mysys/my_thr_init.c
// Set mutex type to "fast" a.k.a "adaptive"
//
// In this case the thread may steal the mutex from some other thread
// that is waiting for the same mutex. This will save us some
// context switches but may cause a thread to 'starve forever' while
// waiting for the mutex (not likely if the code within the mutex is
// short).
init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_ADAPTIVE_NP);
}
#endif
#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
void Mutex::RECURSIVE_INITIALIZER(void* arg) {
init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_RECURSIVE_NP);
}
#endif
/**
* Implementation of ReadWriteMutex class using POSIX rw lock
*
* @version $Id:$
*/
class ReadWriteMutex::impl {
public:
impl() : initialized_(false) {
#ifndef THRIFT_NO_CONTENTION_PROFILING
profileTime_ = 0;
#endif
int ret = pthread_rwlock_init(&rw_lock_, NULL);
THRIFT_UNUSED_VARIABLE(ret);
assert(ret == 0);
initialized_ = true;
}
~impl() {
if (initialized_) {
initialized_ = false;
int ret = pthread_rwlock_destroy(&rw_lock_);
THRIFT_UNUSED_VARIABLE(ret);
assert(ret == 0);
}
}
void acquireRead() const {
PROFILE_MUTEX_START_LOCK();
pthread_rwlock_rdlock(&rw_lock_);
PROFILE_MUTEX_NOT_LOCKED(); // not exclusive, so use not-locked path
}
void acquireWrite() const {
PROFILE_MUTEX_START_LOCK();
pthread_rwlock_wrlock(&rw_lock_);
PROFILE_MUTEX_LOCKED();
}
bool attemptRead() const { return !pthread_rwlock_tryrdlock(&rw_lock_); }
bool attemptWrite() const { return !pthread_rwlock_trywrlock(&rw_lock_); }
void release() const {
PROFILE_MUTEX_START_UNLOCK();
pthread_rwlock_unlock(&rw_lock_);
PROFILE_MUTEX_UNLOCKED();
}
private:
mutable pthread_rwlock_t rw_lock_;
mutable bool initialized_;
#ifndef THRIFT_NO_CONTENTION_PROFILING
mutable int64_t profileTime_;
#endif
};
ReadWriteMutex::ReadWriteMutex() : impl_(new ReadWriteMutex::impl()) {
}
void ReadWriteMutex::acquireRead() const {
impl_->acquireRead();
}
void ReadWriteMutex::acquireWrite() const {
impl_->acquireWrite();
}
bool ReadWriteMutex::attemptRead() const {
return impl_->attemptRead();
}
bool ReadWriteMutex::attemptWrite() const {
return impl_->attemptWrite();
}
void ReadWriteMutex::release() const {
impl_->release();
}
NoStarveReadWriteMutex::NoStarveReadWriteMutex() : writerWaiting_(false) {
}
void NoStarveReadWriteMutex::acquireRead() const {
if (writerWaiting_) {
// writer is waiting, block on the writer's mutex until he's done with it
mutex_.lock();
mutex_.unlock();
}
ReadWriteMutex::acquireRead();
}
void NoStarveReadWriteMutex::acquireWrite() const {
// if we can acquire the rwlock the easy way, we're done
if (attemptWrite()) {
return;
}
// failed to get the rwlock, do it the hard way:
// locking the mutex and setting writerWaiting will cause all new readers to
// block on the mutex rather than on the rwlock.
mutex_.lock();
writerWaiting_ = true;
ReadWriteMutex::acquireWrite();
writerWaiting_ = false;
mutex_.unlock();
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,180 @@
/*
* 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 _THRIFT_CONCURRENCY_MUTEX_H_
#define _THRIFT_CONCURRENCY_MUTEX_H_ 1
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <stdint.h>
namespace apache {
namespace thrift {
namespace concurrency {
#ifndef THRIFT_NO_CONTENTION_PROFILING
/**
* Determines if the Thrift Mutex and ReadWriteMutex classes will attempt to
* profile their blocking acquire methods. If this value is set to non-zero,
* Thrift will attempt to invoke the callback once every profilingSampleRate
* times. However, as the sampling is not synchronized the rate is not
* guranateed, and could be subject to big bursts and swings. Please ensure
* your sampling callback is as performant as your application requires.
*
* The callback will get called with the wait time taken to lock the mutex in
* usec and a (void*) that uniquely identifies the Mutex (or ReadWriteMutex)
* being locked.
*
* The enableMutexProfiling() function is unsynchronized; calling this function
* while profiling is already enabled may result in race conditions. On
* architectures where a pointer assignment is atomic, this is safe but there
* is no guarantee threads will agree on a single callback within any
* particular time period.
*/
typedef void (*MutexWaitCallback)(const void* id, int64_t waitTimeMicros);
void enableMutexProfiling(int32_t profilingSampleRate, MutexWaitCallback callback);
#endif
/**
* A simple mutex class
*
* @version $Id:$
*/
class Mutex {
public:
typedef void (*Initializer)(void*);
Mutex(Initializer init = DEFAULT_INITIALIZER);
virtual ~Mutex() {}
virtual void lock() const;
virtual bool trylock() const;
virtual bool timedlock(int64_t milliseconds) const;
virtual void unlock() const;
void* getUnderlyingImpl() const;
static void DEFAULT_INITIALIZER(void*);
static void ADAPTIVE_INITIALIZER(void*);
static void RECURSIVE_INITIALIZER(void*);
private:
class impl;
boost::shared_ptr<impl> impl_;
};
class ReadWriteMutex {
public:
ReadWriteMutex();
virtual ~ReadWriteMutex() {}
// these get the lock and block until it is done successfully
virtual void acquireRead() const;
virtual void acquireWrite() const;
// these attempt to get the lock, returning false immediately if they fail
virtual bool attemptRead() const;
virtual bool attemptWrite() const;
// this releases both read and write locks
virtual void release() const;
private:
class impl;
boost::shared_ptr<impl> impl_;
};
/**
* A ReadWriteMutex that guarantees writers will not be starved by readers:
* When a writer attempts to acquire the mutex, all new readers will be
* blocked from acquiring the mutex until the writer has acquired and
* released it. In some operating systems, this may already be guaranteed
* by a regular ReadWriteMutex.
*/
class NoStarveReadWriteMutex : public ReadWriteMutex {
public:
NoStarveReadWriteMutex();
virtual void acquireRead() const;
virtual void acquireWrite() const;
private:
Mutex mutex_;
mutable volatile bool writerWaiting_;
};
class Guard : boost::noncopyable {
public:
Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) {
if (timeout == 0) {
value.lock();
} else if (timeout < 0) {
if (!value.trylock()) {
mutex_ = NULL;
}
} else {
if (!value.timedlock(timeout)) {
mutex_ = NULL;
}
}
}
~Guard() {
if (mutex_) {
mutex_->unlock();
}
}
operator bool() const { return (mutex_ != NULL); }
private:
const Mutex* mutex_;
};
// Can be used as second argument to RWGuard to make code more readable
// as to whether we're doing acquireRead() or acquireWrite().
enum RWGuardType { RW_READ = 0, RW_WRITE = 1 };
class RWGuard : boost::noncopyable {
public:
RWGuard(const ReadWriteMutex& value, bool write = false) : rw_mutex_(value) {
if (write) {
rw_mutex_.acquireWrite();
} else {
rw_mutex_.acquireRead();
}
}
RWGuard(const ReadWriteMutex& value, RWGuardType type) : rw_mutex_(value) {
if (type == RW_WRITE) {
rw_mutex_.acquireWrite();
} else {
rw_mutex_.acquireRead();
}
}
~RWGuard() { rw_mutex_.release(); }
private:
const ReadWriteMutex& rw_mutex_;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_MUTEX_H_

View file

@ -0,0 +1,52 @@
/*
* 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 _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_
#define _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_ 1
// clang-format off
#include <thrift/thrift-config.h>
#if USE_BOOST_THREAD
# include <thrift/concurrency/BoostThreadFactory.h>
#elif USE_STD_THREAD
# include <thrift/concurrency/StdThreadFactory.h>
#else
# include <thrift/concurrency/PosixThreadFactory.h>
#endif
// clang-format on
namespace apache {
namespace thrift {
namespace concurrency {
// clang-format off
#if USE_BOOST_THREAD
typedef BoostThreadFactory PlatformThreadFactory;
#elif USE_STD_THREAD
typedef StdThreadFactory PlatformThreadFactory;
#else
typedef PosixThreadFactory PlatformThreadFactory;
#endif
// clang-format on
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_PLATFORMTHREADFACTORY_H_

View file

@ -0,0 +1,317 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/PosixThreadFactory.h>
#include <thrift/concurrency/Exception.h>
#if GOOGLE_PERFTOOLS_REGISTER_THREAD
#include <google/profiler.h>
#endif
#include <assert.h>
#include <pthread.h>
#include <iostream>
#include <boost/weak_ptr.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
using boost::shared_ptr;
using boost::weak_ptr;
/**
* The POSIX thread class.
*
* @version $Id:$
*/
class PthreadThread : public Thread {
public:
enum STATE { uninitialized, starting, started, stopping, stopped };
static const int MB = 1024 * 1024;
static void* threadMain(void* arg);
private:
pthread_t pthread_;
STATE state_;
int policy_;
int priority_;
int stackSize_;
weak_ptr<PthreadThread> self_;
bool detached_;
public:
PthreadThread(int policy,
int priority,
int stackSize,
bool detached,
shared_ptr<Runnable> runnable)
:
#ifndef _WIN32
pthread_(0),
#endif // _WIN32
state_(uninitialized),
policy_(policy),
priority_(priority),
stackSize_(stackSize),
detached_(detached) {
this->Thread::runnable(runnable);
}
~PthreadThread() {
/* Nothing references this thread, if is is not detached, do a join
now, otherwise the thread-id and, possibly, other resources will
be leaked. */
if (!detached_) {
try {
join();
} catch (...) {
// We're really hosed.
}
}
}
void start() {
if (state_ != uninitialized) {
return;
}
pthread_attr_t thread_attr;
if (pthread_attr_init(&thread_attr) != 0) {
throw SystemResourceException("pthread_attr_init failed");
}
if (pthread_attr_setdetachstate(&thread_attr,
detached_ ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE)
!= 0) {
throw SystemResourceException("pthread_attr_setdetachstate failed");
}
// Set thread stack size
if (pthread_attr_setstacksize(&thread_attr, MB * stackSize_) != 0) {
throw SystemResourceException("pthread_attr_setstacksize failed");
}
// Set thread policy
#ifdef _WIN32
// WIN32 Pthread implementation doesn't seem to support sheduling policies other then
// PosixThreadFactory::OTHER - runtime error
policy_ = PosixThreadFactory::OTHER;
#endif
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
if (pthread_attr_setschedpolicy(&thread_attr, policy_) != 0) {
throw SystemResourceException("pthread_attr_setschedpolicy failed");
}
#endif
struct sched_param sched_param;
sched_param.sched_priority = priority_;
// Set thread priority
if (pthread_attr_setschedparam(&thread_attr, &sched_param) != 0) {
throw SystemResourceException("pthread_attr_setschedparam failed");
}
// Create reference
shared_ptr<PthreadThread>* selfRef = new shared_ptr<PthreadThread>();
*selfRef = self_.lock();
state_ = starting;
if (pthread_create(&pthread_, &thread_attr, threadMain, (void*)selfRef) != 0) {
throw SystemResourceException("pthread_create failed");
}
}
void join() {
if (!detached_ && state_ != uninitialized) {
void* ignore;
/* XXX
If join fails it is most likely due to the fact
that the last reference was the thread itself and cannot
join. This results in leaked threads and will eventually
cause the process to run out of thread resources.
We're beyond the point of throwing an exception. Not clear how
best to handle this. */
int res = pthread_join(pthread_, &ignore);
detached_ = (res == 0);
if (res != 0) {
GlobalOutput.printf("PthreadThread::join(): fail with code %d", res);
}
} else {
GlobalOutput.printf("PthreadThread::join(): detached thread");
}
}
Thread::id_t getId() {
#ifndef _WIN32
return (Thread::id_t)pthread_;
#else
return (Thread::id_t)pthread_.p;
#endif // _WIN32
}
shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
void runnable(shared_ptr<Runnable> value) { Thread::runnable(value); }
void weakRef(shared_ptr<PthreadThread> self) {
assert(self.get() == this);
self_ = weak_ptr<PthreadThread>(self);
}
};
void* PthreadThread::threadMain(void* arg) {
shared_ptr<PthreadThread> thread = *(shared_ptr<PthreadThread>*)arg;
delete reinterpret_cast<shared_ptr<PthreadThread>*>(arg);
if (thread == NULL) {
return (void*)0;
}
if (thread->state_ != starting) {
return (void*)0;
}
#if GOOGLE_PERFTOOLS_REGISTER_THREAD
ProfilerRegisterThread();
#endif
thread->state_ = started;
thread->runnable()->run();
if (thread->state_ != stopping && thread->state_ != stopped) {
thread->state_ = stopping;
}
return (void*)0;
}
/**
* Converts generic posix thread schedule policy enums into pthread
* API values.
*/
static int toPthreadPolicy(PosixThreadFactory::POLICY policy) {
switch (policy) {
case PosixThreadFactory::OTHER:
return SCHED_OTHER;
case PosixThreadFactory::FIFO:
return SCHED_FIFO;
case PosixThreadFactory::ROUND_ROBIN:
return SCHED_RR;
}
return SCHED_OTHER;
}
/**
* Converts relative thread priorities to absolute value based on posix
* thread scheduler policy
*
* The idea is simply to divide up the priority range for the given policy
* into the correpsonding relative priority level (lowest..highest) and
* then pro-rate accordingly.
*/
static int toPthreadPriority(PosixThreadFactory::POLICY policy, PosixThreadFactory::PRIORITY priority) {
int pthread_policy = toPthreadPolicy(policy);
int min_priority = 0;
int max_priority = 0;
#ifdef HAVE_SCHED_GET_PRIORITY_MIN
min_priority = sched_get_priority_min(pthread_policy);
#endif
#ifdef HAVE_SCHED_GET_PRIORITY_MAX
max_priority = sched_get_priority_max(pthread_policy);
#endif
int quanta = (PosixThreadFactory::HIGHEST - PosixThreadFactory::LOWEST) + 1;
float stepsperquanta = (float)(max_priority - min_priority) / quanta;
if (priority <= PosixThreadFactory::HIGHEST) {
return (int)(min_priority + stepsperquanta * priority);
} else {
// should never get here for priority increments.
assert(false);
return (int)(min_priority + stepsperquanta * PosixThreadFactory::NORMAL);
}
}
PosixThreadFactory::PosixThreadFactory(POLICY policy,
PRIORITY priority,
int stackSize,
bool detached)
: ThreadFactory(detached),
policy_(policy),
priority_(priority),
stackSize_(stackSize) {
}
PosixThreadFactory::PosixThreadFactory(bool detached)
: ThreadFactory(detached),
policy_(ROUND_ROBIN),
priority_(NORMAL),
stackSize_(1) {
}
shared_ptr<Thread> PosixThreadFactory::newThread(shared_ptr<Runnable> runnable) const {
shared_ptr<PthreadThread> result
= shared_ptr<PthreadThread>(new PthreadThread(toPthreadPolicy(policy_),
toPthreadPriority(policy_, priority_),
stackSize_,
isDetached(),
runnable));
result->weakRef(result);
runnable->thread(result);
return result;
}
int PosixThreadFactory::getStackSize() const {
return stackSize_;
}
void PosixThreadFactory::setStackSize(int value) {
stackSize_ = value;
}
PosixThreadFactory::PRIORITY PosixThreadFactory::getPriority() const {
return priority_;
}
void PosixThreadFactory::setPriority(PRIORITY value) {
priority_ = value;
}
Thread::id_t PosixThreadFactory::getCurrentThreadId() const {
#ifndef _WIN32
return (Thread::id_t)pthread_self();
#else
return (Thread::id_t)pthread_self().p;
#endif // _WIN32
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,129 @@
/*
* 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 _THRIFT_CONCURRENCY_POSIXTHREADFACTORY_H_
#define _THRIFT_CONCURRENCY_POSIXTHREADFACTORY_H_ 1
#include <thrift/concurrency/Thread.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* A thread factory to create posix threads
*
* @version $Id:$
*/
class PosixThreadFactory : public ThreadFactory {
public:
/**
* POSIX Thread scheduler policies
*/
enum POLICY { OTHER, FIFO, ROUND_ROBIN };
/**
* POSIX Thread scheduler relative priorities,
*
* Absolute priority is determined by scheduler policy and OS. This
* enumeration specifies relative priorities such that one can specify a
* priority within a giving scheduler policy without knowing the absolute
* value of the priority.
*/
enum PRIORITY {
LOWEST = 0,
LOWER = 1,
LOW = 2,
NORMAL = 3,
HIGH = 4,
HIGHER = 5,
HIGHEST = 6,
INCREMENT = 7,
DECREMENT = 8
};
/**
* Posix thread (pthread) factory. All threads created by a factory are reference-counted
* via boost::shared_ptr and boost::weak_ptr. The factory guarantees that threads and
* the Runnable tasks they host will be properly cleaned up once the last strong reference
* to both is given up.
*
* Threads are created with the specified policy, priority, stack-size and detachable-mode
* detached means the thread is free-running and will release all system resources the
* when it completes. A detachable thread is not joinable. The join method
* of a detachable thread will return immediately with no error.
*
* By default threads are not joinable.
*/
PosixThreadFactory(POLICY policy = ROUND_ROBIN,
PRIORITY priority = NORMAL,
int stackSize = 1,
bool detached = true);
/**
* Provide a constructor compatible with the other factories
* The default policy is POLICY::ROUND_ROBIN.
* The default priority is PRIORITY::NORMAL.
* The default stackSize is 1.
*/
PosixThreadFactory(bool detached);
// From ThreadFactory;
boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
// From ThreadFactory;
Thread::id_t getCurrentThreadId() const;
/**
* Gets stack size for newly created threads
*
* @return int size in megabytes
*/
virtual int getStackSize() const;
/**
* Sets stack size for newly created threads
*
* @param value size in megabytes
*/
virtual void setStackSize(int value);
/**
* Gets priority relative to current policy
*/
virtual PRIORITY getPriority() const;
/**
* Sets priority relative to current policy
*/
virtual void setPriority(PRIORITY priority);
private:
POLICY policy_;
PRIORITY priority_;
int stackSize_;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_POSIXTHREADFACTORY_H_

View file

@ -0,0 +1,213 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Util.h>
#include <thrift/transport/PlatformSocket.h>
#include <assert.h>
#include <condition_variable>
#include <chrono>
#include <thread>
#include <mutex>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Monitor implementation using the std thread library
*
* @version $Id:$
*/
class Monitor::Impl {
public:
Impl() : ownedMutex_(new Mutex()), conditionVariable_(), mutex_(NULL) { init(ownedMutex_.get()); }
Impl(Mutex* mutex) : ownedMutex_(), conditionVariable_(), mutex_(NULL) { init(mutex); }
Impl(Monitor* monitor) : ownedMutex_(), conditionVariable_(), mutex_(NULL) {
init(&(monitor->mutex()));
}
Mutex& mutex() { return *mutex_; }
void lock() { mutex_->lock(); }
void unlock() { mutex_->unlock(); }
/**
* Exception-throwing version of waitForTimeRelative(), called simply
* wait(int64) for historical reasons. Timeout is in milliseconds.
*
* If the condition occurs, this function returns cleanly; on timeout or
* error an exception is thrown.
*/
void wait(int64_t timeout_ms) {
int result = waitForTimeRelative(timeout_ms);
if (result == THRIFT_ETIMEDOUT) {
throw TimedOutException();
} else if (result != 0) {
throw TException("Monitor::wait() failed");
}
}
/**
* Waits until the specified timeout in milliseconds for the condition to
* occur, or waits forever if timeout_ms == 0.
*
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTimeRelative(int64_t timeout_ms) {
if (timeout_ms == 0LL) {
return waitForever();
}
assert(mutex_);
std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
bool timedout = (conditionVariable_.wait_for(lock, std::chrono::milliseconds(timeout_ms))
== std::cv_status::timeout);
lock.release();
return (timedout ? THRIFT_ETIMEDOUT : 0);
}
/**
* Waits until the absolute time specified using struct THRIFT_TIMESPEC.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const THRIFT_TIMESPEC* abstime) {
struct timeval temp;
temp.tv_sec = static_cast<long>(abstime->tv_sec);
temp.tv_usec = static_cast<long>(abstime->tv_nsec) / 1000;
return waitForTime(&temp);
}
/**
* Waits until the absolute time specified using struct timeval.
* Returns 0 if condition occurs, THRIFT_ETIMEDOUT on timeout, or an error code.
*/
int waitForTime(const struct timeval* abstime) {
assert(mutex_);
std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
struct timeval currenttime;
Util::toTimeval(currenttime, Util::currentTime());
long tv_sec = static_cast<long>(abstime->tv_sec - currenttime.tv_sec);
long tv_usec = static_cast<long>(abstime->tv_usec - currenttime.tv_usec);
if (tv_sec < 0)
tv_sec = 0;
if (tv_usec < 0)
tv_usec = 0;
std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
bool timedout = (conditionVariable_.wait_for(lock,
std::chrono::seconds(tv_sec)
+ std::chrono::microseconds(tv_usec))
== std::cv_status::timeout);
lock.release();
return (timedout ? THRIFT_ETIMEDOUT : 0);
}
/**
* Waits forever until the condition occurs.
* Returns 0 if condition occurs, or an error code otherwise.
*/
int waitForever() {
assert(mutex_);
std::timed_mutex* mutexImpl = static_cast<std::timed_mutex*>(mutex_->getUnderlyingImpl());
assert(mutexImpl);
std::unique_lock<std::timed_mutex> lock(*mutexImpl, std::adopt_lock);
conditionVariable_.wait(lock);
lock.release();
return 0;
}
void notify() { conditionVariable_.notify_one(); }
void notifyAll() { conditionVariable_.notify_all(); }
private:
void init(Mutex* mutex) { mutex_ = mutex; }
const std::unique_ptr<Mutex> ownedMutex_;
std::condition_variable_any conditionVariable_;
Mutex* mutex_;
};
Monitor::Monitor() : impl_(new Monitor::Impl()) {
}
Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {
}
Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {
}
Monitor::~Monitor() {
delete impl_;
}
Mutex& Monitor::mutex() const {
return const_cast<Monitor::Impl*>(impl_)->mutex();
}
void Monitor::lock() const {
const_cast<Monitor::Impl*>(impl_)->lock();
}
void Monitor::unlock() const {
const_cast<Monitor::Impl*>(impl_)->unlock();
}
void Monitor::wait(int64_t timeout) const {
const_cast<Monitor::Impl*>(impl_)->wait(timeout);
}
int Monitor::waitForTime(const THRIFT_TIMESPEC* abstime) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
}
int Monitor::waitForTime(const timeval* abstime) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTime(abstime);
}
int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
return const_cast<Monitor::Impl*>(impl_)->waitForTimeRelative(timeout_ms);
}
int Monitor::waitForever() const {
return const_cast<Monitor::Impl*>(impl_)->waitForever();
}
void Monitor::notify() const {
const_cast<Monitor::Impl*>(impl_)->notify();
}
void Monitor::notifyAll() const {
const_cast<Monitor::Impl*>(impl_)->notifyAll();
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,67 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/Mutex.h>
#include <thrift/concurrency/Util.h>
#include <cassert>
#include <chrono>
#include <mutex>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Implementation of Mutex class using C++11 std::timed_mutex
*
* @version $Id:$
*/
class Mutex::impl : public std::timed_mutex {};
Mutex::Mutex(Initializer init) : impl_(new Mutex::impl()) {
}
void* Mutex::getUnderlyingImpl() const {
return impl_.get();
}
void Mutex::lock() const {
impl_->lock();
}
bool Mutex::trylock() const {
return impl_->try_lock();
}
bool Mutex::timedlock(int64_t ms) const {
return impl_->try_lock_for(std::chrono::milliseconds(ms));
}
void Mutex::unlock() const {
impl_->unlock();
}
void Mutex::DEFAULT_INITIALIZER(void* arg) {
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,135 @@
/*
* 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 <thrift/thrift-config.h>
#if USE_STD_THREAD
#include <thrift/concurrency/StdThreadFactory.h>
#include <thrift/concurrency/Exception.h>
#include <cassert>
#include <boost/enable_shared_from_this.hpp>
#include <boost/weak_ptr.hpp>
#include <thread>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* The C++11 thread class.
*
* Note that we use boost shared_ptr rather than std shared_ptrs here
* because the Thread/Runnable classes use those and we don't want to
* mix them.
*
* @version $Id:$
*/
class StdThread : public Thread, public boost::enable_shared_from_this<StdThread> {
public:
enum STATE { uninitialized, starting, started, stopping, stopped };
static void threadMain(boost::shared_ptr<StdThread> thread);
private:
std::unique_ptr<std::thread> thread_;
STATE state_;
bool detached_;
public:
StdThread(bool detached, boost::shared_ptr<Runnable> runnable)
: state_(uninitialized), detached_(detached) {
this->Thread::runnable(runnable);
}
~StdThread() {
if (!detached_) {
try {
join();
} catch (...) {
// We're really hosed.
}
}
}
void start() {
if (state_ != uninitialized) {
return;
}
boost::shared_ptr<StdThread> selfRef = shared_from_this();
state_ = starting;
thread_ = std::unique_ptr<std::thread>(new std::thread(threadMain, selfRef));
if (detached_)
thread_->detach();
}
void join() {
if (!detached_ && state_ != uninitialized) {
thread_->join();
}
}
Thread::id_t getId() { return thread_.get() ? thread_->get_id() : std::thread::id(); }
boost::shared_ptr<Runnable> runnable() const { return Thread::runnable(); }
void runnable(boost::shared_ptr<Runnable> value) { Thread::runnable(value); }
};
void StdThread::threadMain(boost::shared_ptr<StdThread> thread) {
if (thread == NULL) {
return;
}
if (thread->state_ != starting) {
return;
}
thread->state_ = started;
thread->runnable()->run();
if (thread->state_ != stopping && thread->state_ != stopped) {
thread->state_ = stopping;
}
return;
}
StdThreadFactory::StdThreadFactory(bool detached) : ThreadFactory(detached) {
}
boost::shared_ptr<Thread> StdThreadFactory::newThread(boost::shared_ptr<Runnable> runnable) const {
boost::shared_ptr<StdThread> result = boost::shared_ptr<StdThread>(new StdThread(isDetached(), runnable));
runnable->thread(result);
return result;
}
Thread::id_t StdThreadFactory::getCurrentThreadId() const {
return std::this_thread::get_id();
}
}
}
} // apache::thrift::concurrency
#endif // USE_STD_THREAD

View file

@ -0,0 +1,61 @@
/*
* 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 _THRIFT_CONCURRENCY_STDTHREADFACTORY_H_
#define _THRIFT_CONCURRENCY_STDTHREADFACTORY_H_ 1
#include <thrift/concurrency/Thread.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* A thread factory to create std::threads.
*
* @version $Id:$
*/
class StdThreadFactory : public ThreadFactory {
public:
/**
* Std thread factory. All threads created by a factory are reference-counted
* via boost::shared_ptr and boost::weak_ptr. The factory guarantees that threads and
* the Runnable tasks they host will be properly cleaned up once the last strong reference
* to both is given up.
*
* By default threads are not joinable.
*/
StdThreadFactory(bool detached = true);
// From ThreadFactory;
boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const;
// From ThreadFactory;
Thread::id_t getCurrentThreadId() const;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_STDTHREADFACTORY_H_

View file

@ -0,0 +1,178 @@
/*
* 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 _THRIFT_CONCURRENCY_THREAD_H_
#define _THRIFT_CONCURRENCY_THREAD_H_ 1
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <thrift/thrift-config.h>
#if USE_BOOST_THREAD
#include <boost/thread.hpp>
#elif USE_STD_THREAD
#include <thread>
#else
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#endif
namespace apache {
namespace thrift {
namespace concurrency {
class Thread;
/**
* Minimal runnable class. More or less analogous to java.lang.Runnable.
*
* @version $Id:$
*/
class Runnable {
public:
virtual ~Runnable(){};
virtual void run() = 0;
/**
* Gets the thread object that is hosting this runnable object - can return
* an empty boost::shared pointer if no references remain on that thread object
*/
virtual boost::shared_ptr<Thread> thread() { return thread_.lock(); }
/**
* Sets the thread that is executing this object. This is only meant for
* use by concrete implementations of Thread.
*/
virtual void thread(boost::shared_ptr<Thread> value) { thread_ = value; }
private:
boost::weak_ptr<Thread> thread_;
};
/**
* Minimal thread class. Returned by thread factory bound to a Runnable object
* and ready to start execution. More or less analogous to java.lang.Thread
* (minus all the thread group, priority, mode and other baggage, since that
* is difficult to abstract across platforms and is left for platform-specific
* ThreadFactory implemtations to deal with
*
* @see apache::thrift::concurrency::ThreadFactory)
*/
class Thread {
public:
#if USE_BOOST_THREAD
typedef boost::thread::id id_t;
static inline bool is_current(id_t t) { return t == boost::this_thread::get_id(); }
static inline id_t get_current() { return boost::this_thread::get_id(); }
#elif USE_STD_THREAD
typedef std::thread::id id_t;
static inline bool is_current(id_t t) { return t == std::this_thread::get_id(); }
static inline id_t get_current() { return std::this_thread::get_id(); }
#else
typedef pthread_t id_t;
static inline bool is_current(id_t t) { return pthread_equal(pthread_self(), t); }
static inline id_t get_current() { return pthread_self(); }
#endif
virtual ~Thread(){};
/**
* Starts the thread. Does platform specific thread creation and
* configuration then invokes the run method of the Runnable object bound
* to this thread.
*/
virtual void start() = 0;
/**
* Join this thread. If this thread is joinable, the calling thread blocks
* until this thread completes. If the target thread is not joinable, then
* nothing happens.
*/
virtual void join() = 0;
/**
* Gets the thread's platform-specific ID
*/
virtual id_t getId() = 0;
/**
* Gets the runnable object this thread is hosting
*/
virtual boost::shared_ptr<Runnable> runnable() const { return _runnable; }
protected:
virtual void runnable(boost::shared_ptr<Runnable> value) { _runnable = value; }
private:
boost::shared_ptr<Runnable> _runnable;
};
/**
* Factory to create platform-specific thread object and bind them to Runnable
* object for execution
*/
class ThreadFactory {
protected:
ThreadFactory(bool detached) : detached_(detached) { }
public:
virtual ~ThreadFactory() { }
/**
* Gets current detached mode
*/
bool isDetached() const { return detached_; }
/**
* Sets the detached disposition of newly created threads.
*/
void setDetached(bool detached) { detached_ = detached; }
/**
* Create a new thread.
*/
virtual boost::shared_ptr<Thread> newThread(boost::shared_ptr<Runnable> runnable) const = 0;
/**
* Gets the current thread id or unknown_thread_id if the current thread is not a thrift thread
*/
virtual Thread::id_t getCurrentThreadId() const = 0;
/**
* For code readability define the unknown/undefined thread id
*/
static const Thread::id_t unknown_thread_id;
private:
bool detached_;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_THREAD_H_

View file

@ -0,0 +1,588 @@
/*
* 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 <thrift/thrift-config.h>
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/concurrency/Util.h>
#include <boost/shared_ptr.hpp>
#include <stdexcept>
#include <deque>
#include <set>
#if defined(DEBUG)
#include <iostream>
#endif // defined(DEBUG)
namespace apache {
namespace thrift {
namespace concurrency {
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
/**
* ThreadManager class
*
* This class manages a pool of threads. It uses a ThreadFactory to create
* threads. It never actually creates or destroys worker threads, rather
* it maintains statistics on number of idle threads, number of active threads,
* task backlog, and average wait and service times.
*
* There are three different monitors used for signaling different conditions
* however they all share the same mutex_.
*
* @version $Id:$
*/
class ThreadManager::Impl : public ThreadManager {
public:
Impl()
: workerCount_(0),
workerMaxCount_(0),
idleCount_(0),
pendingTaskCountMax_(0),
expiredCount_(0),
state_(ThreadManager::UNINITIALIZED),
monitor_(&mutex_),
maxMonitor_(&mutex_),
workerMonitor_(&mutex_) {}
~Impl() { stop(); }
void start();
void stop();
ThreadManager::STATE state() const { return state_; }
shared_ptr<ThreadFactory> threadFactory() const {
Guard g(mutex_);
return threadFactory_;
}
void threadFactory(shared_ptr<ThreadFactory> value) {
Guard g(mutex_);
if (threadFactory_ && threadFactory_->isDetached() != value->isDetached()) {
throw InvalidArgumentException();
}
threadFactory_ = value;
}
void addWorker(size_t value);
void removeWorker(size_t value);
size_t idleWorkerCount() const { return idleCount_; }
size_t workerCount() const {
Guard g(mutex_);
return workerCount_;
}
size_t pendingTaskCount() const {
Guard g(mutex_);
return tasks_.size();
}
size_t totalTaskCount() const {
Guard g(mutex_);
return tasks_.size() + workerCount_ - idleCount_;
}
size_t pendingTaskCountMax() const {
Guard g(mutex_);
return pendingTaskCountMax_;
}
size_t expiredTaskCount() {
Guard g(mutex_);
return expiredCount_;
}
void pendingTaskCountMax(const size_t value) {
Guard g(mutex_);
pendingTaskCountMax_ = value;
}
void add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration);
void remove(shared_ptr<Runnable> task);
shared_ptr<Runnable> removeNextPending();
void removeExpiredTasks() {
removeExpired(false);
}
void setExpireCallback(ExpireCallback expireCallback);
private:
/**
* Remove one or more expired tasks.
* \param[in] justOne if true, try to remove just one task and return
*/
void removeExpired(bool justOne);
/**
* \returns whether it is acceptable to block, depending on the current thread id
*/
bool canSleep() const;
/**
* Lowers the maximum worker count and blocks until enough worker threads complete
* to get to the new maximum worker limit. The caller is responsible for acquiring
* a lock on the class mutex_.
*/
void removeWorkersUnderLock(size_t value);
size_t workerCount_;
size_t workerMaxCount_;
size_t idleCount_;
size_t pendingTaskCountMax_;
size_t expiredCount_;
ExpireCallback expireCallback_;
ThreadManager::STATE state_;
shared_ptr<ThreadFactory> threadFactory_;
friend class ThreadManager::Task;
typedef std::deque<shared_ptr<Task> > TaskQueue;
TaskQueue tasks_;
Mutex mutex_;
Monitor monitor_;
Monitor maxMonitor_;
Monitor workerMonitor_; // used to synchronize changes in worker count
friend class ThreadManager::Worker;
std::set<shared_ptr<Thread> > workers_;
std::set<shared_ptr<Thread> > deadWorkers_;
std::map<const Thread::id_t, shared_ptr<Thread> > idMap_;
};
class ThreadManager::Task : public Runnable {
public:
enum STATE { WAITING, EXECUTING, TIMEDOUT, COMPLETE };
Task(shared_ptr<Runnable> runnable, int64_t expiration = 0LL)
: runnable_(runnable),
state_(WAITING),
expireTime_(expiration != 0LL ? Util::currentTime() + expiration : 0LL) {}
~Task() {}
void run() {
if (state_ == EXECUTING) {
runnable_->run();
state_ = COMPLETE;
}
}
shared_ptr<Runnable> getRunnable() { return runnable_; }
int64_t getExpireTime() const { return expireTime_; }
private:
shared_ptr<Runnable> runnable_;
friend class ThreadManager::Worker;
STATE state_;
int64_t expireTime_;
};
class ThreadManager::Worker : public Runnable {
enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
public:
Worker(ThreadManager::Impl* manager) : manager_(manager), state_(UNINITIALIZED) {}
~Worker() {}
private:
bool isActive() const {
return (manager_->workerCount_ <= manager_->workerMaxCount_)
|| (manager_->state_ == JOINING && !manager_->tasks_.empty());
}
public:
/**
* Worker entry point
*
* As long as worker thread is running, pull tasks off the task queue and
* execute.
*/
void run() {
Guard g(manager_->mutex_);
/**
* This method has three parts; one is to check for and account for
* admitting a task which happens under a lock. Then the lock is released
* and the task itself is executed. Finally we do some accounting
* under lock again when the task completes.
*/
/**
* Admitting
*/
/**
* Increment worker semaphore and notify manager if worker count reached
* desired max
*/
bool active = manager_->workerCount_ < manager_->workerMaxCount_;
if (active) {
if (++manager_->workerCount_ == manager_->workerMaxCount_) {
manager_->workerMonitor_.notify();
}
}
while (active) {
/**
* While holding manager monitor block for non-empty task queue (Also
* check that the thread hasn't been requested to stop). Once the queue
* is non-empty, dequeue a task, release monitor, and execute. If the
* worker max count has been decremented such that we exceed it, mark
* ourself inactive, decrement the worker count and notify the manager
* (technically we're notifying the next blocked thread but eventually
* the manager will see it.
*/
active = isActive();
while (active && manager_->tasks_.empty()) {
manager_->idleCount_++;
manager_->monitor_.wait();
active = isActive();
manager_->idleCount_--;
}
shared_ptr<ThreadManager::Task> task;
if (active) {
if (!manager_->tasks_.empty()) {
task = manager_->tasks_.front();
manager_->tasks_.pop_front();
if (task->state_ == ThreadManager::Task::WAITING) {
// If the state is changed to anything other than EXECUTING or TIMEDOUT here
// then the execution loop needs to be changed below.
task->state_ =
(task->getExpireTime() && task->getExpireTime() < Util::currentTime()) ?
ThreadManager::Task::TIMEDOUT :
ThreadManager::Task::EXECUTING;
}
}
/* If we have a pending task max and we just dropped below it, wakeup any
thread that might be blocked on add. */
if (manager_->pendingTaskCountMax_ != 0
&& manager_->tasks_.size() <= manager_->pendingTaskCountMax_ - 1) {
manager_->maxMonitor_.notify();
}
}
/**
* Execution - not holding a lock
*/
if (task) {
if (task->state_ == ThreadManager::Task::EXECUTING) {
// Release the lock so we can run the task without blocking the thread manager
manager_->mutex_.unlock();
try {
task->run();
} catch (const std::exception& e) {
GlobalOutput.printf("[ERROR] task->run() raised an exception: %s", e.what());
} catch (...) {
GlobalOutput.printf("[ERROR] task->run() raised an unknown exception");
}
// Re-acquire the lock to proceed in the thread manager
manager_->mutex_.lock();
} else if (manager_->expireCallback_) {
// The only other state the task could have been in is TIMEDOUT (see above)
manager_->expireCallback_(task->getRunnable());
manager_->expiredCount_++;
}
}
}
/**
* Final accounting for the worker thread that is done working
*/
manager_->deadWorkers_.insert(this->thread());
if (--manager_->workerCount_ == manager_->workerMaxCount_) {
manager_->workerMonitor_.notify();
}
}
private:
ThreadManager::Impl* manager_;
friend class ThreadManager::Impl;
STATE state_;
};
void ThreadManager::Impl::addWorker(size_t value) {
std::set<shared_ptr<Thread> > newThreads;
for (size_t ix = 0; ix < value; ix++) {
shared_ptr<ThreadManager::Worker> worker
= shared_ptr<ThreadManager::Worker>(new ThreadManager::Worker(this));
newThreads.insert(threadFactory_->newThread(worker));
}
Guard g(mutex_);
workerMaxCount_ += value;
workers_.insert(newThreads.begin(), newThreads.end());
for (std::set<shared_ptr<Thread> >::iterator ix = newThreads.begin(); ix != newThreads.end();
++ix) {
shared_ptr<ThreadManager::Worker> worker
= dynamic_pointer_cast<ThreadManager::Worker, Runnable>((*ix)->runnable());
worker->state_ = ThreadManager::Worker::STARTING;
(*ix)->start();
idMap_.insert(std::pair<const Thread::id_t, shared_ptr<Thread> >((*ix)->getId(), *ix));
}
while (workerCount_ != workerMaxCount_) {
workerMonitor_.wait();
}
}
void ThreadManager::Impl::start() {
Guard g(mutex_);
if (state_ == ThreadManager::STOPPED) {
return;
}
if (state_ == ThreadManager::UNINITIALIZED) {
if (!threadFactory_) {
throw InvalidArgumentException();
}
state_ = ThreadManager::STARTED;
monitor_.notifyAll();
}
while (state_ == STARTING) {
monitor_.wait();
}
}
void ThreadManager::Impl::stop() {
Guard g(mutex_);
bool doStop = false;
if (state_ != ThreadManager::STOPPING && state_ != ThreadManager::JOINING
&& state_ != ThreadManager::STOPPED) {
doStop = true;
state_ = ThreadManager::JOINING;
}
if (doStop) {
removeWorkersUnderLock(workerCount_);
}
state_ = ThreadManager::STOPPED;
}
void ThreadManager::Impl::removeWorker(size_t value) {
Guard g(mutex_);
removeWorkersUnderLock(value);
}
void ThreadManager::Impl::removeWorkersUnderLock(size_t value) {
if (value > workerMaxCount_) {
throw InvalidArgumentException();
}
workerMaxCount_ -= value;
if (idleCount_ > value) {
// There are more idle workers than we need to remove,
// so notify enough of them so they can terminate.
for (size_t ix = 0; ix < value; ix++) {
monitor_.notify();
}
} else {
// There are as many or less idle workers than we need to remove,
// so just notify them all so they can terminate.
monitor_.notifyAll();
}
while (workerCount_ != workerMaxCount_) {
workerMonitor_.wait();
}
for (std::set<shared_ptr<Thread> >::iterator ix = deadWorkers_.begin();
ix != deadWorkers_.end();
++ix) {
// when used with a joinable thread factory, we join the threads as we remove them
if (!threadFactory_->isDetached()) {
(*ix)->join();
}
idMap_.erase((*ix)->getId());
workers_.erase(*ix);
}
deadWorkers_.clear();
}
bool ThreadManager::Impl::canSleep() const {
const Thread::id_t id = threadFactory_->getCurrentThreadId();
return idMap_.find(id) == idMap_.end();
}
void ThreadManager::Impl::add(shared_ptr<Runnable> value, int64_t timeout, int64_t expiration) {
Guard g(mutex_, timeout);
if (!g) {
throw TimedOutException();
}
if (state_ != ThreadManager::STARTED) {
throw IllegalStateException(
"ThreadManager::Impl::add ThreadManager "
"not started");
}
// if we're at a limit, remove an expired task to see if the limit clears
if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
removeExpired(true);
}
if (pendingTaskCountMax_ > 0 && (tasks_.size() >= pendingTaskCountMax_)) {
if (canSleep() && timeout >= 0) {
while (pendingTaskCountMax_ > 0 && tasks_.size() >= pendingTaskCountMax_) {
// This is thread safe because the mutex is shared between monitors.
maxMonitor_.wait(timeout);
}
} else {
throw TooManyPendingTasksException();
}
}
tasks_.push_back(shared_ptr<ThreadManager::Task>(new ThreadManager::Task(value, expiration)));
// If idle thread is available notify it, otherwise all worker threads are
// running and will get around to this task in time.
if (idleCount_ > 0) {
monitor_.notify();
}
}
void ThreadManager::Impl::remove(shared_ptr<Runnable> task) {
Guard g(mutex_);
if (state_ != ThreadManager::STARTED) {
throw IllegalStateException(
"ThreadManager::Impl::remove ThreadManager not "
"started");
}
for (TaskQueue::iterator it = tasks_.begin(); it != tasks_.end(); ++it)
{
if ((*it)->getRunnable() == task)
{
tasks_.erase(it);
return;
}
}
}
boost::shared_ptr<Runnable> ThreadManager::Impl::removeNextPending() {
Guard g(mutex_);
if (state_ != ThreadManager::STARTED) {
throw IllegalStateException(
"ThreadManager::Impl::removeNextPending "
"ThreadManager not started");
}
if (tasks_.empty()) {
return boost::shared_ptr<Runnable>();
}
shared_ptr<ThreadManager::Task> task = tasks_.front();
tasks_.pop_front();
return task->getRunnable();
}
void ThreadManager::Impl::removeExpired(bool justOne) {
// this is always called under a lock
int64_t now = 0LL;
for (TaskQueue::iterator it = tasks_.begin(); it != tasks_.end(); )
{
if (now == 0LL) {
now = Util::currentTime();
}
if ((*it)->getExpireTime() > 0LL && (*it)->getExpireTime() < now) {
if (expireCallback_) {
expireCallback_((*it)->getRunnable());
}
it = tasks_.erase(it);
++expiredCount_;
if (justOne) {
return;
}
}
else
{
++it;
}
}
}
void ThreadManager::Impl::setExpireCallback(ExpireCallback expireCallback) {
Guard g(mutex_);
expireCallback_ = expireCallback;
}
class SimpleThreadManager : public ThreadManager::Impl {
public:
SimpleThreadManager(size_t workerCount = 4, size_t pendingTaskCountMax = 0)
: workerCount_(workerCount), pendingTaskCountMax_(pendingTaskCountMax) {}
void start() {
ThreadManager::Impl::pendingTaskCountMax(pendingTaskCountMax_);
ThreadManager::Impl::start();
addWorker(workerCount_);
}
private:
const size_t workerCount_;
const size_t pendingTaskCountMax_;
};
shared_ptr<ThreadManager> ThreadManager::newThreadManager() {
return shared_ptr<ThreadManager>(new ThreadManager::Impl());
}
shared_ptr<ThreadManager> ThreadManager::newSimpleThreadManager(size_t count,
size_t pendingTaskCountMax) {
return shared_ptr<ThreadManager>(new SimpleThreadManager(count, pendingTaskCountMax));
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,214 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_
#define _THRIFT_CONCURRENCY_THREADMANAGER_H_ 1
#include <boost/shared_ptr.hpp>
#include <thrift/cxxfunctional.h>
#include <sys/types.h>
#include <thrift/concurrency/Thread.h>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Thread Pool Manager and related classes
*
* @version $Id:$
*/
class ThreadManager;
/**
* ThreadManager class
*
* This class manages a pool of threads. It uses a ThreadFactory to create
* threads. It never actually creates or destroys worker threads, rather
* it maintains statistics on number of idle threads, number of active threads,
* task backlog, and average wait and service times and informs the PoolPolicy
* object bound to instances of this manager of interesting transitions. It is
* then up the PoolPolicy object to decide if the thread pool size needs to be
* adjusted and call this object addWorker and removeWorker methods to make
* changes.
*
* This design allows different policy implementations to use this code to
* handle basic worker thread management and worker task execution and focus on
* policy issues. The simplest policy, StaticPolicy, does nothing other than
* create a fixed number of threads.
*/
class ThreadManager {
protected:
ThreadManager() {}
public:
typedef apache::thrift::stdcxx::function<void(boost::shared_ptr<Runnable>)> ExpireCallback;
virtual ~ThreadManager() {}
/**
* Starts the thread manager. Verifies all attributes have been properly
* initialized, then allocates necessary resources to begin operation
*/
virtual void start() = 0;
/**
* Stops the thread manager. Aborts all remaining unprocessed task, shuts
* down all created worker threads, and releases all allocated resources.
* This method blocks for all worker threads to complete, thus it can
* potentially block forever if a worker thread is running a task that
* won't terminate.
*
* Worker threads will be joined depending on the threadFactory's detached
* disposition.
*/
virtual void stop() = 0;
enum STATE { UNINITIALIZED, STARTING, STARTED, JOINING, STOPPING, STOPPED };
virtual STATE state() const = 0;
/**
* \returns the current thread factory
*/
virtual boost::shared_ptr<ThreadFactory> threadFactory() const = 0;
/**
* Set the thread factory.
* \throws InvalidArgumentException if the new thread factory has a different
* detached disposition than the one replacing it
*/
virtual void threadFactory(boost::shared_ptr<ThreadFactory> value) = 0;
/**
* Adds worker thread(s).
*/
virtual void addWorker(size_t value = 1) = 0;
/**
* Removes worker thread(s).
* Threads are joined if the thread factory detached disposition allows it.
* Blocks until the number of worker threads reaches the new limit.
* \param[in] value the number to remove
* \throws InvalidArgumentException if the value is greater than the number
* of workers
*/
virtual void removeWorker(size_t value = 1) = 0;
/**
* Gets the current number of idle worker threads
*/
virtual size_t idleWorkerCount() const = 0;
/**
* Gets the current number of total worker threads
*/
virtual size_t workerCount() const = 0;
/**
* Gets the current number of pending tasks
*/
virtual size_t pendingTaskCount() const = 0;
/**
* Gets the current number of pending and executing tasks
*/
virtual size_t totalTaskCount() const = 0;
/**
* Gets the maximum pending task count. 0 indicates no maximum
*/
virtual size_t pendingTaskCountMax() const = 0;
/**
* Gets the number of tasks which have been expired without being run
* since start() was called.
*/
virtual size_t expiredTaskCount() = 0;
/**
* Adds a task to be executed at some time in the future by a worker thread.
*
* This method will block if pendingTaskCountMax() in not zero and pendingTaskCount()
* is greater than or equalt to pendingTaskCountMax(). If this method is called in the
* context of a ThreadManager worker thread it will throw a
* TooManyPendingTasksException
*
* @param task The task to queue for execution
*
* @param timeout Time to wait in milliseconds to add a task when a pending-task-count
* is specified. Specific cases:
* timeout = 0 : Wait forever to queue task.
* timeout = -1 : Return immediately if pending task count exceeds specified max
* @param expiration when nonzero, the number of milliseconds the task is valid
* to be run; if exceeded, the task will be dropped off the queue and not run.
*
* @throws TooManyPendingTasksException Pending task count exceeds max pending task count
*/
virtual void add(boost::shared_ptr<Runnable> task,
int64_t timeout = 0LL,
int64_t expiration = 0LL) = 0;
/**
* Removes a pending task
*/
virtual void remove(boost::shared_ptr<Runnable> task) = 0;
/**
* Remove the next pending task which would be run.
*
* @return the task removed.
*/
virtual boost::shared_ptr<Runnable> removeNextPending() = 0;
/**
* Remove tasks from front of task queue that have expired.
*/
virtual void removeExpiredTasks() = 0;
/**
* Set a callback to be called when a task is expired and not run.
*
* @param expireCallback a function called with the shared_ptr<Runnable> for
* the expired task.
*/
virtual void setExpireCallback(ExpireCallback expireCallback) = 0;
static boost::shared_ptr<ThreadManager> newThreadManager();
/**
* Creates a simple thread manager the uses count number of worker threads and has
* a pendingTaskCountMax maximum pending tasks. The default, 0, specified no limit
* on pending tasks
*/
static boost::shared_ptr<ThreadManager> newSimpleThreadManager(size_t count = 4,
size_t pendingTaskCountMax = 0);
class Task;
class Worker;
class Impl;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_THREADMANAGER_H_

View file

@ -0,0 +1,305 @@
/*
* 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 <thrift/concurrency/TimerManager.h>
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Util.h>
#include <assert.h>
#include <iostream>
#include <set>
namespace apache {
namespace thrift {
namespace concurrency {
using boost::shared_ptr;
/**
* TimerManager class
*
* @version $Id:$
*/
class TimerManager::Task : public Runnable {
public:
enum STATE { WAITING, EXECUTING, CANCELLED, COMPLETE };
Task(shared_ptr<Runnable> runnable) : runnable_(runnable), state_(WAITING) {}
~Task() {}
void run() {
if (state_ == EXECUTING) {
runnable_->run();
state_ = COMPLETE;
}
}
private:
shared_ptr<Runnable> runnable_;
friend class TimerManager::Dispatcher;
STATE state_;
};
class TimerManager::Dispatcher : public Runnable {
public:
Dispatcher(TimerManager* manager) : manager_(manager) {}
~Dispatcher() {}
/**
* Dispatcher entry point
*
* As long as dispatcher thread is running, pull tasks off the task taskMap_
* and execute.
*/
void run() {
{
Synchronized s(manager_->monitor_);
if (manager_->state_ == TimerManager::STARTING) {
manager_->state_ = TimerManager::STARTED;
manager_->monitor_.notifyAll();
}
}
do {
std::set<shared_ptr<TimerManager::Task> > expiredTasks;
{
Synchronized s(manager_->monitor_);
task_iterator expiredTaskEnd;
int64_t now = Util::currentTime();
while (manager_->state_ == TimerManager::STARTED
&& (expiredTaskEnd = manager_->taskMap_.upper_bound(now))
== manager_->taskMap_.begin()) {
int64_t timeout = 0LL;
if (!manager_->taskMap_.empty()) {
timeout = manager_->taskMap_.begin()->first - now;
}
assert((timeout != 0 && manager_->taskCount_ > 0)
|| (timeout == 0 && manager_->taskCount_ == 0));
try {
manager_->monitor_.wait(timeout);
} catch (TimedOutException&) {
}
now = Util::currentTime();
}
if (manager_->state_ == TimerManager::STARTED) {
for (task_iterator ix = manager_->taskMap_.begin(); ix != expiredTaskEnd; ix++) {
shared_ptr<TimerManager::Task> task = ix->second;
expiredTasks.insert(task);
if (task->state_ == TimerManager::Task::WAITING) {
task->state_ = TimerManager::Task::EXECUTING;
}
manager_->taskCount_--;
}
manager_->taskMap_.erase(manager_->taskMap_.begin(), expiredTaskEnd);
}
}
for (std::set<shared_ptr<Task> >::iterator ix = expiredTasks.begin();
ix != expiredTasks.end();
++ix) {
(*ix)->run();
}
} while (manager_->state_ == TimerManager::STARTED);
{
Synchronized s(manager_->monitor_);
if (manager_->state_ == TimerManager::STOPPING) {
manager_->state_ = TimerManager::STOPPED;
manager_->monitor_.notify();
}
}
return;
}
private:
TimerManager* manager_;
friend class TimerManager;
};
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4355) // 'this' used in base member initializer list
#endif
TimerManager::TimerManager()
: taskCount_(0),
state_(TimerManager::UNINITIALIZED),
dispatcher_(shared_ptr<Dispatcher>(new Dispatcher(this))) {
}
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
TimerManager::~TimerManager() {
// If we haven't been explicitly stopped, do so now. We don't need to grab
// the monitor here, since stop already takes care of reentrancy.
if (state_ != STOPPED) {
try {
stop();
} catch (...) {
// We're really hosed.
}
}
}
void TimerManager::start() {
bool doStart = false;
{
Synchronized s(monitor_);
if (!threadFactory_) {
throw InvalidArgumentException();
}
if (state_ == TimerManager::UNINITIALIZED) {
state_ = TimerManager::STARTING;
doStart = true;
}
}
if (doStart) {
dispatcherThread_ = threadFactory_->newThread(dispatcher_);
dispatcherThread_->start();
}
{
Synchronized s(monitor_);
while (state_ == TimerManager::STARTING) {
monitor_.wait();
}
assert(state_ != TimerManager::STARTING);
}
}
void TimerManager::stop() {
bool doStop = false;
{
Synchronized s(monitor_);
if (state_ == TimerManager::UNINITIALIZED) {
state_ = TimerManager::STOPPED;
} else if (state_ != STOPPING && state_ != STOPPED) {
doStop = true;
state_ = STOPPING;
monitor_.notifyAll();
}
while (state_ != STOPPED) {
monitor_.wait();
}
}
if (doStop) {
// Clean up any outstanding tasks
taskMap_.clear();
// Remove dispatcher's reference to us.
dispatcher_->manager_ = NULL;
}
}
shared_ptr<const ThreadFactory> TimerManager::threadFactory() const {
Synchronized s(monitor_);
return threadFactory_;
}
void TimerManager::threadFactory(shared_ptr<const ThreadFactory> value) {
Synchronized s(monitor_);
threadFactory_ = value;
}
size_t TimerManager::taskCount() const {
return taskCount_;
}
void TimerManager::add(shared_ptr<Runnable> task, int64_t timeout) {
int64_t now = Util::currentTime();
timeout += now;
{
Synchronized s(monitor_);
if (state_ != TimerManager::STARTED) {
throw IllegalStateException();
}
// If the task map is empty, we will kick the dispatcher for sure. Otherwise, we kick him
// if the expiration time is shorter than the current value. Need to test before we insert,
// because the new task might insert at the front.
bool notifyRequired = (taskCount_ == 0) ? true : timeout < taskMap_.begin()->first;
taskCount_++;
taskMap_.insert(
std::pair<int64_t, shared_ptr<Task> >(timeout, shared_ptr<Task>(new Task(task))));
// If the task map was empty, or if we have an expiration that is earlier
// than any previously seen, kick the dispatcher so it can update its
// timeout
if (notifyRequired) {
monitor_.notify();
}
}
}
void TimerManager::add(shared_ptr<Runnable> task, const struct THRIFT_TIMESPEC& value) {
int64_t expiration;
Util::toMilliseconds(expiration, value);
int64_t now = Util::currentTime();
if (expiration < now) {
throw InvalidArgumentException();
}
add(task, expiration - now);
}
void TimerManager::add(shared_ptr<Runnable> task, const struct timeval& value) {
int64_t expiration;
Util::toMilliseconds(expiration, value);
int64_t now = Util::currentTime();
if (expiration < now) {
throw InvalidArgumentException();
}
add(task, expiration - now);
}
void TimerManager::remove(shared_ptr<Runnable> task) {
(void)task;
Synchronized s(monitor_);
if (state_ != TimerManager::STARTED) {
throw IllegalStateException();
}
}
TimerManager::STATE TimerManager::state() const {
return state_;
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,126 @@
/*
* 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 _THRIFT_CONCURRENCY_TIMERMANAGER_H_
#define _THRIFT_CONCURRENCY_TIMERMANAGER_H_ 1
#include <thrift/concurrency/Exception.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/concurrency/Thread.h>
#include <boost/shared_ptr.hpp>
#include <map>
#include <time.h>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Timer Manager
*
* This class dispatches timer tasks when they fall due.
*
* @version $Id:$
*/
class TimerManager {
public:
TimerManager();
virtual ~TimerManager();
virtual boost::shared_ptr<const ThreadFactory> threadFactory() const;
virtual void threadFactory(boost::shared_ptr<const ThreadFactory> value);
/**
* Starts the timer manager service
*
* @throws IllegalArgumentException Missing thread factory attribute
*/
virtual void start();
/**
* Stops the timer manager service
*/
virtual void stop();
virtual size_t taskCount() const;
/**
* Adds a task to be executed at some time in the future by a worker thread.
*
* @param task The task to execute
* @param timeout Time in milliseconds to delay before executing task
*/
virtual void add(boost::shared_ptr<Runnable> task, int64_t timeout);
/**
* Adds a task to be executed at some time in the future by a worker thread.
*
* @param task The task to execute
* @param timeout Absolute time in the future to execute task.
*/
virtual void add(boost::shared_ptr<Runnable> task, const struct THRIFT_TIMESPEC& timeout);
/**
* Adds a task to be executed at some time in the future by a worker thread.
*
* @param task The task to execute
* @param timeout Absolute time in the future to execute task.
*/
virtual void add(boost::shared_ptr<Runnable> task, const struct timeval& timeout);
/**
* Removes a pending task
*
* @throws NoSuchTaskException Specified task doesn't exist. It was either
* processed already or this call was made for a
* task that was never added to this timer
*
* @throws UncancellableTaskException Specified task is already being
* executed or has completed execution.
*/
virtual void remove(boost::shared_ptr<Runnable> task);
enum STATE { UNINITIALIZED, STARTING, STARTED, STOPPING, STOPPED };
virtual STATE state() const;
private:
boost::shared_ptr<const ThreadFactory> threadFactory_;
class Task;
friend class Task;
std::multimap<int64_t, boost::shared_ptr<Task> > taskMap_;
size_t taskCount_;
Monitor monitor_;
STATE state_;
class Dispatcher;
friend class Dispatcher;
boost::shared_ptr<Dispatcher> dispatcher_;
boost::shared_ptr<Thread> dispatcherThread_;
typedef std::multimap<int64_t, boost::shared_ptr<TimerManager::Task> >::iterator task_iterator;
typedef std::pair<task_iterator, task_iterator> task_range;
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_TIMERMANAGER_H_

View file

@ -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.
*/
#include <thrift/thrift-config.h>
#include <thrift/Thrift.h>
#include <thrift/concurrency/Util.h>
#if defined(HAVE_SYS_TIME_H)
#include <sys/time.h>
#endif
namespace apache {
namespace thrift {
namespace concurrency {
int64_t Util::currentTimeTicks(int64_t ticksPerSec) {
int64_t result;
struct timeval now;
int ret = THRIFT_GETTIMEOFDAY(&now, NULL);
assert(ret == 0);
THRIFT_UNUSED_VARIABLE(ret); // squelching "unused variable" warning
toTicks(result, now, ticksPerSec);
return result;
}
}
}
} // apache::thrift::concurrency

View file

@ -0,0 +1,151 @@
/*
* 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 _THRIFT_CONCURRENCY_UTIL_H_
#define _THRIFT_CONCURRENCY_UTIL_H_ 1
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <thrift/transport/PlatformSocket.h>
namespace apache {
namespace thrift {
namespace concurrency {
/**
* Utility methods
*
* This class contains basic utility methods for converting time formats,
* and other common platform-dependent concurrency operations.
* It should not be included in API headers for other concurrency library
* headers, since it will, by definition, pull in all sorts of horrid
* platform dependent stuff. Rather it should be inluded directly in
* concurrency library implementation source.
*
* @version $Id:$
*/
class Util {
static const int64_t NS_PER_S = 1000000000LL;
static const int64_t US_PER_S = 1000000LL;
static const int64_t MS_PER_S = 1000LL;
static const int64_t NS_PER_MS = NS_PER_S / MS_PER_S;
static const int64_t NS_PER_US = NS_PER_S / US_PER_S;
static const int64_t US_PER_MS = US_PER_S / MS_PER_S;
public:
/**
* Converts millisecond timestamp into a THRIFT_TIMESPEC struct
*
* @param struct THRIFT_TIMESPEC& result
* @param time or duration in milliseconds
*/
static void toTimespec(struct THRIFT_TIMESPEC& result, int64_t value) {
result.tv_sec = value / MS_PER_S; // ms to s
result.tv_nsec = (value % MS_PER_S) * NS_PER_MS; // ms to ns
}
static void toTimeval(struct timeval& result, int64_t value) {
result.tv_sec = static_cast<uint32_t>(value / MS_PER_S); // ms to s
result.tv_usec = static_cast<uint32_t>((value % MS_PER_S) * US_PER_MS); // ms to us
}
static void toTicks(int64_t& result,
int64_t secs,
int64_t oldTicks,
int64_t oldTicksPerSec,
int64_t newTicksPerSec) {
result = secs * newTicksPerSec;
result += oldTicks * newTicksPerSec / oldTicksPerSec;
int64_t oldPerNew = oldTicksPerSec / newTicksPerSec;
if (oldPerNew && ((oldTicks % oldPerNew) >= (oldPerNew / 2))) {
++result;
}
}
/**
* Converts struct THRIFT_TIMESPEC to arbitrary-sized ticks since epoch
*/
static void toTicks(int64_t& result, const struct THRIFT_TIMESPEC& value, int64_t ticksPerSec) {
return toTicks(result, value.tv_sec, value.tv_nsec, NS_PER_S, ticksPerSec);
}
/**
* Converts struct timeval to arbitrary-sized ticks since epoch
*/
static void toTicks(int64_t& result, const struct timeval& value, int64_t ticksPerSec) {
return toTicks(result, (unsigned long)value.tv_sec, (unsigned long)value.tv_usec, US_PER_S, ticksPerSec);
}
/**
* Converts struct THRIFT_TIMESPEC to milliseconds
*/
static void toMilliseconds(int64_t& result, const struct THRIFT_TIMESPEC& value) {
return toTicks(result, value, MS_PER_S);
}
/**
* Converts struct timeval to milliseconds
*/
static void toMilliseconds(int64_t& result, const struct timeval& value) {
return toTicks(result, value, MS_PER_S);
}
/**
* Converts struct THRIFT_TIMESPEC to microseconds
*/
static void toUsec(int64_t& result, const struct THRIFT_TIMESPEC& value) {
return toTicks(result, value, US_PER_S);
}
/**
* Converts struct timeval to microseconds
*/
static void toUsec(int64_t& result, const struct timeval& value) {
return toTicks(result, value, US_PER_S);
}
/**
* Get current time as a number of arbitrary-size ticks from epoch
*/
static int64_t currentTimeTicks(int64_t ticksPerSec);
/**
* Get current time as milliseconds from epoch
*/
static int64_t currentTime() { return currentTimeTicks(MS_PER_S); }
/**
* Get current time as micros from epoch
*/
static int64_t currentTimeUsec() { return currentTimeTicks(US_PER_S); }
};
}
}
} // apache::thrift::concurrency
#endif // #ifndef _THRIFT_CONCURRENCY_UTIL_H_

View file

@ -0,0 +1,132 @@
/*
* 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 _THRIFT_CXXFUNCTIONAL_H_
#define _THRIFT_CXXFUNCTIONAL_H_ 1
// clang-format off
/**
* Loads <functional> from the 'right' location, depending
* on compiler and whether or not it's using C++03 with TR1
* or C++11.
*/
/*
* MSVC 10 and 11 have the <functional> stuff at <functional>.
* In MSVC 10 all of the implementations live in std::tr1.
* In MSVC 11 all of the implementations live in std, with aliases
* in std::tr1 to point to the ones in std.
*/
#if defined(_WIN32) && !defined(__MINGW32__)
#define _THRIFT_USING_MICROSOFT_STDLIB 1
#endif
#ifdef __clang__
/* Clang has two options, depending on standard library:
* - no -stdlib or -stdlib=libstdc++ set; uses GNU libstdc++.
* <tr1/functional>
* - -stdlib=libc++; uses LLVM libc++.
* <functional>, no 'std::tr1'.
*
* The compiler itself doesn't define anything differently
* depending on the value of -stdlib, but the library headers
* will set different preprocessor options. In order to check,
* though, we have to pull in some library header.
*/
#include <utility>
/* With LLVM libc++, utility pulls in __config, which sets
_LIBCPP_VERSION. */
#if defined(_LIBCPP_VERSION)
#define _THRIFT_USING_CLANG_LIBCXX 1
/* With GNU libstdc++, utility pulls in bits/c++config.h,
which sets __GLIBCXX__. */
#elif defined(__GLIBCXX__)
#define _THRIFT_USING_GNU_LIBSTDCXX 1
/* No idea. */
#else
#error Unable to detect which C++ standard library is in use.
#endif
#elif __GNUC__
#define _THRIFT_USING_GNU_LIBSTDCXX 1
#endif
#if _THRIFT_USING_MICROSOFT_STDLIB
#include <functional>
namespace apache { namespace thrift { namespace stdcxx {
using ::std::tr1::function;
using ::std::tr1::bind;
namespace placeholders {
using ::std::tr1::placeholders::_1;
using ::std::tr1::placeholders::_2;
using ::std::tr1::placeholders::_3;
using ::std::tr1::placeholders::_4;
using ::std::tr1::placeholders::_5;
using ::std::tr1::placeholders::_6;
} // apache::thrift::stdcxx::placeholders
}}} // apache::thrift::stdcxx
#elif _THRIFT_USING_CLANG_LIBCXX
#include <functional>
namespace apache { namespace thrift { namespace stdcxx {
using ::std::function;
using ::std::bind;
namespace placeholders {
using ::std::placeholders::_1;
using ::std::placeholders::_2;
using ::std::placeholders::_3;
using ::std::placeholders::_4;
using ::std::placeholders::_5;
using ::std::placeholders::_6;
} // apache::thrift::stdcxx::placeholders
}}} // apache::thrift::stdcxx
#elif _THRIFT_USING_GNU_LIBSTDCXX
#ifdef USE_BOOST_THREAD
#include <boost/tr1/functional.hpp>
#else
#include <tr1/functional>
#endif
namespace apache { namespace thrift { namespace stdcxx {
using ::std::tr1::function;
using ::std::tr1::bind;
namespace placeholders {
using ::std::tr1::placeholders::_1;
using ::std::tr1::placeholders::_2;
using ::std::tr1::placeholders::_3;
using ::std::tr1::placeholders::_4;
using ::std::tr1::placeholders::_5;
using ::std::tr1::placeholders::_6;
} // apache::thrift::stdcxx::placeholders
}}} // apache::thrift::stdcxx
#endif
// Alias for thrift c++ compatibility namespace
namespace tcxx = apache::thrift::stdcxx;
#endif // #ifndef _THRIFT_CXXFUNCTIONAL_H_

View file

@ -0,0 +1,132 @@
/*
* 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 <thrift/processor/PeekProcessor.h>
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
using namespace apache::thrift;
namespace apache {
namespace thrift {
namespace processor {
PeekProcessor::PeekProcessor() {
memoryBuffer_.reset(new TMemoryBuffer());
targetTransport_ = memoryBuffer_;
}
PeekProcessor::~PeekProcessor() {
}
void PeekProcessor::initialize(boost::shared_ptr<TProcessor> actualProcessor,
boost::shared_ptr<TProtocolFactory> protocolFactory,
boost::shared_ptr<TPipedTransportFactory> transportFactory) {
actualProcessor_ = actualProcessor;
pipedProtocol_ = protocolFactory->getProtocol(targetTransport_);
transportFactory_ = transportFactory;
transportFactory_->initializeTargetTransport(targetTransport_);
}
boost::shared_ptr<TTransport> PeekProcessor::getPipedTransport(boost::shared_ptr<TTransport> in) {
return transportFactory_->getTransport(in);
}
void PeekProcessor::setTargetTransport(boost::shared_ptr<TTransport> targetTransport) {
targetTransport_ = targetTransport;
if (boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport_)) {
memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(targetTransport);
} else if (boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)) {
memoryBuffer_ = boost::dynamic_pointer_cast<TMemoryBuffer>(
boost::dynamic_pointer_cast<TPipedTransport>(targetTransport_)->getTargetTransport());
}
if (!memoryBuffer_) {
throw TException(
"Target transport must be a TMemoryBuffer or a TPipedTransport with TMemoryBuffer");
}
}
bool PeekProcessor::process(boost::shared_ptr<TProtocol> in,
boost::shared_ptr<TProtocol> out,
void* connectionContext) {
std::string fname;
TMessageType mtype;
int32_t seqid;
in->readMessageBegin(fname, mtype, seqid);
if (mtype != T_CALL && mtype != T_ONEWAY) {
throw TException("Unexpected message type");
}
// Peek at the name
peekName(fname);
TType ftype;
int16_t fid;
while (true) {
in->readFieldBegin(fname, ftype, fid);
if (ftype == T_STOP) {
break;
}
// Peek at the variable
peek(in, ftype, fid);
in->readFieldEnd();
}
in->readMessageEnd();
in->getTransport()->readEnd();
//
// All the data is now in memoryBuffer_ and ready to be processed
//
// Let's first take a peek at the full data in memory
uint8_t* buffer;
uint32_t size;
memoryBuffer_->getBuffer(&buffer, &size);
peekBuffer(buffer, size);
// Done peeking at variables
peekEnd();
bool ret = actualProcessor_->process(pipedProtocol_, out, connectionContext);
memoryBuffer_->resetBuffer();
return ret;
}
void PeekProcessor::peekName(const std::string& fname) {
(void)fname;
}
void PeekProcessor::peekBuffer(uint8_t* buffer, uint32_t size) {
(void)buffer;
(void)size;
}
void PeekProcessor::peek(boost::shared_ptr<TProtocol> in, TType ftype, int16_t fid) {
(void)fid;
in->skip(ftype);
}
void PeekProcessor::peekEnd() {
}
}
}
}

View file

@ -0,0 +1,83 @@
/*
* 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 PEEKPROCESSOR_H
#define PEEKPROCESSOR_H
#include <string>
#include <thrift/TProcessor.h>
#include <thrift/transport/TTransport.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TBufferTransports.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace processor {
/*
* Class for peeking at the raw data that is being processed by another processor
* and gives the derived class a chance to change behavior accordingly
*
*/
class PeekProcessor : public apache::thrift::TProcessor {
public:
PeekProcessor();
virtual ~PeekProcessor();
// Input here: actualProcessor - the underlying processor
// protocolFactory - the protocol factory used to wrap the memory buffer
// transportFactory - this TPipedTransportFactory is used to wrap the source transport
// via a call to getPipedTransport
void initialize(
boost::shared_ptr<apache::thrift::TProcessor> actualProcessor,
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
boost::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory);
boost::shared_ptr<apache::thrift::transport::TTransport> getPipedTransport(
boost::shared_ptr<apache::thrift::transport::TTransport> in);
void setTargetTransport(boost::shared_ptr<apache::thrift::transport::TTransport> targetTransport);
virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> in,
boost::shared_ptr<apache::thrift::protocol::TProtocol> out,
void* connectionContext);
// The following three functions can be overloaded by child classes to
// achieve desired peeking behavior
virtual void peekName(const std::string& fname);
virtual void peekBuffer(uint8_t* buffer, uint32_t size);
virtual void peek(boost::shared_ptr<apache::thrift::protocol::TProtocol> in,
apache::thrift::protocol::TType ftype,
int16_t fid);
virtual void peekEnd();
private:
boost::shared_ptr<apache::thrift::TProcessor> actualProcessor_;
boost::shared_ptr<apache::thrift::protocol::TProtocol> pipedProtocol_;
boost::shared_ptr<apache::thrift::transport::TPipedTransportFactory> transportFactory_;
boost::shared_ptr<apache::thrift::transport::TMemoryBuffer> memoryBuffer_;
boost::shared_ptr<apache::thrift::transport::TTransport> targetTransport_;
};
}
}
} // apache::thrift::processor
#endif

View file

@ -0,0 +1,242 @@
/*
* 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 STATSPROCESSOR_H
#define STATSPROCESSOR_H
#include <boost/shared_ptr.hpp>
#include <thrift/transport/TTransport.h>
#include <thrift/protocol/TProtocol.h>
#include <TProcessor.h>
namespace apache {
namespace thrift {
namespace processor {
/*
* Class for keeping track of function call statistics and printing them if desired
*
*/
class StatsProcessor : public apache::thrift::TProcessor {
public:
StatsProcessor(bool print, bool frequency) : print_(print), frequency_(frequency) {}
virtual ~StatsProcessor(){};
virtual bool process(boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot,
boost::shared_ptr<apache::thrift::protocol::TProtocol> poprot,
void* serverContext) {
piprot_ = piprot;
std::string fname;
apache::thrift::protocol::TMessageType mtype;
int32_t seqid;
piprot_->readMessageBegin(fname, mtype, seqid);
if (mtype != apache::thrift::protocol::T_CALL && mtype != apache::thrift::protocol::T_ONEWAY) {
if (print_) {
printf("Unknown message type\n");
}
throw apache::thrift::TException("Unexpected message type");
}
if (print_) {
printf("%s (", fname.c_str());
}
if (frequency_) {
if (frequency_map_.find(fname) != frequency_map_.end()) {
frequency_map_[fname]++;
} else {
frequency_map_[fname] = 1;
}
}
apache::thrift::protocol::TType ftype;
int16_t fid;
while (true) {
piprot_->readFieldBegin(fname, ftype, fid);
if (ftype == apache::thrift::protocol::T_STOP) {
break;
}
printAndPassToBuffer(ftype);
if (print_) {
printf(", ");
}
}
if (print_) {
printf("\b\b)\n");
}
return true;
}
const std::map<std::string, int64_t>& get_frequency_map() { return frequency_map_; }
protected:
void printAndPassToBuffer(apache::thrift::protocol::TType ftype) {
switch (ftype) {
case apache::thrift::protocol::T_BOOL: {
bool boolv;
piprot_->readBool(boolv);
if (print_) {
printf("%d", boolv);
}
} break;
case apache::thrift::protocol::T_BYTE: {
int8_t bytev;
piprot_->readByte(bytev);
if (print_) {
printf("%d", bytev);
}
} break;
case apache::thrift::protocol::T_I16: {
int16_t i16;
piprot_->readI16(i16);
if (print_) {
printf("%d", i16);
}
} break;
case apache::thrift::protocol::T_I32: {
int32_t i32;
piprot_->readI32(i32);
if (print_) {
printf("%d", i32);
}
} break;
case apache::thrift::protocol::T_I64: {
int64_t i64;
piprot_->readI64(i64);
if (print_) {
printf("%ld", i64);
}
} break;
case apache::thrift::protocol::T_DOUBLE: {
double dub;
piprot_->readDouble(dub);
if (print_) {
printf("%f", dub);
}
} break;
case apache::thrift::protocol::T_STRING: {
std::string str;
piprot_->readString(str);
if (print_) {
printf("%s", str.c_str());
}
} break;
case apache::thrift::protocol::T_STRUCT: {
std::string name;
int16_t fid;
apache::thrift::protocol::TType ftype;
piprot_->readStructBegin(name);
if (print_) {
printf("<");
}
while (true) {
piprot_->readFieldBegin(name, ftype, fid);
if (ftype == apache::thrift::protocol::T_STOP) {
break;
}
printAndPassToBuffer(ftype);
if (print_) {
printf(",");
}
piprot_->readFieldEnd();
}
piprot_->readStructEnd();
if (print_) {
printf("\b>");
}
} break;
case apache::thrift::protocol::T_MAP: {
apache::thrift::protocol::TType keyType;
apache::thrift::protocol::TType valType;
uint32_t i, size;
piprot_->readMapBegin(keyType, valType, size);
if (print_) {
printf("{");
}
for (i = 0; i < size; i++) {
printAndPassToBuffer(keyType);
if (print_) {
printf("=>");
}
printAndPassToBuffer(valType);
if (print_) {
printf(",");
}
}
piprot_->readMapEnd();
if (print_) {
printf("\b}");
}
} break;
case apache::thrift::protocol::T_SET: {
apache::thrift::protocol::TType elemType;
uint32_t i, size;
piprot_->readSetBegin(elemType, size);
if (print_) {
printf("{");
}
for (i = 0; i < size; i++) {
printAndPassToBuffer(elemType);
if (print_) {
printf(",");
}
}
piprot_->readSetEnd();
if (print_) {
printf("\b}");
}
} break;
case apache::thrift::protocol::T_LIST: {
apache::thrift::protocol::TType elemType;
uint32_t i, size;
piprot_->readListBegin(elemType, size);
if (print_) {
printf("[");
}
for (i = 0; i < size; i++) {
printAndPassToBuffer(elemType);
if (print_) {
printf(",");
}
}
piprot_->readListEnd();
if (print_) {
printf("\b]");
}
} break;
default:
break;
}
}
boost::shared_ptr<apache::thrift::protocol::TProtocol> piprot_;
std::map<std::string, int64_t> frequency_map_;
bool print_;
bool frequency_;
};
}
}
} // apache::thrift::processor
#endif

View file

@ -0,0 +1,201 @@
/*
* 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 THRIFT_TMULTIPLEXEDPROCESSOR_H_
#define THRIFT_TMULTIPLEXEDPROCESSOR_H_ 1
#include <thrift/protocol/TProtocolDecorator.h>
#include <thrift/TApplicationException.h>
#include <thrift/TProcessor.h>
#include <boost/tokenizer.hpp>
namespace apache {
namespace thrift {
using boost::shared_ptr;
namespace protocol {
/**
* To be able to work with any protocol, we needed
* to allow them to call readMessageBegin() and get a TMessage in exactly
* the standard format, without the service name prepended to TMessage.name.
*/
class StoredMessageProtocol : public TProtocolDecorator {
public:
StoredMessageProtocol(shared_ptr<protocol::TProtocol> _protocol,
const std::string& _name,
const TMessageType _type,
const int32_t _seqid)
: TProtocolDecorator(_protocol), name(_name), type(_type), seqid(_seqid) {}
uint32_t readMessageBegin_virt(std::string& _name, TMessageType& _type, int32_t& _seqid) {
_name = name;
_type = type;
_seqid = seqid;
return 0; // (Normal TProtocol read functions return number of bytes read)
}
std::string name;
TMessageType type;
int32_t seqid;
};
} // namespace protocol
/**
* <code>TMultiplexedProcessor</code> is a <code>TProcessor</code> allowing
* a single <code>TServer</code> to provide multiple services.
*
* <p>To do so, you instantiate the processor and then register additional
* processors with it, as shown in the following example:</p>
*
* <blockquote><code>
* shared_ptr<TMultiplexedProcessor> processor(new TMultiplexedProcessor());
*
* processor->registerProcessor(
* "Calculator",
* shared_ptr<TProcessor>( new CalculatorProcessor(
* shared_ptr<CalculatorHandler>( new CalculatorHandler()))));
*
* processor->registerProcessor(
* "WeatherReport",
* shared_ptr<TProcessor>( new WeatherReportProcessor(
* shared_ptr<WeatherReportHandler>( new WeatherReportHandler()))));
*
* shared_ptr<TServerTransport> transport(new TServerSocket(9090));
* TSimpleServer server(processor, transport);
*
* server.serve();
* </code></blockquote>
*/
class TMultiplexedProcessor : public TProcessor {
public:
typedef std::map<std::string, shared_ptr<TProcessor> > services_t;
/**
* 'Register' a service with this <code>TMultiplexedProcessor</code>. This
* allows us to broker requests to individual services by using the service
* name to select them at request time.
*
* \param [in] serviceName Name of a service, has to be identical to the name
* declared in the Thrift IDL, e.g. "WeatherReport".
* \param [in] processor Implementation of a service, usually referred to
* as "handlers", e.g. WeatherReportHandler,
* implementing WeatherReportIf interface.
*/
void registerProcessor(const std::string& serviceName, shared_ptr<TProcessor> processor) {
services[serviceName] = processor;
}
/**
* This implementation of <code>process</code> performs the following steps:
*
* <ol>
* <li>Read the beginning of the message.</li>
* <li>Extract the service name from the message.</li>
* <li>Using the service name to locate the appropriate processor.</li>
* <li>Dispatch to the processor, with a decorated instance of TProtocol
* that allows readMessageBegin() to return the original TMessage.</li>
* </ol>
*
* \throws TException If the message type is not T_CALL or T_ONEWAY, if
* the service name was not found in the message, or if the service
* name was not found in the service map.
*/
bool process(shared_ptr<protocol::TProtocol> in,
shared_ptr<protocol::TProtocol> out,
void* connectionContext) {
std::string name;
protocol::TMessageType type;
int32_t seqid;
// Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
// message header. This pulls the message "off the wire", which we'll
// deal with at the end of this method.
in->readMessageBegin(name, type, seqid);
if (type != protocol::T_CALL && type != protocol::T_ONEWAY) {
// Unexpected message type.
in->skip(::apache::thrift::protocol::T_STRUCT);
in->readMessageEnd();
in->getTransport()->readEnd();
const std::string msg("TMultiplexedProcessor: Unexpected message type");
::apache::thrift::TApplicationException
x(::apache::thrift::TApplicationException::PROTOCOL_ERROR, msg);
out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
x.write(out.get());
out->writeMessageEnd();
out->getTransport()->writeEnd();
out->getTransport()->flush();
throw TException(msg);
}
// Extract the service name
boost::tokenizer<boost::char_separator<char> > tok(name, boost::char_separator<char>(":"));
std::vector<std::string> tokens;
std::copy(tok.begin(), tok.end(), std::back_inserter(tokens));
// A valid message should consist of two tokens: the service
// name and the name of the method to call.
if (tokens.size() == 2) {
// Search for a processor associated with this service name.
services_t::iterator it = services.find(tokens[0]);
if (it != services.end()) {
shared_ptr<TProcessor> processor = it->second;
// Let the processor registered for this service name
// process the message.
return processor
->process(shared_ptr<protocol::TProtocol>(
new protocol::StoredMessageProtocol(in, tokens[1], type, seqid)),
out,
connectionContext);
} else {
// Unknown service.
in->skip(::apache::thrift::protocol::T_STRUCT);
in->readMessageEnd();
in->getTransport()->readEnd();
std::string msg("TMultiplexedProcessor: Unknown service: ");
msg += tokens[0];
::apache::thrift::TApplicationException
x(::apache::thrift::TApplicationException::PROTOCOL_ERROR, msg);
out->writeMessageBegin(name, ::apache::thrift::protocol::T_EXCEPTION, seqid);
x.write(out.get());
out->writeMessageEnd();
out->getTransport()->writeEnd();
out->getTransport()->flush();
msg += ". Did you forget to call registerProcessor()?";
throw TException(msg);
}
}
return false;
}
private:
/** Map of service processor objects, indexed by service names. */
services_t services;
};
}
}
#endif // THRIFT_TMULTIPLEXEDPROCESSOR_H_

View file

@ -0,0 +1,317 @@
/*
* 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 <thrift/protocol/TBase64Utils.h>
#include <boost/static_assert.hpp>
using std::string;
namespace apache {
namespace thrift {
namespace protocol {
static const uint8_t* kBase64EncodeTable
= (const uint8_t*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
void base64_encode(const uint8_t* in, uint32_t len, uint8_t* buf) {
buf[0] = kBase64EncodeTable[(in[0] >> 2) & 0x3f];
if (len == 3) {
buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
buf[2] = kBase64EncodeTable[((in[1] << 2) & 0x3c) | ((in[2] >> 6) & 0x03)];
buf[3] = kBase64EncodeTable[in[2] & 0x3f];
} else if (len == 2) {
buf[1] = kBase64EncodeTable[((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0f)];
buf[2] = kBase64EncodeTable[(in[1] << 2) & 0x3c];
} else { // len == 1
buf[1] = kBase64EncodeTable[(in[0] << 4) & 0x30];
}
}
static const uint8_t kBase64DecodeTable[256] = {
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0x3e,
0xff,
0xff,
0xff,
0x3f,
0x34,
0x35,
0x36,
0x37,
0x38,
0x39,
0x3a,
0x3b,
0x3c,
0x3d,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
0x10,
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0x1a,
0x1b,
0x1c,
0x1d,
0x1e,
0x1f,
0x20,
0x21,
0x22,
0x23,
0x24,
0x25,
0x26,
0x27,
0x28,
0x29,
0x2a,
0x2b,
0x2c,
0x2d,
0x2e,
0x2f,
0x30,
0x31,
0x32,
0x33,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
};
void base64_decode(uint8_t* buf, uint32_t len) {
buf[0] = (kBase64DecodeTable[buf[0]] << 2) | (kBase64DecodeTable[buf[1]] >> 4);
if (len > 2) {
buf[1] = ((kBase64DecodeTable[buf[1]] << 4) & 0xf0) | (kBase64DecodeTable[buf[2]] >> 2);
if (len > 3) {
buf[2] = ((kBase64DecodeTable[buf[2]] << 6) & 0xc0) | (kBase64DecodeTable[buf[3]]);
}
}
}
}
}
} // apache::thrift::protocol

View file

@ -0,0 +1,45 @@
/*
* 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 _THRIFT_PROTOCOL_TBASE64UTILS_H_
#define _THRIFT_PROTOCOL_TBASE64UTILS_H_
#include <stdint.h>
#include <string>
namespace apache {
namespace thrift {
namespace protocol {
// in must be at least len bytes
// len must be 1, 2, or 3
// buf must be a buffer of at least 4 bytes and may not overlap in
// the data is not padded with '='; the caller can do this if desired
void base64_encode(const uint8_t* in, uint32_t len, uint8_t* buf);
// buf must be a buffer of at least 4 bytes and contain base64 encoded values
// buf will be changed to contain output bytes
// len is number of bytes to consume from input (must be 2, 3, or 4)
// no '=' padding should be included in the input
void base64_decode(uint8_t* buf, uint32_t len);
}
}
} // apache::thrift::protocol
#endif // #define _THRIFT_PROTOCOL_TBASE64UTILS_H_

View file

@ -0,0 +1,250 @@
/*
* 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 _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_ 1
#include <thrift/protocol/TProtocol.h>
#include <thrift/protocol/TVirtualProtocol.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace protocol {
/**
* The default binary protocol for thrift. Writes all data in a very basic
* binary format, essentially just spitting out the raw bytes.
*
*/
template <class Transport_, class ByteOrder_ = TNetworkBigEndian>
class TBinaryProtocolT : public TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> > {
public:
static const int32_t VERSION_MASK = ((int32_t)0xffff0000);
static const int32_t VERSION_1 = ((int32_t)0x80010000);
// VERSION_2 (0x80020000) was taken by TDenseProtocol (which has since been removed)
TBinaryProtocolT(boost::shared_ptr<Transport_> trans)
: TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >(trans),
trans_(trans.get()),
string_limit_(0),
container_limit_(0),
strict_read_(false),
strict_write_(true) {}
TBinaryProtocolT(boost::shared_ptr<Transport_> trans,
int32_t string_limit,
int32_t container_limit,
bool strict_read,
bool strict_write)
: TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >(trans),
trans_(trans.get()),
string_limit_(string_limit),
container_limit_(container_limit),
strict_read_(strict_read),
strict_write_(strict_write) {}
void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
void setStrict(bool strict_read, bool strict_write) {
strict_read_ = strict_read;
strict_write_ = strict_write;
}
/**
* Writing functions.
*/
/*ol*/ uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid);
/*ol*/ uint32_t writeMessageEnd();
inline uint32_t writeStructBegin(const char* name);
inline uint32_t writeStructEnd();
inline uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
inline uint32_t writeFieldEnd();
inline uint32_t writeFieldStop();
inline uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
inline uint32_t writeMapEnd();
inline uint32_t writeListBegin(const TType elemType, const uint32_t size);
inline uint32_t writeListEnd();
inline uint32_t writeSetBegin(const TType elemType, const uint32_t size);
inline uint32_t writeSetEnd();
inline uint32_t writeBool(const bool value);
inline uint32_t writeByte(const int8_t byte);
inline uint32_t writeI16(const int16_t i16);
inline uint32_t writeI32(const int32_t i32);
inline uint32_t writeI64(const int64_t i64);
inline uint32_t writeDouble(const double dub);
template <typename StrType>
inline uint32_t writeString(const StrType& str);
inline uint32_t writeBinary(const std::string& str);
/**
* Reading functions
*/
/*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
/*ol*/ uint32_t readMessageEnd();
inline uint32_t readStructBegin(std::string& name);
inline uint32_t readStructEnd();
inline uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
inline uint32_t readFieldEnd();
inline uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
inline uint32_t readMapEnd();
inline uint32_t readListBegin(TType& elemType, uint32_t& size);
inline uint32_t readListEnd();
inline uint32_t readSetBegin(TType& elemType, uint32_t& size);
inline uint32_t readSetEnd();
inline uint32_t readBool(bool& value);
// Provide the default readBool() implementation for std::vector<bool>
using TVirtualProtocol<TBinaryProtocolT<Transport_, ByteOrder_> >::readBool;
inline uint32_t readByte(int8_t& byte);
inline uint32_t readI16(int16_t& i16);
inline uint32_t readI32(int32_t& i32);
inline uint32_t readI64(int64_t& i64);
inline uint32_t readDouble(double& dub);
template <typename StrType>
inline uint32_t readString(StrType& str);
inline uint32_t readBinary(std::string& str);
protected:
template <typename StrType>
uint32_t readStringBody(StrType& str, int32_t sz);
Transport_* trans_;
int32_t string_limit_;
int32_t container_limit_;
// Enforce presence of version identifier
bool strict_read_;
bool strict_write_;
};
typedef TBinaryProtocolT<TTransport> TBinaryProtocol;
typedef TBinaryProtocolT<TTransport, TNetworkLittleEndian> TLEBinaryProtocol;
/**
* Constructs binary protocol handlers
*/
template <class Transport_, class ByteOrder_ = TNetworkBigEndian>
class TBinaryProtocolFactoryT : public TProtocolFactory {
public:
TBinaryProtocolFactoryT()
: string_limit_(0), container_limit_(0), strict_read_(false), strict_write_(true) {}
TBinaryProtocolFactoryT(int32_t string_limit,
int32_t container_limit,
bool strict_read,
bool strict_write)
: string_limit_(string_limit),
container_limit_(container_limit),
strict_read_(strict_read),
strict_write_(strict_write) {}
virtual ~TBinaryProtocolFactoryT() {}
void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
void setStrict(bool strict_read, bool strict_write) {
strict_read_ = strict_read;
strict_write_ = strict_write;
}
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
boost::shared_ptr<Transport_> specific_trans = boost::dynamic_pointer_cast<Transport_>(trans);
TProtocol* prot;
if (specific_trans) {
prot = new TBinaryProtocolT<Transport_, ByteOrder_>(specific_trans,
string_limit_,
container_limit_,
strict_read_,
strict_write_);
} else {
prot = new TBinaryProtocolT<TTransport, ByteOrder_>(trans,
string_limit_,
container_limit_,
strict_read_,
strict_write_);
}
return boost::shared_ptr<TProtocol>(prot);
}
private:
int32_t string_limit_;
int32_t container_limit_;
bool strict_read_;
bool strict_write_;
};
typedef TBinaryProtocolFactoryT<TTransport> TBinaryProtocolFactory;
typedef TBinaryProtocolFactoryT<TTransport, TNetworkLittleEndian> TLEBinaryProtocolFactory;
}
}
} // apache::thrift::protocol
#include <thrift/protocol/TBinaryProtocol.tcc>
#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_H_

View file

@ -0,0 +1,454 @@
/*
* 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 _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
#define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
#include <thrift/protocol/TBinaryProtocol.h>
#include <limits>
namespace apache {
namespace thrift {
namespace protocol {
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
if (this->strict_write_) {
int32_t version = (VERSION_1) | ((int32_t)messageType);
uint32_t wsize = 0;
wsize += writeI32(version);
wsize += writeString(name);
wsize += writeI32(seqid);
return wsize;
} else {
uint32_t wsize = 0;
wsize += writeString(name);
wsize += writeByte((int8_t)messageType);
wsize += writeI32(seqid);
return wsize;
}
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructBegin(const char* name) {
(void)name;
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldBegin(const char* name,
const TType fieldType,
const int16_t fieldId) {
(void)name;
uint32_t wsize = 0;
wsize += writeByte((int8_t)fieldType);
wsize += writeI16(fieldId);
return wsize;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldStop() {
return writeByte((int8_t)T_STOP);
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapBegin(const TType keyType,
const TType valType,
const uint32_t size) {
uint32_t wsize = 0;
wsize += writeByte((int8_t)keyType);
wsize += writeByte((int8_t)valType);
wsize += writeI32((int32_t)size);
return wsize;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListBegin(const TType elemType,
const uint32_t size) {
uint32_t wsize = 0;
wsize += writeByte((int8_t)elemType);
wsize += writeI32((int32_t)size);
return wsize;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetBegin(const TType elemType,
const uint32_t size) {
uint32_t wsize = 0;
wsize += writeByte((int8_t)elemType);
wsize += writeI32((int32_t)size);
return wsize;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBool(const bool value) {
uint8_t tmp = value ? 1 : 0;
this->trans_->write(&tmp, 1);
return 1;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeByte(const int8_t byte) {
this->trans_->write((uint8_t*)&byte, 1);
return 1;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI16(const int16_t i16) {
int16_t net = (int16_t)ByteOrder_::toWire16(i16);
this->trans_->write((uint8_t*)&net, 2);
return 2;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI32(const int32_t i32) {
int32_t net = (int32_t)ByteOrder_::toWire32(i32);
this->trans_->write((uint8_t*)&net, 4);
return 4;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI64(const int64_t i64) {
int64_t net = (int64_t)ByteOrder_::toWire64(i64);
this->trans_->write((uint8_t*)&net, 8);
return 8;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeDouble(const double dub) {
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
uint64_t bits = bitwise_cast<uint64_t>(dub);
bits = ByteOrder_::toWire64(bits);
this->trans_->write((uint8_t*)&bits, 8);
return 8;
}
template <class Transport_, class ByteOrder_>
template <typename StrType>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeString(const StrType& str) {
if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
throw TProtocolException(TProtocolException::SIZE_LIMIT);
uint32_t size = static_cast<uint32_t>(str.size());
uint32_t result = writeI32((int32_t)size);
if (size > 0) {
this->trans_->write((uint8_t*)str.data(), size);
}
return result + size;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string& str) {
return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
}
/**
* Reading functions
*/
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageBegin(std::string& name,
TMessageType& messageType,
int32_t& seqid) {
uint32_t result = 0;
int32_t sz;
result += readI32(sz);
if (sz < 0) {
// Check for correct version number
int32_t version = sz & VERSION_MASK;
if (version != VERSION_1) {
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
}
messageType = (TMessageType)(sz & 0x000000ff);
result += readString(name);
result += readI32(seqid);
} else {
if (this->strict_read_) {
throw TProtocolException(TProtocolException::BAD_VERSION,
"No version identifier... old protocol client in strict mode?");
} else {
// Handle pre-versioned input
int8_t type;
result += readStringBody(name, sz);
result += readByte(type);
messageType = (TMessageType)type;
result += readI32(seqid);
}
}
return result;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructBegin(std::string& name) {
name = "";
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldBegin(std::string& name,
TType& fieldType,
int16_t& fieldId) {
(void)name;
uint32_t result = 0;
int8_t type;
result += readByte(type);
fieldType = (TType)type;
if (fieldType == T_STOP) {
fieldId = 0;
return result;
}
result += readI16(fieldId);
return result;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
TType& valType,
uint32_t& size) {
int8_t k, v;
uint32_t result = 0;
int32_t sizei;
result += readByte(k);
keyType = (TType)k;
result += readByte(v);
valType = (TType)v;
result += readI32(sizei);
if (sizei < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
} else if (this->container_limit_ && sizei > this->container_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
size = (uint32_t)sizei;
return result;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListBegin(TType& elemType, uint32_t& size) {
int8_t e;
uint32_t result = 0;
int32_t sizei;
result += readByte(e);
elemType = (TType)e;
result += readI32(sizei);
if (sizei < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
} else if (this->container_limit_ && sizei > this->container_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
size = (uint32_t)sizei;
return result;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetBegin(TType& elemType, uint32_t& size) {
int8_t e;
uint32_t result = 0;
int32_t sizei;
result += readByte(e);
elemType = (TType)e;
result += readI32(sizei);
if (sizei < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
} else if (this->container_limit_ && sizei > this->container_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
size = (uint32_t)sizei;
return result;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetEnd() {
return 0;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBool(bool& value) {
uint8_t b[1];
this->trans_->readAll(b, 1);
value = *(int8_t*)b != 0;
return 1;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readByte(int8_t& byte) {
uint8_t b[1];
this->trans_->readAll(b, 1);
byte = *(int8_t*)b;
return 1;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI16(int16_t& i16) {
union bytes {
uint8_t b[2];
int16_t all;
} theBytes;
this->trans_->readAll(theBytes.b, 2);
i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all);
return 2;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI32(int32_t& i32) {
union bytes {
uint8_t b[4];
int32_t all;
} theBytes;
this->trans_->readAll(theBytes.b, 4);
i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all);
return 4;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI64(int64_t& i64) {
union bytes {
uint8_t b[8];
int64_t all;
} theBytes;
this->trans_->readAll(theBytes.b, 8);
i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all);
return 8;
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readDouble(double& dub) {
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
union bytes {
uint8_t b[8];
uint64_t all;
} theBytes;
this->trans_->readAll(theBytes.b, 8);
theBytes.all = ByteOrder_::fromWire64(theBytes.all);
dub = bitwise_cast<double>(theBytes.all);
return 8;
}
template <class Transport_, class ByteOrder_>
template <typename StrType>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readString(StrType& str) {
uint32_t result;
int32_t size;
result = readI32(size);
return result + readStringBody(str, size);
}
template <class Transport_, class ByteOrder_>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str) {
return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
}
template <class Transport_, class ByteOrder_>
template <typename StrType>
uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
uint32_t result = 0;
// Catch error cases
if (size < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
}
if (this->string_limit_ > 0 && size > this->string_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
// Catch empty string case
if (size == 0) {
str.clear();
return result;
}
// Try to borrow first
const uint8_t* borrow_buf;
uint32_t got = size;
if ((borrow_buf = this->trans_->borrow(NULL, &got))) {
str.assign((const char*)borrow_buf, size);
this->trans_->consume(size);
return size;
}
str.resize(size);
this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
return (uint32_t)size;
}
}
}
} // apache::thrift::protocol
#endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_

View file

@ -0,0 +1,266 @@
/*
* 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 _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_
#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_H_ 1
#include <thrift/protocol/TVirtualProtocol.h>
#include <stack>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace protocol {
/**
* C++ Implementation of the Compact Protocol as described in THRIFT-110
*/
template <class Transport_>
class TCompactProtocolT : public TVirtualProtocol<TCompactProtocolT<Transport_> > {
public:
static const int8_t PROTOCOL_ID = (int8_t)0x82u;
static const int8_t VERSION_N = 1;
static const int8_t VERSION_MASK = 0x1f; // 0001 1111
protected:
static const int8_t TYPE_MASK = (int8_t)0xE0u; // 1110 0000
static const int8_t TYPE_BITS = 0x07; // 0000 0111
static const int32_t TYPE_SHIFT_AMOUNT = 5;
Transport_* trans_;
/**
* (Writing) If we encounter a boolean field begin, save the TField here
* so it can have the value incorporated.
*/
struct {
const char* name;
TType fieldType;
int16_t fieldId;
} booleanField_;
/**
* (Reading) If we read a field header, and it's a boolean field, save
* the boolean value here so that readBool can use it.
*/
struct {
bool hasBoolValue;
bool boolValue;
} boolValue_;
/**
* Used to keep track of the last field for the current and previous structs,
* so we can do the delta stuff.
*/
std::stack<int16_t> lastField_;
int16_t lastFieldId_;
public:
TCompactProtocolT(boost::shared_ptr<Transport_> trans)
: TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
trans_(trans.get()),
lastFieldId_(0),
string_limit_(0),
string_buf_(NULL),
string_buf_size_(0),
container_limit_(0) {
booleanField_.name = NULL;
boolValue_.hasBoolValue = false;
}
TCompactProtocolT(boost::shared_ptr<Transport_> trans,
int32_t string_limit,
int32_t container_limit)
: TVirtualProtocol<TCompactProtocolT<Transport_> >(trans),
trans_(trans.get()),
lastFieldId_(0),
string_limit_(string_limit),
string_buf_(NULL),
string_buf_size_(0),
container_limit_(container_limit) {
booleanField_.name = NULL;
boolValue_.hasBoolValue = false;
}
~TCompactProtocolT() { free(string_buf_); }
/**
* Writing functions
*/
virtual uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid);
uint32_t writeStructBegin(const char* name);
uint32_t writeStructEnd();
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
uint32_t writeFieldStop();
uint32_t writeListBegin(const TType elemType, const uint32_t size);
uint32_t writeSetBegin(const TType elemType, const uint32_t size);
virtual uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
uint32_t writeBool(const bool value);
uint32_t writeByte(const int8_t byte);
uint32_t writeI16(const int16_t i16);
uint32_t writeI32(const int32_t i32);
uint32_t writeI64(const int64_t i64);
uint32_t writeDouble(const double dub);
uint32_t writeString(const std::string& str);
uint32_t writeBinary(const std::string& str);
/**
* These methods are called by structs, but don't actually have any wired
* output or purpose
*/
virtual uint32_t writeMessageEnd() { return 0; }
uint32_t writeMapEnd() { return 0; }
uint32_t writeListEnd() { return 0; }
uint32_t writeSetEnd() { return 0; }
uint32_t writeFieldEnd() { return 0; }
protected:
int32_t writeFieldBeginInternal(const char* name,
const TType fieldType,
const int16_t fieldId,
int8_t typeOverride);
uint32_t writeCollectionBegin(const TType elemType, int32_t size);
uint32_t writeVarint32(uint32_t n);
uint32_t writeVarint64(uint64_t n);
uint64_t i64ToZigzag(const int64_t l);
uint32_t i32ToZigzag(const int32_t n);
inline int8_t getCompactType(const TType ttype);
public:
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
uint32_t readStructBegin(std::string& name);
uint32_t readStructEnd();
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
uint32_t readListBegin(TType& elemType, uint32_t& size);
uint32_t readSetBegin(TType& elemType, uint32_t& size);
uint32_t readBool(bool& value);
// Provide the default readBool() implementation for std::vector<bool>
using TVirtualProtocol<TCompactProtocolT<Transport_> >::readBool;
uint32_t readByte(int8_t& byte);
uint32_t readI16(int16_t& i16);
uint32_t readI32(int32_t& i32);
uint32_t readI64(int64_t& i64);
uint32_t readDouble(double& dub);
uint32_t readString(std::string& str);
uint32_t readBinary(std::string& str);
/*
*These methods are here for the struct to call, but don't have any wire
* encoding.
*/
uint32_t readMessageEnd() { return 0; }
uint32_t readFieldEnd() { return 0; }
uint32_t readMapEnd() { return 0; }
uint32_t readListEnd() { return 0; }
uint32_t readSetEnd() { return 0; }
protected:
uint32_t readVarint32(int32_t& i32);
uint32_t readVarint64(int64_t& i64);
int32_t zigzagToI32(uint32_t n);
int64_t zigzagToI64(uint64_t n);
TType getTType(int8_t type);
// Buffer for reading strings, save for the lifetime of the protocol to
// avoid memory churn allocating memory on every string read
int32_t string_limit_;
uint8_t* string_buf_;
int32_t string_buf_size_;
int32_t container_limit_;
};
typedef TCompactProtocolT<TTransport> TCompactProtocol;
/**
* Constructs compact protocol handlers
*/
template <class Transport_>
class TCompactProtocolFactoryT : public TProtocolFactory {
public:
TCompactProtocolFactoryT() : string_limit_(0), container_limit_(0) {}
TCompactProtocolFactoryT(int32_t string_limit, int32_t container_limit)
: string_limit_(string_limit), container_limit_(container_limit) {}
virtual ~TCompactProtocolFactoryT() {}
void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
void setContainerSizeLimit(int32_t container_limit) { container_limit_ = container_limit; }
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
boost::shared_ptr<Transport_> specific_trans = boost::dynamic_pointer_cast<Transport_>(trans);
TProtocol* prot;
if (specific_trans) {
prot = new TCompactProtocolT<Transport_>(specific_trans, string_limit_, container_limit_);
} else {
prot = new TCompactProtocol(trans, string_limit_, container_limit_);
}
return boost::shared_ptr<TProtocol>(prot);
}
private:
int32_t string_limit_;
int32_t container_limit_;
};
typedef TCompactProtocolFactoryT<TTransport> TCompactProtocolFactory;
}
}
} // apache::thrift::protocol
#include <thrift/protocol/TCompactProtocol.tcc>
#endif

View file

@ -0,0 +1,826 @@
/*
* 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 _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
#define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1
#include <limits>
#include "thrift/config.h"
/*
* TCompactProtocol::i*ToZigzag depend on the fact that the right shift
* operator on a signed integer is an arithmetic (sign-extending) shift.
* If this is not the case, the current implementation will not work.
* If anyone encounters this error, we can try to figure out the best
* way to implement an arithmetic right shift on their platform.
*/
#if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
# error "Unable to determine the behavior of a signed right shift"
#endif
#if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
# error "TCompactProtocol currently only works if a signed right shift is arithmetic"
#endif
#ifdef __GNUC__
#define UNLIKELY(val) (__builtin_expect((val), 0))
#else
#define UNLIKELY(val) (val)
#endif
namespace apache { namespace thrift { namespace protocol {
namespace detail { namespace compact {
enum Types {
CT_STOP = 0x00,
CT_BOOLEAN_TRUE = 0x01,
CT_BOOLEAN_FALSE = 0x02,
CT_BYTE = 0x03,
CT_I16 = 0x04,
CT_I32 = 0x05,
CT_I64 = 0x06,
CT_DOUBLE = 0x07,
CT_BINARY = 0x08,
CT_LIST = 0x09,
CT_SET = 0x0A,
CT_MAP = 0x0B,
CT_STRUCT = 0x0C
};
const int8_t TTypeToCType[16] = {
CT_STOP, // T_STOP
0, // unused
CT_BOOLEAN_TRUE, // T_BOOL
CT_BYTE, // T_BYTE
CT_DOUBLE, // T_DOUBLE
0, // unused
CT_I16, // T_I16
0, // unused
CT_I32, // T_I32
0, // unused
CT_I64, // T_I64
CT_BINARY, // T_STRING
CT_STRUCT, // T_STRUCT
CT_MAP, // T_MAP
CT_SET, // T_SET
CT_LIST, // T_LIST
};
}} // end detail::compact namespace
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeMessageBegin(
const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
uint32_t wsize = 0;
wsize += writeByte(PROTOCOL_ID);
wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
wsize += writeVarint32(seqid);
wsize += writeString(name);
return wsize;
}
/**
* Write a field header containing the field id and field type. If the
* difference between the current field id and the last one is small (< 15),
* then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
* field id will follow the type header as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeFieldBegin(const char* name,
const TType fieldType,
const int16_t fieldId) {
if (fieldType == T_BOOL) {
booleanField_.name = name;
booleanField_.fieldType = fieldType;
booleanField_.fieldId = fieldId;
} else {
return writeFieldBeginInternal(name, fieldType, fieldId, -1);
}
return 0;
}
/**
* Write the STOP symbol so we know there are no more fields in this struct.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeFieldStop() {
return writeByte(T_STOP);
}
/**
* Write a struct begin. This doesn't actually put anything on the wire. We
* use it as an opportunity to put special placeholder markers on the field
* stack so we can get the field id deltas correct.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeStructBegin(const char* name) {
(void) name;
lastField_.push(lastFieldId_);
lastFieldId_ = 0;
return 0;
}
/**
* Write a struct end. This doesn't actually put anything on the wire. We use
* this as an opportunity to pop the last field from the current struct off
* of the field stack.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeStructEnd() {
lastFieldId_ = lastField_.top();
lastField_.pop();
return 0;
}
/**
* Write a List header.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeListBegin(const TType elemType,
const uint32_t size) {
return writeCollectionBegin(elemType, size);
}
/**
* Write a set header.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeSetBegin(const TType elemType,
const uint32_t size) {
return writeCollectionBegin(elemType, size);
}
/**
* Write a map header. If the map is empty, omit the key and value type
* headers, as we don't need any additional information to skip it.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeMapBegin(const TType keyType,
const TType valType,
const uint32_t size) {
uint32_t wsize = 0;
if (size == 0) {
wsize += writeByte(0);
} else {
wsize += writeVarint32(size);
wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType));
}
return wsize;
}
/**
* Write a boolean value. Potentially, this could be a boolean field, in
* which case the field header info isn't written yet. If so, decide what the
* right type header is for the value and then write the field header.
* Otherwise, write a single byte.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeBool(const bool value) {
uint32_t wsize = 0;
if (booleanField_.name != NULL) {
// we haven't written the field header yet
wsize
+= writeFieldBeginInternal(booleanField_.name,
booleanField_.fieldType,
booleanField_.fieldId,
static_cast<int8_t>(value
? detail::compact::CT_BOOLEAN_TRUE
: detail::compact::CT_BOOLEAN_FALSE));
booleanField_.name = NULL;
} else {
// we're not part of a field, so just write the value
wsize
+= writeByte(static_cast<int8_t>(value
? detail::compact::CT_BOOLEAN_TRUE
: detail::compact::CT_BOOLEAN_FALSE));
}
return wsize;
}
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeByte(const int8_t byte) {
trans_->write((uint8_t*)&byte, 1);
return 1;
}
/**
* Write an i16 as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI16(const int16_t i16) {
return writeVarint32(i32ToZigzag(i16));
}
/**
* Write an i32 as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI32(const int32_t i32) {
return writeVarint32(i32ToZigzag(i32));
}
/**
* Write an i64 as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeI64(const int64_t i64) {
return writeVarint64(i64ToZigzag(i64));
}
/**
* Write a double to the wire as 8 bytes.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
uint64_t bits = bitwise_cast<uint64_t>(dub);
bits = THRIFT_htolell(bits);
trans_->write((uint8_t*)&bits, 8);
return 8;
}
/**
* Write a string to the wire with a varint size preceding.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
return writeBinary(str);
}
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
if(str.size() > (std::numeric_limits<uint32_t>::max)())
throw TProtocolException(TProtocolException::SIZE_LIMIT);
uint32_t ssize = static_cast<uint32_t>(str.size());
uint32_t wsize = writeVarint32(ssize) ;
// checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
// transforming the check to ssize > uint_max - wsize
if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
throw TProtocolException(TProtocolException::SIZE_LIMIT);
wsize += ssize;
trans_->write((uint8_t*)str.data(), ssize);
return wsize;
}
//
// Internal Writing methods
//
/**
* The workhorse of writeFieldBegin. It has the option of doing a
* 'type override' of the type header. This is used specifically in the
* boolean field case.
*/
template <class Transport_>
int32_t TCompactProtocolT<Transport_>::writeFieldBeginInternal(
const char* name,
const TType fieldType,
const int16_t fieldId,
int8_t typeOverride) {
(void) name;
uint32_t wsize = 0;
// if there's a type override, use that.
int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride);
// check if we can use delta encoding for the field id
if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) {
// write them together
wsize += writeByte(static_cast<int8_t>((fieldId - lastFieldId_)
<< 4 | typeToWrite));
} else {
// write them separate
wsize += writeByte(typeToWrite);
wsize += writeI16(fieldId);
}
lastFieldId_ = fieldId;
return wsize;
}
/**
* Abstract method for writing the start of lists and sets. List and sets on
* the wire differ only by the type indicator.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeCollectionBegin(const TType elemType,
int32_t size) {
uint32_t wsize = 0;
if (size <= 14) {
wsize += writeByte(static_cast<int8_t>(size
<< 4 | getCompactType(elemType)));
} else {
wsize += writeByte(0xf0 | getCompactType(elemType));
wsize += writeVarint32(size);
}
return wsize;
}
/**
* Write an i32 as a varint. Results in 1-5 bytes on the wire.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) {
uint8_t buf[5];
uint32_t wsize = 0;
while (true) {
if ((n & ~0x7F) == 0) {
buf[wsize++] = (int8_t)n;
break;
} else {
buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
n >>= 7;
}
}
trans_->write(buf, wsize);
return wsize;
}
/**
* Write an i64 as a varint. Results in 1-10 bytes on the wire.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::writeVarint64(uint64_t n) {
uint8_t buf[10];
uint32_t wsize = 0;
while (true) {
if ((n & ~0x7FL) == 0) {
buf[wsize++] = (int8_t)n;
break;
} else {
buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
n >>= 7;
}
}
trans_->write(buf, wsize);
return wsize;
}
/**
* Convert l into a zigzag long. This allows negative numbers to be
* represented compactly as a varint.
*/
template <class Transport_>
uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
return (l << 1) ^ (l >> 63);
}
/**
* Convert n into a zigzag int. This allows negative numbers to be
* represented compactly as a varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
return (n << 1) ^ (n >> 31);
}
/**
* Given a TType value, find the appropriate detail::compact::Types value
*/
template <class Transport_>
int8_t TCompactProtocolT<Transport_>::getCompactType(const TType ttype) {
return detail::compact::TTypeToCType[ttype];
}
//
// Reading Methods
//
/**
* Read a message header.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readMessageBegin(
std::string& name,
TMessageType& messageType,
int32_t& seqid) {
uint32_t rsize = 0;
int8_t protocolId;
int8_t versionAndType;
int8_t version;
rsize += readByte(protocolId);
if (protocolId != PROTOCOL_ID) {
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier");
}
rsize += readByte(versionAndType);
version = (int8_t)(versionAndType & VERSION_MASK);
if (version != VERSION_N) {
throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
}
messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
rsize += readVarint32(seqid);
rsize += readString(name);
return rsize;
}
/**
* Read a struct begin. There's nothing on the wire for this, but it is our
* opportunity to push a new struct begin marker on the field stack.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readStructBegin(std::string& name) {
name = "";
lastField_.push(lastFieldId_);
lastFieldId_ = 0;
return 0;
}
/**
* Doesn't actually consume any wire data, just removes the last field for
* this struct from the field stack.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readStructEnd() {
lastFieldId_ = lastField_.top();
lastField_.pop();
return 0;
}
/**
* Read a field header off the wire.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readFieldBegin(std::string& name,
TType& fieldType,
int16_t& fieldId) {
(void) name;
uint32_t rsize = 0;
int8_t byte;
int8_t type;
rsize += readByte(byte);
type = (byte & 0x0f);
// if it's a stop, then we can return immediately, as the struct is over.
if (type == T_STOP) {
fieldType = T_STOP;
fieldId = 0;
return rsize;
}
// mask off the 4 MSB of the type header. it could contain a field id delta.
int16_t modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
if (modifier == 0) {
// not a delta, look ahead for the zigzag varint field id.
rsize += readI16(fieldId);
} else {
fieldId = (int16_t)(lastFieldId_ + modifier);
}
fieldType = getTType(type);
// if this happens to be a boolean field, the value is encoded in the type
if (type == detail::compact::CT_BOOLEAN_TRUE ||
type == detail::compact::CT_BOOLEAN_FALSE) {
// save the boolean value in a special instance variable.
boolValue_.hasBoolValue = true;
boolValue_.boolValue =
(type == detail::compact::CT_BOOLEAN_TRUE ? true : false);
}
// push the new field onto the field stack so we can keep the deltas going.
lastFieldId_ = fieldId;
return rsize;
}
/**
* Read a map header off the wire. If the size is zero, skip reading the key
* and value type. This means that 0-length maps will yield TMaps without the
* "correct" types.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readMapBegin(TType& keyType,
TType& valType,
uint32_t& size) {
uint32_t rsize = 0;
int8_t kvType = 0;
int32_t msize = 0;
rsize += readVarint32(msize);
if (msize != 0)
rsize += readByte(kvType);
if (msize < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
} else if (container_limit_ && msize > container_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
keyType = getTType((int8_t)((uint8_t)kvType >> 4));
valType = getTType((int8_t)((uint8_t)kvType & 0xf));
size = (uint32_t)msize;
return rsize;
}
/**
* Read a list header off the wire. If the list size is 0-14, the size will
* be packed into the element type header. If it's a longer list, the 4 MSB
* of the element type header will be 0xF, and a varint will follow with the
* true size.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readListBegin(TType& elemType,
uint32_t& size) {
int8_t size_and_type;
uint32_t rsize = 0;
int32_t lsize;
rsize += readByte(size_and_type);
lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
if (lsize == 15) {
rsize += readVarint32(lsize);
}
if (lsize < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
} else if (container_limit_ && lsize > container_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
elemType = getTType((int8_t)(size_and_type & 0x0f));
size = (uint32_t)lsize;
return rsize;
}
/**
* Read a set header off the wire. If the set size is 0-14, the size will
* be packed into the element type header. If it's a longer set, the 4 MSB
* of the element type header will be 0xF, and a varint will follow with the
* true size.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readSetBegin(TType& elemType,
uint32_t& size) {
return readListBegin(elemType, size);
}
/**
* Read a boolean off the wire. If this is a boolean field, the value should
* already have been read during readFieldBegin, so we'll just consume the
* pre-stored value. Otherwise, read a byte.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readBool(bool& value) {
if (boolValue_.hasBoolValue == true) {
value = boolValue_.boolValue;
boolValue_.hasBoolValue = false;
return 0;
} else {
int8_t val;
readByte(val);
value = (val == detail::compact::CT_BOOLEAN_TRUE);
return 1;
}
}
/**
* Read a single byte off the wire. Nothing interesting here.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readByte(int8_t& byte) {
uint8_t b[1];
trans_->readAll(b, 1);
byte = *(int8_t*)b;
return 1;
}
/**
* Read an i16 from the wire as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI16(int16_t& i16) {
int32_t value;
uint32_t rsize = readVarint32(value);
i16 = (int16_t)zigzagToI32(value);
return rsize;
}
/**
* Read an i32 from the wire as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI32(int32_t& i32) {
int32_t value;
uint32_t rsize = readVarint32(value);
i32 = zigzagToI32(value);
return rsize;
}
/**
* Read an i64 from the wire as a zigzag varint.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readI64(int64_t& i64) {
int64_t value;
uint32_t rsize = readVarint64(value);
i64 = zigzagToI64(value);
return rsize;
}
/**
* No magic here - just read a double off the wire.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
union {
uint64_t bits;
uint8_t b[8];
} u;
trans_->readAll(u.b, 8);
u.bits = THRIFT_letohll(u.bits);
dub = bitwise_cast<double>(u.bits);
return 8;
}
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readString(std::string& str) {
return readBinary(str);
}
/**
* Read a byte[] from the wire.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readBinary(std::string& str) {
int32_t rsize = 0;
int32_t size;
rsize += readVarint32(size);
// Catch empty string case
if (size == 0) {
str = "";
return rsize;
}
// Catch error cases
if (size < 0) {
throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
}
if (string_limit_ > 0 && size > string_limit_) {
throw TProtocolException(TProtocolException::SIZE_LIMIT);
}
// Use the heap here to prevent stack overflow for v. large strings
if (size > string_buf_size_ || string_buf_ == NULL) {
void* new_string_buf = std::realloc(string_buf_, (uint32_t)size);
if (new_string_buf == NULL) {
throw std::bad_alloc();
}
string_buf_ = (uint8_t*)new_string_buf;
string_buf_size_ = size;
}
trans_->readAll(string_buf_, size);
str.assign((char*)string_buf_, size);
return rsize + (uint32_t)size;
}
/**
* Read an i32 from the wire as a varint. The MSB of each byte is set
* if there is another byte to follow. This can read up to 5 bytes.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readVarint32(int32_t& i32) {
int64_t val;
uint32_t rsize = readVarint64(val);
i32 = (int32_t)val;
return rsize;
}
/**
* Read an i64 from the wire as a proper varint. The MSB of each byte is set
* if there is another byte to follow. This can read up to 10 bytes.
*/
template <class Transport_>
uint32_t TCompactProtocolT<Transport_>::readVarint64(int64_t& i64) {
uint32_t rsize = 0;
uint64_t val = 0;
int shift = 0;
uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
uint32_t buf_size = sizeof(buf);
const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
// Fast path.
if (borrowed != NULL) {
while (true) {
uint8_t byte = borrowed[rsize];
rsize++;
val |= (uint64_t)(byte & 0x7f) << shift;
shift += 7;
if (!(byte & 0x80)) {
i64 = val;
trans_->consume(rsize);
return rsize;
}
// Have to check for invalid data so we don't crash.
if (UNLIKELY(rsize == sizeof(buf))) {
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
}
}
}
// Slow path.
else {
while (true) {
uint8_t byte;
rsize += trans_->readAll(&byte, 1);
val |= (uint64_t)(byte & 0x7f) << shift;
shift += 7;
if (!(byte & 0x80)) {
i64 = val;
return rsize;
}
// Might as well check for invalid data on the slow path too.
if (UNLIKELY(rsize >= sizeof(buf))) {
throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
}
}
}
}
/**
* Convert from zigzag int to int.
*/
template <class Transport_>
int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
}
/**
* Convert from zigzag long to long.
*/
template <class Transport_>
int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
}
template <class Transport_>
TType TCompactProtocolT<Transport_>::getTType(int8_t type) {
switch (type) {
case T_STOP:
return T_STOP;
case detail::compact::CT_BOOLEAN_FALSE:
case detail::compact::CT_BOOLEAN_TRUE:
return T_BOOL;
case detail::compact::CT_BYTE:
return T_BYTE;
case detail::compact::CT_I16:
return T_I16;
case detail::compact::CT_I32:
return T_I32;
case detail::compact::CT_I64:
return T_I64;
case detail::compact::CT_DOUBLE:
return T_DOUBLE;
case detail::compact::CT_BINARY:
return T_STRING;
case detail::compact::CT_LIST:
return T_LIST;
case detail::compact::CT_SET:
return T_SET;
case detail::compact::CT_MAP:
return T_MAP;
case detail::compact::CT_STRUCT:
return T_STRUCT;
default:
throw TException(std::string("don't know what type: ") + (char)type);
}
}
}}} // apache::thrift::protocol
#endif // _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_

View file

@ -0,0 +1,394 @@
/*
* 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 <thrift/protocol/TDebugProtocol.h>
#include <cassert>
#include <cctype>
#include <cstdio>
#include <stdexcept>
#include <boost/static_assert.hpp>
#include <boost/lexical_cast.hpp>
using std::string;
static string byte_to_hex(const uint8_t byte) {
char buf[3];
int ret = std::sprintf(buf, "%02x", (int)byte);
THRIFT_UNUSED_VARIABLE(ret);
assert(ret == 2);
assert(buf[2] == '\0');
return buf;
}
namespace apache {
namespace thrift {
namespace protocol {
string TDebugProtocol::fieldTypeName(TType type) {
switch (type) {
case T_STOP:
return "stop";
case T_VOID:
return "void";
case T_BOOL:
return "bool";
case T_BYTE:
return "byte";
case T_I16:
return "i16";
case T_I32:
return "i32";
case T_U64:
return "u64";
case T_I64:
return "i64";
case T_DOUBLE:
return "double";
case T_STRING:
return "string";
case T_STRUCT:
return "struct";
case T_MAP:
return "map";
case T_SET:
return "set";
case T_LIST:
return "list";
case T_UTF8:
return "utf8";
case T_UTF16:
return "utf16";
default:
return "unknown";
}
}
void TDebugProtocol::indentUp() {
indent_str_ += string(indent_inc, ' ');
}
void TDebugProtocol::indentDown() {
if (indent_str_.length() < (string::size_type)indent_inc) {
throw TProtocolException(TProtocolException::INVALID_DATA);
}
indent_str_.erase(indent_str_.length() - indent_inc);
}
uint32_t TDebugProtocol::writePlain(const string& str) {
if (str.length() > (std::numeric_limits<uint32_t>::max)())
throw TProtocolException(TProtocolException::SIZE_LIMIT);
trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
return static_cast<uint32_t>(str.length());
}
uint32_t TDebugProtocol::writeIndented(const string& str) {
if (str.length() > (std::numeric_limits<uint32_t>::max)())
throw TProtocolException(TProtocolException::SIZE_LIMIT);
if (indent_str_.length() > (std::numeric_limits<uint32_t>::max)())
throw TProtocolException(TProtocolException::SIZE_LIMIT);
uint64_t total_len = indent_str_.length() + str.length();
if (total_len > (std::numeric_limits<uint32_t>::max)())
throw TProtocolException(TProtocolException::SIZE_LIMIT);
trans_->write((uint8_t*)indent_str_.data(), static_cast<uint32_t>(indent_str_.length()));
trans_->write((uint8_t*)str.data(), static_cast<uint32_t>(str.length()));
return static_cast<uint32_t>(indent_str_.length() + str.length());
}
uint32_t TDebugProtocol::startItem() {
uint32_t size;
switch (write_state_.back()) {
case UNINIT:
// XXX figure out what to do here.
// throw TProtocolException(TProtocolException::INVALID_DATA);
// return writeIndented(str);
return 0;
case STRUCT:
return 0;
case SET:
return writeIndented("");
case MAP_KEY:
return writeIndented("");
case MAP_VALUE:
return writePlain(" -> ");
case LIST:
size = writeIndented("[" + boost::lexical_cast<string>(list_idx_.back()) + "] = ");
list_idx_.back()++;
return size;
default:
throw std::logic_error("Invalid enum value.");
}
}
uint32_t TDebugProtocol::endItem() {
// uint32_t size;
switch (write_state_.back()) {
case UNINIT:
// XXX figure out what to do here.
// throw TProtocolException(TProtocolException::INVALID_DATA);
// return writeIndented(str);
return 0;
case STRUCT:
return writePlain(",\n");
case SET:
return writePlain(",\n");
case MAP_KEY:
write_state_.back() = MAP_VALUE;
return 0;
case MAP_VALUE:
write_state_.back() = MAP_KEY;
return writePlain(",\n");
case LIST:
return writePlain(",\n");
default:
throw std::logic_error("Invalid enum value.");
}
}
uint32_t TDebugProtocol::writeItem(const std::string& str) {
uint32_t size = 0;
size += startItem();
size += writePlain(str);
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
(void)seqid;
string mtype;
switch (messageType) {
case T_CALL:
mtype = "call";
break;
case T_REPLY:
mtype = "reply";
break;
case T_EXCEPTION:
mtype = "exn";
break;
case T_ONEWAY:
mtype = "oneway";
break;
}
uint32_t size = writeIndented("(" + mtype + ") " + name + "(");
indentUp();
return size;
}
uint32_t TDebugProtocol::writeMessageEnd() {
indentDown();
return writeIndented(")\n");
}
uint32_t TDebugProtocol::writeStructBegin(const char* name) {
uint32_t size = 0;
size += startItem();
size += writePlain(string(name) + " {\n");
indentUp();
write_state_.push_back(STRUCT);
return size;
}
uint32_t TDebugProtocol::writeStructEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeFieldBegin(const char* name,
const TType fieldType,
const int16_t fieldId) {
// sprintf(id_str, "%02d", fieldId);
string id_str = boost::lexical_cast<string>(fieldId);
if (id_str.length() == 1)
id_str = '0' + id_str;
return writeIndented(id_str + ": " + name + " (" + fieldTypeName(fieldType) + ") = ");
}
uint32_t TDebugProtocol::writeFieldEnd() {
assert(write_state_.back() == STRUCT);
return 0;
}
uint32_t TDebugProtocol::writeFieldStop() {
return 0;
// writeIndented("***STOP***\n");
}
uint32_t TDebugProtocol::writeMapBegin(const TType keyType,
const TType valType,
const uint32_t size) {
// TODO(dreiss): Optimize short maps?
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"map<" + fieldTypeName(keyType) + "," + fieldTypeName(valType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(MAP_KEY);
return bsize;
}
uint32_t TDebugProtocol::writeMapEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeListBegin(const TType elemType, const uint32_t size) {
// TODO(dreiss): Optimize short arrays.
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"list<" + fieldTypeName(elemType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(LIST);
list_idx_.push_back(0);
return bsize;
}
uint32_t TDebugProtocol::writeListEnd() {
indentDown();
write_state_.pop_back();
list_idx_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
// TODO(dreiss): Optimize short sets.
uint32_t bsize = 0;
bsize += startItem();
bsize += writePlain(
"set<" + fieldTypeName(elemType) + ">"
"[" + boost::lexical_cast<string>(size) + "] {\n");
indentUp();
write_state_.push_back(SET);
return bsize;
}
uint32_t TDebugProtocol::writeSetEnd() {
indentDown();
write_state_.pop_back();
uint32_t size = 0;
size += writeIndented("}");
size += endItem();
return size;
}
uint32_t TDebugProtocol::writeBool(const bool value) {
return writeItem(value ? "true" : "false");
}
uint32_t TDebugProtocol::writeByte(const int8_t byte) {
return writeItem("0x" + byte_to_hex(byte));
}
uint32_t TDebugProtocol::writeI16(const int16_t i16) {
return writeItem(boost::lexical_cast<string>(i16));
}
uint32_t TDebugProtocol::writeI32(const int32_t i32) {
return writeItem(boost::lexical_cast<string>(i32));
}
uint32_t TDebugProtocol::writeI64(const int64_t i64) {
return writeItem(boost::lexical_cast<string>(i64));
}
uint32_t TDebugProtocol::writeDouble(const double dub) {
return writeItem(boost::lexical_cast<string>(dub));
}
uint32_t TDebugProtocol::writeString(const string& str) {
// XXX Raw/UTF-8?
string to_show = str;
if (to_show.length() > (string::size_type)string_limit_) {
to_show = str.substr(0, string_prefix_size_);
to_show += "[...](" + boost::lexical_cast<string>(str.length()) + ")";
}
string output = "\"";
for (string::const_iterator it = to_show.begin(); it != to_show.end(); ++it) {
if (*it == '\\') {
output += "\\\\";
} else if (*it == '"') {
output += "\\\"";
// passing characters <0 to std::isprint causes asserts. isprint takes an
// int, so we need to be careful of sign extension
} else if (std::isprint((unsigned char)*it)) {
output += *it;
} else {
switch (*it) {
case '\a':
output += "\\a";
break;
case '\b':
output += "\\b";
break;
case '\f':
output += "\\f";
break;
case '\n':
output += "\\n";
break;
case '\r':
output += "\\r";
break;
case '\t':
output += "\\t";
break;
case '\v':
output += "\\v";
break;
default:
output += "\\x";
output += byte_to_hex(*it);
}
}
}
output += '\"';
return writeItem(output);
}
uint32_t TDebugProtocol::writeBinary(const string& str) {
// XXX Hex?
return TDebugProtocol::writeString(str);
}
}
}
} // apache::thrift::protocol

View file

@ -0,0 +1,204 @@
/*
* 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 _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_
#define _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_ 1
#include <thrift/protocol/TVirtualProtocol.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace protocol {
/*
!!! EXPERIMENTAL CODE !!!
This protocol is very much a work in progress.
It doesn't handle many cases properly.
It throws exceptions in many cases.
It probably segfaults in many cases.
Bug reports and feature requests are welcome.
Complaints are not. :R
*/
/**
* Protocol that prints the payload in a nice human-readable format.
* Reading from this protocol is not supported.
*
*/
class TDebugProtocol : public TVirtualProtocol<TDebugProtocol> {
private:
enum write_state_t { UNINIT, STRUCT, LIST, SET, MAP_KEY, MAP_VALUE };
public:
TDebugProtocol(boost::shared_ptr<TTransport> trans)
: TVirtualProtocol<TDebugProtocol>(trans),
trans_(trans.get()),
string_limit_(DEFAULT_STRING_LIMIT),
string_prefix_size_(DEFAULT_STRING_PREFIX_SIZE) {
write_state_.push_back(UNINIT);
}
static const int32_t DEFAULT_STRING_LIMIT = 256;
static const int32_t DEFAULT_STRING_PREFIX_SIZE = 16;
void setStringSizeLimit(int32_t string_limit) { string_limit_ = string_limit; }
void setStringPrefixSize(int32_t string_prefix_size) { string_prefix_size_ = string_prefix_size; }
uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid);
uint32_t writeMessageEnd();
uint32_t writeStructBegin(const char* name);
uint32_t writeStructEnd();
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
uint32_t writeFieldEnd();
uint32_t writeFieldStop();
uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
uint32_t writeMapEnd();
uint32_t writeListBegin(const TType elemType, const uint32_t size);
uint32_t writeListEnd();
uint32_t writeSetBegin(const TType elemType, const uint32_t size);
uint32_t writeSetEnd();
uint32_t writeBool(const bool value);
uint32_t writeByte(const int8_t byte);
uint32_t writeI16(const int16_t i16);
uint32_t writeI32(const int32_t i32);
uint32_t writeI64(const int64_t i64);
uint32_t writeDouble(const double dub);
uint32_t writeString(const std::string& str);
uint32_t writeBinary(const std::string& str);
private:
void indentUp();
void indentDown();
uint32_t writePlain(const std::string& str);
uint32_t writeIndented(const std::string& str);
uint32_t startItem();
uint32_t endItem();
uint32_t writeItem(const std::string& str);
static std::string fieldTypeName(TType type);
TTransport* trans_;
int32_t string_limit_;
int32_t string_prefix_size_;
std::string indent_str_;
static const int indent_inc = 2;
std::vector<write_state_t> write_state_;
std::vector<int> list_idx_;
};
/**
* Constructs debug protocol handlers
*/
class TDebugProtocolFactory : public TProtocolFactory {
public:
TDebugProtocolFactory() {}
virtual ~TDebugProtocolFactory() {}
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
return boost::shared_ptr<TProtocol>(new TDebugProtocol(trans));
}
};
}
}
} // apache::thrift::protocol
// TODO(dreiss): Move (part of) ThriftDebugString into a .cpp file and remove this.
#include <thrift/transport/TBufferTransports.h>
namespace apache {
namespace thrift {
template <typename ThriftStruct>
std::string ThriftDebugString(const ThriftStruct& ts) {
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
TMemoryBuffer* buffer = new TMemoryBuffer;
boost::shared_ptr<TTransport> trans(buffer);
TDebugProtocol protocol(trans);
ts.write(&protocol);
uint8_t* buf;
uint32_t size;
buffer->getBuffer(&buf, &size);
return std::string((char*)buf, (unsigned int)size);
}
// TODO(dreiss): This is badly broken. Don't use it unless you are me.
#if 0
template<typename Object>
std::string DebugString(const std::vector<Object>& vec) {
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
TMemoryBuffer* buffer = new TMemoryBuffer;
boost::shared_ptr<TTransport> trans(buffer);
TDebugProtocol protocol(trans);
// I am gross!
protocol.writeStructBegin("SomeRandomVector");
// TODO: Fix this with a trait.
protocol.writeListBegin((TType)99, vec.size());
typename std::vector<Object>::const_iterator it;
for (it = vec.begin(); it != vec.end(); ++it) {
it->write(&protocol);
}
protocol.writeListEnd();
uint8_t* buf;
uint32_t size;
buffer->getBuffer(&buf, &size);
return std::string((char*)buf, (unsigned int)size);
}
#endif // 0
}
} // apache::thrift
#endif // #ifndef _THRIFT_PROTOCOL_TDEBUGPROTOCOL_H_

View file

@ -0,0 +1,254 @@
/*
* 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 THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_
#define THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_ 1
#include <thrift/protocol/THeaderProtocol.h>
#include <thrift/protocol/TCompactProtocol.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/TApplicationException.h>
#include <limits>
#include <boost/static_assert.hpp>
#include <boost/make_shared.hpp>
namespace apache {
namespace thrift {
namespace protocol {
void THeaderProtocol::resetProtocol() {
if (proto_ && protoId_ == trans_->getProtocolId()) {
return;
}
protoId_ = trans_->getProtocolId();
switch (protoId_) {
case T_BINARY_PROTOCOL:
proto_ = boost::make_shared<TBinaryProtocolT<THeaderTransport> >(trans_);
break;
case T_COMPACT_PROTOCOL:
proto_ = boost::make_shared<TCompactProtocolT<THeaderTransport> >(trans_);
break;
default:
throw TApplicationException(TApplicationException::INVALID_PROTOCOL,
"Unknown protocol requested");
}
}
uint32_t THeaderProtocol::writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqId) {
resetProtocol(); // Reset in case we changed protocols
trans_->setSequenceNumber(seqId);
return proto_->writeMessageBegin(name, messageType, seqId);
}
uint32_t THeaderProtocol::writeMessageEnd() {
return proto_->writeMessageEnd();
}
uint32_t THeaderProtocol::writeStructBegin(const char* name) {
return proto_->writeStructBegin(name);
}
uint32_t THeaderProtocol::writeStructEnd() {
return proto_->writeStructEnd();
}
uint32_t THeaderProtocol::writeFieldBegin(const char* name,
const TType fieldType,
const int16_t fieldId) {
return proto_->writeFieldBegin(name, fieldType, fieldId);
}
uint32_t THeaderProtocol::writeFieldEnd() {
return proto_->writeFieldEnd();
}
uint32_t THeaderProtocol::writeFieldStop() {
return proto_->writeFieldStop();
}
uint32_t THeaderProtocol::writeMapBegin(const TType keyType,
const TType valType,
const uint32_t size) {
return proto_->writeMapBegin(keyType, valType, size);
}
uint32_t THeaderProtocol::writeMapEnd() {
return proto_->writeMapEnd();
}
uint32_t THeaderProtocol::writeListBegin(const TType elemType, const uint32_t size) {
return proto_->writeListBegin(elemType, size);
}
uint32_t THeaderProtocol::writeListEnd() {
return proto_->writeListEnd();
}
uint32_t THeaderProtocol::writeSetBegin(const TType elemType, const uint32_t size) {
return proto_->writeSetBegin(elemType, size);
}
uint32_t THeaderProtocol::writeSetEnd() {
return proto_->writeSetEnd();
}
uint32_t THeaderProtocol::writeBool(const bool value) {
return proto_->writeBool(value);
}
uint32_t THeaderProtocol::writeByte(const int8_t byte) {
return proto_->writeByte(byte);
}
uint32_t THeaderProtocol::writeI16(const int16_t i16) {
return proto_->writeI16(i16);
}
uint32_t THeaderProtocol::writeI32(const int32_t i32) {
return proto_->writeI32(i32);
}
uint32_t THeaderProtocol::writeI64(const int64_t i64) {
return proto_->writeI64(i64);
}
uint32_t THeaderProtocol::writeDouble(const double dub) {
return proto_->writeDouble(dub);
}
uint32_t THeaderProtocol::writeString(const std::string& str) {
return proto_->writeString(str);
}
uint32_t THeaderProtocol::writeBinary(const std::string& str) {
return proto_->writeBinary(str);
}
/**
* Reading functions
*/
uint32_t THeaderProtocol::readMessageBegin(std::string& name,
TMessageType& messageType,
int32_t& seqId) {
// Read the next frame, and change protocols if needed
try {
trans_->resetProtocol();
resetProtocol();
} catch (const TApplicationException& ex) {
writeMessageBegin("", T_EXCEPTION, 0);
ex.write((TProtocol*)this);
writeMessageEnd();
trans_->flush();
// The framing is still good, but we don't know about this protocol.
// In the future, this could be made a client-side only error if
// connection pooling is used.
throw ex;
}
return proto_->readMessageBegin(name, messageType, seqId);
}
uint32_t THeaderProtocol::readMessageEnd() {
return proto_->readMessageEnd();
}
uint32_t THeaderProtocol::readStructBegin(std::string& name) {
return proto_->readStructBegin(name);
}
uint32_t THeaderProtocol::readStructEnd() {
return proto_->readStructEnd();
}
uint32_t THeaderProtocol::readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
return proto_->readFieldBegin(name, fieldType, fieldId);
}
uint32_t THeaderProtocol::readFieldEnd() {
return proto_->readFieldEnd();
}
uint32_t THeaderProtocol::readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
return proto_->readMapBegin(keyType, valType, size);
}
uint32_t THeaderProtocol::readMapEnd() {
return proto_->readMapEnd();
}
uint32_t THeaderProtocol::readListBegin(TType& elemType, uint32_t& size) {
return proto_->readListBegin(elemType, size);
}
uint32_t THeaderProtocol::readListEnd() {
return proto_->readListEnd();
}
uint32_t THeaderProtocol::readSetBegin(TType& elemType, uint32_t& size) {
return proto_->readSetBegin(elemType, size);
}
uint32_t THeaderProtocol::readSetEnd() {
return proto_->readSetEnd();
}
uint32_t THeaderProtocol::readBool(bool& value) {
return proto_->readBool(value);
}
uint32_t THeaderProtocol::readByte(int8_t& byte) {
return proto_->readByte(byte);
}
uint32_t THeaderProtocol::readI16(int16_t& i16) {
return proto_->readI16(i16);
}
uint32_t THeaderProtocol::readI32(int32_t& i32) {
return proto_->readI32(i32);
}
uint32_t THeaderProtocol::readI64(int64_t& i64) {
return proto_->readI64(i64);
}
uint32_t THeaderProtocol::readDouble(double& dub) {
return proto_->readDouble(dub);
}
uint32_t THeaderProtocol::readString(std::string& str) {
return proto_->readString(str);
}
uint32_t THeaderProtocol::readBinary(std::string& binary) {
return proto_->readBinary(binary);
}
}
}
} // apache::thrift::protocol
#endif // #ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_CPP_

View file

@ -0,0 +1,210 @@
/*
* 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 THRIFT_PROTOCOL_THEADERPROTOCOL_H_
#define THRIFT_PROTOCOL_THEADERPROTOCOL_H_ 1
#include <thrift/protocol/TProtocol.h>
#include <thrift/protocol/TProtocolTypes.h>
#include <thrift/protocol/TVirtualProtocol.h>
#include <thrift/transport/THeaderTransport.h>
#include <boost/shared_ptr.hpp>
using apache::thrift::transport::THeaderTransport;
namespace apache {
namespace thrift {
namespace protocol {
/**
* The header protocol for thrift. Reads unframed, framed, header format,
* and http
*
*/
class THeaderProtocol : public TVirtualProtocol<THeaderProtocol> {
protected:
public:
void resetProtocol();
explicit THeaderProtocol(const boost::shared_ptr<TTransport>& trans,
uint16_t protoId = T_COMPACT_PROTOCOL)
: TVirtualProtocol<THeaderProtocol>(boost::shared_ptr<TTransport>(new THeaderTransport(trans))),
trans_(boost::dynamic_pointer_cast<THeaderTransport>(this->getTransport())),
protoId_(protoId) {
trans_->setProtocolId(protoId);
resetProtocol();
}
THeaderProtocol(const boost::shared_ptr<TTransport>& inTrans,
const boost::shared_ptr<TTransport>& outTrans,
uint16_t protoId = T_COMPACT_PROTOCOL)
: TVirtualProtocol<THeaderProtocol>(
boost::shared_ptr<TTransport>(new THeaderTransport(inTrans, outTrans))),
trans_(boost::dynamic_pointer_cast<THeaderTransport>(this->getTransport())),
protoId_(protoId) {
trans_->setProtocolId(protoId);
resetProtocol();
}
~THeaderProtocol() {}
/**
* Functions to work with headers by calling into THeaderTransport
*/
void setProtocolId(uint16_t protoId) {
trans_->setProtocolId(protoId);
resetProtocol();
}
typedef THeaderTransport::StringToStringMap StringToStringMap;
// these work with write headers
void setHeader(const std::string& key, const std::string& value) {
trans_->setHeader(key, value);
}
void clearHeaders() { trans_->clearHeaders(); }
StringToStringMap& getWriteHeaders() { return trans_->getWriteHeaders(); }
// these work with read headers
const StringToStringMap& getHeaders() const { return trans_->getHeaders(); }
/**
* Writing functions.
*/
/*ol*/ uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqId);
/*ol*/ uint32_t writeMessageEnd();
uint32_t writeStructBegin(const char* name);
uint32_t writeStructEnd();
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
uint32_t writeFieldEnd();
uint32_t writeFieldStop();
uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
uint32_t writeMapEnd();
uint32_t writeListBegin(const TType elemType, const uint32_t size);
uint32_t writeListEnd();
uint32_t writeSetBegin(const TType elemType, const uint32_t size);
uint32_t writeSetEnd();
uint32_t writeBool(const bool value);
uint32_t writeByte(const int8_t byte);
uint32_t writeI16(const int16_t i16);
uint32_t writeI32(const int32_t i32);
uint32_t writeI64(const int64_t i64);
uint32_t writeDouble(const double dub);
uint32_t writeString(const std::string& str);
uint32_t writeBinary(const std::string& str);
/**
* Reading functions
*/
/*ol*/ uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqId);
/*ol*/ uint32_t readMessageEnd();
uint32_t readStructBegin(std::string& name);
uint32_t readStructEnd();
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
uint32_t readFieldEnd();
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
uint32_t readMapEnd();
uint32_t readListBegin(TType& elemType, uint32_t& size);
uint32_t readListEnd();
uint32_t readSetBegin(TType& elemType, uint32_t& size);
uint32_t readSetEnd();
uint32_t readBool(bool& value);
// Provide the default readBool() implementation for std::vector<bool>
using TVirtualProtocol<THeaderProtocol>::readBool;
uint32_t readByte(int8_t& byte);
uint32_t readI16(int16_t& i16);
uint32_t readI32(int32_t& i32);
uint32_t readI64(int64_t& i64);
uint32_t readDouble(double& dub);
uint32_t readString(std::string& str);
uint32_t readBinary(std::string& binary);
protected:
boost::shared_ptr<THeaderTransport> trans_;
boost::shared_ptr<TProtocol> proto_;
uint32_t protoId_;
};
class THeaderProtocolFactory : public TProtocolFactory {
public:
virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<transport::TTransport> trans) {
THeaderProtocol* headerProtocol
= new THeaderProtocol(trans, boost::shared_ptr<transport::TTransport>(), T_BINARY_PROTOCOL);
return boost::shared_ptr<TProtocol>(headerProtocol);
}
virtual boost::shared_ptr<TProtocol> getProtocol(
boost::shared_ptr<transport::TTransport> inTrans,
boost::shared_ptr<transport::TTransport> outTrans) {
THeaderProtocol* headerProtocol = new THeaderProtocol(inTrans, outTrans, T_BINARY_PROTOCOL);
return boost::shared_ptr<TProtocol>(headerProtocol);
}
};
}
}
} // apache::thrift::protocol
#endif // #ifndef THRIFT_PROTOCOL_THEADERPROTOCOL_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,324 @@
/*
* 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 _THRIFT_PROTOCOL_TJSONPROTOCOL_H_
#define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1
#include <thrift/protocol/TVirtualProtocol.h>
#include <stack>
namespace apache {
namespace thrift {
namespace protocol {
// Forward declaration
class TJSONContext;
/**
* JSON protocol for Thrift.
*
* Implements a protocol which uses JSON as the wire-format.
*
* Thrift types are represented as described below:
*
* 1. Every Thrift integer type is represented as a JSON number.
*
* 2. Thrift doubles are represented as JSON numbers. Some special values are
* represented as strings:
* a. "NaN" for not-a-number values
* b. "Infinity" for positive infinity
* c. "-Infinity" for negative infinity
*
* 3. Thrift string values are emitted as JSON strings, with appropriate
* escaping.
*
* 4. Thrift binary values are encoded into Base64 and emitted as JSON strings.
* The readBinary() method is written such that it will properly skip if
* called on a Thrift string (although it will decode garbage data).
*
* NOTE: Base64 padding is optional for Thrift binary value encoding. So
* the readBinary() method needs to decode both input strings with padding
* and those without one.
*
* 5. Thrift structs are represented as JSON objects, with the field ID as the
* key, and the field value represented as a JSON object with a single
* key-value pair. The key is a short string identifier for that type,
* followed by the value. The valid type identifiers are: "tf" for bool,
* "i8" for byte, "i16" for 16-bit integer, "i32" for 32-bit integer, "i64"
* for 64-bit integer, "dbl" for double-precision loating point, "str" for
* string (including binary), "rec" for struct ("records"), "map" for map,
* "lst" for list, "set" for set.
*
* 6. Thrift lists and sets are represented as JSON arrays, with the first
* element of the JSON array being the string identifier for the Thrift
* element type and the second element of the JSON array being the count of
* the Thrift elements. The Thrift elements then follow.
*
* 7. Thrift maps are represented as JSON arrays, with the first two elements
* of the JSON array being the string identifiers for the Thrift key type
* and value type, followed by the count of the Thrift pairs, followed by a
* JSON object containing the key-value pairs. Note that JSON keys can only
* be strings, which means that the key type of the Thrift map should be
* restricted to numeric or string types -- in the case of numerics, they
* are serialized as strings.
*
* 8. Thrift messages are represented as JSON arrays, with the protocol
* version #, the message name, the message type, and the sequence ID as
* the first 4 elements.
*
* More discussion of the double handling is probably warranted. The aim of
* the current implementation is to match as closely as possible the behavior
* of Java's Double.toString(), which has no precision loss. Implementors in
* other languages should strive to achieve that where possible. I have not
* yet verified whether boost:lexical_cast, which is doing that work for me in
* C++, loses any precision, but I am leaving this as a future improvement. I
* may try to provide a C component for this, so that other languages could
* bind to the same underlying implementation for maximum consistency.
*
*/
class TJSONProtocol : public TVirtualProtocol<TJSONProtocol> {
public:
TJSONProtocol(boost::shared_ptr<TTransport> ptrans);
~TJSONProtocol();
private:
void pushContext(boost::shared_ptr<TJSONContext> c);
void popContext();
uint32_t writeJSONEscapeChar(uint8_t ch);
uint32_t writeJSONChar(uint8_t ch);
uint32_t writeJSONString(const std::string& str);
uint32_t writeJSONBase64(const std::string& str);
template <typename NumberType>
uint32_t writeJSONInteger(NumberType num);
uint32_t writeJSONDouble(double num);
uint32_t writeJSONObjectStart();
uint32_t writeJSONObjectEnd();
uint32_t writeJSONArrayStart();
uint32_t writeJSONArrayEnd();
uint32_t readJSONSyntaxChar(uint8_t ch);
uint32_t readJSONEscapeChar(uint16_t* out);
uint32_t readJSONString(std::string& str, bool skipContext = false);
uint32_t readJSONBase64(std::string& str);
uint32_t readJSONNumericChars(std::string& str);
template <typename NumberType>
uint32_t readJSONInteger(NumberType& num);
uint32_t readJSONDouble(double& num);
uint32_t readJSONObjectStart();
uint32_t readJSONObjectEnd();
uint32_t readJSONArrayStart();
uint32_t readJSONArrayEnd();
public:
/**
* Writing functions.
*/
uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid);
uint32_t writeMessageEnd();
uint32_t writeStructBegin(const char* name);
uint32_t writeStructEnd();
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId);
uint32_t writeFieldEnd();
uint32_t writeFieldStop();
uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size);
uint32_t writeMapEnd();
uint32_t writeListBegin(const TType elemType, const uint32_t size);
uint32_t writeListEnd();
uint32_t writeSetBegin(const TType elemType, const uint32_t size);
uint32_t writeSetEnd();
uint32_t writeBool(const bool value);
uint32_t writeByte(const int8_t byte);
uint32_t writeI16(const int16_t i16);
uint32_t writeI32(const int32_t i32);
uint32_t writeI64(const int64_t i64);
uint32_t writeDouble(const double dub);
uint32_t writeString(const std::string& str);
uint32_t writeBinary(const std::string& str);
/**
* Reading functions
*/
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid);
uint32_t readMessageEnd();
uint32_t readStructBegin(std::string& name);
uint32_t readStructEnd();
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId);
uint32_t readFieldEnd();
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size);
uint32_t readMapEnd();
uint32_t readListBegin(TType& elemType, uint32_t& size);
uint32_t readListEnd();
uint32_t readSetBegin(TType& elemType, uint32_t& size);
uint32_t readSetEnd();
uint32_t readBool(bool& value);
// Provide the default readBool() implementation for std::vector<bool>
using TVirtualProtocol<TJSONProtocol>::readBool;
uint32_t readByte(int8_t& byte);
uint32_t readI16(int16_t& i16);
uint32_t readI32(int32_t& i32);
uint32_t readI64(int64_t& i64);
uint32_t readDouble(double& dub);
uint32_t readString(std::string& str);
uint32_t readBinary(std::string& str);
class LookaheadReader {
public:
LookaheadReader(TTransport& trans) : trans_(&trans), hasData_(false) {}
uint8_t read() {
if (hasData_) {
hasData_ = false;
} else {
trans_->readAll(&data_, 1);
}
return data_;
}
uint8_t peek() {
if (!hasData_) {
trans_->readAll(&data_, 1);
}
hasData_ = true;
return data_;
}
private:
TTransport* trans_;
bool hasData_;
uint8_t data_;
};
private:
TTransport* trans_;
std::stack<boost::shared_ptr<TJSONContext> > contexts_;
boost::shared_ptr<TJSONContext> context_;
LookaheadReader reader_;
};
/**
* Constructs input and output protocol objects given transports.
*/
class TJSONProtocolFactory : public TProtocolFactory {
public:
TJSONProtocolFactory() {}
virtual ~TJSONProtocolFactory() {}
boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) {
return boost::shared_ptr<TProtocol>(new TJSONProtocol(trans));
}
};
}
}
} // apache::thrift::protocol
// TODO(dreiss): Move part of ThriftJSONString into a .cpp file and remove this.
#include <thrift/transport/TBufferTransports.h>
namespace apache {
namespace thrift {
template <typename ThriftStruct>
std::string ThriftJSONString(const ThriftStruct& ts) {
using namespace apache::thrift::transport;
using namespace apache::thrift::protocol;
TMemoryBuffer* buffer = new TMemoryBuffer;
boost::shared_ptr<TTransport> trans(buffer);
TJSONProtocol protocol(trans);
ts.write(&protocol);
uint8_t* buf;
uint32_t size;
buffer->getBuffer(&buf, &size);
return std::string((char*)buf, (unsigned int)size);
}
}
} // apache::thrift
#endif // #define _THRIFT_PROTOCOL_TJSONPROTOCOL_H_ 1

View file

@ -0,0 +1,40 @@
/*
* 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 <thrift/protocol/TMultiplexedProtocol.h>
#include <thrift/processor/TMultiplexedProcessor.h>
#include <thrift/protocol/TProtocolDecorator.h>
namespace apache {
namespace thrift {
namespace protocol {
uint32_t TMultiplexedProtocol::writeMessageBegin_virt(const std::string& _name,
const TMessageType _type,
const int32_t _seqid) {
if (_type == T_CALL || _type == T_ONEWAY) {
return TProtocolDecorator::writeMessageBegin_virt(serviceName + separator + _name,
_type,
_seqid);
} else {
return TProtocolDecorator::writeMessageBegin_virt(_name, _type, _seqid);
}
}
}
}
}

View file

@ -0,0 +1,95 @@
/*
* 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 THRIFT_TMULTIPLEXEDPROTOCOL_H_
#define THRIFT_TMULTIPLEXEDPROTOCOL_H_ 1
#include <thrift/protocol/TProtocolDecorator.h>
namespace apache {
namespace thrift {
namespace protocol {
using boost::shared_ptr;
/**
* <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
* that allows a Thrift client to communicate with a multiplexing Thrift server,
* by prepending the service name to the function name during function calls.
*
* \note THIS IS NOT USED BY SERVERS. On the server, use
* {@link apache::thrift::TMultiplexedProcessor TMultiplexedProcessor} to handle requests
* from a multiplexing client.
*
* This example uses a single socket transport to invoke two services:
*
* <blockquote><code>
* shared_ptr<TSocket> transport(new TSocket("localhost", 9090));
* transport->open();
*
* shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
*
* shared_ptr<TMultiplexedProtocol> mp1(new TMultiplexedProtocol(protocol, "Calculator"));
* shared_ptr<CalculatorClient> service1(new CalculatorClient(mp1));
*
* shared_ptr<TMultiplexedProtocol> mp2(new TMultiplexedProtocol(protocol, "WeatherReport"));
* shared_ptr<WeatherReportClient> service2(new WeatherReportClient(mp2));
*
* service1->add(2,2);
* int temp = service2->getTemperature();
* </code></blockquote>
*
* @see apache::thrift::protocol::TProtocolDecorator
*/
class TMultiplexedProtocol : public TProtocolDecorator {
public:
/**
* Wrap the specified protocol, allowing it to be used to communicate with a
* multiplexing server. The <code>serviceName</code> is required as it is
* prepended to the message header so that the multiplexing server can broker
* the function call to the proper service.
*
* \param _protocol Your communication protocol of choice, e.g. <code>TBinaryProtocol</code>.
* \param _serviceName The service name of the service communicating via this protocol.
*/
TMultiplexedProtocol(shared_ptr<TProtocol> _protocol, const std::string& _serviceName)
: TProtocolDecorator(_protocol), serviceName(_serviceName), separator(":") {}
virtual ~TMultiplexedProtocol() {}
/**
* Prepends the service name to the function name, separated by TMultiplexedProtocol::SEPARATOR.
*
* \param [in] _name The name of the method to be called in the service.
* \param [in] _type The type of message
* \param [in] _name The sequential id of the message
*
* \throws TException Passed through from wrapped <code>TProtocol</code> instance.
*/
uint32_t writeMessageBegin_virt(const std::string& _name,
const TMessageType _type,
const int32_t _seqid);
private:
const std::string serviceName;
const std::string separator;
};
}
}
}
#endif // THRIFT_TMULTIPLEXEDPROTOCOL_H_

View file

@ -0,0 +1,33 @@
/*
* 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 <thrift/protocol/TProtocol.h>
namespace apache {
namespace thrift {
namespace protocol {
TProtocol::~TProtocol() {}
uint32_t TProtocol::skip_virt(TType type) {
return ::apache::thrift::protocol::skip(*this, type);
}
TProtocolFactory::~TProtocolFactory() {}
}}} // apache::thrift::protocol

View file

@ -0,0 +1,762 @@
/*
* 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 _THRIFT_PROTOCOL_TPROTOCOL_H_
#define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
#ifdef _WIN32
// Need to come before any Windows.h includes
#include <Winsock2.h>
#endif
#include <thrift/transport/TTransport.h>
#include <thrift/protocol/TProtocolException.h>
#include <boost/shared_ptr.hpp>
#include <boost/static_assert.hpp>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include <sys/types.h>
#include <string>
#include <map>
#include <vector>
#include <climits>
// Use this to get around strict aliasing rules.
// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
// The most obvious implementation is to just cast a pointer,
// but that doesn't work.
// For a pretty in-depth explanation of the problem, see
// http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html
template <typename To, typename From>
static inline To bitwise_cast(From from) {
BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
// BAD!!! These are all broken with -O2.
//return *reinterpret_cast<To*>(&from); // BAD!!!
//return *static_cast<To*>(static_cast<void*>(&from)); // BAD!!!
//return *(To*)(void*)&from; // BAD!!!
// Super clean and paritally blessed by section 3.9 of the standard.
//unsigned char c[sizeof(from)];
//memcpy(c, &from, sizeof(from));
//To to;
//memcpy(&to, c, sizeof(c));
//return to;
// Slightly more questionable.
// Same code emitted by GCC.
//To to;
//memcpy(&to, &from, sizeof(from));
//return to;
// Technically undefined, but almost universally supported,
// and the most efficient implementation.
union {
From f;
To t;
} u;
u.f = from;
return u.t;
}
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifndef __THRIFT_BYTE_ORDER
# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
# define __THRIFT_BYTE_ORDER BYTE_ORDER
# define __THRIFT_LITTLE_ENDIAN LITTLE_ENDIAN
# define __THRIFT_BIG_ENDIAN BIG_ENDIAN
# else
# include <boost/config.hpp>
# include <boost/detail/endian.hpp>
# define __THRIFT_BYTE_ORDER BOOST_BYTE_ORDER
# ifdef BOOST_LITTLE_ENDIAN
# define __THRIFT_LITTLE_ENDIAN __THRIFT_BYTE_ORDER
# define __THRIFT_BIG_ENDIAN 0
# else
# define __THRIFT_LITTLE_ENDIAN 0
# define __THRIFT_BIG_ENDIAN __THRIFT_BYTE_ORDER
# endif
# endif
#endif
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
# if !defined(THRIFT_ntohll)
# define THRIFT_ntohll(n) (n)
# define THRIFT_htonll(n) (n)
# endif
# if defined(__GNUC__) && defined(__GLIBC__)
# include <byteswap.h>
# define THRIFT_htolell(n) bswap_64(n)
# define THRIFT_letohll(n) bswap_64(n)
# define THRIFT_htolel(n) bswap_32(n)
# define THRIFT_letohl(n) bswap_32(n)
# define THRIFT_htoles(n) bswap_16(n)
# define THRIFT_letohs(n) bswap_16(n)
# else /* GNUC & GLIBC */
# define bswap_64(n) \
( (((n) & 0xff00000000000000ull) >> 56) \
| (((n) & 0x00ff000000000000ull) >> 40) \
| (((n) & 0x0000ff0000000000ull) >> 24) \
| (((n) & 0x000000ff00000000ull) >> 8) \
| (((n) & 0x00000000ff000000ull) << 8) \
| (((n) & 0x0000000000ff0000ull) << 24) \
| (((n) & 0x000000000000ff00ull) << 40) \
| (((n) & 0x00000000000000ffull) << 56) )
# define bswap_32(n) \
( (((n) & 0xff000000ul) >> 24) \
| (((n) & 0x00ff0000ul) >> 8) \
| (((n) & 0x0000ff00ul) << 8) \
| (((n) & 0x000000fful) << 24) )
# define bswap_16(n) \
( (((n) & ((unsigned short)0xff00ul)) >> 8) \
| (((n) & ((unsigned short)0x00fful)) << 8) )
# define THRIFT_htolell(n) bswap_64(n)
# define THRIFT_letohll(n) bswap_64(n)
# define THRIFT_htolel(n) bswap_32(n)
# define THRIFT_letohl(n) bswap_32(n)
# define THRIFT_htoles(n) bswap_16(n)
# define THRIFT_letohs(n) bswap_16(n)
# endif /* GNUC & GLIBC */
#elif __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
# define THRIFT_htolell(n) (n)
# define THRIFT_letohll(n) (n)
# define THRIFT_htolel(n) (n)
# define THRIFT_letohl(n) (n)
# define THRIFT_htoles(n) (n)
# define THRIFT_letohs(n) (n)
# if defined(__GNUC__) && defined(__GLIBC__)
# include <byteswap.h>
# define THRIFT_ntohll(n) bswap_64(n)
# define THRIFT_htonll(n) bswap_64(n)
# elif defined(_MSC_VER) /* Microsoft Visual C++ */
# define THRIFT_ntohll(n) ( _byteswap_uint64((uint64_t)n) )
# define THRIFT_htonll(n) ( _byteswap_uint64((uint64_t)n) )
# elif !defined(THRIFT_ntohll) /* Not GNUC/GLIBC or MSVC */
# define THRIFT_ntohll(n) ( (((uint64_t)ntohl((uint32_t)n)) << 32) + ntohl((uint32_t)(n >> 32)) )
# define THRIFT_htonll(n) ( (((uint64_t)htonl((uint32_t)n)) << 32) + htonl((uint32_t)(n >> 32)) )
# endif /* GNUC/GLIBC or MSVC or something else */
#else /* __THRIFT_BYTE_ORDER */
# error "Can't define THRIFT_htonll or THRIFT_ntohll!"
#endif
namespace apache {
namespace thrift {
namespace protocol {
using apache::thrift::transport::TTransport;
/**
* Enumerated definition of the types that the Thrift protocol supports.
* Take special note of the T_END type which is used specifically to mark
* the end of a sequence of fields.
*/
enum TType {
T_STOP = 0,
T_VOID = 1,
T_BOOL = 2,
T_BYTE = 3,
T_I08 = 3,
T_I16 = 6,
T_I32 = 8,
T_U64 = 9,
T_I64 = 10,
T_DOUBLE = 4,
T_STRING = 11,
T_UTF7 = 11,
T_STRUCT = 12,
T_MAP = 13,
T_SET = 14,
T_LIST = 15,
T_UTF8 = 16,
T_UTF16 = 17
};
/**
* Enumerated definition of the message types that the Thrift protocol
* supports.
*/
enum TMessageType {
T_CALL = 1,
T_REPLY = 2,
T_EXCEPTION = 3,
T_ONEWAY = 4
};
static const uint32_t DEFAULT_RECURSION_LIMIT = 64;
/**
* Abstract class for a thrift protocol driver. These are all the methods that
* a protocol must implement. Essentially, there must be some way of reading
* and writing all the base types, plus a mechanism for writing out structs
* with indexed fields.
*
* TProtocol objects should not be shared across multiple encoding contexts,
* as they may need to maintain internal state in some protocols (i.e. XML).
* Note that is is acceptable for the TProtocol module to do its own internal
* buffered reads/writes to the underlying TTransport where appropriate (i.e.
* when parsing an input XML stream, reading should be batched rather than
* looking ahead character by character for a close tag).
*
*/
class TProtocol {
public:
virtual ~TProtocol();
/**
* Writing functions.
*/
virtual uint32_t writeMessageBegin_virt(const std::string& name,
const TMessageType messageType,
const int32_t seqid) = 0;
virtual uint32_t writeMessageEnd_virt() = 0;
virtual uint32_t writeStructBegin_virt(const char* name) = 0;
virtual uint32_t writeStructEnd_virt() = 0;
virtual uint32_t writeFieldBegin_virt(const char* name,
const TType fieldType,
const int16_t fieldId) = 0;
virtual uint32_t writeFieldEnd_virt() = 0;
virtual uint32_t writeFieldStop_virt() = 0;
virtual uint32_t writeMapBegin_virt(const TType keyType, const TType valType, const uint32_t size)
= 0;
virtual uint32_t writeMapEnd_virt() = 0;
virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) = 0;
virtual uint32_t writeListEnd_virt() = 0;
virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) = 0;
virtual uint32_t writeSetEnd_virt() = 0;
virtual uint32_t writeBool_virt(const bool value) = 0;
virtual uint32_t writeByte_virt(const int8_t byte) = 0;
virtual uint32_t writeI16_virt(const int16_t i16) = 0;
virtual uint32_t writeI32_virt(const int32_t i32) = 0;
virtual uint32_t writeI64_virt(const int64_t i64) = 0;
virtual uint32_t writeDouble_virt(const double dub) = 0;
virtual uint32_t writeString_virt(const std::string& str) = 0;
virtual uint32_t writeBinary_virt(const std::string& str) = 0;
uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
T_VIRTUAL_CALL();
return writeMessageBegin_virt(name, messageType, seqid);
}
uint32_t writeMessageEnd() {
T_VIRTUAL_CALL();
return writeMessageEnd_virt();
}
uint32_t writeStructBegin(const char* name) {
T_VIRTUAL_CALL();
return writeStructBegin_virt(name);
}
uint32_t writeStructEnd() {
T_VIRTUAL_CALL();
return writeStructEnd_virt();
}
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
T_VIRTUAL_CALL();
return writeFieldBegin_virt(name, fieldType, fieldId);
}
uint32_t writeFieldEnd() {
T_VIRTUAL_CALL();
return writeFieldEnd_virt();
}
uint32_t writeFieldStop() {
T_VIRTUAL_CALL();
return writeFieldStop_virt();
}
uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
T_VIRTUAL_CALL();
return writeMapBegin_virt(keyType, valType, size);
}
uint32_t writeMapEnd() {
T_VIRTUAL_CALL();
return writeMapEnd_virt();
}
uint32_t writeListBegin(const TType elemType, const uint32_t size) {
T_VIRTUAL_CALL();
return writeListBegin_virt(elemType, size);
}
uint32_t writeListEnd() {
T_VIRTUAL_CALL();
return writeListEnd_virt();
}
uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
T_VIRTUAL_CALL();
return writeSetBegin_virt(elemType, size);
}
uint32_t writeSetEnd() {
T_VIRTUAL_CALL();
return writeSetEnd_virt();
}
uint32_t writeBool(const bool value) {
T_VIRTUAL_CALL();
return writeBool_virt(value);
}
uint32_t writeByte(const int8_t byte) {
T_VIRTUAL_CALL();
return writeByte_virt(byte);
}
uint32_t writeI16(const int16_t i16) {
T_VIRTUAL_CALL();
return writeI16_virt(i16);
}
uint32_t writeI32(const int32_t i32) {
T_VIRTUAL_CALL();
return writeI32_virt(i32);
}
uint32_t writeI64(const int64_t i64) {
T_VIRTUAL_CALL();
return writeI64_virt(i64);
}
uint32_t writeDouble(const double dub) {
T_VIRTUAL_CALL();
return writeDouble_virt(dub);
}
uint32_t writeString(const std::string& str) {
T_VIRTUAL_CALL();
return writeString_virt(str);
}
uint32_t writeBinary(const std::string& str) {
T_VIRTUAL_CALL();
return writeBinary_virt(str);
}
/**
* Reading functions
*/
virtual uint32_t readMessageBegin_virt(std::string& name,
TMessageType& messageType,
int32_t& seqid) = 0;
virtual uint32_t readMessageEnd_virt() = 0;
virtual uint32_t readStructBegin_virt(std::string& name) = 0;
virtual uint32_t readStructEnd_virt() = 0;
virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) = 0;
virtual uint32_t readFieldEnd_virt() = 0;
virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) = 0;
virtual uint32_t readMapEnd_virt() = 0;
virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) = 0;
virtual uint32_t readListEnd_virt() = 0;
virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) = 0;
virtual uint32_t readSetEnd_virt() = 0;
virtual uint32_t readBool_virt(bool& value) = 0;
virtual uint32_t readBool_virt(std::vector<bool>::reference value) = 0;
virtual uint32_t readByte_virt(int8_t& byte) = 0;
virtual uint32_t readI16_virt(int16_t& i16) = 0;
virtual uint32_t readI32_virt(int32_t& i32) = 0;
virtual uint32_t readI64_virt(int64_t& i64) = 0;
virtual uint32_t readDouble_virt(double& dub) = 0;
virtual uint32_t readString_virt(std::string& str) = 0;
virtual uint32_t readBinary_virt(std::string& str) = 0;
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
T_VIRTUAL_CALL();
return readMessageBegin_virt(name, messageType, seqid);
}
uint32_t readMessageEnd() {
T_VIRTUAL_CALL();
return readMessageEnd_virt();
}
uint32_t readStructBegin(std::string& name) {
T_VIRTUAL_CALL();
return readStructBegin_virt(name);
}
uint32_t readStructEnd() {
T_VIRTUAL_CALL();
return readStructEnd_virt();
}
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
T_VIRTUAL_CALL();
return readFieldBegin_virt(name, fieldType, fieldId);
}
uint32_t readFieldEnd() {
T_VIRTUAL_CALL();
return readFieldEnd_virt();
}
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
T_VIRTUAL_CALL();
return readMapBegin_virt(keyType, valType, size);
}
uint32_t readMapEnd() {
T_VIRTUAL_CALL();
return readMapEnd_virt();
}
uint32_t readListBegin(TType& elemType, uint32_t& size) {
T_VIRTUAL_CALL();
return readListBegin_virt(elemType, size);
}
uint32_t readListEnd() {
T_VIRTUAL_CALL();
return readListEnd_virt();
}
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
T_VIRTUAL_CALL();
return readSetBegin_virt(elemType, size);
}
uint32_t readSetEnd() {
T_VIRTUAL_CALL();
return readSetEnd_virt();
}
uint32_t readBool(bool& value) {
T_VIRTUAL_CALL();
return readBool_virt(value);
}
uint32_t readByte(int8_t& byte) {
T_VIRTUAL_CALL();
return readByte_virt(byte);
}
uint32_t readI16(int16_t& i16) {
T_VIRTUAL_CALL();
return readI16_virt(i16);
}
uint32_t readI32(int32_t& i32) {
T_VIRTUAL_CALL();
return readI32_virt(i32);
}
uint32_t readI64(int64_t& i64) {
T_VIRTUAL_CALL();
return readI64_virt(i64);
}
uint32_t readDouble(double& dub) {
T_VIRTUAL_CALL();
return readDouble_virt(dub);
}
uint32_t readString(std::string& str) {
T_VIRTUAL_CALL();
return readString_virt(str);
}
uint32_t readBinary(std::string& str) {
T_VIRTUAL_CALL();
return readBinary_virt(str);
}
/*
* std::vector is specialized for bool, and its elements are individual bits
* rather than bools. We need to define a different version of readBool()
* to work with std::vector<bool>.
*/
uint32_t readBool(std::vector<bool>::reference value) {
T_VIRTUAL_CALL();
return readBool_virt(value);
}
/**
* Method to arbitrarily skip over data.
*/
uint32_t skip(TType type) {
T_VIRTUAL_CALL();
return skip_virt(type);
}
virtual uint32_t skip_virt(TType type);
inline boost::shared_ptr<TTransport> getTransport() { return ptrans_; }
// TODO: remove these two calls, they are for backwards
// compatibility
inline boost::shared_ptr<TTransport> getInputTransport() { return ptrans_; }
inline boost::shared_ptr<TTransport> getOutputTransport() { return ptrans_; }
// input and output recursion depth are kept separate so that one protocol
// can be used concurrently for both input and output.
void incrementInputRecursionDepth() {
if (recursion_limit_ < ++input_recursion_depth_) {
throw TProtocolException(TProtocolException::DEPTH_LIMIT);
}
}
void decrementInputRecursionDepth() { --input_recursion_depth_; }
void incrementOutputRecursionDepth() {
if (recursion_limit_ < ++output_recursion_depth_) {
throw TProtocolException(TProtocolException::DEPTH_LIMIT);
}
}
void decrementOutputRecursionDepth() { --output_recursion_depth_; }
uint32_t getRecursionLimit() const {return recursion_limit_;}
void setRecurisionLimit(uint32_t depth) {recursion_limit_ = depth;}
protected:
TProtocol(boost::shared_ptr<TTransport> ptrans)
: ptrans_(ptrans), input_recursion_depth_(0), output_recursion_depth_(0), recursion_limit_(DEFAULT_RECURSION_LIMIT)
{}
boost::shared_ptr<TTransport> ptrans_;
private:
TProtocol() {}
uint32_t input_recursion_depth_;
uint32_t output_recursion_depth_;
uint32_t recursion_limit_;
};
/**
* Constructs input and output protocol objects given transports.
*/
class TProtocolFactory {
public:
TProtocolFactory() {}
virtual ~TProtocolFactory();
virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) = 0;
virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> inTrans,
boost::shared_ptr<TTransport> outTrans) {
(void)outTrans;
return getProtocol(inTrans);
}
};
/**
* Dummy protocol class.
*
* This class does nothing, and should never be instantiated.
* It is used only by the generator code.
*/
class TDummyProtocol : public TProtocol {};
// This is the default / legacy choice
struct TNetworkBigEndian
{
static uint16_t toWire16(uint16_t x) {return htons(x);}
static uint32_t toWire32(uint32_t x) {return htonl(x);}
static uint64_t toWire64(uint64_t x) {return THRIFT_htonll(x);}
static uint16_t fromWire16(uint16_t x) {return ntohs(x);}
static uint32_t fromWire32(uint32_t x) {return ntohl(x);}
static uint64_t fromWire64(uint64_t x) {return THRIFT_ntohll(x);}
};
// On most systems, this will be a bit faster than TNetworkBigEndian
struct TNetworkLittleEndian
{
static uint16_t toWire16(uint16_t x) {return THRIFT_htoles(x);}
static uint32_t toWire32(uint32_t x) {return THRIFT_htolel(x);}
static uint64_t toWire64(uint64_t x) {return THRIFT_htolell(x);}
static uint16_t fromWire16(uint16_t x) {return THRIFT_letohs(x);}
static uint32_t fromWire32(uint32_t x) {return THRIFT_letohl(x);}
static uint64_t fromWire64(uint64_t x) {return THRIFT_letohll(x);}
};
struct TOutputRecursionTracker {
TProtocol &prot_;
TOutputRecursionTracker(TProtocol &prot) : prot_(prot) {
prot_.incrementOutputRecursionDepth();
}
~TOutputRecursionTracker() {
prot_.decrementOutputRecursionDepth();
}
};
struct TInputRecursionTracker {
TProtocol &prot_;
TInputRecursionTracker(TProtocol &prot) : prot_(prot) {
prot_.incrementInputRecursionDepth();
}
~TInputRecursionTracker() {
prot_.decrementInputRecursionDepth();
}
};
/**
* Helper template for implementing TProtocol::skip().
*
* Templatized to avoid having to make virtual function calls.
*/
template <class Protocol_>
uint32_t skip(Protocol_& prot, TType type) {
TInputRecursionTracker tracker(prot);
switch (type) {
case T_BOOL: {
bool boolv;
return prot.readBool(boolv);
}
case T_BYTE: {
int8_t bytev;
return prot.readByte(bytev);
}
case T_I16: {
int16_t i16;
return prot.readI16(i16);
}
case T_I32: {
int32_t i32;
return prot.readI32(i32);
}
case T_I64: {
int64_t i64;
return prot.readI64(i64);
}
case T_DOUBLE: {
double dub;
return prot.readDouble(dub);
}
case T_STRING: {
std::string str;
return prot.readBinary(str);
}
case T_STRUCT: {
uint32_t result = 0;
std::string name;
int16_t fid;
TType ftype;
result += prot.readStructBegin(name);
while (true) {
result += prot.readFieldBegin(name, ftype, fid);
if (ftype == T_STOP) {
break;
}
result += skip(prot, ftype);
result += prot.readFieldEnd();
}
result += prot.readStructEnd();
return result;
}
case T_MAP: {
uint32_t result = 0;
TType keyType;
TType valType;
uint32_t i, size;
result += prot.readMapBegin(keyType, valType, size);
for (i = 0; i < size; i++) {
result += skip(prot, keyType);
result += skip(prot, valType);
}
result += prot.readMapEnd();
return result;
}
case T_SET: {
uint32_t result = 0;
TType elemType;
uint32_t i, size;
result += prot.readSetBegin(elemType, size);
for (i = 0; i < size; i++) {
result += skip(prot, elemType);
}
result += prot.readSetEnd();
return result;
}
case T_LIST: {
uint32_t result = 0;
TType elemType;
uint32_t i, size;
result += prot.readListBegin(elemType, size);
for (i = 0; i < size; i++) {
result += skip(prot, elemType);
}
result += prot.readListEnd();
return result;
}
case T_STOP:
case T_VOID:
case T_U64:
case T_UTF8:
case T_UTF16:
break;
}
return 0;
}
}}} // apache::thrift::protocol
#endif // #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1

View file

@ -0,0 +1,151 @@
/*
* 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 THRIFT_TPROTOCOLDECORATOR_H_
#define THRIFT_TPROTOCOLDECORATOR_H_ 1
#include <thrift/protocol/TProtocol.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace protocol {
using boost::shared_ptr;
/**
* <code>TProtocolDecorator</code> forwards all requests to an enclosed
* <code>TProtocol</code> instance, providing a way to author concise
* concrete decorator subclasses.
*
* <p>See p.175 of Design Patterns (by Gamma et al.)</p>
*
* @see apache::thrift::protocol::TMultiplexedProtocol
*/
class TProtocolDecorator : public TProtocol {
public:
virtual ~TProtocolDecorator() {}
// Desc: Initializes the protocol decorator object.
TProtocolDecorator(shared_ptr<TProtocol> proto)
: TProtocol(proto->getTransport()), protocol(proto) {}
virtual uint32_t writeMessageBegin_virt(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
return protocol->writeMessageBegin(name, messageType, seqid);
}
virtual uint32_t writeMessageEnd_virt() { return protocol->writeMessageEnd(); }
virtual uint32_t writeStructBegin_virt(const char* name) {
return protocol->writeStructBegin(name);
}
virtual uint32_t writeStructEnd_virt() { return protocol->writeStructEnd(); }
virtual uint32_t writeFieldBegin_virt(const char* name,
const TType fieldType,
const int16_t fieldId) {
return protocol->writeFieldBegin(name, fieldType, fieldId);
}
virtual uint32_t writeFieldEnd_virt() { return protocol->writeFieldEnd(); }
virtual uint32_t writeFieldStop_virt() { return protocol->writeFieldStop(); }
virtual uint32_t writeMapBegin_virt(const TType keyType,
const TType valType,
const uint32_t size) {
return protocol->writeMapBegin(keyType, valType, size);
}
virtual uint32_t writeMapEnd_virt() { return protocol->writeMapEnd(); }
virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) {
return protocol->writeListBegin(elemType, size);
}
virtual uint32_t writeListEnd_virt() { return protocol->writeListEnd(); }
virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) {
return protocol->writeSetBegin(elemType, size);
}
virtual uint32_t writeSetEnd_virt() { return protocol->writeSetEnd(); }
virtual uint32_t writeBool_virt(const bool value) { return protocol->writeBool(value); }
virtual uint32_t writeByte_virt(const int8_t byte) { return protocol->writeByte(byte); }
virtual uint32_t writeI16_virt(const int16_t i16) { return protocol->writeI16(i16); }
virtual uint32_t writeI32_virt(const int32_t i32) { return protocol->writeI32(i32); }
virtual uint32_t writeI64_virt(const int64_t i64) { return protocol->writeI64(i64); }
virtual uint32_t writeDouble_virt(const double dub) { return protocol->writeDouble(dub); }
virtual uint32_t writeString_virt(const std::string& str) { return protocol->writeString(str); }
virtual uint32_t writeBinary_virt(const std::string& str) { return protocol->writeBinary(str); }
virtual uint32_t readMessageBegin_virt(std::string& name,
TMessageType& messageType,
int32_t& seqid) {
return protocol->readMessageBegin(name, messageType, seqid);
}
virtual uint32_t readMessageEnd_virt() { return protocol->readMessageEnd(); }
virtual uint32_t readStructBegin_virt(std::string& name) {
return protocol->readStructBegin(name);
}
virtual uint32_t readStructEnd_virt() { return protocol->readStructEnd(); }
virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) {
return protocol->readFieldBegin(name, fieldType, fieldId);
}
virtual uint32_t readFieldEnd_virt() { return protocol->readFieldEnd(); }
virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) {
return protocol->readMapBegin(keyType, valType, size);
}
virtual uint32_t readMapEnd_virt() { return protocol->readMapEnd(); }
virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) {
return protocol->readListBegin(elemType, size);
}
virtual uint32_t readListEnd_virt() { return protocol->readListEnd(); }
virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) {
return protocol->readSetBegin(elemType, size);
}
virtual uint32_t readSetEnd_virt() { return protocol->readSetEnd(); }
virtual uint32_t readBool_virt(bool& value) { return protocol->readBool(value); }
virtual uint32_t readBool_virt(std::vector<bool>::reference value) {
return protocol->readBool(value);
}
virtual uint32_t readByte_virt(int8_t& byte) { return protocol->readByte(byte); }
virtual uint32_t readI16_virt(int16_t& i16) { return protocol->readI16(i16); }
virtual uint32_t readI32_virt(int32_t& i32) { return protocol->readI32(i32); }
virtual uint32_t readI64_virt(int64_t& i64) { return protocol->readI64(i64); }
virtual uint32_t readDouble_virt(double& dub) { return protocol->readDouble(dub); }
virtual uint32_t readString_virt(std::string& str) { return protocol->readString(str); }
virtual uint32_t readBinary_virt(std::string& str) { return protocol->readBinary(str); }
private:
shared_ptr<TProtocol> protocol;
};
}
}
}
#endif // THRIFT_TPROTOCOLDECORATOR_H_

View file

@ -0,0 +1,105 @@
/*
* 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 _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_
#define _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_ 1
#include <string>
namespace apache {
namespace thrift {
namespace protocol {
/**
* Class to encapsulate all the possible types of protocol errors that may
* occur in various protocol systems. This provides a sort of generic
* wrapper around the vague UNIX E_ error codes that lets a common code
* base of error handling to be used for various types of protocols, i.e.
* pipes etc.
*
*/
class TProtocolException : public apache::thrift::TException {
public:
/**
* Error codes for the various types of exceptions.
*/
enum TProtocolExceptionType {
UNKNOWN = 0,
INVALID_DATA = 1,
NEGATIVE_SIZE = 2,
SIZE_LIMIT = 3,
BAD_VERSION = 4,
NOT_IMPLEMENTED = 5,
DEPTH_LIMIT = 6
};
TProtocolException() : apache::thrift::TException(), type_(UNKNOWN) {}
TProtocolException(TProtocolExceptionType type) : apache::thrift::TException(), type_(type) {}
TProtocolException(const std::string& message)
: apache::thrift::TException(message), type_(UNKNOWN) {}
TProtocolException(TProtocolExceptionType type, const std::string& message)
: apache::thrift::TException(message), type_(type) {}
virtual ~TProtocolException() throw() {}
/**
* Returns an error code that provides information about the type of error
* that has occurred.
*
* @return Error code
*/
TProtocolExceptionType getType() const { return type_; }
virtual const char* what() const throw() {
if (message_.empty()) {
switch (type_) {
case UNKNOWN:
return "TProtocolException: Unknown protocol exception";
case INVALID_DATA:
return "TProtocolException: Invalid data";
case NEGATIVE_SIZE:
return "TProtocolException: Negative size";
case SIZE_LIMIT:
return "TProtocolException: Exceeded size limit";
case BAD_VERSION:
return "TProtocolException: Invalid version";
case NOT_IMPLEMENTED:
return "TProtocolException: Not implemented";
default:
return "TProtocolException: (Invalid exception type)";
}
} else {
return message_.c_str();
}
}
protected:
/**
* Error code
*/
TProtocolExceptionType type_;
};
}
}
} // apache::thrift::protocol
#endif // #ifndef _THRIFT_PROTOCOL_TPROTOCOLEXCEPTION_H_

View file

@ -0,0 +1,177 @@
/*
* 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 _THRIFT_PROTOCOL_TPROTOCOLTAP_H_
#define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1
#include <thrift/protocol/TVirtualProtocol.h>
namespace apache {
namespace thrift {
namespace protocol {
using apache::thrift::transport::TTransport;
/**
* Puts a wiretap on a protocol object. Any reads to this class are passed
* through to an enclosed protocol object, but also mirrored as write to a
* second protocol object.
*
*/
class TProtocolTap : public TVirtualProtocol<TProtocolTap> {
public:
TProtocolTap(boost::shared_ptr<TProtocol> source, boost::shared_ptr<TProtocol> sink)
: TVirtualProtocol<TProtocolTap>(source->getTransport()), source_(source), sink_(sink) {}
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
uint32_t rv = source_->readMessageBegin(name, messageType, seqid);
sink_->writeMessageBegin(name, messageType, seqid);
return rv;
}
uint32_t readMessageEnd() {
uint32_t rv = source_->readMessageEnd();
sink_->writeMessageEnd();
return rv;
}
uint32_t readStructBegin(std::string& name) {
uint32_t rv = source_->readStructBegin(name);
sink_->writeStructBegin(name.c_str());
return rv;
}
uint32_t readStructEnd() {
uint32_t rv = source_->readStructEnd();
sink_->writeStructEnd();
return rv;
}
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
uint32_t rv = source_->readFieldBegin(name, fieldType, fieldId);
if (fieldType == T_STOP) {
sink_->writeFieldStop();
} else {
sink_->writeFieldBegin(name.c_str(), fieldType, fieldId);
}
return rv;
}
uint32_t readFieldEnd() {
uint32_t rv = source_->readFieldEnd();
sink_->writeFieldEnd();
return rv;
}
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
uint32_t rv = source_->readMapBegin(keyType, valType, size);
sink_->writeMapBegin(keyType, valType, size);
return rv;
}
uint32_t readMapEnd() {
uint32_t rv = source_->readMapEnd();
sink_->writeMapEnd();
return rv;
}
uint32_t readListBegin(TType& elemType, uint32_t& size) {
uint32_t rv = source_->readListBegin(elemType, size);
sink_->writeListBegin(elemType, size);
return rv;
}
uint32_t readListEnd() {
uint32_t rv = source_->readListEnd();
sink_->writeListEnd();
return rv;
}
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
uint32_t rv = source_->readSetBegin(elemType, size);
sink_->writeSetBegin(elemType, size);
return rv;
}
uint32_t readSetEnd() {
uint32_t rv = source_->readSetEnd();
sink_->writeSetEnd();
return rv;
}
uint32_t readBool(bool& value) {
uint32_t rv = source_->readBool(value);
sink_->writeBool(value);
return rv;
}
// Provide the default readBool() implementation for std::vector<bool>
using TVirtualProtocol<TProtocolTap>::readBool;
uint32_t readByte(int8_t& byte) {
uint32_t rv = source_->readByte(byte);
sink_->writeByte(byte);
return rv;
}
uint32_t readI16(int16_t& i16) {
uint32_t rv = source_->readI16(i16);
sink_->writeI16(i16);
return rv;
}
uint32_t readI32(int32_t& i32) {
uint32_t rv = source_->readI32(i32);
sink_->writeI32(i32);
return rv;
}
uint32_t readI64(int64_t& i64) {
uint32_t rv = source_->readI64(i64);
sink_->writeI64(i64);
return rv;
}
uint32_t readDouble(double& dub) {
uint32_t rv = source_->readDouble(dub);
sink_->writeDouble(dub);
return rv;
}
uint32_t readString(std::string& str) {
uint32_t rv = source_->readString(str);
sink_->writeString(str);
return rv;
}
uint32_t readBinary(std::string& str) {
uint32_t rv = source_->readBinary(str);
sink_->writeBinary(str);
return rv;
}
private:
boost::shared_ptr<TProtocol> source_;
boost::shared_ptr<TProtocol> sink_;
};
}
}
} // apache::thrift::protocol
#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTAP_H_ 1

View file

@ -0,0 +1,36 @@
/*
* 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 THRIFT_PROTOCOL_TPROTOCOLTYPES_H_
#define THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1
namespace apache {
namespace thrift {
namespace protocol {
enum PROTOCOL_TYPES {
T_BINARY_PROTOCOL = 0,
T_JSON_PROTOCOL = 1,
T_COMPACT_PROTOCOL = 2,
};
}
}
} // apache::thrift::protocol
#endif // #define _THRIFT_PROTOCOL_TPROTOCOLTYPES_H_ 1

View file

@ -0,0 +1,513 @@
/*
* 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 _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_
#define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1
#include <thrift/protocol/TProtocol.h>
namespace apache {
namespace thrift {
namespace protocol {
using apache::thrift::transport::TTransport;
/**
* Helper class that provides default implementations of TProtocol methods.
*
* This class provides default implementations of the non-virtual TProtocol
* methods. It exists primarily so TVirtualProtocol can derive from it. It
* prevents TVirtualProtocol methods from causing infinite recursion if the
* non-virtual methods are not overridden by the TVirtualProtocol subclass.
*
* You probably don't want to use this class directly. Use TVirtualProtocol
* instead.
*/
class TProtocolDefaults : public TProtocol {
public:
uint32_t readMessageBegin(std::string& name, TMessageType& messageType, int32_t& seqid) {
(void)name;
(void)messageType;
(void)seqid;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readMessageEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readStructBegin(std::string& name) {
(void)name;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readStructEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readFieldBegin(std::string& name, TType& fieldType, int16_t& fieldId) {
(void)name;
(void)fieldType;
(void)fieldId;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readFieldEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readMapBegin(TType& keyType, TType& valType, uint32_t& size) {
(void)keyType;
(void)valType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readMapEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readListBegin(TType& elemType, uint32_t& size) {
(void)elemType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readListEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readSetBegin(TType& elemType, uint32_t& size) {
(void)elemType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readSetEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readBool(bool& value) {
(void)value;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readBool(std::vector<bool>::reference value) {
(void)value;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readByte(int8_t& byte) {
(void)byte;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readI16(int16_t& i16) {
(void)i16;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readI32(int32_t& i32) {
(void)i32;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readI64(int64_t& i64) {
(void)i64;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readDouble(double& dub) {
(void)dub;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readString(std::string& str) {
(void)str;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t readBinary(std::string& str) {
(void)str;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support reading (yet).");
}
uint32_t writeMessageBegin(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
(void)name;
(void)messageType;
(void)seqid;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeMessageEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeStructBegin(const char* name) {
(void)name;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeStructEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeFieldBegin(const char* name, const TType fieldType, const int16_t fieldId) {
(void)name;
(void)fieldType;
(void)fieldId;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeFieldEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeFieldStop() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeMapBegin(const TType keyType, const TType valType, const uint32_t size) {
(void)keyType;
(void)valType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeMapEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeListBegin(const TType elemType, const uint32_t size) {
(void)elemType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeListEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeSetBegin(const TType elemType, const uint32_t size) {
(void)elemType;
(void)size;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeSetEnd() {
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeBool(const bool value) {
(void)value;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeByte(const int8_t byte) {
(void)byte;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeI16(const int16_t i16) {
(void)i16;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeI32(const int32_t i32) {
(void)i32;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeI64(const int64_t i64) {
(void)i64;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeDouble(const double dub) {
(void)dub;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeString(const std::string& str) {
(void)str;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t writeBinary(const std::string& str) {
(void)str;
throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
"this protocol does not support writing (yet).");
}
uint32_t skip(TType type) { return ::apache::thrift::protocol::skip(*this, type); }
protected:
TProtocolDefaults(boost::shared_ptr<TTransport> ptrans) : TProtocol(ptrans) {}
};
/**
* Concrete TProtocol classes should inherit from TVirtualProtocol
* so they don't have to manually override virtual methods.
*/
template <class Protocol_, class Super_ = TProtocolDefaults>
class TVirtualProtocol : public Super_ {
public:
/**
* Writing functions.
*/
virtual uint32_t writeMessageBegin_virt(const std::string& name,
const TMessageType messageType,
const int32_t seqid) {
return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType, seqid);
}
virtual uint32_t writeMessageEnd_virt() {
return static_cast<Protocol_*>(this)->writeMessageEnd();
}
virtual uint32_t writeStructBegin_virt(const char* name) {
return static_cast<Protocol_*>(this)->writeStructBegin(name);
}
virtual uint32_t writeStructEnd_virt() { return static_cast<Protocol_*>(this)->writeStructEnd(); }
virtual uint32_t writeFieldBegin_virt(const char* name,
const TType fieldType,
const int16_t fieldId) {
return static_cast<Protocol_*>(this)->writeFieldBegin(name, fieldType, fieldId);
}
virtual uint32_t writeFieldEnd_virt() { return static_cast<Protocol_*>(this)->writeFieldEnd(); }
virtual uint32_t writeFieldStop_virt() { return static_cast<Protocol_*>(this)->writeFieldStop(); }
virtual uint32_t writeMapBegin_virt(const TType keyType,
const TType valType,
const uint32_t size) {
return static_cast<Protocol_*>(this)->writeMapBegin(keyType, valType, size);
}
virtual uint32_t writeMapEnd_virt() { return static_cast<Protocol_*>(this)->writeMapEnd(); }
virtual uint32_t writeListBegin_virt(const TType elemType, const uint32_t size) {
return static_cast<Protocol_*>(this)->writeListBegin(elemType, size);
}
virtual uint32_t writeListEnd_virt() { return static_cast<Protocol_*>(this)->writeListEnd(); }
virtual uint32_t writeSetBegin_virt(const TType elemType, const uint32_t size) {
return static_cast<Protocol_*>(this)->writeSetBegin(elemType, size);
}
virtual uint32_t writeSetEnd_virt() { return static_cast<Protocol_*>(this)->writeSetEnd(); }
virtual uint32_t writeBool_virt(const bool value) {
return static_cast<Protocol_*>(this)->writeBool(value);
}
virtual uint32_t writeByte_virt(const int8_t byte) {
return static_cast<Protocol_*>(this)->writeByte(byte);
}
virtual uint32_t writeI16_virt(const int16_t i16) {
return static_cast<Protocol_*>(this)->writeI16(i16);
}
virtual uint32_t writeI32_virt(const int32_t i32) {
return static_cast<Protocol_*>(this)->writeI32(i32);
}
virtual uint32_t writeI64_virt(const int64_t i64) {
return static_cast<Protocol_*>(this)->writeI64(i64);
}
virtual uint32_t writeDouble_virt(const double dub) {
return static_cast<Protocol_*>(this)->writeDouble(dub);
}
virtual uint32_t writeString_virt(const std::string& str) {
return static_cast<Protocol_*>(this)->writeString(str);
}
virtual uint32_t writeBinary_virt(const std::string& str) {
return static_cast<Protocol_*>(this)->writeBinary(str);
}
/**
* Reading functions
*/
virtual uint32_t readMessageBegin_virt(std::string& name,
TMessageType& messageType,
int32_t& seqid) {
return static_cast<Protocol_*>(this)->readMessageBegin(name, messageType, seqid);
}
virtual uint32_t readMessageEnd_virt() { return static_cast<Protocol_*>(this)->readMessageEnd(); }
virtual uint32_t readStructBegin_virt(std::string& name) {
return static_cast<Protocol_*>(this)->readStructBegin(name);
}
virtual uint32_t readStructEnd_virt() { return static_cast<Protocol_*>(this)->readStructEnd(); }
virtual uint32_t readFieldBegin_virt(std::string& name, TType& fieldType, int16_t& fieldId) {
return static_cast<Protocol_*>(this)->readFieldBegin(name, fieldType, fieldId);
}
virtual uint32_t readFieldEnd_virt() { return static_cast<Protocol_*>(this)->readFieldEnd(); }
virtual uint32_t readMapBegin_virt(TType& keyType, TType& valType, uint32_t& size) {
return static_cast<Protocol_*>(this)->readMapBegin(keyType, valType, size);
}
virtual uint32_t readMapEnd_virt() { return static_cast<Protocol_*>(this)->readMapEnd(); }
virtual uint32_t readListBegin_virt(TType& elemType, uint32_t& size) {
return static_cast<Protocol_*>(this)->readListBegin(elemType, size);
}
virtual uint32_t readListEnd_virt() { return static_cast<Protocol_*>(this)->readListEnd(); }
virtual uint32_t readSetBegin_virt(TType& elemType, uint32_t& size) {
return static_cast<Protocol_*>(this)->readSetBegin(elemType, size);
}
virtual uint32_t readSetEnd_virt() { return static_cast<Protocol_*>(this)->readSetEnd(); }
virtual uint32_t readBool_virt(bool& value) {
return static_cast<Protocol_*>(this)->readBool(value);
}
virtual uint32_t readBool_virt(std::vector<bool>::reference value) {
return static_cast<Protocol_*>(this)->readBool(value);
}
virtual uint32_t readByte_virt(int8_t& byte) {
return static_cast<Protocol_*>(this)->readByte(byte);
}
virtual uint32_t readI16_virt(int16_t& i16) {
return static_cast<Protocol_*>(this)->readI16(i16);
}
virtual uint32_t readI32_virt(int32_t& i32) {
return static_cast<Protocol_*>(this)->readI32(i32);
}
virtual uint32_t readI64_virt(int64_t& i64) {
return static_cast<Protocol_*>(this)->readI64(i64);
}
virtual uint32_t readDouble_virt(double& dub) {
return static_cast<Protocol_*>(this)->readDouble(dub);
}
virtual uint32_t readString_virt(std::string& str) {
return static_cast<Protocol_*>(this)->readString(str);
}
virtual uint32_t readBinary_virt(std::string& str) {
return static_cast<Protocol_*>(this)->readBinary(str);
}
virtual uint32_t skip_virt(TType type) { return static_cast<Protocol_*>(this)->skip(type); }
/*
* Provide a default skip() implementation that uses non-virtual read
* methods.
*
* Note: subclasses that use TVirtualProtocol to derive from another protocol
* implementation (i.e., not TProtocolDefaults) should beware that this may
* override any non-default skip() implementation provided by the parent
* transport class. They may need to explicitly redefine skip() to call the
* correct parent implementation, if desired.
*/
uint32_t skip(TType type) {
Protocol_* const prot = static_cast<Protocol_*>(this);
return ::apache::thrift::protocol::skip(*prot, type);
}
/*
* Provide a default readBool() implementation for use with
* std::vector<bool>, that behaves the same as reading into a normal bool.
*
* Subclasses can override this if desired, but there normally shouldn't
* be a need to.
*/
uint32_t readBool(std::vector<bool>::reference value) {
bool b = false;
uint32_t ret = static_cast<Protocol_*>(this)->readBool(b);
value = b;
return ret;
}
using Super_::readBool; // so we don't hide readBool(bool&)
protected:
TVirtualProtocol(boost::shared_ptr<TTransport> ptrans) : Super_(ptrans) {}
};
}
}
} // apache::thrift::protocol
#endif // #define _THRIFT_PROTOCOL_TVIRTUALPROTOCOL_H_ 1

View file

@ -0,0 +1,28 @@
#
# 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.
#
set( thriftcppqt5_SOURCES
TQIODeviceTransport.cpp
TQTcpServer.cpp
)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 REQUIRED COMPONENTS Core Network)
ADD_LIBRARY_THRIFT(thriftqt5 ${thriftcppqt5_SOURCES})
TARGET_LINK_LIBRARIES_THRIFT(thriftqt5 Qt5::Core Qt5::Network)
TARGET_LINK_LIBRARIES_THRIFT_AGAINST_THRIFT_LIBRARY(thriftqt5 thrift)

View file

@ -0,0 +1,167 @@
/*
* 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 <thrift/qt/TQIODeviceTransport.h>
#include <QAbstractSocket>
#include <QIODevice>
#include <thrift/transport/TBufferTransports.h>
using boost::shared_ptr;
namespace apache {
namespace thrift {
namespace transport {
TQIODeviceTransport::TQIODeviceTransport(shared_ptr<QIODevice> dev) : dev_(dev) {
}
TQIODeviceTransport::~TQIODeviceTransport() {
dev_->close();
}
void TQIODeviceTransport::open() {
if (!isOpen()) {
throw TTransportException(TTransportException::NOT_OPEN,
"open(): underlying QIODevice isn't open");
}
}
bool TQIODeviceTransport::isOpen() {
return dev_->isOpen();
}
bool TQIODeviceTransport::peek() {
return dev_->bytesAvailable() > 0;
}
void TQIODeviceTransport::close() {
dev_->close();
}
uint32_t TQIODeviceTransport::readAll(uint8_t* buf, uint32_t len) {
uint32_t requestLen = len;
while (len) {
uint32_t readSize;
try {
readSize = read(buf, len);
} catch (...) {
if (len != requestLen) {
// something read already
return requestLen - len;
}
// error but nothing read yet
throw;
}
if (readSize == 0) {
dev_->waitForReadyRead(50);
} else {
buf += readSize;
len -= readSize;
}
}
return requestLen;
}
uint32_t TQIODeviceTransport::read(uint8_t* buf, uint32_t len) {
uint32_t actualSize;
qint64 readSize;
if (!dev_->isOpen()) {
throw TTransportException(TTransportException::NOT_OPEN,
"read(): underlying QIODevice is not open");
}
actualSize = (uint32_t)std::min((qint64)len, dev_->bytesAvailable());
readSize = dev_->read(reinterpret_cast<char*>(buf), actualSize);
if (readSize < 0) {
QAbstractSocket* socket;
if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
throw TTransportException(TTransportException::UNKNOWN,
"Failed to read() from QAbstractSocket",
socket->error());
}
throw TTransportException(TTransportException::UNKNOWN, "Failed to read from from QIODevice");
}
return (uint32_t)readSize;
}
void TQIODeviceTransport::write(const uint8_t* buf, uint32_t len) {
while (len) {
uint32_t written = write_partial(buf, len);
len -= written;
dev_->waitForBytesWritten(50);
}
}
uint32_t TQIODeviceTransport::write_partial(const uint8_t* buf, uint32_t len) {
qint64 written;
if (!dev_->isOpen()) {
throw TTransportException(TTransportException::NOT_OPEN,
"write_partial(): underlying QIODevice is not open");
}
written = dev_->write(reinterpret_cast<const char*>(buf), len);
if (written < 0) {
QAbstractSocket* socket;
if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
throw TTransportException(TTransportException::UNKNOWN,
"write_partial(): failed to write to QAbstractSocket",
socket->error());
}
throw TTransportException(TTransportException::UNKNOWN,
"write_partial(): failed to write to underlying QIODevice");
}
return (uint32_t)written;
}
void TQIODeviceTransport::flush() {
if (!dev_->isOpen()) {
throw TTransportException(TTransportException::NOT_OPEN,
"flush(): underlying QIODevice is not open");
}
QAbstractSocket* socket;
if ((socket = qobject_cast<QAbstractSocket*>(dev_.get()))) {
socket->flush();
} else {
dev_->waitForBytesWritten(1);
}
}
uint8_t* TQIODeviceTransport::borrow(uint8_t* buf, uint32_t* len) {
(void)buf;
(void)len;
return NULL;
}
void TQIODeviceTransport::consume(uint32_t len) {
(void)len;
throw TTransportException(TTransportException::UNKNOWN);
}
}
}
} // apache::thrift::transport

View file

@ -0,0 +1,68 @@
/*
* 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 _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_
#define _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_ 1
#include <boost/shared_ptr.hpp>
#include <thrift/transport/TVirtualTransport.h>
class QIODevice;
namespace apache {
namespace thrift {
namespace transport {
/**
* Transport that operates on a QIODevice (socket, file, etc).
*/
class TQIODeviceTransport
: public apache::thrift::transport::TVirtualTransport<TQIODeviceTransport> {
public:
explicit TQIODeviceTransport(boost::shared_ptr<QIODevice> dev);
virtual ~TQIODeviceTransport();
void open();
bool isOpen();
bool peek();
void close();
uint32_t readAll(uint8_t* buf, uint32_t len);
uint32_t read(uint8_t* buf, uint32_t len);
void write(const uint8_t* buf, uint32_t len);
uint32_t write_partial(const uint8_t* buf, uint32_t len);
void flush();
uint8_t* borrow(uint8_t* buf, uint32_t* len);
void consume(uint32_t len);
private:
TQIODeviceTransport(const TQIODeviceTransport&);
TQIODeviceTransport& operator=(const TQIODeviceTransport&);
boost::shared_ptr<QIODevice> dev_;
};
}
}
} // apache::thrift::transport
#endif // #ifndef _THRIFT_ASYNC_TQIODEVICE_TRANSPORT_H_

View file

@ -0,0 +1,150 @@
/*
* 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 <thrift/qt/TQTcpServer.h>
#include <thrift/qt/TQIODeviceTransport.h>
#include <QMetaType>
#include <QTcpSocket>
#include <thrift/cxxfunctional.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/async/TAsyncProcessor.h>
using boost::shared_ptr;
using apache::thrift::protocol::TProtocol;
using apache::thrift::protocol::TProtocolFactory;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TQIODeviceTransport;
using apache::thrift::stdcxx::function;
using apache::thrift::stdcxx::bind;
QT_USE_NAMESPACE
namespace apache {
namespace thrift {
namespace async {
struct TQTcpServer::ConnectionContext {
shared_ptr<QTcpSocket> connection_;
shared_ptr<TTransport> transport_;
shared_ptr<TProtocol> iprot_;
shared_ptr<TProtocol> oprot_;
explicit ConnectionContext(shared_ptr<QTcpSocket> connection,
shared_ptr<TTransport> transport,
shared_ptr<TProtocol> iprot,
shared_ptr<TProtocol> oprot)
: connection_(connection), transport_(transport), iprot_(iprot), oprot_(oprot) {}
};
TQTcpServer::TQTcpServer(shared_ptr<QTcpServer> server,
shared_ptr<TAsyncProcessor> processor,
shared_ptr<TProtocolFactory> pfact,
QObject* parent)
: QObject(parent), server_(server), processor_(processor), pfact_(pfact) {
qRegisterMetaType<QTcpSocket*>("QTcpSocket*");
connect(server.get(), SIGNAL(newConnection()), SLOT(processIncoming()));
}
TQTcpServer::~TQTcpServer() {
}
void TQTcpServer::processIncoming() {
while (server_->hasPendingConnections()) {
// take ownership of the QTcpSocket; technically it could be deleted
// when the QTcpServer is destroyed, but any real app should delete this
// class before deleting the QTcpServer that we are using
shared_ptr<QTcpSocket> connection(server_->nextPendingConnection());
shared_ptr<TTransport> transport;
shared_ptr<TProtocol> iprot;
shared_ptr<TProtocol> oprot;
try {
transport = shared_ptr<TTransport>(new TQIODeviceTransport(connection));
iprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
oprot = shared_ptr<TProtocol>(pfact_->getProtocol(transport));
} catch (...) {
qWarning("[TQTcpServer] Failed to initialize transports/protocols");
continue;
}
ctxMap_[connection.get()]
= shared_ptr<ConnectionContext>(new ConnectionContext(connection, transport, iprot, oprot));
connect(connection.get(), SIGNAL(readyRead()), SLOT(beginDecode()));
connect(connection.get(), SIGNAL(disconnected()), SLOT(socketClosed()));
}
}
void TQTcpServer::beginDecode() {
QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
Q_ASSERT(connection);
if (ctxMap_.find(connection) == ctxMap_.end()) {
qWarning("[TQTcpServer] Got data on an unknown QTcpSocket");
return;
}
shared_ptr<ConnectionContext> ctx = ctxMap_[connection];
try {
processor_
->process(bind(&TQTcpServer::finish, this, ctx, apache::thrift::stdcxx::placeholders::_1),
ctx->iprot_,
ctx->oprot_);
} catch (const TTransportException& ex) {
qWarning("[TQTcpServer] TTransportException during processing: '%s'", ex.what());
scheduleDeleteConnectionContext(connection);
} catch (...) {
qWarning("[TQTcpServer] Unknown processor exception");
scheduleDeleteConnectionContext(connection);
}
}
void TQTcpServer::socketClosed() {
QTcpSocket* connection(qobject_cast<QTcpSocket*>(sender()));
Q_ASSERT(connection);
scheduleDeleteConnectionContext(connection);
}
void TQTcpServer::deleteConnectionContext(QTcpSocket* connection) {
const ConnectionContextMap::size_type deleted = ctxMap_.erase(connection);
if (0 == deleted) {
qWarning("[TQTcpServer] Unknown QTcpSocket");
}
}
void TQTcpServer::scheduleDeleteConnectionContext(QTcpSocket* connection) {
QMetaObject::invokeMethod(this, "deleteConnectionContext", Qt::QueuedConnection, Q_ARG(QTcpSocket*, connection));
}
void TQTcpServer::finish(shared_ptr<ConnectionContext> ctx, bool healthy) {
if (!healthy) {
qWarning("[TQTcpServer] Processor failed to process data successfully");
deleteConnectionContext(ctx->connection_.get());
}
}
}
}
} // apache::thrift::async

View file

@ -0,0 +1,81 @@
/*
* 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 _THRIFT_TASYNC_QTCP_SERVER_H_
#define _THRIFT_TASYNC_QTCP_SERVER_H_
#include <QObject>
#include <QTcpServer>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace protocol {
class TProtocolFactory;
}
}
} // apache::thrift::protocol
namespace apache {
namespace thrift {
namespace async {
class TAsyncProcessor;
/**
* Server that uses Qt to listen for connections.
* Simply give it a QTcpServer that is listening, along with an async
* processor and a protocol factory, and then run the Qt event loop.
*/
class TQTcpServer : public QObject {
Q_OBJECT
public:
TQTcpServer(boost::shared_ptr<QTcpServer> server,
boost::shared_ptr<TAsyncProcessor> processor,
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> protocolFactory,
QObject* parent = NULL);
virtual ~TQTcpServer();
private Q_SLOTS:
void processIncoming();
void beginDecode();
void socketClosed();
void deleteConnectionContext(QTcpSocket* connection);
private:
Q_DISABLE_COPY(TQTcpServer)
struct ConnectionContext;
void scheduleDeleteConnectionContext(QTcpSocket* connection);
void finish(boost::shared_ptr<ConnectionContext> ctx, bool healthy);
boost::shared_ptr<QTcpServer> server_;
boost::shared_ptr<TAsyncProcessor> processor_;
boost::shared_ptr<apache::thrift::protocol::TProtocolFactory> pfact_;
typedef std::map<QTcpSocket*, boost::shared_ptr<ConnectionContext> > ConnectionContextMap;
ConnectionContextMap ctxMap_;
};
}
}
} // apache::thrift::async
#endif // #ifndef _THRIFT_TASYNC_QTCP_SERVER_H_

View file

@ -0,0 +1,123 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <thrift/server/TConnectedClient.h>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::TProcessor;
using apache::thrift::protocol::TProtocol;
using apache::thrift::server::TServerEventHandler;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using boost::shared_ptr;
using std::string;
TConnectedClient::TConnectedClient(const shared_ptr<TProcessor>& processor,
const shared_ptr<TProtocol>& inputProtocol,
const shared_ptr<TProtocol>& outputProtocol,
const shared_ptr<TServerEventHandler>& eventHandler,
const shared_ptr<TTransport>& client)
: processor_(processor),
inputProtocol_(inputProtocol),
outputProtocol_(outputProtocol),
eventHandler_(eventHandler),
client_(client),
opaqueContext_(0) {
}
TConnectedClient::~TConnectedClient() {
}
void TConnectedClient::run() {
if (eventHandler_) {
opaqueContext_ = eventHandler_->createContext(inputProtocol_, outputProtocol_);
}
for (bool done = false; !done;) {
if (eventHandler_) {
eventHandler_->processContext(opaqueContext_, client_);
}
try {
if (!processor_->process(inputProtocol_, outputProtocol_, opaqueContext_)) {
break;
}
} catch (const TTransportException& ttx) {
switch (ttx.getType()) {
case TTransportException::END_OF_FILE:
case TTransportException::INTERRUPTED:
case TTransportException::TIMED_OUT:
// Client disconnected or was interrupted or did not respond within the receive timeout.
// No logging needed. Done.
done = true;
break;
default: {
// All other transport exceptions are logged.
// State of connection is unknown. Done.
string errStr = string("TConnectedClient died: ") + ttx.what();
GlobalOutput(errStr.c_str());
done = true;
break;
}
}
} catch (const TException& tex) {
string errStr = string("TConnectedClient processing exception: ") + tex.what();
GlobalOutput(errStr.c_str());
// Disconnect from client, because we could not process the message.
done = true;
}
}
cleanup();
}
void TConnectedClient::cleanup() {
if (eventHandler_) {
eventHandler_->deleteContext(opaqueContext_, inputProtocol_, outputProtocol_);
}
try {
inputProtocol_->getTransport()->close();
} catch (const TTransportException& ttx) {
string errStr = string("TConnectedClient input close failed: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
try {
outputProtocol_->getTransport()->close();
} catch (const TTransportException& ttx) {
string errStr = string("TConnectedClient output close failed: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
try {
client_->close();
} catch (const TTransportException& ttx) {
string errStr = string("TConnectedClient client close failed: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
}
}
}
} // apache::thrift::server

View file

@ -0,0 +1,110 @@
/*
* 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 _THRIFT_SERVER_TCONNECTEDCLIENT_H_
#define _THRIFT_SERVER_TCONNECTEDCLIENT_H_ 1
#include <boost/shared_ptr.hpp>
#include <thrift/TProcessor.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/server/TServer.h>
#include <thrift/transport/TTransport.h>
namespace apache {
namespace thrift {
namespace server {
/**
* This represents a client connected to a TServer. The
* processing loop for a client must provide some required
* functionality common to all implementations so it is
* encapsulated here.
*/
class TConnectedClient : public apache::thrift::concurrency::Runnable {
public:
/**
* Constructor.
*
* @param[in] processor the TProcessor
* @param[in] inputProtocol the input TProtocol
* @param[in] outputProtocol the output TProtocol
* @param[in] eventHandler the server event handler
* @param[in] client the TTransport representing the client
*/
TConnectedClient(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::protocol::TProtocol>& inputProtocol,
const boost::shared_ptr<apache::thrift::protocol::TProtocol>& outputProtocol,
const boost::shared_ptr<apache::thrift::server::TServerEventHandler>& eventHandler,
const boost::shared_ptr<apache::thrift::transport::TTransport>& client);
/**
* Destructor.
*/
virtual ~TConnectedClient();
/**
* Drive the client until it is done.
* The client processing loop is:
*
* [optional] call eventHandler->createContext once
* [optional] call eventHandler->processContext per request
* call processor->process per request
* handle expected transport exceptions:
* END_OF_FILE means the client is gone
* INTERRUPTED means the client was interrupted
* by TServerTransport::interruptChildren()
* handle unexpected transport exceptions by logging
* handle standard exceptions by logging
* handle unexpected exceptions by logging
* cleanup()
*/
virtual void run() /* override */;
protected:
/**
* Cleanup after a client. This happens if the client disconnects,
* or if the server is stopped, or if an exception occurs.
*
* The cleanup processing is:
* [optional] call eventHandler->deleteContext once
* close the inputProtocol's TTransport
* close the outputProtocol's TTransport
* close the client
*/
virtual void cleanup();
private:
boost::shared_ptr<apache::thrift::TProcessor> processor_;
boost::shared_ptr<apache::thrift::protocol::TProtocol> inputProtocol_;
boost::shared_ptr<apache::thrift::protocol::TProtocol> outputProtocol_;
boost::shared_ptr<apache::thrift::server::TServerEventHandler> eventHandler_;
boost::shared_ptr<apache::thrift::transport::TTransport> client_;
/**
* Context acquired from the eventHandler_ if one exists.
*/
void* opaqueContext_;
};
}
}
}
#endif // #ifndef _THRIFT_SERVER_TCONNECTEDCLIENT_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,877 @@
/*
* 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 _THRIFT_SERVER_TNONBLOCKINGSERVER_H_
#define _THRIFT_SERVER_TNONBLOCKINGSERVER_H_ 1
#include <thrift/Thrift.h>
#include <thrift/server/TServer.h>
#include <thrift/transport/PlatformSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TSocket.h>
#include <thrift/concurrency/ThreadManager.h>
#include <climits>
#include <thrift/concurrency/Thread.h>
#include <thrift/concurrency/PlatformThreadFactory.h>
#include <thrift/concurrency/Mutex.h>
#include <stack>
#include <vector>
#include <string>
#include <cstdlib>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::transport::TMemoryBuffer;
using apache::thrift::transport::TSocket;
using apache::thrift::protocol::TProtocol;
using apache::thrift::concurrency::Runnable;
using apache::thrift::concurrency::ThreadManager;
using apache::thrift::concurrency::PlatformThreadFactory;
using apache::thrift::concurrency::ThreadFactory;
using apache::thrift::concurrency::Thread;
using apache::thrift::concurrency::Mutex;
using apache::thrift::concurrency::Guard;
#ifdef LIBEVENT_VERSION_NUMBER
#define LIBEVENT_VERSION_MAJOR (LIBEVENT_VERSION_NUMBER >> 24)
#define LIBEVENT_VERSION_MINOR ((LIBEVENT_VERSION_NUMBER >> 16) & 0xFF)
#define LIBEVENT_VERSION_REL ((LIBEVENT_VERSION_NUMBER >> 8) & 0xFF)
#else
// assume latest version 1 series
#define LIBEVENT_VERSION_MAJOR 1
#define LIBEVENT_VERSION_MINOR 14
#define LIBEVENT_VERSION_REL 13
#define LIBEVENT_VERSION_NUMBER \
((LIBEVENT_VERSION_MAJOR << 24) | (LIBEVENT_VERSION_MINOR << 16) | (LIBEVENT_VERSION_REL << 8))
#endif
#if LIBEVENT_VERSION_NUMBER < 0x02000000
typedef THRIFT_SOCKET evutil_socket_t;
#endif
#ifndef SOCKOPT_CAST_T
#ifndef _WIN32
#define SOCKOPT_CAST_T void
#else
#define SOCKOPT_CAST_T char
#endif // _WIN32
#endif
template <class T>
inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
}
template <class T>
inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
return reinterpret_cast<SOCKOPT_CAST_T*>(v);
}
/**
* This is a non-blocking server in C++ for high performance that
* operates a set of IO threads (by default only one). It assumes that
* all incoming requests are framed with a 4 byte length indicator and
* writes out responses using the same framing.
*
* It does not use the TServerTransport framework, but rather has socket
* operations hardcoded for use with select.
*
*/
/// Overload condition actions.
enum TOverloadAction {
T_OVERLOAD_NO_ACTION, ///< Don't handle overload */
T_OVERLOAD_CLOSE_ON_ACCEPT, ///< Drop new connections immediately */
T_OVERLOAD_DRAIN_TASK_QUEUE ///< Drop some tasks from head of task queue */
};
class TNonblockingIOThread;
class TNonblockingServer : public TServer {
private:
class TConnection;
friend class TNonblockingIOThread;
private:
/// Listen backlog
static const int LISTEN_BACKLOG = 1024;
/// Default limit on size of idle connection pool
static const size_t CONNECTION_STACK_LIMIT = 1024;
/// Default limit on frame size
static const int MAX_FRAME_SIZE = 256 * 1024 * 1024;
/// Default limit on total number of connected sockets
static const int MAX_CONNECTIONS = INT_MAX;
/// Default limit on connections in handler/task processing
static const int MAX_ACTIVE_PROCESSORS = INT_MAX;
/// Default size of write buffer
static const int WRITE_BUFFER_DEFAULT_SIZE = 1024;
/// Maximum size of read buffer allocated to idle connection (0 = unlimited)
static const int IDLE_READ_BUFFER_LIMIT = 1024;
/// Maximum size of write buffer allocated to idle connection (0 = unlimited)
static const int IDLE_WRITE_BUFFER_LIMIT = 1024;
/// # of calls before resizing oversized buffers (0 = check only on close)
static const int RESIZE_BUFFER_EVERY_N = 512;
/// # of IO threads to use by default
static const int DEFAULT_IO_THREADS = 1;
/// # of IO threads this server will use
size_t numIOThreads_;
/// Whether to set high scheduling priority for IO threads
bool useHighPriorityIOThreads_;
/// Server socket file descriptor
THRIFT_SOCKET serverSocket_;
/// Port server runs on. Zero when letting OS decide actual port
int port_;
/// Port server actually runs on
int listenPort_;
/// The optional user-provided event-base (for single-thread servers)
event_base* userEventBase_;
/// For processing via thread pool, may be NULL
boost::shared_ptr<ThreadManager> threadManager_;
/// Is thread pool processing?
bool threadPoolProcessing_;
// Factory to create the IO threads
boost::shared_ptr<PlatformThreadFactory> ioThreadFactory_;
// Vector of IOThread objects that will handle our IO
std::vector<boost::shared_ptr<TNonblockingIOThread> > ioThreads_;
// Index of next IO Thread to be used (for round-robin)
uint32_t nextIOThread_;
// Synchronizes access to connection stack and similar data
Mutex connMutex_;
/// Number of TConnection object we've created
size_t numTConnections_;
/// Number of Connections processing or waiting to process
size_t numActiveProcessors_;
/// Limit for how many TConnection objects to cache
size_t connectionStackLimit_;
/// Limit for number of connections processing or waiting to process
size_t maxActiveProcessors_;
/// Limit for number of open connections
size_t maxConnections_;
/// Limit for frame size
size_t maxFrameSize_;
/// Time in milliseconds before an unperformed task expires (0 == infinite).
int64_t taskExpireTime_;
/**
* Hysteresis for overload state. This is the fraction of the overload
* value that needs to be reached before the overload state is cleared;
* must be <= 1.0.
*/
double overloadHysteresis_;
/// Action to take when we're overloaded.
TOverloadAction overloadAction_;
/**
* The write buffer is initialized (and when idleWriteBufferLimit_ is checked
* and found to be exceeded, reinitialized) to this size.
*/
size_t writeBufferDefaultSize_;
/**
* Max read buffer size for an idle TConnection. When we place an idle
* TConnection into connectionStack_ or on every resizeBufferEveryN_ calls,
* we will free the buffer (such that it will be reinitialized by the next
* received frame) if it has exceeded this limit. 0 disables this check.
*/
size_t idleReadBufferLimit_;
/**
* Max write buffer size for an idle connection. When we place an idle
* TConnection into connectionStack_ or on every resizeBufferEveryN_ calls,
* we insure that its write buffer is <= to this size; otherwise we
* replace it with a new one of writeBufferDefaultSize_ bytes to insure that
* idle connections don't hog memory. 0 disables this check.
*/
size_t idleWriteBufferLimit_;
/**
* Every N calls we check the buffer size limits on a connected TConnection.
* 0 disables (i.e. the checks are only done when a connection closes).
*/
int32_t resizeBufferEveryN_;
/// Set if we are currently in an overloaded state.
bool overloaded_;
/// Count of connections dropped since overload started
uint32_t nConnectionsDropped_;
/// Count of connections dropped on overload since server started
uint64_t nTotalConnectionsDropped_;
/**
* This is a stack of all the objects that have been created but that
* are NOT currently in use. When we close a connection, we place it on this
* stack so that the object can be reused later, rather than freeing the
* memory and reallocating a new object later.
*/
std::stack<TConnection*> connectionStack_;
/**
* This container holds pointers to all active connections. This container
* allows the server to clean up unlcosed connection objects at destruction,
* which in turn allows their transports, protocols, processors and handlers
* to deallocate and clean up correctly.
*/
std::vector<TConnection*> activeConnections_;
/**
* Called when server socket had something happen. We accept all waiting
* client connections on listen socket fd and assign TConnection objects
* to handle those requests.
*
* @param fd the listen socket.
* @param which the event flag that triggered the handler.
*/
void handleEvent(THRIFT_SOCKET fd, short which);
void init(int port) {
serverSocket_ = THRIFT_INVALID_SOCKET;
numIOThreads_ = DEFAULT_IO_THREADS;
nextIOThread_ = 0;
useHighPriorityIOThreads_ = false;
port_ = port;
listenPort_ = port;
userEventBase_ = NULL;
threadPoolProcessing_ = false;
numTConnections_ = 0;
numActiveProcessors_ = 0;
connectionStackLimit_ = CONNECTION_STACK_LIMIT;
maxActiveProcessors_ = MAX_ACTIVE_PROCESSORS;
maxConnections_ = MAX_CONNECTIONS;
maxFrameSize_ = MAX_FRAME_SIZE;
taskExpireTime_ = 0;
overloadHysteresis_ = 0.8;
overloadAction_ = T_OVERLOAD_NO_ACTION;
writeBufferDefaultSize_ = WRITE_BUFFER_DEFAULT_SIZE;
idleReadBufferLimit_ = IDLE_READ_BUFFER_LIMIT;
idleWriteBufferLimit_ = IDLE_WRITE_BUFFER_LIMIT;
resizeBufferEveryN_ = RESIZE_BUFFER_EVERY_N;
overloaded_ = false;
nConnectionsDropped_ = 0;
nTotalConnectionsDropped_ = 0;
}
public:
TNonblockingServer(const boost::shared_ptr<TProcessorFactory>& processorFactory, int port)
: TServer(processorFactory) {
init(port);
}
TNonblockingServer(const boost::shared_ptr<TProcessor>& processor, int port)
: TServer(processor) {
init(port);
}
TNonblockingServer(const boost::shared_ptr<TProcessorFactory>& processorFactory,
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
int port,
const boost::shared_ptr<ThreadManager>& threadManager
= boost::shared_ptr<ThreadManager>())
: TServer(processorFactory) {
init(port);
setInputProtocolFactory(protocolFactory);
setOutputProtocolFactory(protocolFactory);
setThreadManager(threadManager);
}
TNonblockingServer(const boost::shared_ptr<TProcessor>& processor,
const boost::shared_ptr<TProtocolFactory>& protocolFactory,
int port,
const boost::shared_ptr<ThreadManager>& threadManager
= boost::shared_ptr<ThreadManager>())
: TServer(processor) {
init(port);
setInputProtocolFactory(protocolFactory);
setOutputProtocolFactory(protocolFactory);
setThreadManager(threadManager);
}
TNonblockingServer(const boost::shared_ptr<TProcessorFactory>& processorFactory,
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
int port,
const boost::shared_ptr<ThreadManager>& threadManager
= boost::shared_ptr<ThreadManager>())
: TServer(processorFactory) {
init(port);
setInputTransportFactory(inputTransportFactory);
setOutputTransportFactory(outputTransportFactory);
setInputProtocolFactory(inputProtocolFactory);
setOutputProtocolFactory(outputProtocolFactory);
setThreadManager(threadManager);
}
TNonblockingServer(const boost::shared_ptr<TProcessor>& processor,
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory,
int port,
const boost::shared_ptr<ThreadManager>& threadManager
= boost::shared_ptr<ThreadManager>())
: TServer(processor) {
init(port);
setInputTransportFactory(inputTransportFactory);
setOutputTransportFactory(outputTransportFactory);
setInputProtocolFactory(inputProtocolFactory);
setOutputProtocolFactory(outputProtocolFactory);
setThreadManager(threadManager);
}
~TNonblockingServer();
void setThreadManager(boost::shared_ptr<ThreadManager> threadManager);
int getListenPort() { return listenPort_; }
boost::shared_ptr<ThreadManager> getThreadManager() { return threadManager_; }
/**
* Sets the number of IO threads used by this server. Can only be used before
* the call to serve() and has no effect afterwards. We always use a
* PosixThreadFactory for the IO worker threads, because they must joinable
* for clean shutdown.
*/
void setNumIOThreads(size_t numThreads) {
numIOThreads_ = numThreads;
// User-provided event-base doesn't works for multi-threaded servers
assert(numIOThreads_ <= 1 || !userEventBase_);
}
/** Return whether the IO threads will get high scheduling priority */
bool useHighPriorityIOThreads() const { return useHighPriorityIOThreads_; }
/** Set whether the IO threads will get high scheduling priority. */
void setUseHighPriorityIOThreads(bool val) { useHighPriorityIOThreads_ = val; }
/** Return the number of IO threads used by this server. */
size_t getNumIOThreads() const { return numIOThreads_; }
/**
* Get the maximum number of unused TConnection we will hold in reserve.
*
* @return the current limit on TConnection pool size.
*/
size_t getConnectionStackLimit() const { return connectionStackLimit_; }
/**
* Set the maximum number of unused TConnection we will hold in reserve.
*
* @param sz the new limit for TConnection pool size.
*/
void setConnectionStackLimit(size_t sz) { connectionStackLimit_ = sz; }
bool isThreadPoolProcessing() const { return threadPoolProcessing_; }
void addTask(boost::shared_ptr<Runnable> task) {
threadManager_->add(task, 0LL, taskExpireTime_);
}
/**
* Return the count of sockets currently connected to.
*
* @return count of connected sockets.
*/
size_t getNumConnections() const { return numTConnections_; }
/**
* Return the count of sockets currently connected to.
*
* @return count of connected sockets.
*/
size_t getNumActiveConnections() const { return getNumConnections() - getNumIdleConnections(); }
/**
* Return the count of connection objects allocated but not in use.
*
* @return count of idle connection objects.
*/
size_t getNumIdleConnections() const { return connectionStack_.size(); }
/**
* Return count of number of connections which are currently processing.
* This is defined as a connection where all data has been received and
* either assigned a task (when threading) or passed to a handler (when
* not threading), and where the handler has not yet returned.
*
* @return # of connections currently processing.
*/
size_t getNumActiveProcessors() const { return numActiveProcessors_; }
/// Increment the count of connections currently processing.
void incrementActiveProcessors() {
Guard g(connMutex_);
++numActiveProcessors_;
}
/// Decrement the count of connections currently processing.
void decrementActiveProcessors() {
Guard g(connMutex_);
if (numActiveProcessors_ > 0) {
--numActiveProcessors_;
}
}
/**
* Get the maximum # of connections allowed before overload.
*
* @return current setting.
*/
size_t getMaxConnections() const { return maxConnections_; }
/**
* Set the maximum # of connections allowed before overload.
*
* @param maxConnections new setting for maximum # of connections.
*/
void setMaxConnections(size_t maxConnections) { maxConnections_ = maxConnections; }
/**
* Get the maximum # of connections waiting in handler/task before overload.
*
* @return current setting.
*/
size_t getMaxActiveProcessors() const { return maxActiveProcessors_; }
/**
* Set the maximum # of connections waiting in handler/task before overload.
*
* @param maxActiveProcessors new setting for maximum # of active processes.
*/
void setMaxActiveProcessors(size_t maxActiveProcessors) {
maxActiveProcessors_ = maxActiveProcessors;
}
/**
* Get the maximum allowed frame size.
*
* If a client tries to send a message larger than this limit,
* its connection will be closed.
*
* @return Maxium frame size, in bytes.
*/
size_t getMaxFrameSize() const { return maxFrameSize_; }
/**
* Set the maximum allowed frame size.
*
* @param maxFrameSize The new maximum frame size.
*/
void setMaxFrameSize(size_t maxFrameSize) { maxFrameSize_ = maxFrameSize; }
/**
* Get fraction of maximum limits before an overload condition is cleared.
*
* @return hysteresis fraction
*/
double getOverloadHysteresis() const { return overloadHysteresis_; }
/**
* Set fraction of maximum limits before an overload condition is cleared.
* A good value would probably be between 0.5 and 0.9.
*
* @param hysteresisFraction fraction <= 1.0.
*/
void setOverloadHysteresis(double hysteresisFraction) {
if (hysteresisFraction <= 1.0 && hysteresisFraction > 0.0) {
overloadHysteresis_ = hysteresisFraction;
}
}
/**
* Get the action the server will take on overload.
*
* @return a TOverloadAction enum value for the currently set action.
*/
TOverloadAction getOverloadAction() const { return overloadAction_; }
/**
* Set the action the server is to take on overload.
*
* @param overloadAction a TOverloadAction enum value for the action.
*/
void setOverloadAction(TOverloadAction overloadAction) { overloadAction_ = overloadAction; }
/**
* Get the time in milliseconds after which a task expires (0 == infinite).
*
* @return a 64-bit time in milliseconds.
*/
int64_t getTaskExpireTime() const { return taskExpireTime_; }
/**
* Set the time in milliseconds after which a task expires (0 == infinite).
*
* @param taskExpireTime a 64-bit time in milliseconds.
*/
void setTaskExpireTime(int64_t taskExpireTime) { taskExpireTime_ = taskExpireTime; }
/**
* Determine if the server is currently overloaded.
* This function checks the maximums for open connections and connections
* currently in processing, and sets an overload condition if they are
* exceeded. The overload will persist until both values are below the
* current hysteresis fraction of their maximums.
*
* @return true if an overload condition exists, false if not.
*/
bool serverOverloaded();
/** Pop and discard next task on threadpool wait queue.
*
* @return true if a task was discarded, false if the wait queue was empty.
*/
bool drainPendingTask();
/**
* Get the starting size of a TConnection object's write buffer.
*
* @return # bytes we initialize a TConnection object's write buffer to.
*/
size_t getWriteBufferDefaultSize() const { return writeBufferDefaultSize_; }
/**
* Set the starting size of a TConnection object's write buffer.
*
* @param size # bytes we initialize a TConnection object's write buffer to.
*/
void setWriteBufferDefaultSize(size_t size) { writeBufferDefaultSize_ = size; }
/**
* Get the maximum size of read buffer allocated to idle TConnection objects.
*
* @return # bytes beyond which we will dealloc idle buffer.
*/
size_t getIdleReadBufferLimit() const { return idleReadBufferLimit_; }
/**
* [NOTE: This is for backwards compatibility, use getIdleReadBufferLimit().]
* Get the maximum size of read buffer allocated to idle TConnection objects.
*
* @return # bytes beyond which we will dealloc idle buffer.
*/
size_t getIdleBufferMemLimit() const { return idleReadBufferLimit_; }
/**
* Set the maximum size read buffer allocated to idle TConnection objects.
* If a TConnection object is found (either on connection close or between
* calls when resizeBufferEveryN_ is set) with more than this much memory
* allocated to its read buffer, we free it and allow it to be reinitialized
* on the next received frame.
*
* @param limit of bytes beyond which we will shrink buffers when checked.
*/
void setIdleReadBufferLimit(size_t limit) { idleReadBufferLimit_ = limit; }
/**
* [NOTE: This is for backwards compatibility, use setIdleReadBufferLimit().]
* Set the maximum size read buffer allocated to idle TConnection objects.
* If a TConnection object is found (either on connection close or between
* calls when resizeBufferEveryN_ is set) with more than this much memory
* allocated to its read buffer, we free it and allow it to be reinitialized
* on the next received frame.
*
* @param limit of bytes beyond which we will shrink buffers when checked.
*/
void setIdleBufferMemLimit(size_t limit) { idleReadBufferLimit_ = limit; }
/**
* Get the maximum size of write buffer allocated to idle TConnection objects.
*
* @return # bytes beyond which we will reallocate buffers when checked.
*/
size_t getIdleWriteBufferLimit() const { return idleWriteBufferLimit_; }
/**
* Set the maximum size write buffer allocated to idle TConnection objects.
* If a TConnection object is found (either on connection close or between
* calls when resizeBufferEveryN_ is set) with more than this much memory
* allocated to its write buffer, we destroy and construct that buffer with
* writeBufferDefaultSize_ bytes.
*
* @param limit of bytes beyond which we will shrink buffers when idle.
*/
void setIdleWriteBufferLimit(size_t limit) { idleWriteBufferLimit_ = limit; }
/**
* Get # of calls made between buffer size checks. 0 means disabled.
*
* @return # of calls between buffer size checks.
*/
int32_t getResizeBufferEveryN() const { return resizeBufferEveryN_; }
/**
* Check buffer sizes every "count" calls. This allows buffer limits
* to be enforced for persistent connections with a controllable degree
* of overhead. 0 disables checks except at connection close.
*
* @param count the number of calls between checks, or 0 to disable
*/
void setResizeBufferEveryN(int32_t count) { resizeBufferEveryN_ = count; }
/**
* Main workhorse function, starts up the server listening on a port and
* loops over the libevent handler.
*/
void serve();
/**
* Causes the server to terminate gracefully (can be called from any thread).
*/
void stop();
/// Creates a socket to listen on and binds it to the local port.
void createAndListenOnSocket();
/**
* Takes a socket created by createAndListenOnSocket() and sets various
* options on it to prepare for use in the server.
*
* @param fd descriptor of socket to be initialized/
*/
void listenSocket(THRIFT_SOCKET fd);
/**
* Register the optional user-provided event-base (for single-thread servers)
*
* This method should be used when the server is running in a single-thread
* mode, and the event base is provided by the user (i.e., the caller).
*
* @param user_event_base the user-provided event-base. The user is
* responsible for freeing the event base memory.
*/
void registerEvents(event_base* user_event_base);
/**
* Returns the optional user-provided event-base (for single-thread servers).
*/
event_base* getUserEventBase() const { return userEventBase_; }
/** Some transports, like THeaderTransport, require passing through
* the framing size instead of stripping it.
*/
bool getHeaderTransport();
private:
/**
* Callback function that the threadmanager calls when a task reaches
* its expiration time. It is needed to clean up the expired connection.
*
* @param task the runnable associated with the expired task.
*/
void expireClose(boost::shared_ptr<Runnable> task);
/**
* Return an initialized connection object. Creates or recovers from
* pool a TConnection and initializes it with the provided socket FD
* and flags.
*
* @param socket FD of socket associated with this connection.
* @param addr the sockaddr of the client
* @param addrLen the length of addr
* @return pointer to initialized TConnection object.
*/
TConnection* createConnection(THRIFT_SOCKET socket, const sockaddr* addr, socklen_t addrLen);
/**
* Returns a connection to pool or deletion. If the connection pool
* (a stack) isn't full, place the connection object on it, otherwise
* just delete it.
*
* @param connection the TConection being returned.
*/
void returnConnection(TConnection* connection);
};
class TNonblockingIOThread : public Runnable {
public:
// Creates an IO thread and sets up the event base. The listenSocket should
// be a valid FD on which listen() has already been called. If the
// listenSocket is < 0, accepting will not be done.
TNonblockingIOThread(TNonblockingServer* server,
int number,
THRIFT_SOCKET listenSocket,
bool useHighPriority);
~TNonblockingIOThread();
// Returns the event-base for this thread.
event_base* getEventBase() const { return eventBase_; }
// Returns the server for this thread.
TNonblockingServer* getServer() const { return server_; }
// Returns the number of this IO thread.
int getThreadNumber() const { return number_; }
// Returns the thread id associated with this object. This should
// only be called after the thread has been started.
Thread::id_t getThreadId() const { return threadId_; }
// Returns the send-fd for task complete notifications.
evutil_socket_t getNotificationSendFD() const { return notificationPipeFDs_[1]; }
// Returns the read-fd for task complete notifications.
evutil_socket_t getNotificationRecvFD() const { return notificationPipeFDs_[0]; }
// Returns the actual thread object associated with this IO thread.
boost::shared_ptr<Thread> getThread() const { return thread_; }
// Sets the actual thread object associated with this IO thread.
void setThread(const boost::shared_ptr<Thread>& t) { thread_ = t; }
// Used by TConnection objects to indicate processing has finished.
bool notify(TNonblockingServer::TConnection* conn);
// Enters the event loop and does not return until a call to stop().
virtual void run();
// Exits the event loop as soon as possible.
void stop();
// Ensures that the event-loop thread is fully finished and shut down.
void join();
/// Registers the events for the notification & listen sockets
void registerEvents();
private:
/**
* C-callable event handler for signaling task completion. Provides a
* callback that libevent can understand that will read a connection
* object's address from a pipe and call connection->transition() for
* that object.
*
* @param fd the descriptor the event occurred on.
*/
static void notifyHandler(evutil_socket_t fd, short which, void* v);
/**
* C-callable event handler for listener events. Provides a callback
* that libevent can understand which invokes server->handleEvent().
*
* @param fd the descriptor the event occurred on.
* @param which the flags associated with the event.
* @param v void* callback arg where we placed TNonblockingServer's "this".
*/
static void listenHandler(evutil_socket_t fd, short which, void* v) {
((TNonblockingServer*)v)->handleEvent(fd, which);
}
/// Exits the loop ASAP in case of shutdown or error.
void breakLoop(bool error);
/// Create the pipe used to notify I/O process of task completion.
void createNotificationPipe();
/// Unregisters our events for notification and listen sockets.
void cleanupEvents();
/// Sets (or clears) high priority scheduling status for the current thread.
void setCurrentThreadHighPriority(bool value);
private:
/// associated server
TNonblockingServer* server_;
/// thread number (for debugging).
const int number_;
/// The actual physical thread id.
Thread::id_t threadId_;
/// If listenSocket_ >= 0, adds an event on the event_base to accept conns
THRIFT_SOCKET listenSocket_;
/// Sets a high scheduling priority when running
bool useHighPriority_;
/// pointer to eventbase to be used for looping
event_base* eventBase_;
/// Set to true if this class is responsible for freeing the event base
/// memory.
bool ownEventBase_;
/// Used with eventBase_ for connection events (only in listener thread)
struct event serverEvent_;
/// Used with eventBase_ for task completion notification
struct event notificationEvent_;
/// File descriptors for pipe used for task completion notification.
evutil_socket_t notificationPipeFDs_[2];
/// Actual IO Thread
boost::shared_ptr<Thread> thread_;
};
}
}
} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TNONBLOCKINGSERVER_H_

View file

@ -0,0 +1,52 @@
/*
* 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 <thrift/thrift-config.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
namespace apache {
namespace thrift {
namespace server {
#ifdef HAVE_SYS_RESOURCE_H
int increase_max_fds(int max_fds = (1 << 24)) {
struct rlimit fdmaxrl;
for (fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds;
max_fds && (setrlimit(RLIMIT_NOFILE, &fdmaxrl) < 0);
fdmaxrl.rlim_cur = max_fds, fdmaxrl.rlim_max = max_fds) {
max_fds /= 2;
}
return static_cast<int>(fdmaxrl.rlim_cur);
}
#endif
}
}
} // apache::thrift::server

View file

@ -0,0 +1,273 @@
/*
* 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 _THRIFT_SERVER_TSERVER_H_
#define _THRIFT_SERVER_TSERVER_H_ 1
#include <thrift/TProcessor.h>
#include <thrift/transport/TServerTransport.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/concurrency/Thread.h>
#include <boost/shared_ptr.hpp>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::TProcessor;
using apache::thrift::protocol::TBinaryProtocolFactory;
using apache::thrift::protocol::TProtocol;
using apache::thrift::protocol::TProtocolFactory;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportFactory;
/**
* Virtual interface class that can handle events from the server core. To
* use this you should subclass it and implement the methods that you care
* about. Your subclass can also store local data that you may care about,
* such as additional "arguments" to these methods (stored in the object
* instance's state).
*/
class TServerEventHandler {
public:
virtual ~TServerEventHandler() {}
/**
* Called before the server begins.
*/
virtual void preServe() {}
/**
* Called when a new client has connected and is about to being processing.
*/
virtual void* createContext(boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output) {
(void)input;
(void)output;
return NULL;
}
/**
* Called when a client has finished request-handling to delete server
* context.
*/
virtual void deleteContext(void* serverContext,
boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output) {
(void)serverContext;
(void)input;
(void)output;
}
/**
* Called when a client is about to call the processor.
*/
virtual void processContext(void* serverContext, boost::shared_ptr<TTransport> transport) {
(void)serverContext;
(void)transport;
}
protected:
/**
* Prevent direct instantiation.
*/
TServerEventHandler() {}
};
/**
* Thrift server.
*
*/
class TServer : public concurrency::Runnable {
public:
virtual ~TServer() {}
virtual void serve() = 0;
virtual void stop() {}
// Allows running the server as a Runnable thread
virtual void run() { serve(); }
boost::shared_ptr<TProcessorFactory> getProcessorFactory() { return processorFactory_; }
boost::shared_ptr<TServerTransport> getServerTransport() { return serverTransport_; }
boost::shared_ptr<TTransportFactory> getInputTransportFactory() { return inputTransportFactory_; }
boost::shared_ptr<TTransportFactory> getOutputTransportFactory() {
return outputTransportFactory_;
}
boost::shared_ptr<TProtocolFactory> getInputProtocolFactory() { return inputProtocolFactory_; }
boost::shared_ptr<TProtocolFactory> getOutputProtocolFactory() { return outputProtocolFactory_; }
boost::shared_ptr<TServerEventHandler> getEventHandler() { return eventHandler_; }
protected:
TServer(const boost::shared_ptr<TProcessorFactory>& processorFactory)
: processorFactory_(processorFactory) {
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
}
TServer(const boost::shared_ptr<TProcessor>& processor)
: processorFactory_(new TSingletonProcessorFactory(processor)) {
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
}
TServer(const boost::shared_ptr<TProcessorFactory>& processorFactory,
const boost::shared_ptr<TServerTransport>& serverTransport)
: processorFactory_(processorFactory), serverTransport_(serverTransport) {
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
}
TServer(const boost::shared_ptr<TProcessor>& processor,
const boost::shared_ptr<TServerTransport>& serverTransport)
: processorFactory_(new TSingletonProcessorFactory(processor)),
serverTransport_(serverTransport) {
setInputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setOutputTransportFactory(boost::shared_ptr<TTransportFactory>(new TTransportFactory()));
setInputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory>(new TBinaryProtocolFactory()));
}
TServer(const boost::shared_ptr<TProcessorFactory>& processorFactory,
const boost::shared_ptr<TServerTransport>& serverTransport,
const boost::shared_ptr<TTransportFactory>& transportFactory,
const boost::shared_ptr<TProtocolFactory>& protocolFactory)
: processorFactory_(processorFactory),
serverTransport_(serverTransport),
inputTransportFactory_(transportFactory),
outputTransportFactory_(transportFactory),
inputProtocolFactory_(protocolFactory),
outputProtocolFactory_(protocolFactory) {}
TServer(const boost::shared_ptr<TProcessor>& processor,
const boost::shared_ptr<TServerTransport>& serverTransport,
const boost::shared_ptr<TTransportFactory>& transportFactory,
const boost::shared_ptr<TProtocolFactory>& protocolFactory)
: processorFactory_(new TSingletonProcessorFactory(processor)),
serverTransport_(serverTransport),
inputTransportFactory_(transportFactory),
outputTransportFactory_(transportFactory),
inputProtocolFactory_(protocolFactory),
outputProtocolFactory_(protocolFactory) {}
TServer(const boost::shared_ptr<TProcessorFactory>& processorFactory,
const boost::shared_ptr<TServerTransport>& serverTransport,
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory)
: processorFactory_(processorFactory),
serverTransport_(serverTransport),
inputTransportFactory_(inputTransportFactory),
outputTransportFactory_(outputTransportFactory),
inputProtocolFactory_(inputProtocolFactory),
outputProtocolFactory_(outputProtocolFactory) {}
TServer(const boost::shared_ptr<TProcessor>& processor,
const boost::shared_ptr<TServerTransport>& serverTransport,
const boost::shared_ptr<TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<TProtocolFactory>& outputProtocolFactory)
: processorFactory_(new TSingletonProcessorFactory(processor)),
serverTransport_(serverTransport),
inputTransportFactory_(inputTransportFactory),
outputTransportFactory_(outputTransportFactory),
inputProtocolFactory_(inputProtocolFactory),
outputProtocolFactory_(outputProtocolFactory) {}
/**
* Get a TProcessor to handle calls on a particular connection.
*
* This method should only be called once per connection (never once per
* call). This allows the TProcessorFactory to return a different processor
* for each connection if it desires.
*/
boost::shared_ptr<TProcessor> getProcessor(boost::shared_ptr<TProtocol> inputProtocol,
boost::shared_ptr<TProtocol> outputProtocol,
boost::shared_ptr<TTransport> transport) {
TConnectionInfo connInfo;
connInfo.input = inputProtocol;
connInfo.output = outputProtocol;
connInfo.transport = transport;
return processorFactory_->getProcessor(connInfo);
}
// Class variables
boost::shared_ptr<TProcessorFactory> processorFactory_;
boost::shared_ptr<TServerTransport> serverTransport_;
boost::shared_ptr<TTransportFactory> inputTransportFactory_;
boost::shared_ptr<TTransportFactory> outputTransportFactory_;
boost::shared_ptr<TProtocolFactory> inputProtocolFactory_;
boost::shared_ptr<TProtocolFactory> outputProtocolFactory_;
boost::shared_ptr<TServerEventHandler> eventHandler_;
public:
void setInputTransportFactory(boost::shared_ptr<TTransportFactory> inputTransportFactory) {
inputTransportFactory_ = inputTransportFactory;
}
void setOutputTransportFactory(boost::shared_ptr<TTransportFactory> outputTransportFactory) {
outputTransportFactory_ = outputTransportFactory;
}
void setInputProtocolFactory(boost::shared_ptr<TProtocolFactory> inputProtocolFactory) {
inputProtocolFactory_ = inputProtocolFactory;
}
void setOutputProtocolFactory(boost::shared_ptr<TProtocolFactory> outputProtocolFactory) {
outputProtocolFactory_ = outputProtocolFactory;
}
void setServerEventHandler(boost::shared_ptr<TServerEventHandler> eventHandler) {
eventHandler_ = eventHandler;
}
};
/**
* Helper function to increase the max file descriptors limit
* for the current process and all of its children.
* By default, tries to increase it to as much as 2^24.
*/
#ifdef HAVE_SYS_RESOURCE_H
int increase_max_fds(int max_fds = (1 << 24));
#endif
}
}
} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TSERVER_H_

View file

@ -0,0 +1,246 @@
/*
* 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 <algorithm>
#include <boost/bind.hpp>
#include <stdexcept>
#include <stdint.h>
#include <thrift/server/TServerFramework.h>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::concurrency::Synchronized;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TTransportFactory;
using apache::thrift::protocol::TProtocol;
using apache::thrift::protocol::TProtocolFactory;
using boost::bind;
using boost::shared_ptr;
using std::string;
TServerFramework::TServerFramework(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory)
: TServer(processorFactory, serverTransport, transportFactory, protocolFactory),
clients_(0),
hwm_(0),
limit_(INT64_MAX) {
}
TServerFramework::TServerFramework(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory)
: TServer(processor, serverTransport, transportFactory, protocolFactory),
clients_(0),
hwm_(0),
limit_(INT64_MAX) {
}
TServerFramework::TServerFramework(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory)
: TServer(processorFactory,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory),
clients_(0),
hwm_(0),
limit_(INT64_MAX) {
}
TServerFramework::TServerFramework(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory)
: TServer(processor,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory),
clients_(0),
hwm_(0),
limit_(INT64_MAX) {
}
TServerFramework::~TServerFramework() {
}
template <typename T>
static void releaseOneDescriptor(const string& name, T& pTransport) {
if (pTransport) {
try {
pTransport->close();
} catch (const TTransportException& ttx) {
string errStr = string("TServerFramework " + name + " close failed: ") + ttx.what();
GlobalOutput(errStr.c_str());
}
}
}
void TServerFramework::serve() {
shared_ptr<TTransport> client;
shared_ptr<TTransport> inputTransport;
shared_ptr<TTransport> outputTransport;
shared_ptr<TProtocol> inputProtocol;
shared_ptr<TProtocol> outputProtocol;
// Start the server listening
serverTransport_->listen();
// Run the preServe event to indicate server is now listening
// and that it is safe to connect.
if (eventHandler_) {
eventHandler_->preServe();
}
// Fetch client from server
for (;;) {
try {
// Dereference any resources from any previous client creation
// such that a blocking accept does not hold them indefinitely.
outputProtocol.reset();
inputProtocol.reset();
outputTransport.reset();
inputTransport.reset();
client.reset();
// If we have reached the limit on the number of concurrent
// clients allowed, wait for one or more clients to drain before
// accepting another.
{
Synchronized sync(mon_);
while (clients_ >= limit_) {
mon_.wait();
}
}
client = serverTransport_->accept();
inputTransport = inputTransportFactory_->getTransport(client);
outputTransport = outputTransportFactory_->getTransport(client);
if (!outputProtocolFactory_) {
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport, outputTransport);
outputProtocol = inputProtocol;
} else {
inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
}
newlyConnectedClient(shared_ptr<TConnectedClient>(
new TConnectedClient(getProcessor(inputProtocol, outputProtocol, client),
inputProtocol,
outputProtocol,
eventHandler_,
client),
bind(&TServerFramework::disposeConnectedClient, this, _1)));
} catch (TTransportException& ttx) {
releaseOneDescriptor("inputTransport", inputTransport);
releaseOneDescriptor("outputTransport", outputTransport);
releaseOneDescriptor("client", client);
if (ttx.getType() == TTransportException::TIMED_OUT) {
// Accept timeout - continue processing.
continue;
} else if (ttx.getType() == TTransportException::END_OF_FILE
|| ttx.getType() == TTransportException::INTERRUPTED) {
// Server was interrupted. This only happens when stopping.
break;
} else {
// All other transport exceptions are logged.
// State of connection is unknown. Done.
string errStr = string("TServerTransport died: ") + ttx.what();
GlobalOutput(errStr.c_str());
break;
}
}
}
releaseOneDescriptor("serverTransport", serverTransport_);
}
int64_t TServerFramework::getConcurrentClientLimit() const {
Synchronized sync(mon_);
return limit_;
}
int64_t TServerFramework::getConcurrentClientCount() const {
Synchronized sync(mon_);
return clients_;
}
int64_t TServerFramework::getConcurrentClientCountHWM() const {
Synchronized sync(mon_);
return hwm_;
}
void TServerFramework::setConcurrentClientLimit(int64_t newLimit) {
if (newLimit < 1) {
throw std::invalid_argument("newLimit must be greater than zero");
}
Synchronized sync(mon_);
limit_ = newLimit;
if (limit_ - clients_ > 0) {
mon_.notify();
}
}
void TServerFramework::stop() {
// Order is important because serve() releases serverTransport_ when it is
// interrupted, which closes the socket that interruptChildren uses.
serverTransport_->interruptChildren();
serverTransport_->interrupt();
}
void TServerFramework::newlyConnectedClient(const boost::shared_ptr<TConnectedClient>& pClient) {
{
Synchronized sync(mon_);
++clients_;
hwm_ = (std::max)(hwm_, clients_);
}
onClientConnected(pClient);
}
void TServerFramework::disposeConnectedClient(TConnectedClient* pClient) {
onClientDisconnected(pClient);
delete pClient;
Synchronized sync(mon_);
if (limit_ - --clients_ > 0) {
mon_.notify();
}
}
}
}
} // apache::thrift::server

View file

@ -0,0 +1,184 @@
/*
* 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 _THRIFT_SERVER_TSERVERFRAMEWORK_H_
#define _THRIFT_SERVER_TSERVERFRAMEWORK_H_ 1
#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include <thrift/TProcessor.h>
#include <thrift/concurrency/Monitor.h>
#include <thrift/server/TConnectedClient.h>
#include <thrift/server/TServer.h>
#include <thrift/transport/TServerTransport.h>
#include <thrift/transport/TTransport.h>
namespace apache {
namespace thrift {
namespace server {
/**
* TServerFramework provides a single consolidated processing loop for
* servers. By having a single processing loop, behavior between servers
* is more predictable and maintenance cost is lowered. Implementations
* of TServerFramework must provide a method to deal with a client that
* connects and one that disconnects.
*
* While this functionality could be rolled directly into TServer, and
* probably should be, it would break the TServer interface contract so
* to maintain backwards compatibility for third party servers, no TServers
* were harmed in the making of this class.
*/
class TServerFramework : public TServer {
public:
TServerFramework(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
TServerFramework(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
TServerFramework(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
TServerFramework(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
virtual ~TServerFramework();
/**
* Accept clients from the TServerTransport and add them for processing.
* Call stop() on another thread to interrupt processing
* and return control to the caller.
* Post-conditions (return guarantees):
* The serverTransport will be closed.
*/
virtual void serve();
/**
* Interrupt serve() so that it meets post-conditions and returns.
*/
virtual void stop();
/**
* Get the concurrent client limit.
* \returns the concurrent client limit
*/
virtual int64_t getConcurrentClientLimit() const;
/**
* Get the number of currently connected clients.
* \returns the number of currently connected clients
*/
virtual int64_t getConcurrentClientCount() const;
/**
* Get the highest number of concurrent clients.
* \returns the highest number of concurrent clients
*/
virtual int64_t getConcurrentClientCountHWM() const;
/**
* Set the concurrent client limit. This can be changed while
* the server is serving however it will not necessarily be
* enforced until the next client is accepted and added. If the
* limit is lowered below the number of connected clients, no
* action is taken to disconnect the clients.
* The default value used if this is not called is INT64_MAX.
* \param[in] newLimit the new limit of concurrent clients
* \throws std::invalid_argument if newLimit is less than 1
*/
virtual void setConcurrentClientLimit(int64_t newLimit);
protected:
/**
* A client has connected. The implementation is responsible for managing the
* lifetime of the client object. This is called during the serve() thread,
* therefore a failure to return quickly will result in new client connection
* delays.
*
* \param[in] pClient the newly connected client
*/
virtual void onClientConnected(const boost::shared_ptr<TConnectedClient>& pClient) = 0;
/**
* A client has disconnected.
* When called:
* The server no longer tracks the client.
* The client TTransport has already been closed.
* The implementation must not delete the pointer.
*
* \param[in] pClient the disconnected client
*/
virtual void onClientDisconnected(TConnectedClient* pClient) = 0;
private:
/**
* Common handling for new connected clients. Implements concurrent
* client rate limiting after onClientConnected returns by blocking the
* serve() thread if the limit has been reached.
*/
void newlyConnectedClient(const boost::shared_ptr<TConnectedClient>& pClient);
/**
* Smart pointer client deletion.
* Calls onClientDisconnected and then deletes pClient.
*/
void disposeConnectedClient(TConnectedClient* pClient);
/**
* Monitor for limiting the number of concurrent clients.
*/
apache::thrift::concurrency::Monitor mon_;
/**
* The number of concurrent clients.
*/
int64_t clients_;
/**
* The high water mark of concurrent clients.
*/
int64_t hwm_;
/**
* The limit on the number of concurrent clients.
*/
int64_t limit_;
};
}
}
} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_

View file

@ -0,0 +1,107 @@
/*
* 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 <thrift/server/TSimpleServer.h>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::protocol::TProtocol;
using apache::thrift::protocol::TProtocolFactory;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TTransportFactory;
using boost::shared_ptr;
using std::string;
TSimpleServer::TSimpleServer(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory)
: TServerFramework(processorFactory, serverTransport, transportFactory, protocolFactory) {
TServerFramework::setConcurrentClientLimit(1);
}
TSimpleServer::TSimpleServer(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory)
: TServerFramework(processor, serverTransport, transportFactory, protocolFactory) {
TServerFramework::setConcurrentClientLimit(1);
}
TSimpleServer::TSimpleServer(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory)
: TServerFramework(processorFactory,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory) {
TServerFramework::setConcurrentClientLimit(1);
}
TSimpleServer::TSimpleServer(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory)
: TServerFramework(processor,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory) {
TServerFramework::setConcurrentClientLimit(1);
}
TSimpleServer::~TSimpleServer() {
}
/**
* The main body of customized implementation for TSimpleServer is quite simple:
* When a client connects, use the serve() thread to drive it to completion thus
* blocking new connections.
*/
void TSimpleServer::onClientConnected(const shared_ptr<TConnectedClient>& pClient) {
pClient->run();
}
/**
* TSimpleServer does not track clients so there is nothing to do here.
*/
void TSimpleServer::onClientDisconnected(TConnectedClient*) {
}
/**
* This makes little sense to the simple server because it is not capable
* of having more than one client at a time, so we hide it.
*/
void TSimpleServer::setConcurrentClientLimit(int64_t) {
}
}
}
} // apache::thrift::server

View file

@ -0,0 +1,77 @@
/*
* 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 _THRIFT_SERVER_TSIMPLESERVER_H_
#define _THRIFT_SERVER_TSIMPLESERVER_H_ 1
#include <thrift/server/TServerFramework.h>
namespace apache {
namespace thrift {
namespace server {
/**
* This is the most basic simple server. It is single-threaded and runs a
* continuous loop of accepting a single connection, processing requests on
* that connection until it closes, and then repeating.
*/
class TSimpleServer : public TServerFramework {
public:
TSimpleServer(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
TSimpleServer(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory);
TSimpleServer(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
TSimpleServer(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory);
virtual ~TSimpleServer();
protected:
virtual void onClientConnected(const boost::shared_ptr<TConnectedClient>& pClient) /* override */;
virtual void onClientDisconnected(TConnectedClient* pClient) /* override */;
private:
void setConcurrentClientLimit(int64_t newLimit); // hide
};
}
}
} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TSIMPLESERVER_H_

View file

@ -0,0 +1,132 @@
/*
* 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 <thrift/server/TThreadPoolServer.h>
namespace apache {
namespace thrift {
namespace server {
using apache::thrift::concurrency::ThreadManager;
using apache::thrift::protocol::TProtocol;
using apache::thrift::protocol::TProtocolFactory;
using apache::thrift::transport::TServerTransport;
using apache::thrift::transport::TTransport;
using apache::thrift::transport::TTransportException;
using apache::thrift::transport::TTransportFactory;
using boost::shared_ptr;
using std::string;
TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory,
const shared_ptr<ThreadManager>& threadManager)
: TServerFramework(processorFactory, serverTransport, transportFactory, protocolFactory),
threadManager_(threadManager),
timeout_(0),
taskExpiration_(0) {
}
TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& transportFactory,
const shared_ptr<TProtocolFactory>& protocolFactory,
const shared_ptr<ThreadManager>& threadManager)
: TServerFramework(processor, serverTransport, transportFactory, protocolFactory),
threadManager_(threadManager),
timeout_(0),
taskExpiration_(0) {
}
TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessorFactory>& processorFactory,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory,
const shared_ptr<ThreadManager>& threadManager)
: TServerFramework(processorFactory,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory),
threadManager_(threadManager),
timeout_(0),
taskExpiration_(0) {
}
TThreadPoolServer::TThreadPoolServer(const shared_ptr<TProcessor>& processor,
const shared_ptr<TServerTransport>& serverTransport,
const shared_ptr<TTransportFactory>& inputTransportFactory,
const shared_ptr<TTransportFactory>& outputTransportFactory,
const shared_ptr<TProtocolFactory>& inputProtocolFactory,
const shared_ptr<TProtocolFactory>& outputProtocolFactory,
const shared_ptr<ThreadManager>& threadManager)
: TServerFramework(processor,
serverTransport,
inputTransportFactory,
outputTransportFactory,
inputProtocolFactory,
outputProtocolFactory),
threadManager_(threadManager),
timeout_(0),
taskExpiration_(0) {
}
TThreadPoolServer::~TThreadPoolServer() {
}
void TThreadPoolServer::serve() {
TServerFramework::serve();
threadManager_->stop();
}
int64_t TThreadPoolServer::getTimeout() const {
return timeout_;
}
void TThreadPoolServer::setTimeout(int64_t value) {
timeout_ = value;
}
int64_t TThreadPoolServer::getTaskExpiration() const {
return taskExpiration_;
}
void TThreadPoolServer::setTaskExpiration(int64_t value) {
taskExpiration_ = value;
}
boost::shared_ptr<apache::thrift::concurrency::ThreadManager>
TThreadPoolServer::getThreadManager() const {
return threadManager_;
}
void TThreadPoolServer::onClientConnected(const shared_ptr<TConnectedClient>& pClient) {
threadManager_->add(pClient, getTimeout(), getTaskExpiration());
}
void TThreadPoolServer::onClientDisconnected(TConnectedClient*) {
}
}
}
} // apache::thrift::server

View file

@ -0,0 +1,101 @@
/*
* 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 _THRIFT_SERVER_TTHREADPOOLSERVER_H_
#define _THRIFT_SERVER_TTHREADPOOLSERVER_H_ 1
#include <boost/atomic.hpp>
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/server/TServerFramework.h>
namespace apache {
namespace thrift {
namespace server {
/**
* Manage clients using a thread pool.
*/
class TThreadPoolServer : public TServerFramework {
public:
TThreadPoolServer(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
const boost::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
= apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
TThreadPoolServer(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
const boost::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
= apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
TThreadPoolServer(
const boost::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
const boost::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
= apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
TThreadPoolServer(
const boost::shared_ptr<apache::thrift::TProcessor>& processor,
const boost::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
const boost::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
const boost::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
const boost::shared_ptr<apache::thrift::concurrency::ThreadManager>& threadManager
= apache::thrift::concurrency::ThreadManager::newSimpleThreadManager());
virtual ~TThreadPoolServer();
/**
* Post-conditions (return guarantees):
* There will be no clients connected.
*/
virtual void serve();
virtual int64_t getTimeout() const;
virtual void setTimeout(int64_t value);
virtual int64_t getTaskExpiration() const;
virtual void setTaskExpiration(int64_t value);
virtual boost::shared_ptr<apache::thrift::concurrency::ThreadManager> getThreadManager() const;
protected:
virtual void onClientConnected(const boost::shared_ptr<TConnectedClient>& pClient) /* override */;
virtual void onClientDisconnected(TConnectedClient* pClient) /* override */;
boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager_;
boost::atomic<int64_t> timeout_;
boost::atomic<int64_t> taskExpiration_;
};
}
}
} // apache::thrift::server
#endif // #ifndef _THRIFT_SERVER_TTHREADPOOLSERVER_H_

Some files were not shown because too many files have changed in this diff Show more