/* * Copyright 2017 The Cartographer Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "cartographer_grpc/internal/framework/server.h" #include #include "glog/logging.h" #include "grpc++/impl/codegen/proto_utils.h" namespace cartographer { namespace cloud { namespace framework { Service::Service(const std::string& service_name, const std::map& rpc_handler_infos, EventQueueSelector event_queue_selector) : rpc_handler_infos_(rpc_handler_infos), event_queue_selector_(event_queue_selector) { for (const auto& rpc_handler_info : rpc_handler_infos_) { // The 'handler' below is set to 'nullptr' indicating that we want to // handle this method asynchronously. this->AddMethod(new ::grpc::internal::RpcServiceMethod( rpc_handler_info.second.fully_qualified_name.c_str(), rpc_handler_info.second.rpc_type, nullptr /* handler */)); } } void Service::StartServing( std::vector& completion_queue_threads, ExecutionContext* execution_context) { int i = 0; for (const auto& rpc_handler_info : rpc_handler_infos_) { for (auto& completion_queue_thread : completion_queue_threads) { std::shared_ptr rpc = active_rpcs_.Add(common::make_unique( i, completion_queue_thread.completion_queue(), event_queue_selector_(), execution_context, rpc_handler_info.second, this, active_rpcs_.GetWeakPtrFactory())); rpc->RequestNextMethodInvocation(); } ++i; } } void Service::StopServing() { shutting_down_ = true; } void Service::HandleEvent(Rpc::Event event, Rpc* rpc, bool ok) { switch (event) { case Rpc::Event::NEW_CONNECTION: HandleNewConnection(rpc, ok); break; case Rpc::Event::READ: HandleRead(rpc, ok); break; case Rpc::Event::WRITE_NEEDED: case Rpc::Event::WRITE: HandleWrite(rpc, ok); break; case Rpc::Event::FINISH: HandleFinish(rpc, ok); break; case Rpc::Event::DONE: HandleDone(rpc, ok); break; } } void Service::HandleNewConnection(Rpc* rpc, bool ok) { if (shutting_down_) { if (ok) { LOG(WARNING) << "Server shutting down. Refusing to handle new RPCs."; } active_rpcs_.Remove(rpc); return; } if (!ok) { LOG(ERROR) << "Failed to establish connection for unknown reason."; active_rpcs_.Remove(rpc); } if (ok) { // For request-streaming RPCs ask the client to start sending requests. rpc->RequestStreamingReadIfNeeded(); } // Create new active rpc to handle next connection and register it for the // incoming connection. Assign event queue in a round-robin fashion. std::unique_ptr new_rpc = rpc->Clone(); new_rpc->SetEventQueue(event_queue_selector_()); active_rpcs_.Add(std::move(new_rpc))->RequestNextMethodInvocation(); } void Service::HandleRead(Rpc* rpc, bool ok) { if (ok) { rpc->OnRequest(); rpc->RequestStreamingReadIfNeeded(); return; } // Reads completed. rpc->OnReadsDone(); RemoveIfNotPending(rpc); } void Service::HandleWrite(Rpc* rpc, bool ok) { if (!ok) { LOG(ERROR) << "Write failed"; } // Send the next message or potentially finish the connection. rpc->HandleSendQueue(); RemoveIfNotPending(rpc); } void Service::HandleFinish(Rpc* rpc, bool ok) { if (!ok) { LOG(ERROR) << "Finish failed"; } rpc->OnFinish(); RemoveIfNotPending(rpc); } void Service::HandleDone(Rpc* rpc, bool ok) { RemoveIfNotPending(rpc); } void Service::RemoveIfNotPending(Rpc* rpc) { if (!rpc->IsAnyEventPending()) { active_rpcs_.Remove(rpc); } } } // namespace framework } // namespace cloud } // namespace cartographer