| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 | 
							- /*
 
-  *
 
-  * Copyright 2015, Google Inc.
 
-  * All rights reserved.
 
-  *
 
-  * Redistribution and use in source and binary forms, with or without
 
-  * modification, are permitted provided that the following conditions are
 
-  * met:
 
-  *
 
-  *     * Redistributions of source code must retain the above copyright
 
-  * notice, this list of conditions and the following disclaimer.
 
-  *     * Redistributions in binary form must reproduce the above
 
-  * copyright notice, this list of conditions and the following disclaimer
 
-  * in the documentation and/or other materials provided with the
 
-  * distribution.
 
-  *     * Neither the name of Google Inc. nor the names of its
 
-  * contributors may be used to endorse or promote products derived from
 
-  * this software without specific prior written permission.
 
-  *
 
-  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
-  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
-  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
-  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
-  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
-  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
-  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
-  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
-  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
-  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
-  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-  *
 
-  */
 
- #include <forward_list>
 
- #include <functional>
 
- #include <memory>
 
- #include <mutex>
 
- #include <thread>
 
- #include <grpc++/generic/async_generic_service.h>
 
- #include <grpc++/resource_quota.h>
 
- #include <grpc++/security/server_credentials.h>
 
- #include <grpc++/server.h>
 
- #include <grpc++/server_builder.h>
 
- #include <grpc++/server_context.h>
 
- #include <grpc++/support/config.h>
 
- #include <grpc/grpc.h>
 
- #include <grpc/support/alloc.h>
 
- #include <grpc/support/host_port.h>
 
- #include <grpc/support/log.h>
 
- #include "src/proto/grpc/testing/services.grpc.pb.h"
 
- #include "test/core/util/test_config.h"
 
- #include "test/cpp/qps/server.h"
 
- namespace grpc {
 
- namespace testing {
 
- template <class RequestType, class ResponseType, class ServiceType,
 
-           class ServerContextType>
 
- class AsyncQpsServerTest final : public grpc::testing::Server {
 
-  public:
 
-   AsyncQpsServerTest(
 
-       const ServerConfig &config,
 
-       std::function<void(ServerBuilder *, ServiceType *)> register_service,
 
-       std::function<void(ServiceType *, ServerContextType *, RequestType *,
 
-                          ServerAsyncResponseWriter<ResponseType> *,
 
-                          CompletionQueue *, ServerCompletionQueue *, void *)>
 
-           request_unary_function,
 
-       std::function<void(ServiceType *, ServerContextType *,
 
-                          ServerAsyncReaderWriter<ResponseType, RequestType> *,
 
-                          CompletionQueue *, ServerCompletionQueue *, void *)>
 
-           request_streaming_function,
 
-       std::function<grpc::Status(const PayloadConfig &, const RequestType *,
 
-                                  ResponseType *)>
 
-           process_rpc)
 
-       : Server(config) {
 
-     char *server_address = NULL;
 
-     gpr_join_host_port(&server_address, "::", port());
 
-     ServerBuilder builder;
 
-     builder.AddListeningPort(server_address,
 
-                              Server::CreateServerCredentials(config));
 
-     gpr_free(server_address);
 
-     register_service(&builder, &async_service_);
 
-     int num_threads = config.async_server_threads();
 
-     if (num_threads <= 0) {  // dynamic sizing
 
-       num_threads = cores();
 
-       gpr_log(GPR_INFO, "Sizing async server to %d threads", num_threads);
 
-     }
 
-     for (int i = 0; i < num_threads; i++) {
 
-       srv_cqs_.emplace_back(builder.AddCompletionQueue());
 
-     }
 
-     if (config.resource_quota_size() > 0) {
 
-       builder.SetResourceQuota(ResourceQuota("AsyncQpsServerTest")
 
-                                    .Resize(config.resource_quota_size()));
 
-     }
 
-     server_ = builder.BuildAndStart();
 
-     using namespace std::placeholders;
 
-     auto process_rpc_bound =
 
-         std::bind(process_rpc, config.payload_config(), _1, _2);
 
-     for (int i = 0; i < 15000; i++) {
 
-       for (int j = 0; j < num_threads; j++) {
 
-         if (request_unary_function) {
 
-           auto request_unary =
 
-               std::bind(request_unary_function, &async_service_, _1, _2, _3,
 
-                         srv_cqs_[j].get(), srv_cqs_[j].get(), _4);
 
-           contexts_.emplace_back(
 
-               new ServerRpcContextUnaryImpl(request_unary, process_rpc_bound));
 
-         }
 
-         if (request_streaming_function) {
 
-           auto request_streaming =
 
-               std::bind(request_streaming_function, &async_service_, _1, _2,
 
-                         srv_cqs_[j].get(), srv_cqs_[j].get(), _3);
 
-           contexts_.emplace_back(new ServerRpcContextStreamingImpl(
 
-               request_streaming, process_rpc_bound));
 
-         }
 
-       }
 
-     }
 
-     for (int i = 0; i < num_threads; i++) {
 
-       shutdown_state_.emplace_back(new PerThreadShutdownState());
 
-       threads_.emplace_back(&AsyncQpsServerTest::ThreadFunc, this, i);
 
-     }
 
-   }
 
-   ~AsyncQpsServerTest() {
 
-     for (auto ss = shutdown_state_.begin(); ss != shutdown_state_.end(); ++ss) {
 
-       std::lock_guard<std::mutex> lock((*ss)->mutex);
 
-       (*ss)->shutdown = true;
 
-     }
 
-     std::thread shutdown_thread(&AsyncQpsServerTest::ShutdownThreadFunc, this);
 
-     for (auto cq = srv_cqs_.begin(); cq != srv_cqs_.end(); ++cq) {
 
-       (*cq)->Shutdown();
 
-     }
 
-     for (auto thr = threads_.begin(); thr != threads_.end(); thr++) {
 
-       thr->join();
 
-     }
 
-     for (auto cq = srv_cqs_.begin(); cq != srv_cqs_.end(); ++cq) {
 
-       bool ok;
 
-       void *got_tag;
 
-       while ((*cq)->Next(&got_tag, &ok))
 
-         ;
 
-     }
 
-     shutdown_thread.join();
 
-   }
 
-  private:
 
-   void ShutdownThreadFunc() {
 
-     // TODO (vpai): Remove this deadline and allow Shutdown to finish properly
 
-     auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(3);
 
-     server_->Shutdown(deadline);
 
-   }
 
-   void ThreadFunc(int thread_idx) {
 
-     // Wait until work is available or we are shutting down
 
-     bool ok;
 
-     void *got_tag;
 
-     while (srv_cqs_[thread_idx]->Next(&got_tag, &ok)) {
 
-       ServerRpcContext *ctx = detag(got_tag);
 
-       // The tag is a pointer to an RPC context to invoke
 
-       // Proceed while holding a lock to make sure that
 
-       // this thread isn't supposed to shut down
 
-       std::lock_guard<std::mutex> l(shutdown_state_[thread_idx]->mutex);
 
-       if (shutdown_state_[thread_idx]->shutdown) {
 
-         return;
 
-       }
 
-       const bool still_going = ctx->RunNextState(ok);
 
-       // if this RPC context is done, refresh it
 
-       if (!still_going) {
 
-         ctx->Reset();
 
-       }
 
-     }
 
-     return;
 
-   }
 
-   class ServerRpcContext {
 
-    public:
 
-     ServerRpcContext() {}
 
-     virtual ~ServerRpcContext(){};
 
-     virtual bool RunNextState(bool) = 0;  // next state, return false if done
 
-     virtual void Reset() = 0;             // start this back at a clean state
 
-   };
 
-   static void *tag(ServerRpcContext *func) {
 
-     return reinterpret_cast<void *>(func);
 
-   }
 
-   static ServerRpcContext *detag(void *tag) {
 
-     return reinterpret_cast<ServerRpcContext *>(tag);
 
-   }
 
-   class ServerRpcContextUnaryImpl final : public ServerRpcContext {
 
-    public:
 
-     ServerRpcContextUnaryImpl(
 
-         std::function<void(ServerContextType *, RequestType *,
 
-                            grpc::ServerAsyncResponseWriter<ResponseType> *,
 
-                            void *)>
 
-             request_method,
 
-         std::function<grpc::Status(const RequestType *, ResponseType *)>
 
-             invoke_method)
 
-         : srv_ctx_(new ServerContextType),
 
-           next_state_(&ServerRpcContextUnaryImpl::invoker),
 
-           request_method_(request_method),
 
-           invoke_method_(invoke_method),
 
-           response_writer_(srv_ctx_.get()) {
 
-       request_method_(srv_ctx_.get(), &req_, &response_writer_,
 
-                       AsyncQpsServerTest::tag(this));
 
-     }
 
-     ~ServerRpcContextUnaryImpl() override {}
 
-     bool RunNextState(bool ok) override { return (this->*next_state_)(ok); }
 
-     void Reset() override {
 
-       srv_ctx_.reset(new ServerContextType);
 
-       req_ = RequestType();
 
-       response_writer_ =
 
-           grpc::ServerAsyncResponseWriter<ResponseType>(srv_ctx_.get());
 
-       // Then request the method
 
-       next_state_ = &ServerRpcContextUnaryImpl::invoker;
 
-       request_method_(srv_ctx_.get(), &req_, &response_writer_,
 
-                       AsyncQpsServerTest::tag(this));
 
-     }
 
-    private:
 
-     bool finisher(bool) { return false; }
 
-     bool invoker(bool ok) {
 
-       if (!ok) {
 
-         return false;
 
-       }
 
-       ResponseType response;
 
-       // Call the RPC processing function
 
-       grpc::Status status = invoke_method_(&req_, &response);
 
-       // Have the response writer work and invoke on_finish when done
 
-       next_state_ = &ServerRpcContextUnaryImpl::finisher;
 
-       response_writer_.Finish(response, status, AsyncQpsServerTest::tag(this));
 
-       return true;
 
-     }
 
-     std::unique_ptr<ServerContextType> srv_ctx_;
 
-     RequestType req_;
 
-     bool (ServerRpcContextUnaryImpl::*next_state_)(bool);
 
-     std::function<void(ServerContextType *, RequestType *,
 
-                        grpc::ServerAsyncResponseWriter<ResponseType> *, void *)>
 
-         request_method_;
 
-     std::function<grpc::Status(const RequestType *, ResponseType *)>
 
-         invoke_method_;
 
-     grpc::ServerAsyncResponseWriter<ResponseType> response_writer_;
 
-   };
 
-   class ServerRpcContextStreamingImpl final : public ServerRpcContext {
 
-    public:
 
-     ServerRpcContextStreamingImpl(
 
-         std::function<void(
 
-             ServerContextType *,
 
-             grpc::ServerAsyncReaderWriter<ResponseType, RequestType> *, void *)>
 
-             request_method,
 
-         std::function<grpc::Status(const RequestType *, ResponseType *)>
 
-             invoke_method)
 
-         : srv_ctx_(new ServerContextType),
 
-           next_state_(&ServerRpcContextStreamingImpl::request_done),
 
-           request_method_(request_method),
 
-           invoke_method_(invoke_method),
 
-           stream_(srv_ctx_.get()) {
 
-       request_method_(srv_ctx_.get(), &stream_, AsyncQpsServerTest::tag(this));
 
-     }
 
-     ~ServerRpcContextStreamingImpl() override {}
 
-     bool RunNextState(bool ok) override { return (this->*next_state_)(ok); }
 
-     void Reset() override {
 
-       srv_ctx_.reset(new ServerContextType);
 
-       req_ = RequestType();
 
-       stream_ = grpc::ServerAsyncReaderWriter<ResponseType, RequestType>(
 
-           srv_ctx_.get());
 
-       // Then request the method
 
-       next_state_ = &ServerRpcContextStreamingImpl::request_done;
 
-       request_method_(srv_ctx_.get(), &stream_, AsyncQpsServerTest::tag(this));
 
-     }
 
-    private:
 
-     bool request_done(bool ok) {
 
-       if (!ok) {
 
-         return false;
 
-       }
 
-       stream_.Read(&req_, AsyncQpsServerTest::tag(this));
 
-       next_state_ = &ServerRpcContextStreamingImpl::read_done;
 
-       return true;
 
-     }
 
-     bool read_done(bool ok) {
 
-       if (ok) {
 
-         // invoke the method
 
-         ResponseType response;
 
-         // Call the RPC processing function
 
-         grpc::Status status = invoke_method_(&req_, &response);
 
-         // initiate the write
 
-         stream_.Write(response, AsyncQpsServerTest::tag(this));
 
-         next_state_ = &ServerRpcContextStreamingImpl::write_done;
 
-       } else {  // client has sent writes done
 
-         // finish the stream
 
-         stream_.Finish(Status::OK, AsyncQpsServerTest::tag(this));
 
-         next_state_ = &ServerRpcContextStreamingImpl::finish_done;
 
-       }
 
-       return true;
 
-     }
 
-     bool write_done(bool ok) {
 
-       // now go back and get another streaming read!
 
-       if (ok) {
 
-         stream_.Read(&req_, AsyncQpsServerTest::tag(this));
 
-         next_state_ = &ServerRpcContextStreamingImpl::read_done;
 
-       } else {
 
-         stream_.Finish(Status::OK, AsyncQpsServerTest::tag(this));
 
-         next_state_ = &ServerRpcContextStreamingImpl::finish_done;
 
-       }
 
-       return true;
 
-     }
 
-     bool finish_done(bool ok) { return false; /* reset the context */ }
 
-     std::unique_ptr<ServerContextType> srv_ctx_;
 
-     RequestType req_;
 
-     bool (ServerRpcContextStreamingImpl::*next_state_)(bool);
 
-     std::function<void(
 
-         ServerContextType *,
 
-         grpc::ServerAsyncReaderWriter<ResponseType, RequestType> *, void *)>
 
-         request_method_;
 
-     std::function<grpc::Status(const RequestType *, ResponseType *)>
 
-         invoke_method_;
 
-     grpc::ServerAsyncReaderWriter<ResponseType, RequestType> stream_;
 
-   };
 
-   std::vector<std::thread> threads_;
 
-   std::unique_ptr<grpc::Server> server_;
 
-   std::vector<std::unique_ptr<grpc::ServerCompletionQueue>> srv_cqs_;
 
-   ServiceType async_service_;
 
-   std::vector<std::unique_ptr<ServerRpcContext>> contexts_;
 
-   struct PerThreadShutdownState {
 
-     mutable std::mutex mutex;
 
-     bool shutdown;
 
-     PerThreadShutdownState() : shutdown(false) {}
 
-   };
 
-   std::vector<std::unique_ptr<PerThreadShutdownState>> shutdown_state_;
 
- };
 
- static void RegisterBenchmarkService(ServerBuilder *builder,
 
-                                      BenchmarkService::AsyncService *service) {
 
-   builder->RegisterService(service);
 
- }
 
- static void RegisterGenericService(ServerBuilder *builder,
 
-                                    grpc::AsyncGenericService *service) {
 
-   builder->RegisterAsyncGenericService(service);
 
- }
 
- static Status ProcessSimpleRPC(const PayloadConfig &,
 
-                                const SimpleRequest *request,
 
-                                SimpleResponse *response) {
 
-   if (request->response_size() > 0) {
 
-     if (!Server::SetPayload(request->response_type(), request->response_size(),
 
-                             response->mutable_payload())) {
 
-       return Status(grpc::StatusCode::INTERNAL, "Error creating payload.");
 
-     }
 
-   }
 
-   return Status::OK;
 
- }
 
- static Status ProcessGenericRPC(const PayloadConfig &payload_config,
 
-                                 const ByteBuffer *request,
 
-                                 ByteBuffer *response) {
 
-   int resp_size = payload_config.bytebuf_params().resp_size();
 
-   std::unique_ptr<char[]> buf(new char[resp_size]);
 
-   grpc_slice s = grpc_slice_from_copied_buffer(buf.get(), resp_size);
 
-   Slice slice(s, Slice::STEAL_REF);
 
-   *response = ByteBuffer(&slice, 1);
 
-   return Status::OK;
 
- }
 
- std::unique_ptr<Server> CreateAsyncServer(const ServerConfig &config) {
 
-   return std::unique_ptr<Server>(
 
-       new AsyncQpsServerTest<SimpleRequest, SimpleResponse,
 
-                              BenchmarkService::AsyncService,
 
-                              grpc::ServerContext>(
 
-           config, RegisterBenchmarkService,
 
-           &BenchmarkService::AsyncService::RequestUnaryCall,
 
-           &BenchmarkService::AsyncService::RequestStreamingCall,
 
-           ProcessSimpleRPC));
 
- }
 
- std::unique_ptr<Server> CreateAsyncGenericServer(const ServerConfig &config) {
 
-   return std::unique_ptr<Server>(
 
-       new AsyncQpsServerTest<ByteBuffer, ByteBuffer, grpc::AsyncGenericService,
 
-                              grpc::GenericServerContext>(
 
-           config, RegisterGenericService, nullptr,
 
-           &grpc::AsyncGenericService::RequestCall, ProcessGenericRPC));
 
- }
 
- }  // namespace testing
 
- }  // namespace grpc
 
 
  |