server_builder.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*
  2. *
  3. * Copyright 2015-2016 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <grpcpp/server_builder.h>
  19. #include <grpc/support/cpu.h>
  20. #include <grpc/support/log.h>
  21. #include <grpcpp/impl/service_type.h>
  22. #include <grpcpp/resource_quota.h>
  23. #include <grpcpp/server.h>
  24. #include <utility>
  25. #include "src/core/lib/gpr/useful.h"
  26. #include "src/cpp/server/thread_pool_interface.h"
  27. namespace grpc {
  28. static std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>*
  29. g_plugin_factory_list;
  30. static gpr_once once_init_plugin_list = GPR_ONCE_INIT;
  31. static void do_plugin_list_init(void) {
  32. g_plugin_factory_list =
  33. new std::vector<std::unique_ptr<ServerBuilderPlugin> (*)()>();
  34. }
  35. ServerBuilder::ServerBuilder()
  36. : max_receive_message_size_(INT_MIN),
  37. max_send_message_size_(INT_MIN),
  38. sync_server_settings_(SyncServerSettings()),
  39. resource_quota_(nullptr),
  40. generic_service_(nullptr) {
  41. gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
  42. for (auto it = g_plugin_factory_list->begin();
  43. it != g_plugin_factory_list->end(); it++) {
  44. auto& factory = *it;
  45. plugins_.emplace_back(factory());
  46. }
  47. // all compression algorithms enabled by default.
  48. enabled_compression_algorithms_bitset_ =
  49. (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1;
  50. memset(&maybe_default_compression_level_, 0,
  51. sizeof(maybe_default_compression_level_));
  52. memset(&maybe_default_compression_algorithm_, 0,
  53. sizeof(maybe_default_compression_algorithm_));
  54. }
  55. ServerBuilder::~ServerBuilder() {
  56. if (resource_quota_ != nullptr) {
  57. grpc_resource_quota_unref(resource_quota_);
  58. }
  59. }
  60. std::unique_ptr<ServerCompletionQueue> ServerBuilder::AddCompletionQueue(
  61. bool is_frequently_polled) {
  62. ServerCompletionQueue* cq = new ServerCompletionQueue(
  63. GRPC_CQ_NEXT,
  64. is_frequently_polled ? GRPC_CQ_DEFAULT_POLLING : GRPC_CQ_NON_LISTENING,
  65. nullptr);
  66. cqs_.push_back(cq);
  67. return std::unique_ptr<ServerCompletionQueue>(cq);
  68. }
  69. ServerBuilder& ServerBuilder::RegisterService(Service* service) {
  70. services_.emplace_back(new NamedService(service));
  71. return *this;
  72. }
  73. ServerBuilder& ServerBuilder::RegisterService(const grpc::string& addr,
  74. Service* service) {
  75. services_.emplace_back(new NamedService(addr, service));
  76. return *this;
  77. }
  78. ServerBuilder& ServerBuilder::RegisterAsyncGenericService(
  79. AsyncGenericService* service) {
  80. if (generic_service_) {
  81. gpr_log(GPR_ERROR,
  82. "Adding multiple AsyncGenericService is unsupported for now. "
  83. "Dropping the service %p",
  84. (void*)service);
  85. } else {
  86. generic_service_ = service;
  87. }
  88. return *this;
  89. }
  90. ServerBuilder& ServerBuilder::SetOption(
  91. std::unique_ptr<ServerBuilderOption> option) {
  92. options_.push_back(std::move(option));
  93. return *this;
  94. }
  95. ServerBuilder& ServerBuilder::SetSyncServerOption(
  96. ServerBuilder::SyncServerOption option, int val) {
  97. switch (option) {
  98. case NUM_CQS:
  99. sync_server_settings_.num_cqs = val;
  100. break;
  101. case MIN_POLLERS:
  102. sync_server_settings_.min_pollers = val;
  103. break;
  104. case MAX_POLLERS:
  105. sync_server_settings_.max_pollers = val;
  106. break;
  107. case CQ_TIMEOUT_MSEC:
  108. sync_server_settings_.cq_timeout_msec = val;
  109. break;
  110. }
  111. return *this;
  112. }
  113. ServerBuilder& ServerBuilder::SetCompressionAlgorithmSupportStatus(
  114. grpc_compression_algorithm algorithm, bool enabled) {
  115. if (enabled) {
  116. GPR_BITSET(&enabled_compression_algorithms_bitset_, algorithm);
  117. } else {
  118. GPR_BITCLEAR(&enabled_compression_algorithms_bitset_, algorithm);
  119. }
  120. return *this;
  121. }
  122. ServerBuilder& ServerBuilder::SetDefaultCompressionLevel(
  123. grpc_compression_level level) {
  124. maybe_default_compression_level_.level = level;
  125. return *this;
  126. }
  127. ServerBuilder& ServerBuilder::SetDefaultCompressionAlgorithm(
  128. grpc_compression_algorithm algorithm) {
  129. maybe_default_compression_algorithm_.is_set = true;
  130. maybe_default_compression_algorithm_.algorithm = algorithm;
  131. return *this;
  132. }
  133. ServerBuilder& ServerBuilder::SetResourceQuota(
  134. const grpc::ResourceQuota& resource_quota) {
  135. if (resource_quota_ != nullptr) {
  136. grpc_resource_quota_unref(resource_quota_);
  137. }
  138. resource_quota_ = resource_quota.c_resource_quota();
  139. grpc_resource_quota_ref(resource_quota_);
  140. return *this;
  141. }
  142. ServerBuilder& ServerBuilder::AddListeningPort(
  143. const grpc::string& addr_uri, std::shared_ptr<ServerCredentials> creds,
  144. int* selected_port) {
  145. const grpc::string uri_scheme = "dns:";
  146. grpc::string addr = addr_uri;
  147. if (addr_uri.compare(0, uri_scheme.size(), uri_scheme) == 0) {
  148. size_t pos = uri_scheme.size();
  149. while (addr_uri[pos] == '/') ++pos; // Skip slashes.
  150. addr = addr_uri.substr(pos);
  151. }
  152. Port port = {addr, std::move(creds), selected_port};
  153. ports_.push_back(port);
  154. return *this;
  155. }
  156. std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
  157. ChannelArguments args;
  158. for (auto option = options_.begin(); option != options_.end(); ++option) {
  159. (*option)->UpdateArguments(&args);
  160. (*option)->UpdatePlugins(&plugins_);
  161. }
  162. for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
  163. (*plugin)->UpdateServerBuilder(this);
  164. (*plugin)->UpdateChannelArguments(&args);
  165. }
  166. if (max_receive_message_size_ >= -1) {
  167. args.SetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH, max_receive_message_size_);
  168. }
  169. // The default message size is -1 (max), so no need to explicitly set it for
  170. // -1.
  171. if (max_send_message_size_ >= 0) {
  172. args.SetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH, max_send_message_size_);
  173. }
  174. args.SetInt(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET,
  175. enabled_compression_algorithms_bitset_);
  176. if (maybe_default_compression_level_.is_set) {
  177. args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL,
  178. maybe_default_compression_level_.level);
  179. }
  180. if (maybe_default_compression_algorithm_.is_set) {
  181. args.SetInt(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM,
  182. maybe_default_compression_algorithm_.algorithm);
  183. }
  184. if (resource_quota_ != nullptr) {
  185. args.SetPointerWithVtable(GRPC_ARG_RESOURCE_QUOTA, resource_quota_,
  186. grpc_resource_quota_arg_vtable());
  187. }
  188. // == Determine if the server has any syncrhonous methods ==
  189. bool has_sync_methods = false;
  190. for (auto it = services_.begin(); it != services_.end(); ++it) {
  191. if ((*it)->service->has_synchronous_methods()) {
  192. has_sync_methods = true;
  193. break;
  194. }
  195. }
  196. if (!has_sync_methods) {
  197. for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
  198. if ((*plugin)->has_sync_methods()) {
  199. has_sync_methods = true;
  200. break;
  201. }
  202. }
  203. }
  204. // If this is a Sync server, i.e a server expositing sync API, then the server
  205. // needs to create some completion queues to listen for incoming requests.
  206. // 'sync_server_cqs' are those internal completion queues.
  207. //
  208. // This is different from the completion queues added to the server via
  209. // ServerBuilder's AddCompletionQueue() method (those completion queues
  210. // are in 'cqs_' member variable of ServerBuilder object)
  211. std::shared_ptr<std::vector<std::unique_ptr<ServerCompletionQueue>>>
  212. sync_server_cqs(std::make_shared<
  213. std::vector<std::unique_ptr<ServerCompletionQueue>>>());
  214. int num_frequently_polled_cqs = 0;
  215. for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
  216. if ((*it)->IsFrequentlyPolled()) {
  217. num_frequently_polled_cqs++;
  218. }
  219. }
  220. const bool is_hybrid_server =
  221. has_sync_methods && num_frequently_polled_cqs > 0;
  222. if (has_sync_methods) {
  223. grpc_cq_polling_type polling_type =
  224. is_hybrid_server ? GRPC_CQ_NON_POLLING : GRPC_CQ_DEFAULT_POLLING;
  225. // Create completion queues to listen to incoming rpc requests
  226. for (int i = 0; i < sync_server_settings_.num_cqs; i++) {
  227. sync_server_cqs->emplace_back(
  228. new ServerCompletionQueue(GRPC_CQ_NEXT, polling_type, nullptr));
  229. }
  230. }
  231. // == Determine if the server has any callback methods ==
  232. bool has_callback_methods = false;
  233. for (auto it = services_.begin(); it != services_.end(); ++it) {
  234. if ((*it)->service->has_callback_methods()) {
  235. has_callback_methods = true;
  236. break;
  237. }
  238. }
  239. // TODO(vjpai): Add a section here for plugins once they can support callback
  240. // methods
  241. if (has_sync_methods) {
  242. // This is a Sync server
  243. gpr_log(GPR_INFO,
  244. "Synchronous server. Num CQs: %d, Min pollers: %d, Max Pollers: "
  245. "%d, CQ timeout (msec): %d",
  246. sync_server_settings_.num_cqs, sync_server_settings_.min_pollers,
  247. sync_server_settings_.max_pollers,
  248. sync_server_settings_.cq_timeout_msec);
  249. }
  250. if (has_callback_methods) {
  251. gpr_log(GPR_INFO, "Callback server.");
  252. }
  253. std::unique_ptr<Server> server(new Server(
  254. max_receive_message_size_, &args, sync_server_cqs,
  255. sync_server_settings_.min_pollers, sync_server_settings_.max_pollers,
  256. sync_server_settings_.cq_timeout_msec, resource_quota_,
  257. std::move(interceptor_creators_)));
  258. ServerInitializer* initializer = server->initializer();
  259. // Register all the completion queues with the server. i.e
  260. // 1. sync_server_cqs: internal completion queues created IF this is a sync
  261. // server
  262. // 2. cqs_: Completion queues added via AddCompletionQueue() call
  263. for (auto it = sync_server_cqs->begin(); it != sync_server_cqs->end(); ++it) {
  264. grpc_server_register_completion_queue(server->server_, (*it)->cq(),
  265. nullptr);
  266. num_frequently_polled_cqs++;
  267. }
  268. if (has_callback_methods) {
  269. auto* cq = server->CallbackCQ();
  270. grpc_server_register_completion_queue(server->server_, cq->cq(), nullptr);
  271. num_frequently_polled_cqs++;
  272. }
  273. // cqs_ contains the completion queue added by calling the ServerBuilder's
  274. // AddCompletionQueue() API. Some of them may not be frequently polled (i.e by
  275. // calling Next() or AsyncNext()) and hence are not safe to be used for
  276. // listening to incoming channels. Such completion queues must be registered
  277. // as non-listening queues
  278. for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
  279. grpc_server_register_completion_queue(server->server_, (*it)->cq(),
  280. nullptr);
  281. }
  282. if (num_frequently_polled_cqs == 0) {
  283. gpr_log(GPR_ERROR,
  284. "At least one of the completion queues must be frequently polled");
  285. return nullptr;
  286. }
  287. for (auto service = services_.begin(); service != services_.end();
  288. service++) {
  289. if (!server->RegisterService((*service)->host.get(), (*service)->service)) {
  290. return nullptr;
  291. }
  292. }
  293. for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
  294. (*plugin)->InitServer(initializer);
  295. }
  296. if (generic_service_) {
  297. server->RegisterAsyncGenericService(generic_service_);
  298. } else {
  299. for (auto it = services_.begin(); it != services_.end(); ++it) {
  300. if ((*it)->service->has_generic_methods()) {
  301. gpr_log(GPR_ERROR,
  302. "Some methods were marked generic but there is no "
  303. "generic service registered.");
  304. return nullptr;
  305. }
  306. }
  307. }
  308. bool added_port = false;
  309. for (auto port = ports_.begin(); port != ports_.end(); port++) {
  310. int r = server->AddListeningPort(port->addr, port->creds.get());
  311. if (!r) {
  312. if (added_port) server->Shutdown();
  313. return nullptr;
  314. }
  315. added_port = true;
  316. if (port->selected_port != nullptr) {
  317. *port->selected_port = r;
  318. }
  319. }
  320. auto cqs_data = cqs_.empty() ? nullptr : &cqs_[0];
  321. server->Start(cqs_data, cqs_.size());
  322. for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
  323. (*plugin)->Finish(initializer);
  324. }
  325. return server;
  326. }
  327. void ServerBuilder::InternalAddPluginFactory(
  328. std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)()) {
  329. gpr_once_init(&once_init_plugin_list, do_plugin_list_init);
  330. (*g_plugin_factory_list).push_back(CreatePlugin);
  331. }
  332. ServerBuilder& ServerBuilder::EnableWorkaround(grpc_workaround_list id) {
  333. switch (id) {
  334. case GRPC_WORKAROUND_ID_CRONET_COMPRESSION:
  335. return AddChannelArgument(GRPC_ARG_WORKAROUND_CRONET_COMPRESSION, 1);
  336. default:
  337. gpr_log(GPR_ERROR, "Workaround %u does not exist or is obsolete.", id);
  338. return *this;
  339. }
  340. }
  341. } // namespace grpc