portable_dispatch.hpp

Go to the documentation of this file.
00001 /*
00002 This file is part of GraphLab.
00003 
00004 GraphLab is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as 
00006 published by the Free Software Foundation, either version 3 of 
00007 the License, or (at your option) any later version.
00008 
00009 GraphLab is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public 
00015 License along with GraphLab.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #ifndef PORTABLE_DISPATCH_HPP
00019 #define PORTABLE_DISPATCH_HPP
00020 #include <string>
00021 #include <boost/unordered_map.hpp>
00022 #include <boost/preprocessor.hpp>
00023 #include <graphlab/rpc/dc_internal_types.hpp>
00024 #include <graphlab/rpc/function_call_dispatch.hpp>
00025 #include <graphlab/rpc/request_dispatch.hpp>
00026 #include <graphlab/util/generics/any.hpp>
00027 #include <graphlab/rpc/portable.hpp>
00028 #include <graphlab/rpc/function_ret_type.hpp>
00029 #include <graphlab/rpc/function_arg_types_def.hpp>
00030 
00031 /**
00032 \ingroup rpc_internal
00033 \file
00034 This is an internal function and should not be used directly.
00035 
00036 The portable calls work in a slightly different way as the regular RPC system.
00037 The receiving function of any portable call must be registered through the REGISTER_RPC
00038 macro. 
00039 
00040 This macro does a few things. Firstly, it instantiates a find_dispatcher
00041 class. The job of the find_dispatcher class is to expand the number of
00042 arguments and the return type and figure out what is the right dispatch function 
00043 type to use.
00044 
00045 If the return type is void, the find_dispatcher is partially specialized,
00046 and will instantiate a PORTABLE_DISPATCH function, which will be returned in the operator()
00047 of the find_dispatch class.
00048 
00049 Otherwise, it instantiates a PORTABLE_REQUESTDISPATCH function which sends back the 
00050 return value of the function.
00051 
00052 Finally, the macro inserts the pointer to the dispatch function into a hashmap in the 
00053 distributed_control class.
00054 */
00055 namespace graphlab {
00056 
00057 
00058 namespace dc_impl {
00059 
00060 namespace portable_detail {
00061 /**
00062 Returns the dispatch function for a variety of functions
00063 template arguments are
00064 \tparam F the function type
00065 \tparam Fret the function return type
00066 \tparam Nargs the number of arguments of F
00067 \tparam f the function itself
00068 \tparam IsRPCCall whether it is an rpccall
00069 */
00070 template<typename F, typename Fret, size_t Nargs, F f, typename IsRPCCall>
00071 struct find_dispatcher{
00072   static void* dispatch_call_fn() { return NULL; }
00073   static void* dispatch_request_fn() { return NULL; }
00074 };
00075 };
00076 
00077 #define GENFN(N) BOOST_PP_CAT(__GLRPC_F, N)
00078 #define GENFN2(N) BOOST_PP_CAT(f, N)
00079 #define GENARGS(Z,N,_)  BOOST_PP_CAT(__GLRPC_F, N)(BOOST_PP_CAT(f, N))
00080 #define GENPARAMS(Z,N,_)  BOOST_PP_CAT(T, N) (BOOST_PP_CAT(f, N)) ; iarc >> (BOOST_PP_CAT(f, N)) ;
00081 #define CHARSTRINGFREE(Z,N,_)  charstring_free(BOOST_PP_CAT(f, N));
00082 
00083 // for the non-intrusive variety
00084 #define GENNIARGS(Z,N,_)  BOOST_PP_CAT(__GLRPC_NIF, N)(BOOST_PP_CAT(f, N))
00085 
00086 
00087 #define PORTABLE_DISPATCH_GENERATOR(Z,N,_) \
00088 template<typename DcType, typename F, F f  BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
00089 void BOOST_PP_CAT(PORTABLEDISPATCH,N) (DcType& dc, procid_t source, unsigned char packet_type_mask, \
00090                std::istream &strm) { \
00091   iarchive iarc(strm); \
00092   BOOST_PP_REPEAT(N, GENPARAMS, _)                \
00093   f(dc, source BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_)  ); \
00094   BOOST_PP_REPEAT(N, CHARSTRINGFREE, _)                \
00095 } \
00096 \
00097 template<typename DcType, typename F, F f  BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
00098 void BOOST_PP_CAT(PORTABLE_REQUESTDISPATCH,N) (DcType& dc, procid_t source, unsigned char packet_type_mask, \
00099                std::istream &strm) { \
00100   iarchive iarc(strm); \
00101   size_t id; iarc >> id;                        \
00102   BOOST_PP_REPEAT(N, GENPARAMS, _)                \
00103   typename function_ret_type<__GLRPC_FRESULT>::type ret = function_ret_type<__GLRPC_FRESULT>::BOOST_PP_CAT(fcall, BOOST_PP_ADD(N, 2))   \
00104                                                   (f, dc, source BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENARGS ,_)); \
00105   BOOST_PP_REPEAT(N, CHARSTRINGFREE, _)                \
00106   boost::iostreams::stream<resizing_array_sink> retstrm(128);    \
00107   oarchive oarc(retstrm); \
00108   oarc << ret; \
00109   retstrm.flush(); \
00110   if (packet_type_mask & CONTROL_PACKET) { \
00111     dc.control_call(source, PORTABLE(reply_increment_counter), id, blob(retstrm->str, retstrm->len));\
00112   } \
00113   else {  \
00114     dc.fast_remote_call(source, PORTABLE(reply_increment_counter), id, blob(retstrm->str, retstrm->len));\
00115   } \
00116 } \
00117 \
00118 template<typename DcType, typename F, F f  BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
00119 void BOOST_PP_CAT(PORTABLE_NONINTRUSIVE_DISPATCH,N) (DcType& dc, procid_t source, unsigned char packet_type_mask, \
00120                std::istream &strm) { \
00121   iarchive iarc(strm); \
00122   BOOST_PP_REPEAT(N, GENPARAMS, _)                \
00123   f(BOOST_PP_ENUM(N,GENNIARGS ,_)  ); \
00124   BOOST_PP_REPEAT(N, CHARSTRINGFREE, _)                \
00125 } \
00126 \
00127 template<typename DcType, typename F, F f  BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, typename T)> \
00128 void BOOST_PP_CAT(PORTABLE_NONINTRUSIVE_REQUESTDISPATCH,N) (DcType& dc, procid_t source, unsigned char packet_type_mask,  \
00129                std::istream &strm) { \
00130   iarchive iarc(strm); \
00131   size_t id; iarc >> id;                        \
00132   BOOST_PP_REPEAT(N, GENPARAMS, _)                \
00133   typename function_ret_type<__GLRPC_FRESULT>::type ret = function_ret_type<__GLRPC_FRESULT>::BOOST_PP_CAT(fcall, N) \
00134                                           (f BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N,GENNIARGS ,_)); \
00135   BOOST_PP_REPEAT(N, CHARSTRINGFREE, _)                \
00136   boost::iostreams::stream<resizing_array_sink> retstrm(128);    \
00137   oarchive oarc(retstrm); \
00138   oarc << ret; \
00139   retstrm.flush(); \
00140   if (packet_type_mask & CONTROL_PACKET) { \
00141     dc.control_call(source, PORTABLE(reply_increment_counter), id, blob(retstrm->str, retstrm->len));\
00142   } \
00143   else {  \
00144     dc.fast_remote_call(source, PORTABLE(reply_increment_counter), id, blob(retstrm->str, retstrm->len));\
00145   } \
00146   free(retstrm->str);                                                 \
00147 } 
00148 
00149 
00150 
00151 
00152 BOOST_PP_REPEAT(BOOST_PP_INC(6), PORTABLE_DISPATCH_GENERATOR, _)
00153 
00154 #undef GENFN
00155 #undef GENFN2
00156 #undef GENARGS
00157 #undef GENPARAMS
00158 #undef GENNIARGS
00159 #undef DISPATCH_GENERATOR
00160 /*
00161 template<typename CommType, typename F> 
00162 struct find_dispatcher<CommType, F, 0>{
00163   static void* dispatchfn() {
00164     return DISPATCH0<CommType, F>;
00165   }
00166 };
00167 
00168 
00169 template<typename CommType, typename F> 
00170 struct find_dispatcher<CommType, F, 1>{
00171   static typename distributed_control<CommType>::dispatch_type dispatchfn() {
00172     return (DISPATCH1<CommType, F, F0>);
00173   }
00174 };*/
00175 
00176 // c++ will select the most specific template first
00177 #define GENFN(Z,N,_) BOOST_PP_EXPAND(BOOST_PP_CAT(__GLRPC_F, N))
00178 #define GENNIFN(Z,N,_) BOOST_PP_EXPAND(BOOST_PP_CAT(__GLRPC_NIF, N))
00179 
00180 namespace portable_detail {
00181 
00182 #define PORTABLE_FIND_DISPATCH_GENERATOR(Z, N, _) \
00183 template<typename F, typename Fret, F f, typename IsRPCCall> \
00184 struct find_dispatcher<F, Fret, N, f, IsRPCCall>{  \
00185   static dispatch_type dispatch_call_fn() { \
00186     return BOOST_PP_CAT(PORTABLE_NONINTRUSIVE_DISPATCH, N)<distributed_control, F, f BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, GENNIFN, _)>; \
00187   } \
00188  static dispatch_type dispatch_request_fn() { \
00189     return BOOST_PP_CAT(PORTABLE_NONINTRUSIVE_REQUESTDISPATCH, N)<distributed_control, F, f BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, GENNIFN, _)>; \
00190   } \
00191 };  \
00192 \
00193 template<typename F, typename Fret, F f> \
00194 struct find_dispatcher<F, Fret, BOOST_PP_ADD(N, 2), f, boost::mpl::bool_<true> >{  \
00195   static dispatch_type dispatch_call_fn() { \
00196     return BOOST_PP_CAT(PORTABLEDISPATCH, N)<distributed_control, F, f BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, GENFN, _)>; \
00197   }  \
00198   static dispatch_type dispatch_request_fn() { \
00199     return BOOST_PP_CAT(PORTABLE_REQUESTDISPATCH, N)<distributed_control, F, f BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM(N, GENFN, _)>; \
00200   } \
00201 }; 
00202 BOOST_PP_REPEAT(6, PORTABLE_FIND_DISPATCH_GENERATOR, _)
00203 #undef PORTABLE_FIND_DISPATCH_GENERATOR
00204 #undef GENFN
00205 
00206 }
00207 
00208 } // namespace dc_impl
00209 } // namespace graphlab
00210 
00211 #include <graphlab/rpc/function_arg_types_undef.hpp>
00212 #endif
00213