auser-poolparty 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +1 -1
- data/examples/monitored_cloud.rb +1 -1
- data/examples/thrift/thrift_example.rb +1 -1
- data/lib/proto/command_interface_handler.rb +1 -1
- data/vendor/gems/thrift/CHANGES +35 -0
- data/vendor/gems/thrift/CONTRIBUTORS +77 -0
- data/vendor/gems/thrift/DISCLAIMER +6 -0
- data/vendor/gems/thrift/LICENSE +202 -0
- data/vendor/gems/thrift/Makefile.am +28 -0
- data/vendor/gems/thrift/NEWS +79 -0
- data/vendor/gems/thrift/NOTICE +26 -0
- data/vendor/gems/thrift/README +137 -0
- data/vendor/gems/thrift/aclocal/ax_boost_base.m4 +198 -0
- data/vendor/gems/thrift/aclocal/ax_javac_and_java.m4 +107 -0
- data/vendor/gems/thrift/aclocal/ax_lib_event.m4 +194 -0
- data/vendor/gems/thrift/aclocal/ax_lib_zlib.m4 +173 -0
- data/vendor/gems/thrift/aclocal/ax_signed_right_shift.m4 +127 -0
- data/vendor/gems/thrift/aclocal/ax_thrift_internal.m4 +39 -0
- data/vendor/gems/thrift/bootstrap.sh +35 -0
- data/vendor/gems/thrift/cleanup.sh +58 -0
- data/vendor/gems/thrift/compiler/cpp/Makefile.am +136 -0
- data/vendor/gems/thrift/compiler/cpp/README +39 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_cocoa_generator.cc +2331 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_cpp_generator.cc +3003 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_csharp_generator.cc +1700 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_erl_generator.cc +932 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_generator.cc +173 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_generator.h +321 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_hs_generator.cc +1445 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_html_generator.cc +637 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_java_generator.cc +3069 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_ocaml_generator.cc +1673 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_oop_generator.h +77 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_perl_generator.cc +1812 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_php_generator.cc +2281 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_py_generator.cc +2310 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_rb_generator.cc +1114 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_st_generator.cc +1071 -0
- data/vendor/gems/thrift/compiler/cpp/src/generate/t_xsd_generator.cc +354 -0
- data/vendor/gems/thrift/compiler/cpp/src/globals.h +117 -0
- data/vendor/gems/thrift/compiler/cpp/src/main.cc +1207 -0
- data/vendor/gems/thrift/compiler/cpp/src/main.h +103 -0
- data/vendor/gems/thrift/compiler/cpp/src/md5.c +381 -0
- data/vendor/gems/thrift/compiler/cpp/src/md5.h +91 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_base_type.h +137 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_const.h +59 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_const_value.h +121 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_container.h +56 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_doc.h +51 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_enum.h +59 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_enum_value.h +64 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_field.h +150 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_function.h +93 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_list.h +56 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_map.h +64 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_program.h +223 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_scope.h +86 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_service.h +68 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_set.h +55 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_struct.h +127 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_type.h +176 -0
- data/vendor/gems/thrift/compiler/cpp/src/parse/t_typedef.h +70 -0
- data/vendor/gems/thrift/compiler/cpp/src/platform.h +36 -0
- data/vendor/gems/thrift/compiler/cpp/src/thriftl.ll +303 -0
- data/vendor/gems/thrift/compiler/cpp/src/thrifty.yy +1140 -0
- data/vendor/gems/thrift/configure.ac +255 -0
- data/vendor/gems/thrift/contrib/fb303/LICENSE +16 -0
- data/vendor/gems/thrift/contrib/fb303/Makefile.am +31 -0
- data/vendor/gems/thrift/contrib/fb303/README +37 -0
- data/vendor/gems/thrift/contrib/fb303/acinclude.m4 +258 -0
- data/vendor/gems/thrift/contrib/fb303/aclocal/ax_boost_base.m4 +198 -0
- data/vendor/gems/thrift/contrib/fb303/bootstrap.sh +26 -0
- data/vendor/gems/thrift/contrib/fb303/configure.ac +115 -0
- data/vendor/gems/thrift/contrib/fb303/cpp/FacebookBase.cpp +124 -0
- data/vendor/gems/thrift/contrib/fb303/cpp/FacebookBase.h +103 -0
- data/vendor/gems/thrift/contrib/fb303/cpp/Makefile.am +84 -0
- data/vendor/gems/thrift/contrib/fb303/cpp/ServiceTracker.cpp +481 -0
- data/vendor/gems/thrift/contrib/fb303/cpp/ServiceTracker.h +215 -0
- data/vendor/gems/thrift/contrib/fb303/global_footer.mk +21 -0
- data/vendor/gems/thrift/contrib/fb303/global_header.mk +38 -0
- data/vendor/gems/thrift/contrib/fb303/if/fb303.thrift +112 -0
- data/vendor/gems/thrift/contrib/fb303/java/FacebookBase.java +103 -0
- data/vendor/gems/thrift/contrib/fb303/java/build.xml +84 -0
- data/vendor/gems/thrift/contrib/fb303/php/FacebookBase.php +89 -0
- data/vendor/gems/thrift/contrib/fb303/py/Makefile.am +44 -0
- data/vendor/gems/thrift/contrib/fb303/py/fb303/FacebookBase.py +82 -0
- data/vendor/gems/thrift/contrib/fb303/py/fb303_scripts/__init__.py +20 -0
- data/vendor/gems/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py +195 -0
- data/vendor/gems/thrift/contrib/fb303/py/setup.py +27 -0
- data/vendor/gems/thrift/contrib/thrift.el +126 -0
- data/vendor/gems/thrift/contrib/thrift.spec +206 -0
- data/vendor/gems/thrift/contrib/thrift.vim +91 -0
- data/vendor/gems/thrift/contrib/thrift_dump.cpp +91 -0
- data/vendor/gems/thrift/doc/lgpl-2.1.txt +504 -0
- data/vendor/gems/thrift/doc/otp-base-license.txt +20 -0
- data/vendor/gems/thrift/doc/thrift.bnf +96 -0
- data/vendor/gems/thrift/doc/thrift.tex +1057 -0
- data/vendor/gems/thrift/lib/Makefile.am +55 -0
- data/vendor/gems/thrift/lib/cocoa/README +21 -0
- data/vendor/gems/thrift/lib/cocoa/src/TApplicationException.h +44 -0
- data/vendor/gems/thrift/lib/cocoa/src/TApplicationException.m +130 -0
- data/vendor/gems/thrift/lib/cocoa/src/TException.h +34 -0
- data/vendor/gems/thrift/lib/cocoa/src/TException.m +64 -0
- data/vendor/gems/thrift/lib/cocoa/src/TProcessor.h +29 -0
- data/vendor/gems/thrift/lib/cocoa/src/TProcessorFactory.h +27 -0
- data/vendor/gems/thrift/lib/cocoa/src/TSharedProcessorFactory.h +27 -0
- data/vendor/gems/thrift/lib/cocoa/src/TSharedProcessorFactory.m +51 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TBinaryProtocol.h +51 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TBinaryProtocol.m +477 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocol.h +148 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocolException.h +25 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocolException.m +23 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocolFactory.h +29 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocolUtil.h +29 -0
- data/vendor/gems/thrift/lib/cocoa/src/protocol/TProtocolUtil.m +104 -0
- data/vendor/gems/thrift/lib/cocoa/src/server/TSocketServer.h +50 -0
- data/vendor/gems/thrift/lib/cocoa/src/server/TSocketServer.m +153 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/THTTPClient.h +42 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/THTTPClient.m +159 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TNSFileHandleTransport.h +35 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TNSFileHandleTransport.m +91 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TNSStreamTransport.h +38 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TNSStreamTransport.m +89 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TSocketClient.h +32 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TSocketClient.m +58 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TTransport.h +36 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TTransportException.h +30 -0
- data/vendor/gems/thrift/lib/cocoa/src/transport/TTransportException.m +43 -0
- data/vendor/gems/thrift/lib/cpp/Makefile.am +158 -0
- data/vendor/gems/thrift/lib/cpp/README +67 -0
- data/vendor/gems/thrift/lib/cpp/src/TLogging.h +163 -0
- data/vendor/gems/thrift/lib/cpp/src/TProcessor.h +53 -0
- data/vendor/gems/thrift/lib/cpp/src/TReflectionLocal.h +96 -0
- data/vendor/gems/thrift/lib/cpp/src/Thrift.cpp +148 -0
- data/vendor/gems/thrift/lib/cpp/src/Thrift.h +191 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Exception.h +60 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/FunctionRunner.h +77 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Monitor.cpp +137 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Monitor.h +84 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Mutex.cpp +160 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Mutex.h +114 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/PosixThreadFactory.cpp +314 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/PosixThreadFactory.h +130 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Thread.h +125 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/ThreadManager.cpp +493 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/ThreadManager.h +169 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/TimerManager.cpp +284 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/TimerManager.h +122 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Util.cpp +55 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/Util.h +100 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/test/Tests.cpp +155 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/test/ThreadFactoryTests.h +354 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/test/ThreadManagerTests.h +379 -0
- data/vendor/gems/thrift/lib/cpp/src/concurrency/test/TimerManagerTests.h +155 -0
- data/vendor/gems/thrift/lib/cpp/src/processor/PeekProcessor.cpp +122 -0
- data/vendor/gems/thrift/lib/cpp/src/processor/PeekProcessor.h +77 -0
- data/vendor/gems/thrift/lib/cpp/src/processor/StatsProcessor.h +264 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TBase64Utils.cpp +79 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TBase64Utils.h +42 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TBinaryProtocol.cpp +394 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TBinaryProtocol.h +254 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TCompactProtocol.cpp +736 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TCompactProtocol.h +279 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TDebugProtocol.cpp +346 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TDebugProtocol.h +225 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TDenseProtocol.cpp +762 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TDenseProtocol.h +253 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TJSONProtocol.cpp +998 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TJSONProtocol.h +340 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TOneWayProtocol.h +304 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TProtocol.h +438 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TProtocolException.h +104 -0
- data/vendor/gems/thrift/lib/cpp/src/protocol/TProtocolTap.h +187 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TNonblockingServer.cpp +750 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TNonblockingServer.h +435 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TServer.cpp +38 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TServer.h +213 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TSimpleServer.cpp +118 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TSimpleServer.h +70 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TThreadPoolServer.cpp +217 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TThreadPoolServer.h +79 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TThreadedServer.cpp +243 -0
- data/vendor/gems/thrift/lib/cpp/src/server/TThreadedServer.h +74 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TBufferTransports.cpp +370 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TBufferTransports.h +667 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TFDTransport.cpp +77 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TFDTransport.h +73 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TFileTransport.cpp +953 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TFileTransport.h +442 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/THttpClient.cpp +348 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/THttpClient.h +111 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TServerSocket.cpp +368 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TServerSocket.h +76 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TServerTransport.h +92 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TShortReadTransport.h +96 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSimpleFileTransport.cpp +54 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSimpleFileTransport.h +41 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSocket.cpp +591 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSocket.h +242 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSocketPool.cpp +235 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TSocketPool.h +191 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TTransport.h +224 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TTransportException.cpp +31 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TTransportException.h +117 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TTransportUtils.cpp +178 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TTransportUtils.h +287 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TZlibTransport.cpp +299 -0
- data/vendor/gems/thrift/lib/cpp/src/transport/TZlibTransport.h +219 -0
- data/vendor/gems/thrift/lib/cpp/thrift-nb.pc.in +30 -0
- data/vendor/gems/thrift/lib/cpp/thrift-z.pc.in +30 -0
- data/vendor/gems/thrift/lib/cpp/thrift.pc.in +29 -0
- data/vendor/gems/thrift/lib/csharp/Makefile.am +70 -0
- data/vendor/gems/thrift/lib/csharp/README +26 -0
- data/vendor/gems/thrift/lib/csharp/ThriftMSBuildTask/Properties/AssemblyInfo.cs +55 -0
- data/vendor/gems/thrift/lib/csharp/ThriftMSBuildTask/ThriftBuild.cs +242 -0
- data/vendor/gems/thrift/lib/csharp/ThriftMSBuildTask/ThriftMSBuildTask.csproj +62 -0
- data/vendor/gems/thrift/lib/csharp/src/Collections/THashSet.cs +142 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TBase.cs +34 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TBinaryProtocol.cs +392 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TField.cs +58 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TList.cs +50 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TMap.cs +58 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TMessage.cs +58 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TMessageType.cs +31 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TProtocol.cs +87 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TProtocolException.cs +61 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TProtocolFactory.cs +29 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TProtocolUtil.cs +94 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TSet.cs +50 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TStruct.cs +42 -0
- data/vendor/gems/thrift/lib/csharp/src/Protocol/TType.cs +40 -0
- data/vendor/gems/thrift/lib/csharp/src/Server/TServer.cs +135 -0
- data/vendor/gems/thrift/lib/csharp/src/Server/TSimpleServer.cs +148 -0
- data/vendor/gems/thrift/lib/csharp/src/Server/TThreadPoolServer.cs +186 -0
- data/vendor/gems/thrift/lib/csharp/src/Server/TThreadedServer.cs +234 -0
- data/vendor/gems/thrift/lib/csharp/src/TApplicationException.cs +131 -0
- data/vendor/gems/thrift/lib/csharp/src/TProcessor.cs +29 -0
- data/vendor/gems/thrift/lib/csharp/src/Thrift.csproj +73 -0
- data/vendor/gems/thrift/lib/csharp/src/Thrift.sln +35 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TBufferedTransport.cs +100 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TServerSocket.cs +157 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TServerTransport.cs +39 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TSocket.cs +144 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TStreamTransport.cs +103 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TTransport.cs +66 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TTransportException.cs +64 -0
- data/vendor/gems/thrift/lib/csharp/src/Transport/TTransportFactory.cs +38 -0
- data/vendor/gems/thrift/lib/erl/Makefile +37 -0
- data/vendor/gems/thrift/lib/erl/README +56 -0
- data/vendor/gems/thrift/lib/erl/build/beamver +59 -0
- data/vendor/gems/thrift/lib/erl/build/buildtargets.mk +15 -0
- data/vendor/gems/thrift/lib/erl/build/colors.mk +24 -0
- data/vendor/gems/thrift/lib/erl/build/docs.mk +12 -0
- data/vendor/gems/thrift/lib/erl/build/mime.types +98 -0
- data/vendor/gems/thrift/lib/erl/build/otp.mk +146 -0
- data/vendor/gems/thrift/lib/erl/build/otp_subdir.mk +85 -0
- data/vendor/gems/thrift/lib/erl/build/raw_test.mk +29 -0
- data/vendor/gems/thrift/lib/erl/include/thrift_constants.hrl +54 -0
- data/vendor/gems/thrift/lib/erl/include/thrift_protocol.hrl +31 -0
- data/vendor/gems/thrift/lib/erl/src/Makefile +116 -0
- data/vendor/gems/thrift/lib/erl/src/test_handler.erl +26 -0
- data/vendor/gems/thrift/lib/erl/src/test_service.erl +29 -0
- data/vendor/gems/thrift/lib/erl/src/thrift.app.src +44 -0
- data/vendor/gems/thrift/lib/erl/src/thrift.appup.src +1 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_base64_transport.erl +64 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_binary_protocol.erl +325 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_buffered_transport.erl +180 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_client.erl +384 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_disk_log_transport.erl +118 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_file_transport.erl +87 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_framed_transport.erl +208 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_http_transport.erl +199 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_memory_buffer.erl +164 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_processor.erl +188 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_protocol.erl +356 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_server.erl +183 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_service.erl +25 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_socket_server.erl +249 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_socket_transport.erl +119 -0
- data/vendor/gems/thrift/lib/erl/src/thrift_transport.erl +57 -0
- data/vendor/gems/thrift/lib/erl/vsn.mk +1 -0
- data/vendor/gems/thrift/lib/hs/README +82 -0
- data/vendor/gems/thrift/lib/hs/Setup.lhs +23 -0
- data/vendor/gems/thrift/lib/hs/TODO +2 -0
- data/vendor/gems/thrift/lib/hs/Thrift.cabal +20 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift.hs +111 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift/Protocol.hs +191 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift/Protocol/Binary.hs +147 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift/Server.hs +65 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift/Transport.hs +60 -0
- data/vendor/gems/thrift/lib/hs/src/Thrift/Transport/Handle.hs +58 -0
- data/vendor/gems/thrift/lib/java/Makefile.am +38 -0
- data/vendor/gems/thrift/lib/java/README +43 -0
- data/vendor/gems/thrift/lib/java/build.xml +195 -0
- data/vendor/gems/thrift/lib/java/ivy.xml +8 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/IntRangeSet.java +171 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TApplicationException.java +123 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TBase.java +66 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TBaseHelper.java +102 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TByteArrayOutputStream.java +46 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TDeserializer.java +94 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TException.java +45 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TFieldRequirementType.java +30 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TProcessor.java +32 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TProcessorFactory.java +39 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/TSerializer.java +110 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/FieldMetaData.java +69 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/FieldValueMetaData.java +42 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/ListMetaData.java +29 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/MapMetaData.java +31 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/SetMetaData.java +29 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/meta_data/StructMetaData.java +31 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TBase64Utils.java +128 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TBinaryProtocol.java +331 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TCompactProtocol.java +741 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TField.java +48 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TJSONProtocol.java +927 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TList.java +38 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TMap.java +40 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TMessage.java +48 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TMessageType.java +31 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TProtocol.java +146 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolException.java +81 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolFactory.java +30 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TProtocolUtil.java +158 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TSet.java +42 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TSimpleJSONProtocol.java +384 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TStruct.java +36 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/protocol/TType.java +40 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/server/THsHaServer.java +304 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/server/TNonblockingServer.java +772 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/server/TServer.java +126 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/server/TSimpleServer.java +145 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/server/TThreadPoolServer.java +271 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TFramedTransport.java +126 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/THttpClient.java +157 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TIOStreamTransport.java +159 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TMemoryBuffer.java +98 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerSocket.java +160 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingServerTransport.java +31 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingSocket.java +213 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TNonblockingTransport.java +31 -0
- data/vendor/gems/thrift/lib/java/src/org/apache/thrift/transport/TServerSocket.java +145 -0
- metadata +348 -37
- data/vendor/gems/trollop/FAQ.txt +0 -35
- data/vendor/gems/trollop/History.txt +0 -84
- data/vendor/gems/trollop/Manifest.txt +0 -7
- data/vendor/gems/trollop/README.txt +0 -38
- data/vendor/gems/trollop/Rakefile +0 -36
- data/vendor/gems/trollop/lib/trollop.rb +0 -695
- data/vendor/gems/trollop/release-script.txt +0 -13
- data/vendor/gems/trollop/test/test_trollop.rb +0 -957
- data/vendor/gems/trollop/www/index.html +0 -167
@@ -0,0 +1,20 @@
|
|
1
|
+
Tue Oct 24 12:28:44 CDT 2006
|
2
|
+
|
3
|
+
Copyright (c) <2006> <Martin J. Logan, Erlware>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software (OTP Base, fslib, G.A.S) and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
16
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
17
|
+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
18
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
20
|
+
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,96 @@
|
|
1
|
+
Thrift Protocol Structure
|
2
|
+
|
3
|
+
Last Modified: 2007-Jun-29
|
4
|
+
|
5
|
+
--------------------------------------------------------------------
|
6
|
+
|
7
|
+
Licensed to the Apache Software Foundation (ASF) under one
|
8
|
+
or more contributor license agreements. See the NOTICE file
|
9
|
+
distributed with this work for additional information
|
10
|
+
regarding copyright ownership. The ASF licenses this file
|
11
|
+
to you under the Apache License, Version 2.0 (the
|
12
|
+
"License"); you may not use this file except in compliance
|
13
|
+
with the License. You may obtain a copy of the License at
|
14
|
+
|
15
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
16
|
+
|
17
|
+
Unless required by applicable law or agreed to in writing,
|
18
|
+
software distributed under the License is distributed on an
|
19
|
+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
20
|
+
KIND, either express or implied. See the License for the
|
21
|
+
specific language governing permissions and limitations
|
22
|
+
under the License.
|
23
|
+
|
24
|
+
--------------------------------------------------------------------
|
25
|
+
|
26
|
+
This document describes the structure of the Thrift protocol
|
27
|
+
without specifying the encoding. Thus, the order of elements
|
28
|
+
could in some cases be rearranged depending upon the TProtocol
|
29
|
+
implementation, but this document specifies the minimum required
|
30
|
+
structure. There are some "dumb" terminals like STRING and INT
|
31
|
+
that take the place of an actual encoding specification.
|
32
|
+
|
33
|
+
They key point to notice is that ALL messages are just one wrapped
|
34
|
+
<struct>. Depending upon the message type, the <struct> can be
|
35
|
+
interpreted as the argument list to a function, the return value
|
36
|
+
of a function, or an exception.
|
37
|
+
|
38
|
+
--------------------------------------------------------------------
|
39
|
+
|
40
|
+
<message> ::= <message-begin> <struct> <message-end>
|
41
|
+
|
42
|
+
<message-begin> ::= <method-name> <message-type> <message-seqid>
|
43
|
+
|
44
|
+
<method-name> ::= STRING
|
45
|
+
|
46
|
+
<message-type> ::= T_CALL | T_REPLY | T_EXCEPTION
|
47
|
+
|
48
|
+
<message-seqid> ::= I32
|
49
|
+
|
50
|
+
<struct> ::= <struct-begin> <field>* <field-stop> <struct-end>
|
51
|
+
|
52
|
+
<struct-begin> ::= <struct-name>
|
53
|
+
|
54
|
+
<struct-name> ::= STRING
|
55
|
+
|
56
|
+
<field-stop> ::= T_STOP
|
57
|
+
|
58
|
+
<field> ::= <field-begin> <field-data> <field-end>
|
59
|
+
|
60
|
+
<field-begin> ::= <field-name> <field-type> <field-id>
|
61
|
+
|
62
|
+
<field-name> ::= STRING
|
63
|
+
|
64
|
+
<field-type> ::= T_BOOL | T_BYTE | T_I8 | T_I16 | T_I32 | T_I64 | T_DOUBLE
|
65
|
+
| T_STRING | T_BINARY | T_STRUCT | T_MAP | T_SET | T_LIST
|
66
|
+
|
67
|
+
<field-id> ::= I16
|
68
|
+
|
69
|
+
<field-data> ::= I8 | I16 | I32 | I64 | DOUBLE | STRING | BINARY
|
70
|
+
<struct> | <map> | <list> | <set>
|
71
|
+
|
72
|
+
<map> ::= <map-begin> <field-datum>* <map-end>
|
73
|
+
|
74
|
+
<map-begin> ::= <map-key-type> <map-value-type> <map-size>
|
75
|
+
|
76
|
+
<map-key-type> ::= <field-type>
|
77
|
+
|
78
|
+
<map-value-type> ::= <field-type>
|
79
|
+
|
80
|
+
<map-size> ::= I32
|
81
|
+
|
82
|
+
<list> ::= <list-begin> <field-data>* <list-end>
|
83
|
+
|
84
|
+
<list-begin> ::= <list-elem-type> <list-size>
|
85
|
+
|
86
|
+
<list-elem-type> ::= <field-type>
|
87
|
+
|
88
|
+
<list-size> ::= I32
|
89
|
+
|
90
|
+
<set> ::= <set-begin> <field-data>* <set-end>
|
91
|
+
|
92
|
+
<set-begin> ::= <set-elem-type> <set-size>
|
93
|
+
|
94
|
+
<set-elem-type> ::= <field-type>
|
95
|
+
|
96
|
+
<set-size> ::= I32
|
@@ -0,0 +1,1057 @@
|
|
1
|
+
%-----------------------------------------------------------------------------
|
2
|
+
%
|
3
|
+
% Thrift whitepaper
|
4
|
+
%
|
5
|
+
% Name: thrift.tex
|
6
|
+
%
|
7
|
+
% Authors: Mark Slee (mcslee@facebook.com)
|
8
|
+
%
|
9
|
+
% Created: 05 March 2007
|
10
|
+
%
|
11
|
+
% You will need a copy of sigplanconf.cls to format this document.
|
12
|
+
% It is available at <http://www.sigplan.org/authorInformation.htm>.
|
13
|
+
%
|
14
|
+
%-----------------------------------------------------------------------------
|
15
|
+
|
16
|
+
|
17
|
+
\documentclass[nocopyrightspace,blockstyle]{sigplanconf}
|
18
|
+
|
19
|
+
\usepackage{amssymb}
|
20
|
+
\usepackage{amsfonts}
|
21
|
+
\usepackage{amsmath}
|
22
|
+
\usepackage{url}
|
23
|
+
|
24
|
+
\begin{document}
|
25
|
+
|
26
|
+
% \conferenceinfo{WXYZ '05}{date, City.}
|
27
|
+
% \copyrightyear{2007}
|
28
|
+
% \copyrightdata{[to be supplied]}
|
29
|
+
|
30
|
+
% \titlebanner{banner above paper title} % These are ignored unless
|
31
|
+
% \preprintfooter{short description of paper} % 'preprint' option specified.
|
32
|
+
|
33
|
+
\title{Thrift: Scalable Cross-Language Services Implementation}
|
34
|
+
\subtitle{}
|
35
|
+
|
36
|
+
\authorinfo{Mark Slee, Aditya Agarwal and Marc Kwiatkowski}
|
37
|
+
{Facebook, 156 University Ave, Palo Alto, CA}
|
38
|
+
{\{mcslee,aditya,marc\}@facebook.com}
|
39
|
+
|
40
|
+
\maketitle
|
41
|
+
|
42
|
+
\begin{abstract}
|
43
|
+
Thrift is a software library and set of code-generation tools developed at
|
44
|
+
Facebook to expedite development and implementation of efficient and scalable
|
45
|
+
backend services. Its primary goal is to enable efficient and reliable
|
46
|
+
communication across programming languages by abstracting the portions of each
|
47
|
+
language that tend to require the most customization into a common library
|
48
|
+
that is implemented in each language. Specifically, Thrift allows developers to
|
49
|
+
define datatypes and service interfaces in a single language-neutral file
|
50
|
+
and generate all the necessary code to build RPC clients and servers.
|
51
|
+
|
52
|
+
This paper details the motivations and design choices we made in Thrift, as
|
53
|
+
well as some of the more interesting implementation details. It is not
|
54
|
+
intended to be taken as research, but rather it is an exposition on what we did
|
55
|
+
and why.
|
56
|
+
\end{abstract}
|
57
|
+
|
58
|
+
% \category{D.3.3}{Programming Languages}{Language constructs and features}
|
59
|
+
|
60
|
+
%\terms
|
61
|
+
%Languages, serialization, remote procedure call
|
62
|
+
|
63
|
+
%\keywords
|
64
|
+
%Data description language, interface definition language, remote procedure call
|
65
|
+
|
66
|
+
\section{Introduction}
|
67
|
+
As Facebook's traffic and network structure have scaled, the resource
|
68
|
+
demands of many operations on the site (i.e. search,
|
69
|
+
ad selection and delivery, event logging) have presented technical requirements
|
70
|
+
drastically outside the scope of the LAMP framework. In our implementation of
|
71
|
+
these services, various programming languages have been selected to
|
72
|
+
optimize for the right combination of performance, ease and speed of
|
73
|
+
development, availability of existing libraries, etc. By and large,
|
74
|
+
Facebook's engineering culture has tended towards choosing the best
|
75
|
+
tools and implementations available over standardizing on any one
|
76
|
+
programming language and begrudgingly accepting its inherent limitations.
|
77
|
+
|
78
|
+
Given this design choice, we were presented with the challenge of building
|
79
|
+
a transparent, high-performance bridge across many programming languages.
|
80
|
+
We found that most available solutions were either too limited, did not offer
|
81
|
+
sufficient datatype freedom, or suffered from subpar performance.
|
82
|
+
\footnote{See Appendix A for a discussion of alternative systems.}
|
83
|
+
|
84
|
+
The solution that we have implemented combines a language-neutral software
|
85
|
+
stack implemented across numerous programming languages and an associated code
|
86
|
+
generation engine that transforms a simple interface and data definition
|
87
|
+
language into client and server remote procedure call libraries.
|
88
|
+
Choosing static code generation over a dynamic system allows us to create
|
89
|
+
validated code that can be run without the need for
|
90
|
+
any advanced introspective run-time type checking. It is also designed to
|
91
|
+
be as simple as possible for the developer, who can typically define all
|
92
|
+
the necessary data structures and interfaces for a complex service in a single
|
93
|
+
short file.
|
94
|
+
|
95
|
+
Surprised that a robust open solution to these relatively common problems
|
96
|
+
did not yet exist, we committed early on to making the Thrift implementation
|
97
|
+
open source.
|
98
|
+
|
99
|
+
In evaluating the challenges of cross-language interaction in a networked
|
100
|
+
environment, some key components were identified:
|
101
|
+
|
102
|
+
\textit{Types.} A common type system must exist across programming languages
|
103
|
+
without requiring that the application developer use custom Thrift datatypes
|
104
|
+
or write their own serialization code. That is,
|
105
|
+
a C++ programmer should be able to transparently exchange a strongly typed
|
106
|
+
STL map for a dynamic Python dictionary. Neither
|
107
|
+
programmer should be forced to write any code below the application layer
|
108
|
+
to achieve this. Section 2 details the Thrift type system.
|
109
|
+
|
110
|
+
\textit{Transport.} Each language must have a common interface to
|
111
|
+
bidirectional raw data transport. The specifics of how a given
|
112
|
+
transport is implemented should not matter to the service developer.
|
113
|
+
The same application code should be able to run against TCP stream sockets,
|
114
|
+
raw data in memory, or files on disk. Section 3 details the Thrift Transport
|
115
|
+
layer.
|
116
|
+
|
117
|
+
\textit{Protocol.} Datatypes must have some way of using the Transport
|
118
|
+
layer to encode and decode themselves. Again, the application
|
119
|
+
developer need not be concerned by this layer. Whether the service uses
|
120
|
+
an XML or binary protocol is immaterial to the application code.
|
121
|
+
All that matters is that the data can be read and written in a consistent,
|
122
|
+
deterministic matter. Section 4 details the Thrift Protocol layer.
|
123
|
+
|
124
|
+
\textit{Versioning.} For robust services, the involved datatypes must
|
125
|
+
provide a mechanism for versioning themselves. Specifically,
|
126
|
+
it should be possible to add or remove fields in an object or alter the
|
127
|
+
argument list of a function without any interruption in service (or,
|
128
|
+
worse yet, nasty segmentation faults). Section 5 details Thrift's versioning
|
129
|
+
system.
|
130
|
+
|
131
|
+
\textit{Processors.} Finally, we generate code capable of processing data
|
132
|
+
streams to accomplish remote procedure calls. Section 6 details the generated
|
133
|
+
code and TProcessor paradigm.
|
134
|
+
|
135
|
+
Section 7 discusses implementation details, and Section 8 describes
|
136
|
+
our conclusions.
|
137
|
+
|
138
|
+
\section{Types}
|
139
|
+
|
140
|
+
The goal of the Thrift type system is to enable programmers to develop using
|
141
|
+
completely natively defined types, no matter what programming language they
|
142
|
+
use. By design, the Thrift type system does not introduce any special dynamic
|
143
|
+
types or wrapper objects. It also does not require that the developer write
|
144
|
+
any code for object serialization or transport. The Thrift IDL (Interface
|
145
|
+
Definition Language) file is
|
146
|
+
logically a way for developers to annotate their data structures with the
|
147
|
+
minimal amount of extra information necessary to tell a code generator
|
148
|
+
how to safely transport the objects across languages.
|
149
|
+
|
150
|
+
\subsection{Base Types}
|
151
|
+
|
152
|
+
The type system rests upon a few base types. In considering which types to
|
153
|
+
support, we aimed for clarity and simplicity over abundance, focusing
|
154
|
+
on the key types available in all programming languages, ommitting any
|
155
|
+
niche types available only in specific languages.
|
156
|
+
|
157
|
+
The base types supported by Thrift are:
|
158
|
+
\begin{itemize}
|
159
|
+
\item \texttt{bool} A boolean value, true or false
|
160
|
+
\item \texttt{byte} A signed byte
|
161
|
+
\item \texttt{i16} A 16-bit signed integer
|
162
|
+
\item \texttt{i32} A 32-bit signed integer
|
163
|
+
\item \texttt{i64} A 64-bit signed integer
|
164
|
+
\item \texttt{double} A 64-bit floating point number
|
165
|
+
\item \texttt{string} An encoding-agnostic text or binary string
|
166
|
+
\item \texttt{binary} A byte array representation for blobs
|
167
|
+
\end{itemize}
|
168
|
+
|
169
|
+
Of particular note is the absence of unsigned integer types. Because these
|
170
|
+
types have no direct translation to native primitive types in many languages,
|
171
|
+
the advantages they afford are lost. Further, there is no way to prevent the
|
172
|
+
application developer in a language like Python from assigning a negative value
|
173
|
+
to an integer variable, leading to unpredictable behavior. From a design
|
174
|
+
standpoint, we observed that unsigned integers were very rarely, if ever, used
|
175
|
+
for arithmetic purposes, but in practice were much more often used as keys or
|
176
|
+
identifiers. In this case, the sign is irrelevant. Signed integers serve this
|
177
|
+
same purpose and can be safely cast to their unsigned counterparts (most
|
178
|
+
commonly in C++) when absolutely necessary.
|
179
|
+
|
180
|
+
\subsection{Structs}
|
181
|
+
|
182
|
+
A Thrift struct defines a common object to be used across languages. A struct
|
183
|
+
is essentially equivalent to a class in object oriented programming
|
184
|
+
languages. A struct has a set of strongly typed fields, each with a unique
|
185
|
+
name identifier. The basic syntax for defining a Thrift struct looks very
|
186
|
+
similar to a C struct definition. Fields may be annotated with an integer field
|
187
|
+
identifier (unique to the scope of that struct) and optional default values.
|
188
|
+
Field identifiers will be automatically assigned if omitted, though they are
|
189
|
+
strongly encouraged for versioning reasons discussed later.
|
190
|
+
|
191
|
+
\subsection{Containers}
|
192
|
+
|
193
|
+
Thrift containers are strongly typed containers that map to the most commonly
|
194
|
+
used containers in common programming languages. They are annotated using
|
195
|
+
the C++ template (or Java Generics) style. There are three types available:
|
196
|
+
\begin{itemize}
|
197
|
+
\item \texttt{list<type>} An ordered list of elements. Translates directly into
|
198
|
+
an STL \texttt{vector}, Java \texttt{ArrayList}, or native array in scripting languages. May
|
199
|
+
contain duplicates.
|
200
|
+
\item \texttt{set<type>} An unordered set of unique elements. Translates into
|
201
|
+
an STL \texttt{set}, Java \texttt{HashSet}, \texttt{set} in Python, or native
|
202
|
+
dictionary in PHP/Ruby.
|
203
|
+
\item \texttt{map<type1,type2>} A map of strictly unique keys to values
|
204
|
+
Translates into an STL \texttt{map}, Java \texttt{HashMap}, PHP associative
|
205
|
+
array, or Python/Ruby dictionary.
|
206
|
+
\end{itemize}
|
207
|
+
|
208
|
+
While defaults are provided, the type mappings are not explicitly fixed. Custom
|
209
|
+
code generator directives have been added to substitute custom types in
|
210
|
+
destination languages (i.e.
|
211
|
+
\texttt{hash\_map} or Google's sparse hash map can be used in C++). The
|
212
|
+
only requirement is that the custom types support all the necessary iteration
|
213
|
+
primitives. Container elements may be of any valid Thrift type, including other
|
214
|
+
containers or structs.
|
215
|
+
|
216
|
+
\begin{verbatim}
|
217
|
+
struct Example {
|
218
|
+
1:i32 number=10,
|
219
|
+
2:i64 bigNumber,
|
220
|
+
3:double decimals,
|
221
|
+
4:string name="thrifty"
|
222
|
+
}\end{verbatim}
|
223
|
+
|
224
|
+
In the target language, each definition generates a type with two methods,
|
225
|
+
\texttt{read} and \texttt{write}, which perform serialization and transport
|
226
|
+
of the objects using a Thrift TProtocol object.
|
227
|
+
|
228
|
+
\subsection{Exceptions}
|
229
|
+
|
230
|
+
Exceptions are syntactically and functionally equivalent to structs except
|
231
|
+
that they are declared using the \texttt{exception} keyword instead of the
|
232
|
+
\texttt{struct} keyword.
|
233
|
+
|
234
|
+
The generated objects inherit from an exception base class as appropriate
|
235
|
+
in each target programming language, in order to seamlessly
|
236
|
+
integrate with native exception handling in any given
|
237
|
+
language. Again, the design emphasis is on making the code familiar to the
|
238
|
+
application developer.
|
239
|
+
|
240
|
+
\subsection{Services}
|
241
|
+
|
242
|
+
Services are defined using Thrift types. Definition of a service is
|
243
|
+
semantically equivalent to defining an interface (or a pure virtual abstract
|
244
|
+
class) in object oriented
|
245
|
+
programming. The Thrift compiler generates fully functional client and
|
246
|
+
server stubs that implement the interface. Services are defined as follows:
|
247
|
+
|
248
|
+
\begin{verbatim}
|
249
|
+
service <name> {
|
250
|
+
<returntype> <name>(<arguments>)
|
251
|
+
[throws (<exceptions>)]
|
252
|
+
...
|
253
|
+
}\end{verbatim}
|
254
|
+
|
255
|
+
An example:
|
256
|
+
|
257
|
+
\begin{verbatim}
|
258
|
+
service StringCache {
|
259
|
+
void set(1:i32 key, 2:string value),
|
260
|
+
string get(1:i32 key) throws (1:KeyNotFound knf),
|
261
|
+
void delete(1:i32 key)
|
262
|
+
}
|
263
|
+
\end{verbatim}
|
264
|
+
|
265
|
+
Note that \texttt{void} is a valid type for a function return, in addition to
|
266
|
+
all other defined Thrift types. Additionally, an \texttt{async} modifier
|
267
|
+
keyword may be added to a \texttt{void} function, which will generate code that does
|
268
|
+
not wait for a response from the server. Note that a pure \texttt{void}
|
269
|
+
function will return a response to the client which guarantees that the
|
270
|
+
operation has completed on the server side. With \texttt{async} method calls
|
271
|
+
the client will only be guaranteed that the request succeeded at the
|
272
|
+
transport layer. (In many transport scenarios this is inherently unreliable
|
273
|
+
due to the Byzantine Generals' Problem. Therefore, application developers
|
274
|
+
should take care only to use the async optimization in cases where dropped
|
275
|
+
method calls are acceptable or the transport is known to be reliable.)
|
276
|
+
|
277
|
+
Also of note is the fact that argument lists and exception lists for functions
|
278
|
+
are implemented as Thrift structs. All three constructs are identical in both
|
279
|
+
notation and behavior.
|
280
|
+
|
281
|
+
\section{Transport}
|
282
|
+
|
283
|
+
The transport layer is used by the generated code to facilitate data transfer.
|
284
|
+
|
285
|
+
\subsection{Interface}
|
286
|
+
|
287
|
+
A key design choice in the implementation of Thrift was to decouple the
|
288
|
+
transport layer from the code generation layer. Though Thrift is typically
|
289
|
+
used on top of the TCP/IP stack with streaming sockets as the base layer of
|
290
|
+
communication, there was no compelling reason to build that constraint into
|
291
|
+
the system. The performance tradeoff incurred by an abstracted I/O layer
|
292
|
+
(roughly one virtual method lookup / function call per operation) was
|
293
|
+
immaterial compared to the cost of actual I/O operations (typically invoking
|
294
|
+
system calls).
|
295
|
+
|
296
|
+
Fundamentally, generated Thrift code only needs to know how to read and
|
297
|
+
write data. The origin and destination of the data are irrelevant; it may be a
|
298
|
+
socket, a segment of shared memory, or a file on the local disk. The Thrift
|
299
|
+
transport interface supports the following methods:
|
300
|
+
|
301
|
+
\begin{itemize}
|
302
|
+
\item \texttt{open} Opens the tranpsort
|
303
|
+
\item \texttt{close} Closes the tranport
|
304
|
+
\item \texttt{isOpen} Indicates whether the transport is open
|
305
|
+
\item \texttt{read} Reads from the transport
|
306
|
+
\item \texttt{write} Writes to the transport
|
307
|
+
\item \texttt{flush} Forces any pending writes
|
308
|
+
\end{itemize}
|
309
|
+
|
310
|
+
There are a few additional methods not documented here which are used to aid
|
311
|
+
in batching reads and optionally signaling the completion of a read or
|
312
|
+
write operation from the generated code.
|
313
|
+
|
314
|
+
In addition to the above
|
315
|
+
\texttt{TTransport} interface, there is a\\
|
316
|
+
\texttt{TServerTransport} interface
|
317
|
+
used to accept or create primitive transport objects. Its interface is as
|
318
|
+
follows:
|
319
|
+
|
320
|
+
\begin{itemize}
|
321
|
+
\item \texttt{open} Opens the transport
|
322
|
+
\item \texttt{listen} Begins listening for connections
|
323
|
+
\item \texttt{accept} Returns a new client transport
|
324
|
+
\item \texttt{close} Closes the transport
|
325
|
+
\end{itemize}
|
326
|
+
|
327
|
+
\subsection{Implementation}
|
328
|
+
|
329
|
+
The transport interface is designed for simple implementation in any
|
330
|
+
programming language. New transport mechanisms can be easily defined as needed
|
331
|
+
by application developers.
|
332
|
+
|
333
|
+
\subsubsection{TSocket}
|
334
|
+
|
335
|
+
The \texttt{TSocket} class is implemented across all target languages. It
|
336
|
+
provides a common, simple interface to a TCP/IP stream socket.
|
337
|
+
|
338
|
+
\subsubsection{TFileTransport}
|
339
|
+
|
340
|
+
The \texttt{TFileTransport} is an abstraction of an on-disk file to a data
|
341
|
+
stream. It can be used to write out a set of incoming Thrift requests to a file
|
342
|
+
on disk. The on-disk data can then be replayed from the log, either for
|
343
|
+
post-processing or for reproduction and/or simulation of past events.
|
344
|
+
|
345
|
+
\subsubsection{Utilities}
|
346
|
+
|
347
|
+
The Transport interface is designed to support easy extension using common
|
348
|
+
OOP techniques, such as composition. Some simple utilites include the
|
349
|
+
\texttt{TBufferedTransport}, which buffers the writes and reads on an
|
350
|
+
underlying transport, the \texttt{TFramedTransport}, which transmits data with frame
|
351
|
+
size headers for chunking optimization or nonblocking operation, and the
|
352
|
+
\texttt{TMemoryBuffer}, which allows reading and writing directly from the heap
|
353
|
+
or stack memory owned by the process.
|
354
|
+
|
355
|
+
\section{Protocol}
|
356
|
+
|
357
|
+
A second major abstraction in Thrift is the separation of data structure from
|
358
|
+
transport representation. Thrift enforces a certain messaging structure when
|
359
|
+
transporting data, but it is agnostic to the protocol encoding in use. That is,
|
360
|
+
it does not matter whether data is encoded as XML, human-readable ASCII, or a
|
361
|
+
dense binary format as long as the data supports a fixed set of operations
|
362
|
+
that allow it to be deterministically read and written by generated code.
|
363
|
+
|
364
|
+
\subsection{Interface}
|
365
|
+
|
366
|
+
The Thrift Protocol interface is very straightforward. It fundamentally
|
367
|
+
supports two things: 1) bidirectional sequenced messaging, and
|
368
|
+
2) encoding of base types, containers, and structs.
|
369
|
+
|
370
|
+
\begin{verbatim}
|
371
|
+
writeMessageBegin(name, type, seq)
|
372
|
+
writeMessageEnd()
|
373
|
+
writeStructBegin(name)
|
374
|
+
writeStructEnd()
|
375
|
+
writeFieldBegin(name, type, id)
|
376
|
+
writeFieldEnd()
|
377
|
+
writeFieldStop()
|
378
|
+
writeMapBegin(ktype, vtype, size)
|
379
|
+
writeMapEnd()
|
380
|
+
writeListBegin(etype, size)
|
381
|
+
writeListEnd()
|
382
|
+
writeSetBegin(etype, size)
|
383
|
+
writeSetEnd()
|
384
|
+
writeBool(bool)
|
385
|
+
writeByte(byte)
|
386
|
+
writeI16(i16)
|
387
|
+
writeI32(i32)
|
388
|
+
writeI64(i64)
|
389
|
+
writeDouble(double)
|
390
|
+
writeString(string)
|
391
|
+
|
392
|
+
name, type, seq = readMessageBegin()
|
393
|
+
readMessageEnd()
|
394
|
+
name = readStructBegin()
|
395
|
+
readStructEnd()
|
396
|
+
name, type, id = readFieldBegin()
|
397
|
+
readFieldEnd()
|
398
|
+
k, v, size = readMapBegin()
|
399
|
+
readMapEnd()
|
400
|
+
etype, size = readListBegin()
|
401
|
+
readListEnd()
|
402
|
+
etype, size = readSetBegin()
|
403
|
+
readSetEnd()
|
404
|
+
bool = readBool()
|
405
|
+
byte = readByte()
|
406
|
+
i16 = readI16()
|
407
|
+
i32 = readI32()
|
408
|
+
i64 = readI64()
|
409
|
+
double = readDouble()
|
410
|
+
string = readString()
|
411
|
+
\end{verbatim}
|
412
|
+
|
413
|
+
Note that every \texttt{write} function has exactly one \texttt{read} counterpart, with
|
414
|
+
the exception of \texttt{writeFieldStop()}. This is a special method
|
415
|
+
that signals the end of a struct. The procedure for reading a struct is to
|
416
|
+
\texttt{readFieldBegin()} until the stop field is encountered, and then to
|
417
|
+
\texttt{readStructEnd()}. The
|
418
|
+
generated code relies upon this call sequence to ensure that everything written by
|
419
|
+
a protocol encoder can be read by a matching protocol decoder. Further note
|
420
|
+
that this set of functions is by design more robust than necessary.
|
421
|
+
For example, \texttt{writeStructEnd()} is not strictly necessary, as the end of
|
422
|
+
a struct may be implied by the stop field. This method is a convenience for
|
423
|
+
verbose protocols in which it is cleaner to separate these calls (e.g. a closing
|
424
|
+
\texttt{</struct>} tag in XML).
|
425
|
+
|
426
|
+
\subsection{Structure}
|
427
|
+
|
428
|
+
Thrift structures are designed to support encoding into a streaming
|
429
|
+
protocol. The implementation should never need to frame or compute the
|
430
|
+
entire data length of a structure prior to encoding it. This is critical to
|
431
|
+
performance in many scenarios. Consider a long list of relatively large
|
432
|
+
strings. If the protocol interface required reading or writing a list to be an
|
433
|
+
atomic operation, then the implementation would need to perform a linear pass over the
|
434
|
+
entire list before encoding any data. However, if the list can be written
|
435
|
+
as iteration is performed, the corresponding read may begin in parallel,
|
436
|
+
theoretically offering an end-to-end speedup of $(kN - C)$, where $N$ is the size
|
437
|
+
of the list, $k$ the cost factor associated with serializing a single
|
438
|
+
element, and $C$ is fixed offset for the delay between data being written
|
439
|
+
and becoming available to read.
|
440
|
+
|
441
|
+
Similarly, structs do not encode their data lengths a priori. Instead, they are
|
442
|
+
encoded as a sequence of fields, with each field having a type specifier and a
|
443
|
+
unique field identifier. Note that the inclusion of type specifiers allows
|
444
|
+
the protocol to be safely parsed and decoded without any generated code
|
445
|
+
or access to the original IDL file. Structs are terminated by a field header
|
446
|
+
with a special \texttt{STOP} type. Because all the basic types can be read
|
447
|
+
deterministically, all structs (even those containing other structs) can be
|
448
|
+
read deterministically. The Thrift protocol is self-delimiting without any
|
449
|
+
framing and regardless of the encoding format.
|
450
|
+
|
451
|
+
In situations where streaming is unnecessary or framing is advantageous, it
|
452
|
+
can be very simply added into the transport layer, using the
|
453
|
+
\texttt{TFramedTransport} abstraction.
|
454
|
+
|
455
|
+
\subsection{Implementation}
|
456
|
+
|
457
|
+
Facebook has implemented and deployed a space-efficient binary protocol which
|
458
|
+
is used by most backend services. Essentially, it writes all data
|
459
|
+
in a flat binary format. Integer types are converted to network byte order,
|
460
|
+
strings are prepended with their byte length, and all message and field headers
|
461
|
+
are written using the primitive integer serialization constructs. String names
|
462
|
+
for fields are omitted - when using generated code, field identifiers are
|
463
|
+
sufficient.
|
464
|
+
|
465
|
+
We decided against some extreme storage optimizations (i.e. packing
|
466
|
+
small integers into ASCII or using a 7-bit continuation format) for the sake
|
467
|
+
of simplicity and clarity in the code. These alterations can easily be made
|
468
|
+
if and when we encounter a performance-critical use case that demands them.
|
469
|
+
|
470
|
+
\section{Versioning}
|
471
|
+
|
472
|
+
Thrift is robust in the face of versioning and data definition changes. This
|
473
|
+
is critical to enable staged rollouts of changes to deployed services. The
|
474
|
+
system must be able to support reading of old data from log files, as well as
|
475
|
+
requests from out-of-date clients to new servers, and vice versa.
|
476
|
+
|
477
|
+
\subsection{Field Identifiers}
|
478
|
+
|
479
|
+
Versioning in Thrift is implemented via field identifiers. The field header
|
480
|
+
for every member of a struct in Thrift is encoded with a unique field
|
481
|
+
identifier. The combination of this field identifier and its type specifier
|
482
|
+
is used to uniquely identify the field. The Thrift definition language
|
483
|
+
supports automatic assignment of field identifiers, but it is good
|
484
|
+
programming practice to always explicitly specify field identifiers.
|
485
|
+
Identifiers are specified as follows:
|
486
|
+
|
487
|
+
\begin{verbatim}
|
488
|
+
struct Example {
|
489
|
+
1:i32 number=10,
|
490
|
+
2:i64 bigNumber,
|
491
|
+
3:double decimals,
|
492
|
+
4:string name="thrifty"
|
493
|
+
}\end{verbatim}
|
494
|
+
|
495
|
+
To avoid conflicts between manually and automatically assigned identifiers,
|
496
|
+
fields with identifiers omitted are assigned identifiers
|
497
|
+
decrementing from -1, and the language only supports the manual assignment of
|
498
|
+
positive identifiers.
|
499
|
+
|
500
|
+
When data is being deserialized, the generated code can use these identifiers
|
501
|
+
to properly identify the field and determine whether it aligns with a field in
|
502
|
+
its definition file. If a field identifier is not recognized, the generated
|
503
|
+
code can use the type specifier to skip the unknown field without any error.
|
504
|
+
Again, this is possible due to the fact that all datatypes are self
|
505
|
+
delimiting.
|
506
|
+
|
507
|
+
Field identifiers can (and should) also be specified in function argument
|
508
|
+
lists. In fact, argument lists are not only represented as structs on the
|
509
|
+
backend, but actually share the same code in the compiler frontend. This
|
510
|
+
allows for version-safe modification of method parameters
|
511
|
+
|
512
|
+
\begin{verbatim}
|
513
|
+
service StringCache {
|
514
|
+
void set(1:i32 key, 2:string value),
|
515
|
+
string get(1:i32 key) throws (1:KeyNotFound knf),
|
516
|
+
void delete(1:i32 key)
|
517
|
+
}
|
518
|
+
\end{verbatim}
|
519
|
+
|
520
|
+
The syntax for specifying field identifiers was chosen to echo their structure.
|
521
|
+
Structs can be thought of as a dictionary where the identifiers are keys, and
|
522
|
+
the values are strongly-typed named fields.
|
523
|
+
|
524
|
+
Field identifiers internally use the \texttt{i16} Thrift type. Note, however,
|
525
|
+
that the \texttt{TProtocol} abstraction may encode identifiers in any format.
|
526
|
+
|
527
|
+
\subsection{Isset}
|
528
|
+
|
529
|
+
When an unexpected field is encountered, it can be safely ignored and
|
530
|
+
discarded. When an expected field is not found, there must be some way to
|
531
|
+
signal to the developer that it was not present. This is implemented via an
|
532
|
+
inner \texttt{isset} structure inside the defined objects. (Isset functionality
|
533
|
+
is implicit with a \texttt{null} value in PHP, \texttt{None} in Python
|
534
|
+
and \texttt{nil} in Ruby.) Essentially,
|
535
|
+
the inner \texttt{isset} object of each Thrift struct contains a boolean value
|
536
|
+
for each field which denotes whether or not that field is present in the
|
537
|
+
struct. When a reader receives a struct, it should check for a field being set
|
538
|
+
before operating directly on it.
|
539
|
+
|
540
|
+
\begin{verbatim}
|
541
|
+
class Example {
|
542
|
+
public:
|
543
|
+
Example() :
|
544
|
+
number(10),
|
545
|
+
bigNumber(0),
|
546
|
+
decimals(0),
|
547
|
+
name("thrifty") {}
|
548
|
+
|
549
|
+
int32_t number;
|
550
|
+
int64_t bigNumber;
|
551
|
+
double decimals;
|
552
|
+
std::string name;
|
553
|
+
|
554
|
+
struct __isset {
|
555
|
+
__isset() :
|
556
|
+
number(false),
|
557
|
+
bigNumber(false),
|
558
|
+
decimals(false),
|
559
|
+
name(false) {}
|
560
|
+
bool number;
|
561
|
+
bool bigNumber;
|
562
|
+
bool decimals;
|
563
|
+
bool name;
|
564
|
+
} __isset;
|
565
|
+
...
|
566
|
+
}
|
567
|
+
\end{verbatim}
|
568
|
+
|
569
|
+
\subsection{Case Analysis}
|
570
|
+
|
571
|
+
There are four cases in which version mismatches may occur.
|
572
|
+
|
573
|
+
\begin{enumerate}
|
574
|
+
\item \textit{Added field, old client, new server.} In this case, the old
|
575
|
+
client does not send the new field. The new server recognizes that the field
|
576
|
+
is not set, and implements default behavior for out-of-date requests.
|
577
|
+
\item \textit{Removed field, old client, new server.} In this case, the old
|
578
|
+
client sends the removed field. The new server simply ignores it.
|
579
|
+
\item \textit{Added field, new client, old server.} The new client sends a
|
580
|
+
field that the old server does not recognize. The old server simply ignores
|
581
|
+
it and processes as normal.
|
582
|
+
\item \textit{Removed field, new client, old server.} This is the most
|
583
|
+
dangerous case, as the old server is unlikely to have suitable default
|
584
|
+
behavior implemented for the missing field. It is recommended that in this
|
585
|
+
situation the new server be rolled out prior to the new clients.
|
586
|
+
\end{enumerate}
|
587
|
+
|
588
|
+
\subsection{Protocol/Transport Versioning}
|
589
|
+
The \texttt{TProtocol} abstractions are also designed to give protocol
|
590
|
+
implementations the freedom to version themselves in whatever manner they
|
591
|
+
see fit. Specifically, any protocol implementation is free to send whatever
|
592
|
+
it likes in the \texttt{writeMessageBegin()} call. It is entirely up to the
|
593
|
+
implementor how to handle versioning at the protocol level. The key point is
|
594
|
+
that protocol encoding changes are safely isolated from interface definition
|
595
|
+
version changes.
|
596
|
+
|
597
|
+
Note that the exact same is true of the \texttt{TTransport} interface. For
|
598
|
+
example, if we wished to add some new checksumming or error detection to the
|
599
|
+
\texttt{TFileTransport}, we could simply add a version header into the
|
600
|
+
data it writes to the file in such a way that it would still accept old
|
601
|
+
log files without the given header.
|
602
|
+
|
603
|
+
\section{RPC Implementation}
|
604
|
+
|
605
|
+
\subsection{TProcessor}
|
606
|
+
|
607
|
+
The last core interface in the Thrift design is the \texttt{TProcessor},
|
608
|
+
perhaps the most simple of the constructs. The interface is as follows:
|
609
|
+
|
610
|
+
\begin{verbatim}
|
611
|
+
interface TProcessor {
|
612
|
+
bool process(TProtocol in, TProtocol out)
|
613
|
+
throws TException
|
614
|
+
}
|
615
|
+
\end{verbatim}
|
616
|
+
|
617
|
+
The key design idea here is that the complex systems we build can fundamentally
|
618
|
+
be broken down into agents or services that operate on inputs and outputs. In
|
619
|
+
most cases, there is actually just one input and output (an RPC client) that
|
620
|
+
needs handling.
|
621
|
+
|
622
|
+
\subsection{Generated Code}
|
623
|
+
|
624
|
+
When a service is defined, we generate a
|
625
|
+
\texttt{TProcessor} instance capable of handling RPC requests to that service,
|
626
|
+
using a few helpers. The fundamental structure (illustrated in pseudo-C++) is
|
627
|
+
as follows:
|
628
|
+
|
629
|
+
\begin{verbatim}
|
630
|
+
Service.thrift
|
631
|
+
=> Service.cpp
|
632
|
+
interface ServiceIf
|
633
|
+
class ServiceClient : virtual ServiceIf
|
634
|
+
TProtocol in
|
635
|
+
TProtocol out
|
636
|
+
class ServiceProcessor : TProcessor
|
637
|
+
ServiceIf handler
|
638
|
+
|
639
|
+
ServiceHandler.cpp
|
640
|
+
class ServiceHandler : virtual ServiceIf
|
641
|
+
|
642
|
+
TServer.cpp
|
643
|
+
TServer(TProcessor processor,
|
644
|
+
TServerTransport transport,
|
645
|
+
TTransportFactory tfactory,
|
646
|
+
TProtocolFactory pfactory)
|
647
|
+
serve()
|
648
|
+
\end{verbatim}
|
649
|
+
|
650
|
+
From the Thrift definition file, we generate the virtual service interface.
|
651
|
+
A client class is generated, which implements the interface and
|
652
|
+
uses two \texttt{TProtocol} instances to perform the I/O operations. The
|
653
|
+
generated processor implements the \texttt{TProcessor} interface. The generated
|
654
|
+
code has all the logic to handle RPC invocations via the \texttt{process()}
|
655
|
+
call, and takes as a parameter an instance of the service interface, as
|
656
|
+
implemented by the application developer.
|
657
|
+
|
658
|
+
The user provides an implementation of the application interface in separate,
|
659
|
+
non-generated source code.
|
660
|
+
|
661
|
+
\subsection{TServer}
|
662
|
+
|
663
|
+
Finally, the Thrift core libraries provide a \texttt{TServer} abstraction.
|
664
|
+
The \texttt{TServer} object generally works as follows.
|
665
|
+
|
666
|
+
\begin{itemize}
|
667
|
+
\item Use the \texttt{TServerTransport} to get a \texttt{TTransport}
|
668
|
+
\item Use the \texttt{TTransportFactory} to optionally convert the primitive
|
669
|
+
transport into a suitable application transport (typically the
|
670
|
+
\texttt{TBufferedTransportFactory} is used here)
|
671
|
+
\item Use the \texttt{TProtocolFactory} to create an input and output protocol
|
672
|
+
for the \texttt{TTransport}
|
673
|
+
\item Invoke the \texttt{process()} method of the \texttt{TProcessor} object
|
674
|
+
\end{itemize}
|
675
|
+
|
676
|
+
The layers are appropriately separated such that the server code needs to know
|
677
|
+
nothing about any of the transports, encodings, or applications in play. The
|
678
|
+
server encapsulates the logic around connection handling, threading, etc.
|
679
|
+
while the processor deals with RPC. The only code written by the application
|
680
|
+
developer lives in the definitional Thrift file and the interface
|
681
|
+
implementation.
|
682
|
+
|
683
|
+
Facebook has deployed multiple \texttt{TServer} implementations, including
|
684
|
+
the single-threaded \texttt{TSimpleServer}, thread-per-connection
|
685
|
+
\texttt{TThreadedServer}, and thread-pooling \texttt{TThreadPoolServer}.
|
686
|
+
|
687
|
+
The \texttt{TProcessor} interface is very general by design. There is no
|
688
|
+
requirement that a \texttt{TServer} take a generated \texttt{TProcessor}
|
689
|
+
object. Thrift allows the application developer to easily write any type of
|
690
|
+
server that operates on \texttt{TProtocol} objects (for instance, a server
|
691
|
+
could simply stream a certain type of object without any actual RPC method
|
692
|
+
invocation).
|
693
|
+
|
694
|
+
\section{Implementation Details}
|
695
|
+
\subsection{Target Languages}
|
696
|
+
Thrift currently supports five target languages: C++, Java, Python, Ruby, and
|
697
|
+
PHP. At Facebook, we have deployed servers predominantly in C++, Java, and
|
698
|
+
Python. Thrift services implemented in PHP have also been embedded into the
|
699
|
+
Apache web server, providing transparent backend access to many of our
|
700
|
+
frontend constructs using a \texttt{THttpClient} implementation of the
|
701
|
+
\texttt{TTransport} interface.
|
702
|
+
|
703
|
+
Though Thrift was explicitly designed to be much more efficient and robust
|
704
|
+
than typical web technologies, as we were designing our XML-based REST web
|
705
|
+
services API we noticed that Thrift could be easily used to define our
|
706
|
+
service interface. Though we do not currently employ SOAP envelopes (in the
|
707
|
+
authors' opinions there is already far too much repetitive enterprise Java
|
708
|
+
software to do that sort of thing), we were able to quickly extend Thrift to
|
709
|
+
generate XML Schema Definition files for our service, as well as a framework
|
710
|
+
for versioning different implementations of our web service. Though public
|
711
|
+
web services are admittedly tangential to Thrift's core use case and design,
|
712
|
+
Thrift facilitated rapid iteration and affords us the ability to quickly
|
713
|
+
migrate our entire XML-based web service onto a higher performance system
|
714
|
+
should the need arise.
|
715
|
+
|
716
|
+
\subsection{Generated Structs}
|
717
|
+
We made a conscious decision to make our generated structs as transparent as
|
718
|
+
possible. All fields are publicly accessible; there are no \texttt{set()} and
|
719
|
+
\texttt{get()} methods. Similarly, use of the \texttt{isset} object is not
|
720
|
+
enforced. We do not include any \texttt{FieldNotSetException} construct.
|
721
|
+
Developers have the option to use these fields to write more robust code, but
|
722
|
+
the system is robust to the developer ignoring the \texttt{isset} construct
|
723
|
+
entirely and will provide suitable default behavior in all cases.
|
724
|
+
|
725
|
+
This choice was motivated by the desire to ease application development. Our stated
|
726
|
+
goal is not to make developers learn a rich new library in their language of
|
727
|
+
choice, but rather to generate code that allow them to work with the constructs
|
728
|
+
that are most familiar in each language.
|
729
|
+
|
730
|
+
We also made the \texttt{read()} and \texttt{write()} methods of the generated
|
731
|
+
objects public so that the objects can be used outside of the context
|
732
|
+
of RPC clients and servers. Thrift is a useful tool simply for generating
|
733
|
+
objects that are easily serializable across programming languages.
|
734
|
+
|
735
|
+
\subsection{RPC Method Identification}
|
736
|
+
Method calls in RPC are implemented by sending the method name as a string. One
|
737
|
+
issue with this approach is that longer method names require more bandwidth.
|
738
|
+
We experimented with using fixed-size hashes to identify methods, but in the
|
739
|
+
end concluded that the savings were not worth the headaches incurred. Reliably
|
740
|
+
dealing with conflicts across versions of an interface definition file is
|
741
|
+
impossible without a meta-storage system (i.e. to generate non-conflicting
|
742
|
+
hashes for the current version of a file, we would have to know about all
|
743
|
+
conflicts that ever existed in any previous version of the file).
|
744
|
+
|
745
|
+
We wanted to avoid too many unnecessary string comparisons upon
|
746
|
+
method invocation. To deal with this, we generate maps from strings to function
|
747
|
+
pointers, so that invocation is effectively accomplished via a constant-time
|
748
|
+
hash lookup in the common case. This requires the use of a couple interesting
|
749
|
+
code constructs. Because Java does not have function pointers, process
|
750
|
+
functions are all private member classes implementing a common interface.
|
751
|
+
|
752
|
+
\begin{verbatim}
|
753
|
+
private class ping implements ProcessFunction {
|
754
|
+
public void process(int seqid,
|
755
|
+
TProtocol iprot,
|
756
|
+
TProtocol oprot)
|
757
|
+
throws TException
|
758
|
+
{ ...}
|
759
|
+
}
|
760
|
+
|
761
|
+
HashMap<String,ProcessFunction> processMap_ =
|
762
|
+
new HashMap<String,ProcessFunction>();
|
763
|
+
\end{verbatim}
|
764
|
+
|
765
|
+
In C++, we use a relatively esoteric language construct: member function
|
766
|
+
pointers.
|
767
|
+
|
768
|
+
\begin{verbatim}
|
769
|
+
std::map<std::string,
|
770
|
+
void (ExampleServiceProcessor::*)(int32_t,
|
771
|
+
facebook::thrift::protocol::TProtocol*,
|
772
|
+
facebook::thrift::protocol::TProtocol*)>
|
773
|
+
processMap_;
|
774
|
+
\end{verbatim}
|
775
|
+
|
776
|
+
Using these techniques, the cost of string processing is minimized, and we
|
777
|
+
reap the benefit of being able to easily debug corrupt or misunderstood data by
|
778
|
+
inspecting it for known string method names.
|
779
|
+
|
780
|
+
\subsection{Servers and Multithreading}
|
781
|
+
Thrift services require basic multithreading to handle simultaneous
|
782
|
+
requests from multiple clients. For the Python and Java implementations of
|
783
|
+
Thrift server logic, the standard threading libraries distributed with the
|
784
|
+
languages provide adequate support. For the C++ implementation, no standard multithread runtime
|
785
|
+
library exists. Specifically, robust, lightweight, and portable
|
786
|
+
thread manager and timer class implementations do not exist. We investigated
|
787
|
+
existing implementations, namely \texttt{boost::thread},
|
788
|
+
\texttt{boost::threadpool}, \texttt{ACE\_Thread\_Manager} and
|
789
|
+
\texttt{ACE\_Timer}.
|
790
|
+
|
791
|
+
While \texttt{boost::threads}\cite{boost.threads} provides clean,
|
792
|
+
lightweight and robust implementations of multi-thread primitives (mutexes,
|
793
|
+
conditions, threads) it does not provide a thread manager or timer
|
794
|
+
implementation.
|
795
|
+
|
796
|
+
\texttt{boost::threadpool}\cite{boost.threadpool} also looked promising but
|
797
|
+
was not far enough along for our purposes. We wanted to limit the dependency on
|
798
|
+
third-party libraries as much as possible. Because\\
|
799
|
+
\texttt{boost::threadpool} is
|
800
|
+
not a pure template library and requires runtime libraries and because it is
|
801
|
+
not yet part of the official Boost distribution we felt it was not ready for
|
802
|
+
use in Thrift. As \texttt{boost::threadpool} evolves and especially if it is
|
803
|
+
added to the Boost distribution we may reconsider our decision to not use it.
|
804
|
+
|
805
|
+
ACE has both a thread manager and timer class in addition to multi-thread
|
806
|
+
primitives. The biggest problem with ACE is that it is ACE. Unlike Boost, ACE
|
807
|
+
API quality is poor. Everything in ACE has large numbers of dependencies on
|
808
|
+
everything else in ACE - thus forcing developers to throw out standard
|
809
|
+
classes, such as STL collections, in favor of ACE's homebrewed implementations. In
|
810
|
+
addition, unlike Boost, ACE implementations demonstrate little understanding
|
811
|
+
of the power and pitfalls of C++ programming and take no advantage of modern
|
812
|
+
templating techniques to ensure compile time safety and reasonable compiler
|
813
|
+
error messages. For all these reasons, ACE was rejected. Instead, we chose
|
814
|
+
to implement our own library, described in the following sections.
|
815
|
+
|
816
|
+
\subsection{Thread Primitives}
|
817
|
+
|
818
|
+
The Thrift thread libraries are implemented in the namespace\\
|
819
|
+
\texttt{facebook::thrift::concurrency} and have three components:
|
820
|
+
\begin{itemize}
|
821
|
+
\item primitives
|
822
|
+
\item thread pool manager
|
823
|
+
\item timer manager
|
824
|
+
\end{itemize}
|
825
|
+
|
826
|
+
As mentioned above, we were hesitant to introduce any additional dependencies
|
827
|
+
on Thrift. We decided to use \texttt{boost::shared\_ptr} because it is so
|
828
|
+
useful for multithreaded application, it requires no link-time or
|
829
|
+
runtime libraries (i.e. it is a pure template library) and it is due
|
830
|
+
to become part of the C++0x standard.
|
831
|
+
|
832
|
+
We implement standard \texttt{Mutex} and \texttt{Condition} classes, and a
|
833
|
+
\texttt{Monitor} class. The latter is simply a combination of a mutex and
|
834
|
+
condition variable and is analogous to the \texttt{Monitor} implementation provided for
|
835
|
+
the Java \texttt{Object} class. This is also sometimes referred to as a barrier. We
|
836
|
+
provide a \texttt{Synchronized} guard class to allow Java-like synchronized blocks.
|
837
|
+
This is just a bit of syntactic sugar, but, like its Java counterpart, clearly
|
838
|
+
delimits critical sections of code. Unlike its Java counterpart, we still
|
839
|
+
have the ability to programmatically lock, unlock, block, and signal monitors.
|
840
|
+
|
841
|
+
\begin{verbatim}
|
842
|
+
void run() {
|
843
|
+
{Synchronized s(manager->monitor);
|
844
|
+
if (manager->state == TimerManager::STARTING) {
|
845
|
+
manager->state = TimerManager::STARTED;
|
846
|
+
manager->monitor.notifyAll();
|
847
|
+
}
|
848
|
+
}
|
849
|
+
}
|
850
|
+
\end{verbatim}
|
851
|
+
|
852
|
+
We again borrowed from Java the distinction between a thread and a runnable
|
853
|
+
class. A \texttt{Thread} is the actual schedulable object. The
|
854
|
+
\texttt{Runnable} is the logic to execute within the thread.
|
855
|
+
The \texttt{Thread} implementation deals with all the platform-specific thread
|
856
|
+
creation and destruction issues, while the \texttt{Runnable} implementation deals
|
857
|
+
with the application-specific per-thread logic. The benefit of this approach
|
858
|
+
is that developers can easily subclass the Runnable class without pulling in
|
859
|
+
platform-specific super-classes.
|
860
|
+
|
861
|
+
\subsection{Thread, Runnable, and shared\_ptr}
|
862
|
+
We use \texttt{boost::shared\_ptr} throughout the \texttt{ThreadManager} and
|
863
|
+
\texttt{TimerManager} implementations to guarantee cleanup of dead objects that can
|
864
|
+
be accessed by multiple threads. For \texttt{Thread} class implementations,
|
865
|
+
\texttt{boost::shared\_ptr} usage requires particular attention to make sure
|
866
|
+
\texttt{Thread} objects are neither leaked nor dereferenced prematurely while
|
867
|
+
creating and shutting down threads.
|
868
|
+
|
869
|
+
Thread creation requires calling into a C library. (In our case the POSIX
|
870
|
+
thread library, \texttt{libpthread}, but the same would be true for WIN32 threads).
|
871
|
+
Typically, the OS makes few, if any, guarantees about when \texttt{ThreadMain}, a C thread's entry-point function, will be called. Therefore, it is
|
872
|
+
possible that our thread create call,
|
873
|
+
\texttt{ThreadFactory::newThread()} could return to the caller
|
874
|
+
well before that time. To ensure that the returned \texttt{Thread} object is not
|
875
|
+
prematurely cleaned up if the caller gives up its reference prior to the
|
876
|
+
\texttt{ThreadMain} call, the \texttt{Thread} object makes a weak referenence to
|
877
|
+
itself in its \texttt{start} method.
|
878
|
+
|
879
|
+
With the weak reference in hand the \texttt{ThreadMain} function can attempt to get
|
880
|
+
a strong reference before entering the \texttt{Runnable::run} method of the
|
881
|
+
\texttt{Runnable} object bound to the \texttt{Thread}. If no strong references to the
|
882
|
+
thread are obtained between exiting \texttt{Thread::start} and entering \texttt{ThreadMain}, the weak reference returns \texttt{null} and the function
|
883
|
+
exits immediately.
|
884
|
+
|
885
|
+
The need for the \texttt{Thread} to make a weak reference to itself has a
|
886
|
+
significant impact on the API. Since references are managed through the
|
887
|
+
\texttt{boost::shared\_ptr} templates, the \texttt{Thread} object must have a reference
|
888
|
+
to itself wrapped by the same \texttt{boost::shared\_ptr} envelope that is returned
|
889
|
+
to the caller. This necessitated the use of the factory pattern.
|
890
|
+
\texttt{ThreadFactory} creates the raw \texttt{Thread} object and a
|
891
|
+
\texttt{boost::shared\_ptr} wrapper, and calls a private helper method of the class
|
892
|
+
implementing the \texttt{Thread} interface (in this case, \texttt{PosixThread::weakRef})
|
893
|
+
to allow it to make add weak reference to itself through the
|
894
|
+
\texttt{boost::shared\_ptr} envelope.
|
895
|
+
|
896
|
+
\texttt{Thread} and \texttt{Runnable} objects reference each other. A \texttt{Runnable}
|
897
|
+
object may need to know about the thread in which it is executing, and a Thread, obviously,
|
898
|
+
needs to know what \texttt{Runnable} object it is hosting. This interdependency is
|
899
|
+
further complicated because the lifecycle of each object is independent of the
|
900
|
+
other. An application may create a set of \texttt{Runnable} object to be reused in different threads, or it may create and forget a \texttt{Runnable} object
|
901
|
+
once a thread has been created and started for it.
|
902
|
+
|
903
|
+
The \texttt{Thread} class takes a \texttt{boost::shared\_ptr} reference to the hosted
|
904
|
+
\texttt{Runnable} object in its constructor, while the \texttt{Runnable} class has an
|
905
|
+
explicit \texttt{thread} method to allow explicit binding of the hosted thread.
|
906
|
+
\texttt{ThreadFactory::newThread} binds the objects to each other.
|
907
|
+
|
908
|
+
\subsection{ThreadManager}
|
909
|
+
|
910
|
+
\texttt{ThreadManager} creates a pool of worker threads and
|
911
|
+
allows applications to schedule tasks for execution as free worker threads
|
912
|
+
become available. The \texttt{ThreadManager} does not implement dynamic
|
913
|
+
thread pool resizing, but provides primitives so that applications can add
|
914
|
+
and remove threads based on load. This approach was chosen because
|
915
|
+
implementing load metrics and thread pool size is very application
|
916
|
+
specific. For example some applications may want to adjust pool size based
|
917
|
+
on running-average of work arrival rates that are measured via polled
|
918
|
+
samples. Others may simply wish to react immediately to work-queue
|
919
|
+
depth high and low water marks. Rather than trying to create a complex
|
920
|
+
API abstract enough to capture these different approaches, we
|
921
|
+
simply leave it up to the particular application and provide the
|
922
|
+
primitives to enact the desired policy and sample current status.
|
923
|
+
|
924
|
+
\subsection{TimerManager}
|
925
|
+
|
926
|
+
\texttt{TimerManager} allows applications to schedule
|
927
|
+
\texttt{Runnable} objects for execution at some point in the future. Its specific task
|
928
|
+
is to allows applications to sample \texttt{ThreadManager} load at regular
|
929
|
+
intervals and make changes to the thread pool size based on application policy.
|
930
|
+
Of course, it can be used to generate any number of timer or alarm events.
|
931
|
+
|
932
|
+
The default implementation of \texttt{TimerManager} uses a single thread to
|
933
|
+
execute expired \texttt{Runnable} objects. Thus, if a timer operation needs to
|
934
|
+
do a large amount of work and especially if it needs to do blocking I/O,
|
935
|
+
that should be done in a separate thread.
|
936
|
+
|
937
|
+
\subsection{Nonblocking Operation}
|
938
|
+
Though the Thrift transport interfaces map more directly to a blocking I/O
|
939
|
+
model, we have implemented a high performance \texttt{TNonBlockingServer}
|
940
|
+
in C++ based on \texttt{libevent} and the \texttt{TFramedTransport}. We
|
941
|
+
implemented this by moving all I/O into one tight event loop using a
|
942
|
+
state machine. Essentially, the event loop reads framed requests into
|
943
|
+
\texttt{TMemoryBuffer} objects. Once entire requests are ready, they are
|
944
|
+
dispatched to the \texttt{TProcessor} object which can read directly from
|
945
|
+
the data in memory.
|
946
|
+
|
947
|
+
\subsection{Compiler}
|
948
|
+
The Thrift compiler is implemented in C++ using standard \texttt{lex}/\texttt{yacc}
|
949
|
+
lexing and parsing. Though it could have been implemented with fewer
|
950
|
+
lines of code in another language (i.e. Python Lex-Yacc (PLY) or \texttt{ocamlyacc}), using C++
|
951
|
+
forces explicit definition of the language constructs. Strongly typing the
|
952
|
+
parse tree elements (debatably) makes the code more approachable for new
|
953
|
+
developers.
|
954
|
+
|
955
|
+
Code generation is done using two passes. The first pass looks only for
|
956
|
+
include files and type definitions. Type definitions are not checked during
|
957
|
+
this phase, since they may depend upon include files. All included files
|
958
|
+
are sequentially scanned in a first pass. Once the include tree has been
|
959
|
+
resolved, a second pass over all files is taken that inserts type definitions
|
960
|
+
into the parse tree and raises an error on any undefined types. The program is
|
961
|
+
then generated against the parse tree.
|
962
|
+
|
963
|
+
Due to inherent complexities and potential for circular dependencies,
|
964
|
+
we explicitly disallow forward declaration. Two Thrift structs cannot
|
965
|
+
each contain an instance of the other. (Since we do not allow \texttt{null}
|
966
|
+
struct instances in the generated C++ code, this would actually be impossible.)
|
967
|
+
|
968
|
+
\subsection{TFileTransport}
|
969
|
+
The \texttt{TFileTransport} logs Thrift requests/structs by
|
970
|
+
framing incoming data with its length and writing it out to disk.
|
971
|
+
Using a framed on-disk format allows for better error checking and
|
972
|
+
helps with the processing of a finite number of discrete events. The\\
|
973
|
+
\texttt{TFileWriterTransport} uses a system of swapping in-memory buffers
|
974
|
+
to ensure good performance while logging large amounts of data.
|
975
|
+
A Thrift log file is split up into chunks of a specified size; logged messages
|
976
|
+
are not allowed to cross chunk boundaries. A message that would cross a chunk
|
977
|
+
boundary will cause padding to be added until the end of the chunk and the
|
978
|
+
first byte of the message are aligned to the beginning of the next chunk.
|
979
|
+
Partitioning the file into chunks makes it possible to read and interpret data
|
980
|
+
from a particular point in the file.
|
981
|
+
|
982
|
+
\section{Facebook Thrift Services}
|
983
|
+
Thrift has been employed in a large number of applications at Facebook, including
|
984
|
+
search, logging, mobile, ads and the developer platform. Two specific usages are discussed below.
|
985
|
+
|
986
|
+
\subsection{Search}
|
987
|
+
Thrift is used as the underlying protocol and transport layer for the Facebook Search service.
|
988
|
+
The multi-language code generation is well suited for search because it allows for application
|
989
|
+
development in an efficient server side language (C++) and allows the Facebook PHP-based web application
|
990
|
+
to make calls to the search service using Thrift PHP libraries. There is also a large
|
991
|
+
variety of search stats, deployment and testing functionality that is built on top
|
992
|
+
of generated Python code. Additionally, the Thrift log file format is
|
993
|
+
used as a redo log for providing real-time search index updates. Thrift has allowed the
|
994
|
+
search team to leverage each language for its strengths and to develop code at a rapid pace.
|
995
|
+
|
996
|
+
\subsection{Logging}
|
997
|
+
The Thrift \texttt{TFileTransport} functionality is used for structured logging. Each
|
998
|
+
service function definition along with its parameters can be considered to be
|
999
|
+
a structured log entry identified by the function name. This log can then be used for
|
1000
|
+
a variety of purposes, including inline and offline processing, stats aggregation and as a redo log.
|
1001
|
+
|
1002
|
+
\section{Conclusions}
|
1003
|
+
Thrift has enabled Facebook to build scalable backend
|
1004
|
+
services efficiently by enabling engineers to divide and conquer. Application
|
1005
|
+
developers can focus on application code without worrying about the
|
1006
|
+
sockets layer. We avoid duplicated work by writing buffering and I/O logic
|
1007
|
+
in one place, rather than interspersing it in each application.
|
1008
|
+
|
1009
|
+
Thrift has been employed in a wide variety of applications at Facebook,
|
1010
|
+
including search, logging, mobile, ads, and the developer platform. We have
|
1011
|
+
found that the marginal performance cost incurred by an extra layer of
|
1012
|
+
software abstraction is far eclipsed by the gains in developer efficiency and
|
1013
|
+
systems reliability.
|
1014
|
+
|
1015
|
+
\appendix
|
1016
|
+
|
1017
|
+
\section{Similar Systems}
|
1018
|
+
The following are software systems similar to Thrift. Each is (very!) briefly
|
1019
|
+
described:
|
1020
|
+
|
1021
|
+
\begin{itemize}
|
1022
|
+
\item \textit{SOAP.} XML-based. Designed for web services via HTTP, excessive
|
1023
|
+
XML parsing overhead.
|
1024
|
+
\item \textit{CORBA.} Relatively comprehensive, debatably overdesigned and
|
1025
|
+
heavyweight. Comparably cumbersome software installation.
|
1026
|
+
\item \textit{COM.} Embraced mainly in Windows client softare. Not an entirely
|
1027
|
+
open solution.
|
1028
|
+
\item \textit{Pillar.} Lightweight and high-performance, but missing versioning
|
1029
|
+
and abstraction.
|
1030
|
+
\item \textit{Protocol Buffers.} Closed-source, owned by Google. Described in
|
1031
|
+
Sawzall paper.
|
1032
|
+
\end{itemize}
|
1033
|
+
|
1034
|
+
\acks
|
1035
|
+
|
1036
|
+
Many thanks for feedback on Thrift (and extreme trial by fire) are due to
|
1037
|
+
Martin Smith, Karl Voskuil and Yishan Wong.
|
1038
|
+
|
1039
|
+
Thrift is a successor to Pillar, a similar system developed
|
1040
|
+
by Adam D'Angelo, first while at Caltech and continued later at Facebook.
|
1041
|
+
Thrift simply would not have happened without Adam's insights.
|
1042
|
+
|
1043
|
+
\begin{thebibliography}{}
|
1044
|
+
|
1045
|
+
\bibitem{boost.threads}
|
1046
|
+
Kempf, William,
|
1047
|
+
``Boost.Threads'',
|
1048
|
+
\url{http://www.boost.org/doc/html/threads.html}
|
1049
|
+
|
1050
|
+
\bibitem{boost.threadpool}
|
1051
|
+
Henkel, Philipp,
|
1052
|
+
``threadpool'',
|
1053
|
+
\url{http://threadpool.sourceforge.net}
|
1054
|
+
|
1055
|
+
\end{thebibliography}
|
1056
|
+
|
1057
|
+
\end{document}
|