Derecho  0.9
Distributed systems toolkit for RDMA
remote_invocable.hpp
Go to the documentation of this file.
1 
7 #pragma once
8 
9 #include <functional>
10 #include <numeric>
11 #include <type_traits>
12 
13 #include "rpc_utils.hpp"
15 #include <derecho/utils/logger.hpp>
16 #include <mutils/FunctionalMap.hpp>
17 #include <mutils/tuple_extras.hpp>
18 #include <spdlog/spdlog.h>
19 
20 namespace derecho {
21 
22 namespace rpc {
23 
25 bool in_rpc_handler();
26 
27 //Technically, RemoteInvocable "specializes" this template for the case where
28 //the second parameter is a std::function<Ret(Args...)>. However, there is no
29 //implementation for any other specialization, so this template is meaningless.
30 template <FunctionTag, typename>
32 
33 template <FunctionTag, typename>
35 
46 template <FunctionTag Tag, typename Ret, typename... Args>
47 struct RemoteInvoker<Tag, std::function<Ret(Args...)>> {
48  using remote_function_type = std::function<Ret(Args...)>;
51 
52  Ret* returnRet() {
53  return nullptr;
54  }
55 
56  /* Maps invocation-instance IDs to results sets
57  Weijia: Although the maximum pending RPC is controlled by the window
58  size option in the configuration, the user application may not retrieve
59  the results on time. Therefore, the results may piled up and we need more
60  slots for the results than window size. We hardwired this to 4K here.
61  TODO: Obviously, this is not space efficient. Let's find a better RPC
62  return value mechanism.
63  */
64 
65  #define MAX_CONCURRENT_RPCS_PER_INVOKER (4096)
67  std::atomic<unsigned short> invocation_id_sequencer;
68  // std::mutex map_lock; - we don't need a lock on the result map anymore.
69  using lock_t = std::unique_lock<std::mutex>;
70 
71  /* use this from within a derived class to retrieve precisely this RemoteInvoker
72  * (this way, all the inherited RemoteInvoker methods in the subclass do not need
73  * to worry about type collisions)*/
75  std::integral_constant<FunctionTag, Tag> const* const,
76  const Args&...) {
77  return *this;
78  }
79 
80  using barray = char*;
81  using cbarray = const char*;
82 
83  inline auto serialize_one(barray) { return 0; }
84 
85  template <typename A, typename... Rest>
86  inline auto serialize_one(barray v, const A& a, const Rest&... rest) {
87  auto size = mutils::to_bytes(a, v);
88  return size + serialize_one(v + size, rest...);
89  }
90 
91  inline auto serialize_all(barray v, const Args&... args) {
92  return serialize_one(v, args...);
93  }
94 
100  struct send_return {
101  std::size_t size;
102  char* buf;
105  };
106 
114  send_return send(const std::function<char*(int)>& out_alloc,
115  const std::decay_t<Args>&... remote_args) {
116  // auto invocation_id = mutils::long_rand();
117  std::size_t invocation_id = invocation_id_sequencer++;
118  invocation_id %= MAX_CONCURRENT_RPCS_PER_INVOKER;
119  std::size_t size = mutils::bytes_size(invocation_id);
120  {
121  auto t = {std::size_t{0}, std::size_t{0}, mutils::bytes_size(remote_args)...};
122  size += std::accumulate(t.begin(), t.end(), 0);
123  }
124  char* serialized_args = out_alloc(size);
125  {
126  auto v = serialized_args + mutils::to_bytes(invocation_id, serialized_args);
127  auto check_size = mutils::bytes_size(invocation_id) + serialize_all(v, remote_args...);
128  assert_always(check_size == size);
129  }
130 
131  // lock_t l{map_lock};
132  results_vector[invocation_id].reset();
133  PendingResults<Ret>& pending_results = results_vector[invocation_id];
134 
135  dbg_default_trace("Ready to send an RPC call message with invocation ID {}", invocation_id);
136  return send_return{size, serialized_args, pending_results.get_future(),
137  pending_results};
138  }
139 
146  template <typename definitely_char>
148  std::false_type*,
150  const node_id_t& nid, const char* response,
151  const std::function<definitely_char*(int)>&) {
152  //note: find where this exception is set on the sending side!
153  bool is_exception = response[0];
154  long int invocation_id = ((long int*)(response + 1))[0];
155  // lock_t l{map_lock};
156  // we unlock the map here to avoid the deadlock:
157  // The p2p handler thread, on receiving an RPC REPLY may get this lock
158  // before sst_detect thread finish handling the corresponding ordered
159  // send locally. However, sst_detect thread may be so slow that it
160  // hasn't finish deliverying of a previous ordered send, therefore waits
161  // for the map_lock in the following call stack:
162  // - RPCManager::rpc_message_handler() ->
163  // - RPCManager::parse_and_receive() ->
164  // - RPCManager::receive_message()->
165  // - receivers->at(indx)->
166  // - RemoteInvoker::receive_response().
167  // therefore, the promise for the next ordered_send, on which the
168  // p2p handler thread is waiting for, cannot be fulfilled.
169  // dead lock!!!
170  // We use this workaround by just release the results_map lock as early
171  // because we have 64K slots and we assume after 64K messages, this
172  // corresponding ordered_send has been finished already.
173  // TODO: make a better plan along with garbage collection.
174  // l.unlock();
175  // TODO: garbage collection for the responses.
176  // More on May-7th (Weijia):
177  // We don't need to lock the results container (now results_vector)
178  // anymore. The vector is initialized at the beginning. The p2p rpc
179  // reuse the slot by reseting it. No deleting, insertion, or
180  // replacement operations at all. But we still need a better garbage
181  // collection mechanism.
182  if(is_exception) {
183  results_vector[invocation_id].set_exception(nid, std::make_exception_ptr(remote_exception_occurred{nid}));
184  } else {
185  dbg_default_trace("Received an RPC response for invocation ID {} from node {}", invocation_id, nid);
186  results_vector[invocation_id].set_value(nid, *mutils::from_bytes<Ret>(dsm, response + 1 + sizeof(invocation_id)));
187  }
188  return recv_ret{Opcode(), 0, nullptr, nullptr};
189  }
190 
195  inline recv_ret receive_response(std::true_type*,
197  const node_id_t& nid, const char* response,
198  const std::function<char*(int)>&) {
199  if(response[0]) throw remote_exception_occurred{nid};
200  assert_always(false && "was not expecting a response!");
201  }
202 
212  inline recv_ret receive_response( //mutils::DeserializationManager* dsm,
214  const node_id_t& nid, const char* response,
215  const std::function<char*(int)>& f) {
216  constexpr std::is_same<void, Ret>* choice{nullptr};
217  // return receive_response(choice, dsm, nid, response, f);
219  return receive_response(choice, &dsm, nid, response, f);
220  }
221 
228  inline void fulfill_pending_results_vector(long int invocation_id, const node_list_t& who) {
229  // I think this function is never called
230  assert_always(false);
231  results_vector[invocation_id].fulfill_map(who);
232  }
233 
245  RemoteInvoker(uint32_t class_id, uint32_t instance_id,
246  std::map<Opcode, receive_fun_t>& receivers)
247  : invoke_opcode{class_id, instance_id, Tag, false},
248  reply_opcode{class_id, instance_id, Tag, true},
249  invocation_id_sequencer(0) {
250  receivers.emplace(reply_opcode, [this](auto... a) {
251  return this->receive_response(a...);
252  });
253  }
254 };
255 
266 template <FunctionTag Tag, typename Ret, typename... Args>
267 struct RemoteInvocable<Tag, std::function<Ret(Args...)>> {
268  using remote_function_type = std::function<Ret(Args...)>;
272 
273  /* use this from within a derived class to retrieve precisely this RemoteInvocable
274  * (this way, all the inherited RemoteInvocable methods in the subclass do not need
275  * to worry about type collisions)*/
277  std::integral_constant<FunctionTag, Tag> const* const,
278  const Args&...) {
279  return *this;
280  }
281 
289  inline recv_ret receive_call(std::false_type const* const,
291  const node_id_t& caller, const char* _recv_buf,
292  const std::function<char*(int)>& out_alloc) {
293  long int invocation_id = ((long int*)_recv_buf)[0];
294  auto recv_buf = _recv_buf + sizeof(long int);
295  try {
296  const auto result = mutils::deserialize_and_run(dsm, recv_buf, remote_invocable_function);
297  const auto result_size = mutils::bytes_size(result) + sizeof(long int) + 1;
298  auto out = out_alloc(result_size);
299  out[0] = false;
300  ((long int*)(out + 1))[0] = invocation_id;
301  mutils::to_bytes(result, out + sizeof(invocation_id) + 1);
302  dbg_default_trace("Ready to send an RPC reply for invocation ID {} to node {}", invocation_id, caller);
303  return recv_ret{reply_opcode, result_size, out, nullptr};
304  } catch(...) {
305  char* out = out_alloc(sizeof(long int) + 1);
306  out[0] = true;
307  ((long int*)(out + 1))[0] = invocation_id;
308  return recv_ret{reply_opcode, sizeof(long int) + 1, out,
309  std::current_exception()};
310  }
311  }
312 
317  inline recv_ret receive_call(std::true_type const* const,
319  const node_id_t&, const char* _recv_buf,
320  const std::function<char*(int)>&) {
321  //TODO: Need to catch exceptions here, and possibly send them back, since void functions can still throw exceptions!
322  auto recv_buf = _recv_buf + sizeof(long int);
323  mutils::deserialize_and_run(dsm, recv_buf, remote_invocable_function);
324  return recv_ret{reply_opcode, 0, nullptr};
325  }
326 
337  inline recv_ret receive_call( //mutils::DeserializationManager* dsm,
339  const node_id_t& who, const char* recv_buf,
340  const std::function<char*(int)>& out_alloc) {
341  constexpr std::is_same<Ret, void>* choice{nullptr};
342  // return this->receive_call(choice, dsm, who, recv_buf, out_alloc);
344  return this->receive_call(choice, &dsm, who, recv_buf, out_alloc);
345  }
346 
356  RemoteInvocable(uint32_t class_id, uint32_t instance_id,
357  std::map<Opcode, receive_fun_t>& receivers,
358  std::function<Ret(Args...)> f)
359  : remote_invocable_function(f),
360  invoke_opcode{class_id, instance_id, Tag, false},
361  reply_opcode{class_id, instance_id, Tag, true} {
362  receivers.emplace(invoke_opcode, [this](auto... a) {
363  return this->receive_call(a...);
364  });
365  }
366 };
367 
370 template <FunctionTag Tag, typename NotAFunction>
371 struct wrapped;
372 
380 template <FunctionTag Tag, typename Ret, typename... Arguments>
381 struct wrapped<Tag, std::function<Ret(Arguments...)>> {
382  using fun_t = std::function<Ret(Arguments...)>;
384 };
385 
392 template <FunctionTag Tag, typename Ret, typename Class, typename... Arguments>
394  using fun_t = Ret (Class::*)(Arguments...);
396 };
397 
402 template <FunctionTag Tag, typename Ret, typename Class, typename... Arguments>
404  using fun_t = Ret (Class::*)(Arguments...) const;
406 };
407 
419 template <typename NewClass, FunctionTag Tag, typename Ret, typename... Args>
420 wrapped<Tag, std::function<Ret(Args...)>> bind_to_instance(std::unique_ptr<NewClass>* _this,
422  assert(_this);
423  return wrapped<Tag, std::function<Ret(Args...)>>{
424  [_this, fun = partial.fun](Args... arguments) {
425  assert(_this);
426  assert(_this->get());
427  return (_this->get()->*fun)(arguments...);
428  }};
429 }
430 
435 template <typename NewClass, FunctionTag Tag, typename Ret, typename... Args>
436 wrapped<Tag, std::function<Ret(Args...)>> bind_to_instance(std::unique_ptr<NewClass>* _this,
438  assert(_this);
439  return wrapped<Tag, std::function<Ret(Args...)>>{
440  [_this, fun = partial.fun](Args... arguments) {
441  return (_this->get()->*fun)(arguments...);
442  }};
443 }
444 
459 template <FunctionTag Tag, typename NewClass, typename Ret, typename... Args>
460 partial_wrapped<Tag, Ret, NewClass, Args...> tag(Ret (NewClass::*fun)(Args...)) {
461  static_assert(!std::is_reference<Ret>::value && !std::is_pointer<Ret>::value, "RPC-registered functions cannot return references or pointers!");
462  //Fold-expression asserts the boolean expression for all Args in the parameter pack
463  static_assert(((std::is_reference<Args>::value || sizeof(Args) < 2 * sizeof(void*)) && ...), "RPC-registered functions must take non-pointer-size arguments by reference to avoid extra copying.");
464  return partial_wrapped<Tag, Ret, NewClass, Args...>{fun};
465 }
466 
468 template <FunctionTag Tag, typename NewClass, typename Ret, typename... Args>
469 const_partial_wrapped<Tag, Ret, NewClass, Args...> tag(Ret (NewClass::*fun)(Args...) const) {
470  static_assert(!std::is_reference<Ret>::value && !std::is_pointer<Ret>::value, "RPC-registered functions cannot return references or pointers!");
471  static_assert(((std::is_reference<Args>::value || sizeof(Args) < 2 * sizeof(void*)) && ...), "RPC-registered functions must take non-pointer-size arguments by reference to avoid extra copying.");
472  return const_partial_wrapped<Tag, Ret, NewClass, Args...>{fun};
473 }
474 
475 /* Technically, RemoteInvocablePairs specializes this template for the cases
476  * where the parameter pack is a list of types of the form wrapped<id, FunType>
477  * However, there is only one specialization, so using RemoteInvocablePairs for
478  * anything other than wrapped<id, FunType> is meaningless.
479  */
480 template <typename...>
482 
487 template <FunctionTag id, typename FunType>
490  RemoteInvocablePairs(uint32_t class_id,
491  uint32_t instance_id,
492  std::map<Opcode, receive_fun_t>& receivers, FunType function_ptr)
493  : RemoteInvoker<id, FunType>(class_id, instance_id, receivers),
494  RemoteInvocable<id, FunType>(class_id, instance_id, receivers, function_ptr) {}
495 
498 };
499 
512 template <FunctionTag id, typename FunType, typename... rest>
513 struct RemoteInvocablePairs<wrapped<id, FunType>, rest...>
514  : public RemoteInvoker<id, FunType>, public RemoteInvocable<id, FunType>, public RemoteInvocablePairs<rest...> {
515  template <typename... RestFunTypes>
516  RemoteInvocablePairs(uint32_t class_id,
517  uint32_t instance_id,
518  std::map<Opcode, receive_fun_t>& receivers,
519  FunType function_ptr,
520  RestFunTypes&&... function_ptrs)
521  : RemoteInvoker<id, FunType>(class_id, instance_id, receivers),
522  RemoteInvocable<id, FunType>(class_id, instance_id, receivers, function_ptr),
523  RemoteInvocablePairs<rest...>(class_id, instance_id, receivers, std::forward<RestFunTypes>(function_ptrs)...) {}
524 
525  //Ensure the inherited functions from RemoteInvoker and RemoteInvokable are visible
528  using RemoteInvocablePairs<rest...>::get_invoker;
529  using RemoteInvocablePairs<rest...>::get_handler;
530 };
531 
536 template <typename...>
538 
543 template <FunctionTag Tag, typename FunType>
545  RemoteInvokers(uint32_t class_id,
546  uint32_t instance_id,
547  std::map<Opcode, receive_fun_t>& receivers)
548  : RemoteInvoker<Tag, FunType>(class_id, instance_id, receivers) {}
549 
551 };
552 
563 template <FunctionTag Tag, typename FunType, typename... RestWrapped>
564 struct RemoteInvokers<wrapped<Tag, FunType>, RestWrapped...>
565  : public RemoteInvoker<Tag, FunType>, public RemoteInvokers<RestWrapped...> {
566  RemoteInvokers(uint32_t class_id,
567  uint32_t instance_id,
568  std::map<Opcode, receive_fun_t>& receivers)
569  : RemoteInvoker<Tag, FunType>(class_id, instance_id, receivers),
570  RemoteInvokers<RestWrapped...>(class_id, instance_id, receivers) {}
571 
573  using RemoteInvokers<RestWrapped...>::get_invoker;
574 };
575 
586 template <class IdentifyingClass, typename... WrappedFuns>
587 class RemoteInvocableClass : private RemoteInvocablePairs<WrappedFuns...> {
588 public:
589  const node_id_t nid;
590 
591  RemoteInvocableClass(node_id_t nid, uint32_t type_id, uint32_t instance_id,
592  std::map<Opcode, receive_fun_t>& rvrs, const WrappedFuns&... fs)
593  : RemoteInvocablePairs<WrappedFuns...>(type_id, instance_id, rvrs, fs.fun...),
594  nid(nid) {}
595 
596  template <FunctionTag Tag, typename... Args>
597  std::size_t get_size_for_ordered_send(Args&&... a) {
598  //only used for size calculation
599  long int invocation_id = 0;
600  std::size_t function_call_size = mutils::bytes_size(invocation_id);
601  {
602  function_call_size += (0 + ... + mutils::bytes_size(a));
603  }
604  //Add the header_size that send() adds to the invoker's out_alloc
605  return function_call_size + remote_invocation_utilities::header_space();
606  }
607 
608  template <FunctionTag Tag, typename... Args>
609  auto* getReturnType(Args&&... args) {
610  constexpr std::integral_constant<FunctionTag, Tag>* choice{nullptr};
611  return this->get_invoker(choice, args...).returnRet();
612  }
613 
624  template <FunctionTag Tag, typename... Args>
625  auto send(const std::function<char*(int)>& out_alloc, Args&&... args) {
626  using namespace remote_invocation_utilities;
627 
628  constexpr std::integral_constant<FunctionTag, Tag>* choice{nullptr};
629  auto& invoker = this->get_invoker(choice, args...);
630  const auto header_size = header_space();
631  auto sent_return = invoker.send(
632  [&out_alloc, &header_size](std::size_t size) {
633  return out_alloc(size + header_size) + header_size;
634  },
635  std::forward<Args>(args)...);
636 
637  std::size_t payload_size = sent_return.size;
638  char* buf = sent_return.buf - header_size;
639  uint32_t flags = 0;
640  /*
641  set the cascading flag if necessary.
642  This is not important because, unlike p2p_send, ordered_send/query
643  does not distinguish cascading and non cascading sends. However,
644  to keep the format consistency, we keep the flags field in the RPC
645  message header reserved for future use.
646 
647  if (in_rpc_handler()) {
648  RPC_HEADER_FLAG_SET(flags,CASCADE);
649  dbg_default_info("send cascading message.");
650  }
651  */
652  populate_header(buf, payload_size, invoker.invoke_opcode, nid, flags);
653 
654  using Ret = typename decltype(sent_return.results)::type;
655  /*
656  much like previous definition, except with
657  two fewer fields
658  */
659  struct send_return {
660  QueryResults<Ret> results;
661  PendingResults<Ret>& pending;
662  //LifeTracker
663  /*
664 class LifeTracker {
665 std::function<void () > deleter;
666 ~LifeTraker(){
667 deleter();
668 }
669 };
670 
671 LifeTracker{[invocation_id, &map](){map.erase(invocation_id);}};
672  */
673  };
674  return send_return{std::move(sent_return.results),
675  sent_return.pending};
676  }
677 
678  using specialized_to = IdentifyingClass;
679  RemoteInvocableClass& for_class(IdentifyingClass*) {
680  return *this;
681  }
682 };
683 
687 template <class IdentifyingClass>
688 class RemoteInvocableClass<IdentifyingClass> {
689 public:
690  const node_id_t nid;
691 
692  RemoteInvocableClass(node_id_t nid, uint32_t type_id, uint32_t instance_id,
693  std::map<Opcode, receive_fun_t>& rvrs)
694  : nid(nid) {}
695 
696  template <FunctionTag Tag, typename... Args>
697  std::size_t get_size(Args&&... a) {
698  auto invocation_id = mutils::long_rand();
699  std::size_t size = mutils::bytes_size(invocation_id);
700  {
701  auto t = {std::size_t{0}, std::size_t{0}, mutils::bytes_size(a)...};
702  size += std::accumulate(t.begin(), t.end(), 0);
703  }
704  return size;
705  }
706 
707  template <FunctionTag Tag, typename... Args>
708  auto* getReturnType(Args&&... args) {
709  void* null_and_void(nullptr);
710  return null_and_void;
711  }
712 
713  using specialized_to = IdentifyingClass;
714  RemoteInvocableClass& for_class(IdentifyingClass*) {
715  return *this;
716  }
717 };
718 
735 template <class IdentifyingClass, typename... WrappedFuns>
736 auto build_remote_invocable_class(const node_id_t nid, const uint32_t type_id, const uint32_t instance_id,
737  std::map<Opcode, receive_fun_t>& rvrs,
738  const WrappedFuns&... fs) {
739  return std::make_unique<RemoteInvocableClass<IdentifyingClass, WrappedFuns...>>(nid, type_id, instance_id, rvrs, fs...);
740 }
741 
753 template <class IdentifyingClass, typename... WrappedFuns>
754 class RemoteInvokerForClass : private RemoteInvokers<WrappedFuns...> {
755 public:
756  const node_id_t nid;
757 
758  RemoteInvokerForClass(node_id_t nid, uint32_t type_id, uint32_t instance_id,
759  std::map<Opcode, receive_fun_t>& rvrs)
760  : RemoteInvokers<WrappedFuns...>(type_id, instance_id, rvrs),
761  nid(nid) {}
762 
763  template <FunctionTag Tag, typename... Args>
764  auto send(const std::function<char*(int)>& out_alloc, Args&&... args) {
765  using namespace remote_invocation_utilities;
766 
767  constexpr std::integral_constant<FunctionTag, Tag>* choice{nullptr};
768  auto& invoker = this->get_invoker(choice, args...);
769  const auto header_size = header_space();
770  auto sent_return = invoker.send(
771  [&out_alloc, &header_size](std::size_t size) {
772  return out_alloc(size + header_size) + header_size;
773  },
774  std::forward<Args>(args)...);
775 
776  std::size_t payload_size = sent_return.size;
777  char* buf = sent_return.buf - header_size;
778  uint32_t flags = 0;
779  if(in_rpc_handler()) {
780  RPC_HEADER_FLAG_SET(flags, CASCADE);
781  dbg_default_info("sending cascading RPC.");
782  }
783  populate_header(buf, payload_size, invoker.invoke_opcode, nid, flags);
784 
785  using Ret = typename decltype(sent_return.results)::type;
786  /*
787  much like previous definition, except with
788  two fewer fields
789  */
790  struct send_return {
791  QueryResults<Ret> results;
792  PendingResults<Ret>& pending;
793  };
794  return send_return{std::move(sent_return.results),
795  sent_return.pending};
796  }
797 };
798 
802 template <class IdentifyingClass>
803 class RemoteInvokerForClass<IdentifyingClass> {
804 public:
805  const node_id_t nid;
806 
807  RemoteInvokerForClass(node_id_t nid, uint32_t type_id, uint32_t instance_id,
808  std::map<Opcode, receive_fun_t>& rvrs)
809  : nid(nid) {}
810 };
811 
827 template <class IdentifyingClass, typename... WrappedFuns>
828 auto build_remote_invoker_for_class(const node_id_t nid, const uint32_t type_id, const uint32_t instance_id,
829  std::map<Opcode, receive_fun_t>& rvrs) {
830  return std::make_unique<RemoteInvokerForClass<IdentifyingClass, WrappedFuns...>>(nid, type_id, instance_id, rvrs);
831 }
832 } // namespace rpc
833 } // namespace derecho
RemoteInvokers(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers)
RemoteInvokers(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers)
wrapped< Tag, std::function< Ret(Args...)> > bind_to_instance(std::unique_ptr< NewClass > *_this, const partial_wrapped< Tag, Ret, NewClass, Args... > &partial)
Converts a partial_wrapped<> containing a pointer-to-member-function to a wrapped<> containing the sa...
recv_ret receive_response(mutils::RemoteDeserialization_v *rdv, const node_id_t &nid, const char *response, const std::function< char *(int)> &f)
Entry point for responses; called when a message is received that contains a response to this RemoteI...
partial_wrapped< Tag, Ret, NewClass, Args... > tag(Ret(NewClass::*fun)(Args...))
User-facing entry point for the series of functions that binds a FunctionTag to a class&#39;s member func...
unsigned long long FunctionTag
Definition: rpc_utils.hpp:54
Data structure that holds a set of promises for a single RPC function call; the promises transmit one...
Definition: rpc_utils.hpp:353
Transforms a class into a "replicated object" with methods that can be invoked by RPC...
An RPC function call can be uniquely identified by the tuple (class, subgroup ID, function ID...
Definition: rpc_utils.hpp:62
Ret(Class::*)(Arguments...) const fun_t
auto * getReturnType(Args &&... args)
auto serialize_one(barray v, const A &a, const Rest &... rest)
send_return send(const std::function< char *(int)> &out_alloc, const std::decay_t< Args > &... remote_args)
Called to construct an RPC message to send that will invoke the remote- invocable function targeted b...
Ret(Class::*)(Arguments...) fun_t
STL namespace.
RemoteInvokerForClass(node_id_t nid, uint32_t type_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs)
bool in_rpc_handler()
defined in rpc_manager.h
RemoteInvoker(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers)
Constructs a RemoteInvoker that provides RPC call marshalling and response-handling for a specific fu...
This matches uses of wrapped<> where the second argument is not a function, and does nothing...
auto build_remote_invocable_class(const node_id_t nid, const uint32_t type_id, const uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs, const WrappedFuns &... fs)
Constructs a RemoteInvocableClass instance that proxies for an instance of the class in the template ...
void reset()
reset this object.
Definition: rpc_utils.hpp:479
Exactly the same as the partial_wrapped template, but for pointer-to-member-functions that are const...
RemoteInvocableClass(node_id_t nid, uint32_t type_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs)
recv_ret receive_call(std::true_type const *const, mutils::DeserializationManager *dsm, const node_id_t &, const char *_recv_buf, const std::function< char *(int)> &)
Specialization of receive_call for void functions, which do not need to send a response.
auto bytes_size(const T &)
Just calls sizeof(T)
auto build_remote_invoker_for_class(const node_id_t nid, const uint32_t type_id, const uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs)
Constructs a RemoteInvokerForClass that can act as a client for the class in the template parameter (...
recv_ret receive_response(std::true_type *, mutils::DeserializationManager *, const node_id_t &nid, const char *response, const std::function< char *(int)> &)
Specialization of receive_response for void functions (which don&#39;t expect any response).
RemoteInvoker & get_invoker(std::integral_constant< FunctionTag, Tag > const *const, const Args &...)
RemoteInvocablePairs(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers, FunType function_ptr, RestFunTypes &&... function_ptrs)
recv_ret receive_call(std::false_type const *const, mutils::DeserializationManager *dsm, const node_id_t &caller, const char *_recv_buf, const std::function< char *(int)> &out_alloc)
Specialization of receive_call for non-void functions.
The manager for any RemoteDeserializationContexts.
void fulfill_pending_results_vector(long int invocation_id, const node_list_t &who)
Populates the pending-results map of a particular invocation of the remote-invocable function...
#define MAX_CONCURRENT_RPCS_PER_INVOKER
std::vector< node_id_t > node_list_t
Definition: rpc_utils.hpp:77
void populate_header(char *reply_buf, const std::size_t &payload_size, const Opcode &op, const node_id_t &from, const uint32_t &flags)
Definition: rpc_utils.hpp:561
void fulfill_map(const node_list_t &who)
Fill pending_map and reply_promises with one promise/future pair for each node that was contacted in ...
Definition: rpc_utils.hpp:390
auto send(const std::function< char *(int)> &out_alloc, Args &&... args)
Constructs a message that will remotely invoke a method of this class, supplying the specified argume...
#define dbg_default_trace(...)
Definition: logger.hpp:40
RemoteInvocable(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers, std::function< Ret(Args...)> f)
Constructs a RemoteInvocable that provides RPC call handling for a specific function, and registers the RPC-handling functions in the given "receivers" map.
Template that pairs a FunctionTag with a pointer-to-member-function.
RemoteInvocableClass(node_id_t nid, uint32_t type_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs, const WrappedFuns &... fs)
RemoteInvocableClass & for_class(IdentifyingClass *)
uint32_t node_id_t
Type alias for Node IDs in a Derecho group.
Return type of all the RemoteInvocable::receive_* methods.
Definition: rpc_utils.hpp:122
Transforms a class into an RPC client for the methods of that class, given a place to store RPC messa...
auto send(const std::function< char *(int)> &out_alloc, Args &&... args)
QueryResults< Ret > get_future()
Constructs and returns a QueryResults representing the "future" end of the response promises in this ...
Definition: rpc_utils.hpp:381
RemoteInvocableClass & for_class(IdentifyingClass *)
auto deserialize_and_run(DeserializationManager *dsm, char *v, const F &fun)
Calls mutils::from_bytes_noalloc<T>(ctx,v), dereferences the result, and passes it to fun...
recv_ret receive_call(mutils::RemoteDeserialization_v *rdv, const node_id_t &who, const char *recv_buf, const std::function< char *(int)> &out_alloc)
Entry point for handling an RPC function call to this RemoteInvocable function.
#define dbg_default_info(...)
Definition: logger.hpp:44
void set_value(const node_id_t &nid, const Ret &v)
Fulfills a promise for a single node&#39;s reply by setting the value that the node returned for the RPC ...
Definition: rpc_utils.hpp:443
std::vector< RemoteDeserializationContext_p > RemoteDeserialization_v
void set_exception(const node_id_t &nid, const std::exception_ptr e)
Fulfills a promise for a single node&#39;s reply by setting an exception that was thrown by the RPC funct...
Definition: rpc_utils.hpp:460
#define assert_always(x...)
Definition: schedule.cpp:10
std::size_t get_size_for_ordered_send(Args &&... a)
std::size_t to_bytes(const ByteRepresentable &b, char *v)
calls b.to_bytes(v) when b is a ByteRepresentable; calls std::memcpy() when b is POD.
Technically, RemoteInvokers is a specialization of this template, but it&#39;s the only specialization...
Data structure that (indirectly) holds a set of futures for a single RPC function call; there is one ...
Definition: rpc_utils.hpp:158
recv_ret receive_response(std::false_type *, mutils::DeserializationManager *dsm, const node_id_t &nid, const char *response, const std::function< definitely_char *(int)> &)
Specialization of receive_response for non-void functions.
RemoteInvokerForClass(node_id_t nid, uint32_t type_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &rvrs)
Indicates that an RPC call failed because executing the RPC function on the remote node resulted in a...
Definition: rpc_utils.hpp:83
RemoteInvocablePairs(uint32_t class_id, uint32_t instance_id, std::map< Opcode, receive_fun_t > &receivers, FunType function_ptr)
RemoteInvocable & get_handler(std::integral_constant< FunctionTag, Tag > const *const, const Args &...)
#define RPC_HEADER_FLAG_SET(f, name)
Definition: rpc_utils.hpp:542