/* * @brief service is implemented by programer, suach as from peloton service * interface * Therefore, a service has several methods. These methods can be registered * using * this function */ bool RpcServer::RegisterService(google::protobuf::Service *service) { // Get the service descriptor const google::protobuf::ServiceDescriptor *descriptor = service->GetDescriptor(); std::hash<std::string> string_hash_fn; /* * Put all of the method names (descriptors), msg types into rpc_method_map_ * For example, peloton service has HeartBeat method, its * request msg type is HeartbeatRequest * response msg type is HeartbeatResponse */ for (int i = 0; i < descriptor->method_count(); ++i) { // Get the method descriptor const google::protobuf::MethodDescriptor *method = descriptor->method(i); // Get request and response type through method descriptor const google::protobuf::Message *request = &service->GetRequestPrototype(method); const google::protobuf::Message *response = &service->GetResponsePrototype(method); // Create the corresponding method structure RpcMethod *rpc_method = new RpcMethod(service, request, response, method); // Put the method into rpc_method_map_: hashcode-->method std::string methodname = std::string(method->full_name()); // TODO: // uint64_t hash = CityHash64(methodname.c_str(), methodname.length()); // although the return type is size_t, again we should specify the size of // the type uint64_t hash = string_hash_fn(methodname); RpcMethodMap::const_iterator iter = rpc_method_map_.find(hash); if (iter == rpc_method_map_.end()) { auto pair = std::make_pair(hash, rpc_method); rpc_method_map_.insert(pair); } } return true; }
/* * Channel is only invoked by protobuf rpc client. So this method is sending * request msg */ void RpcChannel::CallMethod( const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController* controller, const google::protobuf::Message* request, UNUSED_ATTRIBUTE google::protobuf::Message* response, google::protobuf::Closure* done) { PL_ASSERT(request != nullptr); /* run call back function */ if (done != NULL) { done->Run(); } /* Get the rpc function name */ std::string methodname = std::string(method->full_name()); std::hash<std::string> string_hash_fn; /* Set the type */ uint16_t type = MSG_TYPE_REQ; /* Get the hashcode for the rpc function name */ /* we use unit64_t because we should specify the exact length */ uint64_t opcode = string_hash_fn(methodname); /* prepare the sending buf */ uint32_t msg_len = request->ByteSize() + OPCODELEN + TYPELEN; /* total length of the message: header length (4bytes) + message length * (8bytes + ...) */ PL_ASSERT(HEADERLEN == sizeof(msg_len)); char buf[HEADERLEN + msg_len]; /* copy the header into the buf */ PL_MEMCPY(buf, &msg_len, sizeof(msg_len)); /* copy the type into the buf, following the header */ PL_ASSERT(TYPELEN == sizeof(type)); PL_MEMCPY(buf + HEADERLEN, &type, TYPELEN); /* copy the hashcode into the buf, following the type */ PL_ASSERT(OPCODELEN == sizeof(opcode)); PL_MEMCPY(buf + HEADERLEN + TYPELEN, &opcode, OPCODELEN); /* call protobuf to serialize the request message into sending buf */ request->SerializeToArray(buf + HEADERLEN + TYPELEN + OPCODELEN, request->ByteSize()); /* * GET a connection to process the rpc send and recv. If there is a associated * connection * it will be returned. If not, a new connection will be created and connect * to server */ Connection* conn = ConnectionManager::GetInstance().CreateConn( addr_); // CreateConn is used for self connect // Connection* conn = ConnectionManager::GetInstance().GetConn(addr_); /* Connect to server with given address */ if (conn == NULL) { LOG_TRACE("Can't get connection"); // rpc client use this info to decide whether re-send the message controller->SetFailed("Connect Error"); return; } /* write data into sending buffer, when using libevent we don't need loop send */ if (conn->AddToWriteBuffer(buf, HEADERLEN + msg_len) == false) { LOG_TRACE("Write data Error"); return; } }