Merge branch 'master' of https://github.com/grpc/grpc into channel
commit
dffbe4a1eb
150 changed files with 3337 additions and 2132 deletions
@ -0,0 +1,100 @@ |
|||||||
|
[MASTER] |
||||||
|
ignore= |
||||||
|
src/python/grpcio/grpc/beta, |
||||||
|
src/python/grpcio/grpc/framework, |
||||||
|
src/python/grpcio/grpc/framework/common, |
||||||
|
src/python/grpcio/grpc/framework/foundation, |
||||||
|
src/python/grpcio/grpc/framework/interfaces, |
||||||
|
|
||||||
|
[VARIABLES] |
||||||
|
|
||||||
|
# TODO(https://github.com/PyCQA/pylint/issues/1345): How does the inspection |
||||||
|
# not include "unused_" and "ignored_" by default? |
||||||
|
dummy-variables-rgx=^ignored_|^unused_ |
||||||
|
|
||||||
|
[DESIGN] |
||||||
|
|
||||||
|
# NOTE(nathaniel): Not particularly attached to this value; it just seems to |
||||||
|
# be what works for us at the moment (excepting the dead-code-walking Beta |
||||||
|
# API). |
||||||
|
max-args=6 |
||||||
|
|
||||||
|
[MISCELLANEOUS] |
||||||
|
|
||||||
|
# NOTE(nathaniel): We are big fans of "TODO(<issue link>): " and |
||||||
|
# "NOTE(<username or issue link>): ". We do not allow "TODO:", |
||||||
|
# "TODO(<username>):", "FIXME:", or anything else. |
||||||
|
notes=FIXME,XXX |
||||||
|
|
||||||
|
[MESSAGES CONTROL] |
||||||
|
|
||||||
|
disable= |
||||||
|
# -- START OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||||
|
no-self-use, |
||||||
|
unused-argument, |
||||||
|
unused-variable, |
||||||
|
# -- END OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||||
|
|
||||||
|
# TODO(https://github.com/PyCQA/pylint/issues/59#issuecomment-283774279): |
||||||
|
# Enable cyclic-import after a 1.7-or-later pylint release that |
||||||
|
# recognizes our disable=cyclic-import suppressions. |
||||||
|
cyclic-import, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/8622): Enable this after the |
||||||
|
# Beta API is removed. |
||||||
|
duplicate-code, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't seem to |
||||||
|
# understand enum and concurrent.futures; look into this later with the |
||||||
|
# latest pylint version. |
||||||
|
import-error, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Enable this one. |
||||||
|
# Should take a little configuration but not much. |
||||||
|
invalid-name, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): This doesn't seem to |
||||||
|
# work for now? Try with a later pylint? |
||||||
|
locally-disabled, |
||||||
|
# NOTE(nathaniel): What even is this? *Enabling* an inspection results |
||||||
|
# in a warning? How does that encourage more analysis and coverage? |
||||||
|
locally-enabled, |
||||||
|
# NOTE(nathaniel): We don't write doc strings for most private code |
||||||
|
# elements. |
||||||
|
missing-docstring, |
||||||
|
# NOTE(nathaniel): In numeric comparisons it is better to have the |
||||||
|
# lesser (or lesser-or-equal-to) quantity on the left when the |
||||||
|
# expression is true than it is to worry about which is an identifier |
||||||
|
# and which a literal value. |
||||||
|
misplaced-comparison-constant, |
||||||
|
# NOTE(nathaniel): Our completely abstract interface classes don't have |
||||||
|
# constructors. |
||||||
|
no-init, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't yet play |
||||||
|
# nicely with some of our code being implemented in Cython. Maybe in a |
||||||
|
# later version? |
||||||
|
no-name-in-module, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Suppress these where |
||||||
|
# the odd shape of the authentication portion of the API forces them on |
||||||
|
# us and enable everywhere else. |
||||||
|
protected-access, |
||||||
|
# NOTE(nathaniel): Pylint and I will probably never agree on this. |
||||||
|
too-few-public-methods, |
||||||
|
# NOTE(nathaniel): Pylint and I wil probably never agree on this for |
||||||
|
# private classes. For public classes maybe? |
||||||
|
too-many-instance-attributes, |
||||||
|
# NOTE(nathaniel): Some of our modules have a lot of lines... of |
||||||
|
# specification and documentation. Maybe if this were |
||||||
|
# lines-of-code-based we would use it. |
||||||
|
too-many-lines, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have |
||||||
|
# this one if we extracted just a few more helper functions... |
||||||
|
too-many-nested-blocks, |
||||||
|
# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary |
||||||
|
# super-init requirement for abstract class implementations for now. |
||||||
|
super-init-not-called, |
||||||
|
# NOTE(nathaniel): A single statement that always returns program |
||||||
|
# control is better than two statements the first of which sometimes |
||||||
|
# returns program control and the second of which always returns |
||||||
|
# program control. Probably generally, but definitely in the cases of |
||||||
|
# if:/else: and for:/else:. |
||||||
|
useless-else-on-loop, |
||||||
|
no-else-return, |
||||||
|
# NOTE(lidiz): Python 3 make object inheritance default, but not PY2 |
||||||
|
useless-object-inheritance, |
@ -0,0 +1,134 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 gRPC 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 <map> |
||||||
|
|
||||||
|
#include <grpcpp/support/client_interceptor.h> |
||||||
|
|
||||||
|
#ifdef BAZEL_BUILD |
||||||
|
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||||
|
#else |
||||||
|
#include "keyvaluestore.grpc.pb.h" |
||||||
|
#endif |
||||||
|
|
||||||
|
// This is a naive implementation of a cache. A new cache is for each call. For
|
||||||
|
// each new key request, the key is first searched in the map and if found, the
|
||||||
|
// interceptor fills in the return value without making a request to the server.
|
||||||
|
// Only if the key is not found in the cache do we make a request.
|
||||||
|
class CachingInterceptor : public grpc::experimental::Interceptor { |
||||||
|
public: |
||||||
|
CachingInterceptor(grpc::experimental::ClientRpcInfo* info) {} |
||||||
|
|
||||||
|
void Intercept( |
||||||
|
::grpc::experimental::InterceptorBatchMethods* methods) override { |
||||||
|
bool hijack = false; |
||||||
|
if (methods->QueryInterceptionHookPoint( |
||||||
|
grpc::experimental::InterceptionHookPoints:: |
||||||
|
PRE_SEND_INITIAL_METADATA)) { |
||||||
|
// Hijack all calls
|
||||||
|
hijack = true; |
||||||
|
// Create a stream on which this interceptor can make requests
|
||||||
|
stub_ = keyvaluestore::KeyValueStore::NewStub( |
||||||
|
methods->GetInterceptedChannel()); |
||||||
|
stream_ = stub_->GetValues(&context_); |
||||||
|
} |
||||||
|
if (methods->QueryInterceptionHookPoint( |
||||||
|
grpc::experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) { |
||||||
|
// We know that clients perform a Read and a Write in a loop, so we don't
|
||||||
|
// need to maintain a list of the responses.
|
||||||
|
std::string requested_key; |
||||||
|
const keyvaluestore::Request* req_msg = |
||||||
|
static_cast<const keyvaluestore::Request*>(methods->GetSendMessage()); |
||||||
|
if (req_msg != nullptr) { |
||||||
|
requested_key = req_msg->key(); |
||||||
|
} else { |
||||||
|
// The non-serialized form would not be available in certain scenarios,
|
||||||
|
// so add a fallback
|
||||||
|
keyvaluestore::Request req_msg; |
||||||
|
auto* buffer = methods->GetSerializedSendMessage(); |
||||||
|
auto copied_buffer = *buffer; |
||||||
|
GPR_ASSERT( |
||||||
|
grpc::SerializationTraits<keyvaluestore::Request>::Deserialize( |
||||||
|
&copied_buffer, &req_msg) |
||||||
|
.ok()); |
||||||
|
requested_key = req_msg.key(); |
||||||
|
} |
||||||
|
|
||||||
|
// Check if the key is present in the map
|
||||||
|
auto search = cached_map_.find(requested_key); |
||||||
|
if (search != cached_map_.end()) { |
||||||
|
std::cout << "Key " << requested_key << "found in map"; |
||||||
|
response_ = search->second; |
||||||
|
} else { |
||||||
|
std::cout << "Key " << requested_key << "not found in cache"; |
||||||
|
// Key was not found in the cache, so make a request
|
||||||
|
keyvaluestore::Request req; |
||||||
|
req.set_key(requested_key); |
||||||
|
stream_->Write(req); |
||||||
|
keyvaluestore::Response resp; |
||||||
|
stream_->Read(&resp); |
||||||
|
response_ = resp.value(); |
||||||
|
// Insert the pair in the cache for future requests
|
||||||
|
cached_map_.insert({requested_key, response_}); |
||||||
|
} |
||||||
|
} |
||||||
|
if (methods->QueryInterceptionHookPoint( |
||||||
|
grpc::experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) { |
||||||
|
stream_->WritesDone(); |
||||||
|
} |
||||||
|
if (methods->QueryInterceptionHookPoint( |
||||||
|
grpc::experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) { |
||||||
|
keyvaluestore::Response* resp = |
||||||
|
static_cast<keyvaluestore::Response*>(methods->GetRecvMessage()); |
||||||
|
resp->set_value(response_); |
||||||
|
} |
||||||
|
if (methods->QueryInterceptionHookPoint( |
||||||
|
grpc::experimental::InterceptionHookPoints::PRE_RECV_STATUS)) { |
||||||
|
auto* status = methods->GetRecvStatus(); |
||||||
|
*status = grpc::Status::OK; |
||||||
|
} |
||||||
|
// One of Hijack or Proceed always needs to be called to make progress.
|
||||||
|
if (hijack) { |
||||||
|
// Hijack is called only once when PRE_SEND_INITIAL_METADATA is present in
|
||||||
|
// the hook points
|
||||||
|
methods->Hijack(); |
||||||
|
} else { |
||||||
|
// Proceed is an indicator that the interceptor is done intercepting the
|
||||||
|
// batch.
|
||||||
|
methods->Proceed(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
grpc::ClientContext context_; |
||||||
|
std::unique_ptr<keyvaluestore::KeyValueStore::Stub> stub_; |
||||||
|
std::unique_ptr< |
||||||
|
grpc::ClientReaderWriter<keyvaluestore::Request, keyvaluestore::Response>> |
||||||
|
stream_; |
||||||
|
std::map<std::string, std::string> cached_map_; |
||||||
|
std::string response_; |
||||||
|
}; |
||||||
|
|
||||||
|
class CachingInterceptorFactory |
||||||
|
: public grpc::experimental::ClientInterceptorFactoryInterface { |
||||||
|
public: |
||||||
|
grpc::experimental::Interceptor* CreateClientInterceptor( |
||||||
|
grpc::experimental::ClientRpcInfo* info) override { |
||||||
|
return new CachingInterceptor(info); |
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,177 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2018 gRPC 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/global_subchannel_pool.h" |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/subchannel.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
GlobalSubchannelPool::GlobalSubchannelPool() { |
||||||
|
subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_); |
||||||
|
gpr_mu_init(&mu_); |
||||||
|
} |
||||||
|
|
||||||
|
GlobalSubchannelPool::~GlobalSubchannelPool() { |
||||||
|
gpr_mu_destroy(&mu_); |
||||||
|
grpc_avl_unref(subchannel_map_, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
void GlobalSubchannelPool::Init() { |
||||||
|
instance_ = New<RefCountedPtr<GlobalSubchannelPool>>( |
||||||
|
MakeRefCounted<GlobalSubchannelPool>()); |
||||||
|
} |
||||||
|
|
||||||
|
void GlobalSubchannelPool::Shutdown() { |
||||||
|
// To ensure Init() was called before.
|
||||||
|
GPR_ASSERT(instance_ != nullptr); |
||||||
|
// To ensure Shutdown() was not called before.
|
||||||
|
GPR_ASSERT(*instance_ != nullptr); |
||||||
|
instance_->reset(); |
||||||
|
Delete(instance_); |
||||||
|
} |
||||||
|
|
||||||
|
RefCountedPtr<GlobalSubchannelPool> GlobalSubchannelPool::instance() { |
||||||
|
GPR_ASSERT(instance_ != nullptr); |
||||||
|
GPR_ASSERT(*instance_ != nullptr); |
||||||
|
return *instance_; |
||||||
|
} |
||||||
|
|
||||||
|
grpc_subchannel* GlobalSubchannelPool::RegisterSubchannel( |
||||||
|
SubchannelKey* key, grpc_subchannel* constructed) { |
||||||
|
grpc_subchannel* c = nullptr; |
||||||
|
// Compare and swap (CAS) loop:
|
||||||
|
while (c == nullptr) { |
||||||
|
// Ref the shared map to have a local copy.
|
||||||
|
gpr_mu_lock(&mu_); |
||||||
|
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
||||||
|
gpr_mu_unlock(&mu_); |
||||||
|
// Check to see if a subchannel already exists.
|
||||||
|
c = static_cast<grpc_subchannel*>(grpc_avl_get(old_map, key, nullptr)); |
||||||
|
if (c != nullptr) { |
||||||
|
// The subchannel already exists. Reuse it.
|
||||||
|
c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "subchannel_register+reuse"); |
||||||
|
GRPC_SUBCHANNEL_UNREF(constructed, "subchannel_register+found_existing"); |
||||||
|
// Exit the CAS loop without modifying the shared map.
|
||||||
|
} else { |
||||||
|
// There hasn't been such subchannel. Add one.
|
||||||
|
// Note that we should ref the old map first because grpc_avl_add() will
|
||||||
|
// unref it while we still need to access it later.
|
||||||
|
grpc_avl new_map = grpc_avl_add( |
||||||
|
grpc_avl_ref(old_map, nullptr), New<SubchannelKey>(*key), |
||||||
|
GRPC_SUBCHANNEL_WEAK_REF(constructed, "subchannel_register+new"), |
||||||
|
nullptr); |
||||||
|
// Try to publish the change to the shared map. It may happen (but
|
||||||
|
// unlikely) that some other thread has changed the shared map, so compare
|
||||||
|
// to make sure it's unchanged before swapping. Retry if it's changed.
|
||||||
|
gpr_mu_lock(&mu_); |
||||||
|
if (old_map.root == subchannel_map_.root) { |
||||||
|
GPR_SWAP(grpc_avl, new_map, subchannel_map_); |
||||||
|
c = constructed; |
||||||
|
} |
||||||
|
gpr_mu_unlock(&mu_); |
||||||
|
grpc_avl_unref(new_map, nullptr); |
||||||
|
} |
||||||
|
grpc_avl_unref(old_map, nullptr); |
||||||
|
} |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
void GlobalSubchannelPool::UnregisterSubchannel(SubchannelKey* key) { |
||||||
|
bool done = false; |
||||||
|
// Compare and swap (CAS) loop:
|
||||||
|
while (!done) { |
||||||
|
// Ref the shared map to have a local copy.
|
||||||
|
gpr_mu_lock(&mu_); |
||||||
|
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
||||||
|
gpr_mu_unlock(&mu_); |
||||||
|
// Remove the subchannel.
|
||||||
|
// Note that we should ref the old map first because grpc_avl_remove() will
|
||||||
|
// unref it while we still need to access it later.
|
||||||
|
grpc_avl new_map = |
||||||
|
grpc_avl_remove(grpc_avl_ref(old_map, nullptr), key, nullptr); |
||||||
|
// Try to publish the change to the shared map. It may happen (but
|
||||||
|
// unlikely) that some other thread has changed the shared map, so compare
|
||||||
|
// to make sure it's unchanged before swapping. Retry if it's changed.
|
||||||
|
gpr_mu_lock(&mu_); |
||||||
|
if (old_map.root == subchannel_map_.root) { |
||||||
|
GPR_SWAP(grpc_avl, new_map, subchannel_map_); |
||||||
|
done = true; |
||||||
|
} |
||||||
|
gpr_mu_unlock(&mu_); |
||||||
|
grpc_avl_unref(new_map, nullptr); |
||||||
|
grpc_avl_unref(old_map, nullptr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
grpc_subchannel* GlobalSubchannelPool::FindSubchannel(SubchannelKey* key) { |
||||||
|
// Lock, and take a reference to the subchannel map.
|
||||||
|
// We don't need to do the search under a lock as AVL's are immutable.
|
||||||
|
gpr_mu_lock(&mu_); |
||||||
|
grpc_avl index = grpc_avl_ref(subchannel_map_, nullptr); |
||||||
|
gpr_mu_unlock(&mu_); |
||||||
|
grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF( |
||||||
|
static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr)), |
||||||
|
"found_from_pool"); |
||||||
|
grpc_avl_unref(index, nullptr); |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
RefCountedPtr<GlobalSubchannelPool>* GlobalSubchannelPool::instance_ = nullptr; |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
void sck_avl_destroy(void* p, void* user_data) { |
||||||
|
SubchannelKey* key = static_cast<SubchannelKey*>(p); |
||||||
|
Delete(key); |
||||||
|
} |
||||||
|
|
||||||
|
void* sck_avl_copy(void* p, void* unused) { |
||||||
|
const SubchannelKey* key = static_cast<const SubchannelKey*>(p); |
||||||
|
auto* new_key = New<SubchannelKey>(*key); |
||||||
|
return static_cast<void*>(new_key); |
||||||
|
} |
||||||
|
|
||||||
|
long sck_avl_compare(void* a, void* b, void* unused) { |
||||||
|
const SubchannelKey* key_a = static_cast<const SubchannelKey*>(a); |
||||||
|
const SubchannelKey* key_b = static_cast<const SubchannelKey*>(b); |
||||||
|
return key_a->Cmp(*key_b); |
||||||
|
} |
||||||
|
|
||||||
|
void scv_avl_destroy(void* p, void* user_data) { |
||||||
|
GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "global_subchannel_pool"); |
||||||
|
} |
||||||
|
|
||||||
|
void* scv_avl_copy(void* p, void* unused) { |
||||||
|
GRPC_SUBCHANNEL_WEAK_REF((grpc_subchannel*)p, "global_subchannel_pool"); |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const grpc_avl_vtable GlobalSubchannelPool::subchannel_avl_vtable_ = { |
||||||
|
sck_avl_destroy, // destroy_key
|
||||||
|
sck_avl_copy, // copy_key
|
||||||
|
sck_avl_compare, // compare_keys
|
||||||
|
scv_avl_destroy, // destroy_value
|
||||||
|
scv_avl_copy // copy_value
|
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,68 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 gRPC 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// The global subchannel pool. It shares subchannels among channels. There
|
||||||
|
// should be only one instance of this class. Init() should be called once at
|
||||||
|
// the filter initialization time; Shutdown() should be called once at the
|
||||||
|
// filter shutdown time.
|
||||||
|
// TODO(juanlishen): Enable subchannel retention.
|
||||||
|
class GlobalSubchannelPool final : public SubchannelPoolInterface { |
||||||
|
public: |
||||||
|
// The ctor and dtor are not intended to use directly.
|
||||||
|
GlobalSubchannelPool(); |
||||||
|
~GlobalSubchannelPool() override; |
||||||
|
|
||||||
|
// Should be called exactly once at filter initialization time.
|
||||||
|
static void Init(); |
||||||
|
// Should be called exactly once at filter shutdown time.
|
||||||
|
static void Shutdown(); |
||||||
|
|
||||||
|
// Gets the singleton instance.
|
||||||
|
static RefCountedPtr<GlobalSubchannelPool> instance(); |
||||||
|
|
||||||
|
// Implements interface methods.
|
||||||
|
grpc_subchannel* RegisterSubchannel(SubchannelKey* key, |
||||||
|
grpc_subchannel* constructed) override; |
||||||
|
void UnregisterSubchannel(SubchannelKey* key) override; |
||||||
|
grpc_subchannel* FindSubchannel(SubchannelKey* key) override; |
||||||
|
|
||||||
|
private: |
||||||
|
// The singleton instance. (It's a pointer to RefCountedPtr so that this
|
||||||
|
// non-local static object can be trivially destructible.)
|
||||||
|
static RefCountedPtr<GlobalSubchannelPool>* instance_; |
||||||
|
|
||||||
|
// The vtable for subchannel operations in an AVL tree.
|
||||||
|
static const grpc_avl_vtable subchannel_avl_vtable_; |
||||||
|
// A map from subchannel key to subchannel.
|
||||||
|
grpc_avl subchannel_map_; |
||||||
|
// To protect subchannel_map_.
|
||||||
|
gpr_mu mu_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H */ |
@ -0,0 +1,96 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2018 gRPC 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/local_subchannel_pool.h" |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/subchannel.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
LocalSubchannelPool::LocalSubchannelPool() { |
||||||
|
subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_); |
||||||
|
} |
||||||
|
|
||||||
|
LocalSubchannelPool::~LocalSubchannelPool() { |
||||||
|
grpc_avl_unref(subchannel_map_, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_subchannel* LocalSubchannelPool::RegisterSubchannel( |
||||||
|
SubchannelKey* key, grpc_subchannel* constructed) { |
||||||
|
// Check to see if a subchannel already exists.
|
||||||
|
grpc_subchannel* c = static_cast<grpc_subchannel*>( |
||||||
|
grpc_avl_get(subchannel_map_, key, nullptr)); |
||||||
|
if (c != nullptr) { |
||||||
|
// The subchannel already exists. Reuse it.
|
||||||
|
c = GRPC_SUBCHANNEL_REF(c, "subchannel_register+reuse"); |
||||||
|
GRPC_SUBCHANNEL_UNREF(constructed, "subchannel_register+found_existing"); |
||||||
|
} else { |
||||||
|
// There hasn't been such subchannel. Add one.
|
||||||
|
subchannel_map_ = grpc_avl_add(subchannel_map_, New<SubchannelKey>(*key), |
||||||
|
constructed, nullptr); |
||||||
|
c = constructed; |
||||||
|
} |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
void LocalSubchannelPool::UnregisterSubchannel(SubchannelKey* key) { |
||||||
|
subchannel_map_ = grpc_avl_remove(subchannel_map_, key, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_subchannel* LocalSubchannelPool::FindSubchannel(SubchannelKey* key) { |
||||||
|
grpc_subchannel* c = static_cast<grpc_subchannel*>( |
||||||
|
grpc_avl_get(subchannel_map_, key, nullptr)); |
||||||
|
return c == nullptr ? c : GRPC_SUBCHANNEL_REF(c, "found_from_pool"); |
||||||
|
} |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
void sck_avl_destroy(void* p, void* user_data) { |
||||||
|
SubchannelKey* key = static_cast<SubchannelKey*>(p); |
||||||
|
Delete(key); |
||||||
|
} |
||||||
|
|
||||||
|
void* sck_avl_copy(void* p, void* unused) { |
||||||
|
const SubchannelKey* key = static_cast<const SubchannelKey*>(p); |
||||||
|
auto new_key = New<SubchannelKey>(*key); |
||||||
|
return static_cast<void*>(new_key); |
||||||
|
} |
||||||
|
|
||||||
|
long sck_avl_compare(void* a, void* b, void* unused) { |
||||||
|
const SubchannelKey* key_a = static_cast<const SubchannelKey*>(a); |
||||||
|
const SubchannelKey* key_b = static_cast<const SubchannelKey*>(b); |
||||||
|
return key_a->Cmp(*key_b); |
||||||
|
} |
||||||
|
|
||||||
|
void scv_avl_destroy(void* p, void* user_data) {} |
||||||
|
|
||||||
|
void* scv_avl_copy(void* p, void* unused) { return p; } |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const grpc_avl_vtable LocalSubchannelPool::subchannel_avl_vtable_ = { |
||||||
|
sck_avl_destroy, // destroy_key
|
||||||
|
sck_avl_copy, // copy_key
|
||||||
|
sck_avl_compare, // compare_keys
|
||||||
|
scv_avl_destroy, // destroy_value
|
||||||
|
scv_avl_copy // copy_value
|
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,56 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 gRPC 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LOCAL_SUBCHANNEL_POOL_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LOCAL_SUBCHANNEL_POOL_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// The local subchannel pool that is owned by a single channel. It doesn't
|
||||||
|
// support subchannel sharing with other channels by nature. Nor does it support
|
||||||
|
// subchannel retention when a subchannel is not used. The only real purpose of
|
||||||
|
// using this subchannel pool is to allow subchannel reuse within the channel
|
||||||
|
// when an incoming resolver update contains some addresses for which the
|
||||||
|
// channel has already created subchannels.
|
||||||
|
// Thread-unsafe.
|
||||||
|
class LocalSubchannelPool final : public SubchannelPoolInterface { |
||||||
|
public: |
||||||
|
LocalSubchannelPool(); |
||||||
|
~LocalSubchannelPool() override; |
||||||
|
|
||||||
|
// Implements interface methods.
|
||||||
|
// Thread-unsafe. Intended to be invoked within the client_channel combiner.
|
||||||
|
grpc_subchannel* RegisterSubchannel(SubchannelKey* key, |
||||||
|
grpc_subchannel* constructed) override; |
||||||
|
void UnregisterSubchannel(SubchannelKey* key) override; |
||||||
|
grpc_subchannel* FindSubchannel(SubchannelKey* key) override; |
||||||
|
|
||||||
|
private: |
||||||
|
// The vtable for subchannel operations in an AVL tree.
|
||||||
|
static const grpc_avl_vtable subchannel_avl_vtable_; |
||||||
|
// A map from subchannel key to subchannel.
|
||||||
|
grpc_avl subchannel_map_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LOCAL_SUBCHANNEL_POOL_H */ |
@ -0,0 +1,97 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// Copyright 2018 gRPC 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" |
||||||
|
|
||||||
|
#include "src/core/lib/gpr/useful.h" |
||||||
|
|
||||||
|
// The subchannel pool to reuse subchannels.
|
||||||
|
#define GRPC_ARG_SUBCHANNEL_POOL "grpc.subchannel_pool" |
||||||
|
// The subchannel key ID that is only used in test to make each key unique.
|
||||||
|
#define GRPC_ARG_SUBCHANNEL_KEY_TEST_ONLY_ID "grpc.subchannel_key_test_only_id" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
TraceFlag grpc_subchannel_pool_trace(false, "subchannel_pool"); |
||||||
|
|
||||||
|
SubchannelKey::SubchannelKey(const grpc_channel_args* args) { |
||||||
|
Init(args, grpc_channel_args_normalize); |
||||||
|
} |
||||||
|
|
||||||
|
SubchannelKey::~SubchannelKey() { |
||||||
|
grpc_channel_args_destroy(const_cast<grpc_channel_args*>(args_)); |
||||||
|
} |
||||||
|
|
||||||
|
SubchannelKey::SubchannelKey(const SubchannelKey& other) { |
||||||
|
Init(other.args_, grpc_channel_args_copy); |
||||||
|
} |
||||||
|
|
||||||
|
SubchannelKey& SubchannelKey::operator=(const SubchannelKey& other) { |
||||||
|
grpc_channel_args_destroy(const_cast<grpc_channel_args*>(args_)); |
||||||
|
Init(other.args_, grpc_channel_args_copy); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
int SubchannelKey::Cmp(const SubchannelKey& other) const { |
||||||
|
return grpc_channel_args_compare(args_, other.args_); |
||||||
|
} |
||||||
|
|
||||||
|
void SubchannelKey::Init( |
||||||
|
const grpc_channel_args* args, |
||||||
|
grpc_channel_args* (*copy_channel_args)(const grpc_channel_args* args)) { |
||||||
|
args_ = copy_channel_args(args); |
||||||
|
} |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
void* arg_copy(void* p) { |
||||||
|
auto* subchannel_pool = static_cast<SubchannelPoolInterface*>(p); |
||||||
|
subchannel_pool->Ref().release(); |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
void arg_destroy(void* p) { |
||||||
|
auto* subchannel_pool = static_cast<SubchannelPoolInterface*>(p); |
||||||
|
subchannel_pool->Unref(); |
||||||
|
} |
||||||
|
|
||||||
|
int arg_cmp(void* a, void* b) { return GPR_ICMP(a, b); } |
||||||
|
|
||||||
|
const grpc_arg_pointer_vtable subchannel_pool_arg_vtable = { |
||||||
|
arg_copy, arg_destroy, arg_cmp}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
grpc_arg SubchannelPoolInterface::CreateChannelArg( |
||||||
|
SubchannelPoolInterface* subchannel_pool) { |
||||||
|
return grpc_channel_arg_pointer_create( |
||||||
|
const_cast<char*>(GRPC_ARG_SUBCHANNEL_POOL), subchannel_pool, |
||||||
|
&subchannel_pool_arg_vtable); |
||||||
|
} |
||||||
|
|
||||||
|
SubchannelPoolInterface* |
||||||
|
SubchannelPoolInterface::GetSubchannelPoolFromChannelArgs( |
||||||
|
const grpc_channel_args* args) { |
||||||
|
const grpc_arg* arg = grpc_channel_args_find(args, GRPC_ARG_SUBCHANNEL_POOL); |
||||||
|
if (arg == nullptr || arg->type != GRPC_ARG_POINTER) return nullptr; |
||||||
|
return static_cast<SubchannelPoolInterface*>(arg->value.pointer.p); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,94 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 gRPC 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_POOL_INTERFACE_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_POOL_INTERFACE_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/avl/avl.h" |
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
#include "src/core/lib/gprpp/abstract.h" |
||||||
|
#include "src/core/lib/gprpp/ref_counted.h" |
||||||
|
|
||||||
|
struct grpc_subchannel; |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
extern TraceFlag grpc_subchannel_pool_trace; |
||||||
|
|
||||||
|
// A key that can uniquely identify a subchannel.
|
||||||
|
class SubchannelKey { |
||||||
|
public: |
||||||
|
explicit SubchannelKey(const grpc_channel_args* args); |
||||||
|
~SubchannelKey(); |
||||||
|
|
||||||
|
// Copyable.
|
||||||
|
SubchannelKey(const SubchannelKey& other); |
||||||
|
SubchannelKey& operator=(const SubchannelKey& other); |
||||||
|
// Not movable.
|
||||||
|
SubchannelKey(SubchannelKey&&) = delete; |
||||||
|
SubchannelKey& operator=(SubchannelKey&&) = delete; |
||||||
|
|
||||||
|
int Cmp(const SubchannelKey& other) const; |
||||||
|
|
||||||
|
private: |
||||||
|
// Initializes the subchannel key with the given \a args and the function to
|
||||||
|
// copy channel args.
|
||||||
|
void Init( |
||||||
|
const grpc_channel_args* args, |
||||||
|
grpc_channel_args* (*copy_channel_args)(const grpc_channel_args* args)); |
||||||
|
|
||||||
|
const grpc_channel_args* args_; |
||||||
|
}; |
||||||
|
|
||||||
|
// Interface for subchannel pool.
|
||||||
|
// TODO(juanlishen): This refcounting mechanism may lead to memory leak.
|
||||||
|
// To solve that, we should force polling to flush any pending callbacks, then
|
||||||
|
// shut down safely. See https://github.com/grpc/grpc/issues/12560.
|
||||||
|
class SubchannelPoolInterface : public RefCounted<SubchannelPoolInterface> { |
||||||
|
public: |
||||||
|
SubchannelPoolInterface() : RefCounted(&grpc_subchannel_pool_trace) {} |
||||||
|
virtual ~SubchannelPoolInterface() {} |
||||||
|
|
||||||
|
// Registers a subchannel against a key. Returns the subchannel registered
|
||||||
|
// with \a key, which may be different from \a constructed because we reuse
|
||||||
|
// (instead of update) any existing subchannel already registered with \a key.
|
||||||
|
virtual grpc_subchannel* RegisterSubchannel( |
||||||
|
SubchannelKey* key, grpc_subchannel* constructed) GRPC_ABSTRACT; |
||||||
|
|
||||||
|
// Removes the registered subchannel found by \a key.
|
||||||
|
virtual void UnregisterSubchannel(SubchannelKey* key) GRPC_ABSTRACT; |
||||||
|
|
||||||
|
// Finds the subchannel registered for the given subchannel key. Returns NULL
|
||||||
|
// if no such channel exists. Thread-safe.
|
||||||
|
virtual grpc_subchannel* FindSubchannel(SubchannelKey* key) GRPC_ABSTRACT; |
||||||
|
|
||||||
|
// Creates a channel arg from \a subchannel pool.
|
||||||
|
static grpc_arg CreateChannelArg(SubchannelPoolInterface* subchannel_pool); |
||||||
|
|
||||||
|
// Gets the subchannel pool from the channel args.
|
||||||
|
static SubchannelPoolInterface* GetSubchannelPoolFromChannelArgs( |
||||||
|
const grpc_channel_args* args); |
||||||
|
|
||||||
|
GRPC_ABSTRACT_BASE_CLASS |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_POOL_INTERFACE_H */ |
@ -0,0 +1,47 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2019 gRPC 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_GPRPP_OPTIONAL_H |
||||||
|
#define GRPC_CORE_LIB_GPRPP_OPTIONAL_H |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
/* A make-shift alternative for absl::Optional. This can be removed in favor of
|
||||||
|
* that once absl dependencies can be introduced. */ |
||||||
|
template <typename T> |
||||||
|
class Optional { |
||||||
|
public: |
||||||
|
void set(const T& val) { |
||||||
|
value_ = val; |
||||||
|
set_ = true; |
||||||
|
} |
||||||
|
|
||||||
|
bool has_value() { return set_; } |
||||||
|
|
||||||
|
void reset() { set_ = false; } |
||||||
|
|
||||||
|
T value() { return value_; } |
||||||
|
|
||||||
|
private: |
||||||
|
T value_; |
||||||
|
bool set_ = false; |
||||||
|
}; |
||||||
|
|
||||||
|
} /* namespace grpc_core */ |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_LIB_GPRPP_OPTIONAL_H */ |
@ -1,36 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* Copyright 2015 gRPC 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 <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/endpoint.h" |
|
||||||
#include "src/core/lib/iomgr/network_status_tracker.h" |
|
||||||
|
|
||||||
void grpc_network_status_shutdown(void) {} |
|
||||||
|
|
||||||
void grpc_network_status_init(void) { |
|
||||||
// TODO(makarandd): Install callback with OS to monitor network status.
|
|
||||||
} |
|
||||||
|
|
||||||
void grpc_destroy_network_status_monitor() {} |
|
||||||
|
|
||||||
void grpc_network_status_register_endpoint(grpc_endpoint* ep) { (void)ep; } |
|
||||||
|
|
||||||
void grpc_network_status_unregister_endpoint(grpc_endpoint* ep) { (void)ep; } |
|
||||||
|
|
||||||
void grpc_network_status_shutdown_all_endpoints() {} |
|
@ -0,0 +1,110 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
|
||||||
|
// Copyright 2019 The gRPC 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. |
||||||
|
|
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
|
||||||
|
using Grpc.Core.Internal; |
||||||
|
|
||||||
|
namespace Grpc.Core |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Default implementation of <c>ServerCallContext</c>. |
||||||
|
/// </summary> |
||||||
|
internal class DefaultServerCallContext : ServerCallContext |
||||||
|
{ |
||||||
|
private readonly CallSafeHandle callHandle; |
||||||
|
private readonly string method; |
||||||
|
private readonly string host; |
||||||
|
private readonly DateTime deadline; |
||||||
|
private readonly Metadata requestHeaders; |
||||||
|
private readonly CancellationToken cancellationToken; |
||||||
|
private readonly Metadata responseTrailers; |
||||||
|
private Status status; |
||||||
|
private readonly IServerResponseStream serverResponseStream; |
||||||
|
private readonly Lazy<AuthContext> authContext; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Creates a new instance of <c>ServerCallContext</c>. |
||||||
|
/// To allow reuse of ServerCallContext API by different gRPC implementations, the implementation of some members is provided externally. |
||||||
|
/// To provide state, this <c>ServerCallContext</c> instance and <c>extraData</c> will be passed to the member implementations. |
||||||
|
/// </summary> |
||||||
|
internal DefaultServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline, |
||||||
|
Metadata requestHeaders, CancellationToken cancellationToken, IServerResponseStream serverResponseStream) |
||||||
|
{ |
||||||
|
this.callHandle = callHandle; |
||||||
|
this.method = method; |
||||||
|
this.host = host; |
||||||
|
this.deadline = deadline; |
||||||
|
this.requestHeaders = requestHeaders; |
||||||
|
this.cancellationToken = cancellationToken; |
||||||
|
this.responseTrailers = new Metadata(); |
||||||
|
this.status = Status.DefaultSuccess; |
||||||
|
this.serverResponseStream = serverResponseStream; |
||||||
|
// TODO(jtattermusch): avoid unnecessary allocation of factory function and the lazy object |
||||||
|
this.authContext = new Lazy<AuthContext>(GetAuthContextEager); |
||||||
|
} |
||||||
|
|
||||||
|
protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions options) |
||||||
|
{ |
||||||
|
return new ContextPropagationToken(callHandle, deadline, cancellationToken, options); |
||||||
|
} |
||||||
|
|
||||||
|
protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) |
||||||
|
{ |
||||||
|
return serverResponseStream.WriteResponseHeadersAsync(responseHeaders); |
||||||
|
} |
||||||
|
|
||||||
|
protected override string MethodCore => method; |
||||||
|
|
||||||
|
protected override string HostCore => host; |
||||||
|
|
||||||
|
protected override string PeerCore => callHandle.GetPeer(); |
||||||
|
|
||||||
|
protected override DateTime DeadlineCore => deadline; |
||||||
|
|
||||||
|
protected override Metadata RequestHeadersCore => requestHeaders; |
||||||
|
|
||||||
|
protected override CancellationToken CancellationTokenCore => cancellationToken; |
||||||
|
|
||||||
|
protected override Metadata ResponseTrailersCore => responseTrailers; |
||||||
|
|
||||||
|
protected override Status StatusCore |
||||||
|
{ |
||||||
|
get => status; |
||||||
|
set => status = value; |
||||||
|
} |
||||||
|
|
||||||
|
protected override WriteOptions WriteOptionsCore |
||||||
|
{ |
||||||
|
get => serverResponseStream.WriteOptions; |
||||||
|
set => serverResponseStream.WriteOptions = value; |
||||||
|
} |
||||||
|
|
||||||
|
protected override AuthContext AuthContextCore => authContext.Value; |
||||||
|
|
||||||
|
private AuthContext GetAuthContextEager() |
||||||
|
{ |
||||||
|
using (var authContextNative = callHandle.GetAuthContext()) |
||||||
|
{ |
||||||
|
return authContextNative.ToAuthContext(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
#region Copyright notice and license |
||||||
|
// Copyright 2019 The gRPC 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. |
||||||
|
#endregion |
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Grpc.Core.Internal; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Exposes non-generic members of <c>ServerReponseStream</c>. |
||||||
|
/// </summary> |
||||||
|
internal interface IServerResponseStream |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Asynchronously sends response headers for the current call to the client. See <c>ServerCallContext.WriteResponseHeadersAsync</c> for exact semantics. |
||||||
|
/// </summary> |
||||||
|
Task WriteResponseHeadersAsync(Metadata responseHeaders); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the write options. |
||||||
|
/// </summary> |
||||||
|
WriteOptions WriteOptions { get; set; } |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
../../../LICENSE |
@ -0,0 +1 @@ |
|||||||
|
../../../LICENSE |
@ -0,0 +1 @@ |
|||||||
|
../../../LICENSE |
@ -0,0 +1 @@ |
|||||||
|
../../../LICENSE |
@ -1,39 +0,0 @@ |
|||||||
# Copyright 2018 The gRPC 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. |
|
||||||
"""Provides distutils command classes for the GRPC Python setup process.""" |
|
||||||
|
|
||||||
import os |
|
||||||
import shutil |
|
||||||
|
|
||||||
import setuptools |
|
||||||
|
|
||||||
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) |
|
||||||
LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') |
|
||||||
|
|
||||||
|
|
||||||
class Preprocess(setuptools.Command): |
|
||||||
"""Command to copy LICENSE from root directory.""" |
|
||||||
|
|
||||||
description = '' |
|
||||||
user_options = [] |
|
||||||
|
|
||||||
def initialize_options(self): |
|
||||||
pass |
|
||||||
|
|
||||||
def finalize_options(self): |
|
||||||
pass |
|
||||||
|
|
||||||
def run(self): |
|
||||||
if os.path.isfile(LICENSE): |
|
||||||
shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) |
|
@ -0,0 +1 @@ |
|||||||
|
../../../LICENSE |
@ -1,39 +0,0 @@ |
|||||||
# Copyright 2018 gRPC 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. |
|
||||||
"""Provides distutils command classes for the GRPC Python setup process.""" |
|
||||||
|
|
||||||
import os |
|
||||||
import shutil |
|
||||||
|
|
||||||
import setuptools |
|
||||||
|
|
||||||
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) |
|
||||||
LICENSE = os.path.join(ROOT_DIR, '../../../LICENSE') |
|
||||||
|
|
||||||
|
|
||||||
class Preprocess(setuptools.Command): |
|
||||||
"""Command to copy LICENSE from root directory.""" |
|
||||||
|
|
||||||
description = '' |
|
||||||
user_options = [] |
|
||||||
|
|
||||||
def initialize_options(self): |
|
||||||
pass |
|
||||||
|
|
||||||
def finalize_options(self): |
|
||||||
pass |
|
||||||
|
|
||||||
def run(self): |
|
||||||
if os.path.isfile(LICENSE): |
|
||||||
shutil.copyfile(LICENSE, os.path.join(ROOT_DIR, 'LICENSE')) |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue