mirror of https://github.com/grpc/grpc.git
commit
c5423beeb8
373 changed files with 13574 additions and 5352 deletions
@ -0,0 +1,15 @@ |
||||
There are times when we make changes that include a temporary shim for |
||||
backward-compatibility (e.g., a macro or some other function to preserve |
||||
the original API) to avoid having to bump the major version number in |
||||
the next release. However, when we do eventually want to release a |
||||
feature that does change the API in a non-backward-compatible way, we |
||||
will wind up bumping the major version number anyway, at which point we |
||||
can take the opportunity to clean up any pending backward-compatibility |
||||
shims. |
||||
|
||||
This file lists all pending backward-compatibility changes that should |
||||
be cleaned up the next time we are going to bump the major version |
||||
number: |
||||
|
||||
- remove `GRPC_ARG_MAX_MESSAGE_LENGTH` channel arg from |
||||
`include/grpc/impl/codegen/grpc_types.h` (commit `af00d8b`) |
@ -0,0 +1,64 @@ |
||||
gRPC environment variables |
||||
-------------------------- |
||||
|
||||
gRPC C core based implementations (those contained in this repository) expose |
||||
some configuration as environment variables that can be set. |
||||
|
||||
* GRPC_ABORT_ON_LEAKS |
||||
A debugging aid to cause a call to abort() when gRPC objects are leaked past |
||||
grpc_shutdown(). Set to 1 to cause the abort, if unset or 0 it does not |
||||
abort the process. |
||||
|
||||
* GRPC_GOOGLE_CREDENTIALS_ENV_VAR |
||||
The path to find the credentials to use when Google credentials are created |
||||
|
||||
* GRPC_SSL_CIPHER_SUITES |
||||
A colon separated list of cipher suites to use with OpenSSL |
||||
Defaults to: |
||||
ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-GCM-SHA384 |
||||
|
||||
* GRPC_POLL_STRATEGY [posix-style environments only] |
||||
Declares which polling engines to try when starting gRPC. |
||||
This is a comma-separated list of engines, which are tried in priority order |
||||
first -> last. |
||||
Available polling engines include: |
||||
- epoll (linux-only) - a polling engine based around the epoll family of |
||||
system calls |
||||
- poll - a portable polling engine based around poll(), intended to be a |
||||
fallback engine when nothing better exists |
||||
- legacy - the (deprecated) original polling engine for gRPC |
||||
|
||||
* GRPC_TRACE |
||||
A comma separated list of tracers that provide additional insight into how |
||||
gRPC C core is processing requests via debug logs. Available tracers include: |
||||
- api - traces api calls to the C core |
||||
- channel - traces operations on the C core channel stack |
||||
- combiner - traces combiner lock state |
||||
- compression - traces compression operations |
||||
- connectivity_state - traces connectivity state changes to channels |
||||
- channel_stack_builder - traces information about channel stacks being built |
||||
- http - traces state in the http2 transport engine |
||||
- http1 - traces HTTP/1.x operations performed by gRPC |
||||
- flowctl - traces http2 flow control |
||||
- op_failure - traces error information when failure is pushed onto a |
||||
completion queue |
||||
- pending_tags - [debug builds only] traces still-in-progress tags on |
||||
completion queues |
||||
- round_robin - traces the round_robin load balancing policy |
||||
- glb - traces the grpclb load balancer |
||||
- queue_pluck |
||||
- queue_timeout |
||||
- server_channel - lightweight trace of significant server channel events |
||||
- secure_endpoint - traces bytes flowing through encrypted channels |
||||
- transport_security - traces metadata about secure channel establishment |
||||
- tcp - traces bytes in and out of a channel |
||||
'all' can additionally be used to turn all traces on. |
||||
Individual traces can be disabled by prefixing them with '-'. |
||||
Example: |
||||
export GRPC_TRACE=all,-pending_tags |
||||
|
||||
* GRPC_VERBOSITY |
||||
Default gRPC logging verbosity - one of: |
||||
- DEBUG - log all gRPC messages |
||||
- INFO - log INFO and ERROR message |
||||
- ERROR - log only errors |
@ -0,0 +1,30 @@ |
||||
# HTTP to gRPC Status Code Mapping |
||||
|
||||
Since intermediaries are a common part of HTTP infrastructure some responses to |
||||
gRPC requests may be received that do not include the grpc-status header. In |
||||
some cases mapping error codes from an intermediary allows the gRPC client to |
||||
behave more appropriately to the error situation without overloading the |
||||
semantics of either error code. |
||||
|
||||
This table is to be used _only_ for clients that received a response that did |
||||
not include grpc-status. If grpc-status was provided, it _must_ be used. Servers |
||||
_must not_ use this table to determine an HTTP status code to use; the mappings |
||||
are neither symmetric nor 1-to-1. |
||||
|
||||
| HTTP Status Code | gRPC Status Code | |
||||
|----------------------------|--------------------| |
||||
| 400 Bad Request | INTERNAL | |
||||
| 401 Unauthorized | UNAUTHENTICATED | |
||||
| 403 Forbidden | PERMISSION\_DENIED | |
||||
| 404 Not Found | UNIMPLEMENTED | |
||||
| 429 Too Many Requests | UNAVAILABLE | |
||||
| 502 Bad Gateway | UNAVAILABLE | |
||||
| 503 Service Unavailable | UNAVAILABLE | |
||||
| 504 Gateway Timeout | UNAVAILABLE | |
||||
| _All other codes_ | UNKNOWN | |
||||
|
||||
Technically, 1xx should have the entire header skipped and a subsequent header |
||||
be read. See RFC 7540 §8.1. |
||||
|
||||
200 is UNKNOWN because there should be a grpc-status in case of truly OK |
||||
response. |
@ -0,0 +1,192 @@ |
||||
# gRPC Server Reflection Tutorial |
||||
|
||||
gRPC Server Reflection provides information about publicly-accessible gRPC |
||||
services on a server, and assists clients at runtime to construct RPC |
||||
requests and responses without precompiled service information. It is used by |
||||
gRPC CLI, which can be used to introspect server protos and send/receive test |
||||
RPCs. |
||||
|
||||
## Enable Server Reflection |
||||
|
||||
### Enable server reflection in C++ servers |
||||
|
||||
C++ Server Reflection is an add-on library, `libgrpc++_reflction`. To enable C++ |
||||
server reflection, you can link this library to your server binary. |
||||
|
||||
Some platforms (e.g. Ubuntu 11.10 onwards) only link in libraries that directly |
||||
contain symbols used by the application. On these platforms, LD flag |
||||
`--no-as-needed` is needed for for dynamic linking and `--whole-archive` is |
||||
needed for for static linking. |
||||
|
||||
This [Makefile](../examples/cpp/helloworld/Makefile#L37#L45) demonstrates |
||||
enabling c++ server reflection on Linux and MacOS. |
||||
|
||||
## Test services using Server Reflection |
||||
|
||||
After enabling Server Reflection in a server application, you can use gRPC CLI |
||||
to test its services. |
||||
|
||||
Instructions on how to use gRPC CLI can be found at |
||||
[command_line_tool.md](command_line_tool.md), or using `grpc_cli help` command. |
||||
|
||||
Here we use `examples/cpp/helloworld` as an example to show the use of gRPC |
||||
Server Reflection and gRPC CLI. First, we need to build gRPC CLI and setup an |
||||
example server with Server Reflection enabled. |
||||
|
||||
- Setup an example server |
||||
|
||||
Server Reflection has already been enabled in the |
||||
[Makefile](../examples/cpp/helloworld/Makefile) of the helloworld example. We |
||||
can simply make it and run the greeter_server. |
||||
|
||||
```sh |
||||
$ make -C examples/cpp/helloworld |
||||
$ examples/cpp/helloworld/greeter_server & |
||||
``` |
||||
|
||||
- Build gRPC CLI |
||||
|
||||
```sh |
||||
make grpc_cli |
||||
cd bins/opt |
||||
``` |
||||
|
||||
gRPC CLI binary `grpc_cli` can be found at `bins/opt/` folder. This tool is |
||||
still new and does not have a `make install` target yet. |
||||
|
||||
### List services |
||||
|
||||
`grpc_cli ls` command lists services and methods exposed at a given port |
||||
|
||||
- List all the services exposed at a given port |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
helloworld.Greeter |
||||
grpc.reflection.v1alpha.ServerReflection |
||||
``` |
||||
|
||||
- List one service with details |
||||
|
||||
`grpc_cli ls` command inspects a service given its full name (in the format of |
||||
\<package\>.\<service\>). It can print information with a long listing format |
||||
when `-l` flag is set. This flag can be used to get more details about a |
||||
service. |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 helloworld.Greeter -l |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
filename: helloworld.proto |
||||
package: helloworld; |
||||
service Greeter { |
||||
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {} |
||||
} |
||||
|
||||
``` |
||||
|
||||
### List methods |
||||
|
||||
- List one method with details |
||||
|
||||
`grpc_cli ls` command also inspects a method given its full name (in the |
||||
format of \<package\>.\<service\>.\<method\>). |
||||
|
||||
```sh |
||||
$ grpc_cli ls localhost:50051 helloworld.Greeter.SayHello -l |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
rpc SayHello(helloworld.HelloRequest) returns (helloworld.HelloReply) {} |
||||
``` |
||||
|
||||
### Inspect message types |
||||
|
||||
We can use`grpc_cli type` command to inspect request/response types given the |
||||
full name of the type (in the format of \<package\>.\<type\>). |
||||
|
||||
- Get information about the request type |
||||
|
||||
```sh |
||||
$ grpc_cli type localhost:50051 helloworld.HelloRequest |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
message HelloRequest { |
||||
optional string name = 1; |
||||
} |
||||
``` |
||||
|
||||
### Call a remote method |
||||
|
||||
We can send RPCs to a server and get responses using `grpc_cli call` command. |
||||
|
||||
- Call a unary method |
||||
|
||||
```sh |
||||
$ grpc_cli call localhost:50051 SayHello "name: 'gRPC CLI'" |
||||
``` |
||||
|
||||
output: |
||||
```sh |
||||
message: "Hello gRPC CLI" |
||||
``` |
||||
|
||||
## Use Server Reflection in a C++ client |
||||
|
||||
Server Reflection can be used by clients to get information about gRPC services |
||||
at runtime. We've provided a descriptor database called |
||||
[grpc::ProtoReflectionDescriptorDatabase](../test/cpp/util/proto_reflection_descriptor_database.h) |
||||
which implements the |
||||
[google::protobuf::DescriptorDatabase](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor_database#DescriptorDatabase) |
||||
interface. It manages the communication between clients and reflection services |
||||
and the storage of received information. Clients can use it as using a local |
||||
descriptor database. |
||||
|
||||
- To use Server Reflection with grpc::ProtoReflectionDescriptorDatabase, first |
||||
initialize an instance with a grpc::Channel. |
||||
|
||||
```c++ |
||||
std::shared_ptr<grpc::Channel> channel = |
||||
grpc::CreateChannel(server_address, server_cred); |
||||
grpc::ProtoReflectionDescriptorDatabase reflection_db(channel); |
||||
``` |
||||
|
||||
- Then use this instance to feed a |
||||
[google::protobuf::DescriptorPool](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor#DescriptorPool). |
||||
|
||||
```c++ |
||||
google::protobuf::DescriptorPool desc_pool(&reflection_db); |
||||
``` |
||||
|
||||
- Example usage of this descriptor pool |
||||
|
||||
* Get Service/method descriptors. |
||||
|
||||
```c++ |
||||
const google::protobuf::ServiceDescriptor* service_desc = |
||||
desc_pool->FindServiceByName("helloworld.Greeter"); |
||||
const google::protobuf::MethodDescriptor* method_desc = |
||||
desc_pool->FindMethodByName("helloworld.Greeter.SayHello"); |
||||
``` |
||||
|
||||
* Get message type descriptors. |
||||
|
||||
```c++ |
||||
const google::protobuf::Descriptor* request_desc = |
||||
desc_pool->FindMessageTypeByName("helloworld.HelloRequest"); |
||||
``` |
||||
|
||||
* Feed [google::protobuf::DynamicMessageFactory](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.dynamic_message#DynamicMessageFactory). |
||||
|
||||
```c++ |
||||
google::protobuf::DynamicMessageFactory(&desc_pool); |
||||
``` |
@ -0,0 +1,4 @@ |
||||
The roots.pem file is periodically generated from: |
||||
https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt |
||||
using |
||||
https://github.com/agl/extract-nss-root-certs |
@ -0,0 +1,86 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, 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 "src/core/ext/census/trace_context.h" |
||||
|
||||
#include <grpc/census.h> |
||||
#include <grpc/support/log.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "third_party/nanopb/pb_decode.h" |
||||
#include "third_party/nanopb/pb_encode.h" |
||||
|
||||
// This function assumes the TraceContext is valid.
|
||||
size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t buf_size) { |
||||
// Create a stream that will write to our buffer.
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, buf_size); |
||||
|
||||
// encode message
|
||||
bool status = pb_encode(&stream, google_trace_TraceContext_fields, ctxt); |
||||
|
||||
if (!status) { |
||||
gpr_log(GPR_DEBUG, "TraceContext encoding failed: %s", |
||||
PB_GET_ERROR(&stream)); |
||||
return 0; |
||||
} |
||||
|
||||
return stream.bytes_written; |
||||
} |
||||
|
||||
bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t nbytes) { |
||||
// Create a stream that reads nbytes from the buffer.
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, nbytes); |
||||
|
||||
// decode message
|
||||
bool status = pb_decode(&stream, google_trace_TraceContext_fields, ctxt); |
||||
|
||||
if (!status) { |
||||
gpr_log(GPR_DEBUG, "TraceContext decoding failed: %s", |
||||
PB_GET_ERROR(&stream)); |
||||
return false; |
||||
} |
||||
|
||||
// check fields
|
||||
if (!ctxt->has_trace_id) { |
||||
gpr_log(GPR_DEBUG, "Invalid TraceContext: missing trace_id"); |
||||
return false; |
||||
} |
||||
if (!ctxt->has_span_id) { |
||||
gpr_log(GPR_DEBUG, "Invalid TraceContext: missing span_id"); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,68 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, 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. |
||||
* |
||||
*/ |
||||
|
||||
/* Functions for manipulating trace contexts as defined in
|
||||
src/proto/census/trace.proto */ |
||||
#ifndef GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H |
||||
#define GRPC_CORE_EXT_CENSUS_TRACE_CONTEXT_H |
||||
|
||||
#include "src/core/ext/census/gen/trace_context.pb.h" |
||||
|
||||
/* Maximum number of bytes required to encode a TraceContext (31)
|
||||
1 byte for trace_id field |
||||
1 byte for trace_id length |
||||
1 byte for trace_id.hi field |
||||
8 bytes for trace_id.hi (uint64_t) |
||||
1 byte for trace_id.lo field |
||||
8 bytes for trace_id.lo (uint64_t) |
||||
1 byte for span_id field |
||||
8 bytes for span_id (uint64_t) |
||||
1 byte for is_sampled field |
||||
1 byte for is_sampled (bool) */ |
||||
#define TRACE_MAX_CONTEXT_SIZE 31 |
||||
|
||||
/* Encode a trace context (ctxt) into proto format to the buffer provided. The
|
||||
size of buffer must be at least TRACE_MAX_CONTEXT_SIZE. On success, returns the |
||||
number of bytes successfully encoded into buffer. On failure, returns 0. */ |
||||
size_t encode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t buf_size); |
||||
|
||||
/* Decode a proto-encoded TraceContext from the provided buffer into the
|
||||
TraceContext structure (ctxt). The function expects to be supplied the number |
||||
of bytes to be read from buffer (nbytes). This function will also validate that |
||||
the TraceContext has a span_id and a trace_id, and will return false if either |
||||
of these do not exist. On success, returns true and false otherwise. */ |
||||
bool decode_trace_context(google_trace_TraceContext *ctxt, uint8_t *buffer, |
||||
const size_t nbytes); |
||||
|
||||
#endif |
@ -1,75 +1,87 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
//
|
||||
// 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 "src/core/ext/client_config/resolver_result.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
struct grpc_resolver_result { |
||||
gpr_refcount refs; |
||||
grpc_lb_policy *lb_policy; |
||||
grpc_lb_addresses* addresses; |
||||
char* lb_policy_name; |
||||
grpc_channel_args* lb_policy_args; |
||||
}; |
||||
|
||||
grpc_resolver_result *grpc_resolver_result_create() { |
||||
grpc_resolver_result *c = gpr_malloc(sizeof(*c)); |
||||
memset(c, 0, sizeof(*c)); |
||||
gpr_ref_init(&c->refs, 1); |
||||
return c; |
||||
grpc_resolver_result* grpc_resolver_result_create( |
||||
grpc_lb_addresses* addresses, const char* lb_policy_name, |
||||
grpc_channel_args* lb_policy_args) { |
||||
grpc_resolver_result* result = gpr_malloc(sizeof(*result)); |
||||
memset(result, 0, sizeof(*result)); |
||||
gpr_ref_init(&result->refs, 1); |
||||
result->addresses = addresses; |
||||
result->lb_policy_name = gpr_strdup(lb_policy_name); |
||||
result->lb_policy_args = lb_policy_args; |
||||
return result; |
||||
} |
||||
|
||||
void grpc_resolver_result_ref(grpc_resolver_result *c) { gpr_ref(&c->refs); } |
||||
void grpc_resolver_result_ref(grpc_resolver_result* result) { |
||||
gpr_ref(&result->refs); |
||||
} |
||||
|
||||
void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_resolver_result *c) { |
||||
if (gpr_unref(&c->refs)) { |
||||
if (c->lb_policy != NULL) { |
||||
GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "resolver_result"); |
||||
} |
||||
gpr_free(c); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, |
||||
grpc_resolver_result* result) { |
||||
if (gpr_unref(&result->refs)) { |
||||
grpc_lb_addresses_destroy(result->addresses, NULL /* user_data_destroy */); |
||||
gpr_free(result->lb_policy_name); |
||||
grpc_channel_args_destroy(result->lb_policy_args); |
||||
gpr_free(result); |
||||
} |
||||
} |
||||
|
||||
void grpc_resolver_result_set_lb_policy(grpc_resolver_result *c, |
||||
grpc_lb_policy *lb_policy) { |
||||
GPR_ASSERT(c->lb_policy == NULL); |
||||
if (lb_policy) { |
||||
GRPC_LB_POLICY_REF(lb_policy, "resolver_result"); |
||||
} |
||||
c->lb_policy = lb_policy; |
||||
grpc_lb_addresses* grpc_resolver_result_get_addresses( |
||||
grpc_resolver_result* result) { |
||||
return result->addresses; |
||||
} |
||||
|
||||
const char* grpc_resolver_result_get_lb_policy_name( |
||||
grpc_resolver_result* result) { |
||||
return result->lb_policy_name; |
||||
} |
||||
|
||||
grpc_lb_policy *grpc_resolver_result_get_lb_policy(grpc_resolver_result *c) { |
||||
return c->lb_policy; |
||||
grpc_channel_args* grpc_resolver_result_get_lb_policy_args( |
||||
grpc_resolver_result* result) { |
||||
return result->lb_policy_args; |
||||
} |
||||
|
@ -1,52 +1,71 @@ |
||||
/*
|
||||
* |
||||
* 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. |
||||
* |
||||
*/ |
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H |
||||
#define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H |
||||
|
||||
#include "src/core/ext/client_config/lb_policy.h" |
||||
#include "src/core/ext/client_config/lb_policy_factory.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
|
||||
/** Results reported from a grpc_resolver. */ |
||||
// TODO(roth, ctiller): In the long term, we are considering replacing
|
||||
// the resolver_result data structure with grpc_channel_args. The idea is
|
||||
// that the resolver will return a set of channel args that contains the
|
||||
// information that is currently in the resolver_result struct. For
|
||||
// example, there will be specific args indicating the set of addresses
|
||||
// and the name of the LB policy to instantiate. Note that if we did
|
||||
// this, we would probably want to change the data structure of
|
||||
// grpc_channel_args such to a hash table or AVL or some other data
|
||||
// structure that does not require linear search to find keys.
|
||||
|
||||
/// Results reported from a grpc_resolver.
|
||||
typedef struct grpc_resolver_result grpc_resolver_result; |
||||
|
||||
grpc_resolver_result *grpc_resolver_result_create(); |
||||
void grpc_resolver_result_ref(grpc_resolver_result *client_config); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx, |
||||
grpc_resolver_result *client_config); |
||||
/// Takes ownership of \a addresses and \a lb_policy_args.
|
||||
grpc_resolver_result* grpc_resolver_result_create( |
||||
grpc_lb_addresses* addresses, const char* lb_policy_name, |
||||
grpc_channel_args* lb_policy_args); |
||||
void grpc_resolver_result_ref(grpc_resolver_result* result); |
||||
void grpc_resolver_result_unref(grpc_exec_ctx* exec_ctx, |
||||
grpc_resolver_result* result); |
||||
|
||||
/// Caller does NOT take ownership of result.
|
||||
grpc_lb_addresses* grpc_resolver_result_get_addresses( |
||||
grpc_resolver_result* result); |
||||
|
||||
/// Caller does NOT take ownership of result.
|
||||
const char* grpc_resolver_result_get_lb_policy_name( |
||||
grpc_resolver_result* result); |
||||
|
||||
void grpc_resolver_result_set_lb_policy(grpc_resolver_result *client_config, |
||||
grpc_lb_policy *lb_policy); |
||||
grpc_lb_policy *grpc_resolver_result_get_lb_policy( |
||||
grpc_resolver_result *client_config); |
||||
/// Caller does NOT take ownership of result.
|
||||
grpc_channel_args* grpc_resolver_result_get_lb_policy_args( |
||||
grpc_resolver_result* result); |
||||
|
||||
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */ |
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,165 @@ |
||||
//
|
||||
// Copyright 2016, 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 "src/core/lib/channel/message_size_filter.h" |
||||
|
||||
#include <limits.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
// The protobuf library will (by default) start warning at 100 megs.
|
||||
#define DEFAULT_MAX_MESSAGE_LENGTH (4 * 1024 * 1024) |
||||
|
||||
typedef struct call_data { |
||||
// Receive closures are chained: we inject this closure as the
|
||||
// recv_message_ready up-call on transport_stream_op, and remember to
|
||||
// call our next_recv_message_ready member after handling it.
|
||||
grpc_closure recv_message_ready; |
||||
// Used by recv_message_ready.
|
||||
grpc_byte_stream** recv_message; |
||||
// Original recv_message_ready callback, invoked after our own.
|
||||
grpc_closure* next_recv_message_ready; |
||||
} call_data; |
||||
|
||||
typedef struct channel_data { |
||||
size_t max_send_size; |
||||
size_t max_recv_size; |
||||
} channel_data; |
||||
|
||||
// Callback invoked when we receive a message. Here we check the max
|
||||
// receive message size.
|
||||
static void recv_message_ready(grpc_exec_ctx* exec_ctx, void* user_data, |
||||
grpc_error* error) { |
||||
grpc_call_element* elem = user_data; |
||||
call_data* calld = elem->call_data; |
||||
channel_data* chand = elem->channel_data; |
||||
if (*calld->recv_message != NULL && |
||||
(*calld->recv_message)->length > chand->max_recv_size) { |
||||
char* message_string; |
||||
gpr_asprintf( |
||||
&message_string, "Received message larger than max (%u vs. %lu)", |
||||
(*calld->recv_message)->length, (unsigned long)chand->max_recv_size); |
||||
gpr_slice message = gpr_slice_from_copied_string(message_string); |
||||
gpr_free(message_string); |
||||
grpc_call_element_send_cancel_with_message( |
||||
exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message); |
||||
} |
||||
// Invoke the next callback.
|
||||
grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL); |
||||
} |
||||
|
||||
// Start transport op.
|
||||
static void start_transport_stream_op(grpc_exec_ctx* exec_ctx, |
||||
grpc_call_element* elem, |
||||
grpc_transport_stream_op* op) { |
||||
call_data* calld = elem->call_data; |
||||
channel_data* chand = elem->channel_data; |
||||
// Check max send message size.
|
||||
if (op->send_message != NULL && |
||||
op->send_message->length > chand->max_send_size) { |
||||
char* message_string; |
||||
gpr_asprintf(&message_string, "Sent message larger than max (%u vs. %lu)", |
||||
op->send_message->length, (unsigned long)chand->max_send_size); |
||||
gpr_slice message = gpr_slice_from_copied_string(message_string); |
||||
gpr_free(message_string); |
||||
grpc_call_element_send_cancel_with_message( |
||||
exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT, &message); |
||||
} |
||||
// Inject callback for receiving a message.
|
||||
if (op->recv_message_ready != NULL) { |
||||
calld->next_recv_message_ready = op->recv_message_ready; |
||||
calld->recv_message = op->recv_message; |
||||
op->recv_message_ready = &calld->recv_message_ready; |
||||
} |
||||
// Chain to the next filter.
|
||||
grpc_call_next_op(exec_ctx, elem, op); |
||||
} |
||||
|
||||
// Constructor for call_data.
|
||||
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_call_element* elem, |
||||
grpc_call_element_args* args) { |
||||
call_data* calld = elem->call_data; |
||||
calld->next_recv_message_ready = NULL; |
||||
grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem); |
||||
return GRPC_ERROR_NONE; |
||||
} |
||||
|
||||
// Destructor for call_data.
|
||||
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem, |
||||
const grpc_call_final_info* final_info, |
||||
void* ignored) {} |
||||
|
||||
// Constructor for channel_data.
|
||||
static void init_channel_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_channel_element* elem, |
||||
grpc_channel_element_args* args) { |
||||
GPR_ASSERT(!args->is_last); |
||||
channel_data* chand = elem->channel_data; |
||||
memset(chand, 0, sizeof(*chand)); |
||||
chand->max_send_size = DEFAULT_MAX_MESSAGE_LENGTH; |
||||
chand->max_recv_size = DEFAULT_MAX_MESSAGE_LENGTH; |
||||
const grpc_integer_options options = {DEFAULT_MAX_MESSAGE_LENGTH, 0, INT_MAX}; |
||||
for (size_t i = 0; i < args->channel_args->num_args; ++i) { |
||||
if (strcmp(args->channel_args->args[i].key, |
||||
GRPC_ARG_MAX_SEND_MESSAGE_LENGTH) == 0) { |
||||
chand->max_send_size = (size_t)grpc_channel_arg_get_integer( |
||||
&args->channel_args->args[i], options); |
||||
} |
||||
if (strcmp(args->channel_args->args[i].key, |
||||
GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH) == 0) { |
||||
chand->max_recv_size = (size_t)grpc_channel_arg_get_integer( |
||||
&args->channel_args->args[i], options); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Destructor for channel_data.
|
||||
static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, |
||||
grpc_channel_element* elem) {} |
||||
|
||||
const grpc_channel_filter grpc_message_size_filter = { |
||||
start_transport_stream_op, |
||||
grpc_channel_next_op, |
||||
sizeof(call_data), |
||||
init_call_elem, |
||||
grpc_call_stack_ignore_set_pollset_or_pollset_set, |
||||
destroy_call_elem, |
||||
sizeof(channel_data), |
||||
init_channel_elem, |
||||
destroy_channel_elem, |
||||
grpc_call_next_get_peer, |
||||
"message_size"}; |
@ -0,0 +1,39 @@ |
||||
//
|
||||
// Copyright 2016, 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.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H |
||||
#define GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H |
||||
|
||||
#include "src/core/lib/channel/channel_stack.h" |
||||
|
||||
extern const grpc_channel_filter grpc_message_size_filter; |
||||
|
||||
#endif /* GRPC_CORE_LIB_CHANNEL_MESSAGE_SIZE_FILTER_H */ |
@ -0,0 +1,324 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, 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 "src/core/lib/iomgr/combiner.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/iomgr/workqueue.h" |
||||
#include "src/core/lib/profiling/timers.h" |
||||
|
||||
int grpc_combiner_trace = 0; |
||||
|
||||
#define GRPC_COMBINER_TRACE(fn) \ |
||||
do { \
|
||||
if (grpc_combiner_trace) { \
|
||||
fn; \
|
||||
} \
|
||||
} while (0) |
||||
|
||||
struct grpc_combiner { |
||||
grpc_combiner *next_combiner_on_this_exec_ctx; |
||||
grpc_workqueue *optional_workqueue; |
||||
gpr_mpscq queue; |
||||
// state is:
|
||||
// lower bit - zero if orphaned
|
||||
// other bits - number of items queued on the lock
|
||||
gpr_atm state; |
||||
// number of elements in the list that are covered by a poller: if >0, we can
|
||||
// offload safely
|
||||
gpr_atm covered_by_poller; |
||||
bool time_to_execute_final_list; |
||||
bool final_list_covered_by_poller; |
||||
grpc_closure_list final_list; |
||||
grpc_closure offload; |
||||
}; |
||||
|
||||
static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); |
||||
|
||||
typedef struct { |
||||
grpc_error *error; |
||||
bool covered_by_poller; |
||||
} error_data; |
||||
|
||||
static uintptr_t pack_error_data(error_data d) { |
||||
return ((uintptr_t)d.error) | (d.covered_by_poller ? 1 : 0); |
||||
} |
||||
|
||||
static error_data unpack_error_data(uintptr_t p) { |
||||
return (error_data){(grpc_error *)(p & ~(uintptr_t)1), p & 1}; |
||||
} |
||||
|
||||
static bool is_covered_by_poller(grpc_combiner *lock) { |
||||
return lock->final_list_covered_by_poller || |
||||
gpr_atm_acq_load(&lock->covered_by_poller) > 0; |
||||
} |
||||
|
||||
grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) { |
||||
grpc_combiner *lock = gpr_malloc(sizeof(*lock)); |
||||
lock->next_combiner_on_this_exec_ctx = NULL; |
||||
lock->time_to_execute_final_list = false; |
||||
lock->optional_workqueue = optional_workqueue; |
||||
lock->final_list_covered_by_poller = false; |
||||
gpr_atm_no_barrier_store(&lock->state, 1); |
||||
gpr_atm_no_barrier_store(&lock->covered_by_poller, 0); |
||||
gpr_mpscq_init(&lock->queue); |
||||
grpc_closure_list_init(&lock->final_list); |
||||
grpc_closure_init(&lock->offload, offload, lock); |
||||
GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock)); |
||||
return lock; |
||||
} |
||||
|
||||
static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { |
||||
GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock)); |
||||
GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0); |
||||
gpr_mpscq_destroy(&lock->queue); |
||||
GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner"); |
||||
gpr_free(lock); |
||||
} |
||||
|
||||
void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { |
||||
gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -1); |
||||
GRPC_COMBINER_TRACE(gpr_log( |
||||
GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state)); |
||||
if (old_state == 1) { |
||||
really_destroy(exec_ctx, lock); |
||||
} |
||||
} |
||||
|
||||
static void push_last_on_exec_ctx(grpc_exec_ctx *exec_ctx, |
||||
grpc_combiner *lock) { |
||||
lock->next_combiner_on_this_exec_ctx = NULL; |
||||
if (exec_ctx->active_combiner == NULL) { |
||||
exec_ctx->active_combiner = exec_ctx->last_combiner = lock; |
||||
} else { |
||||
exec_ctx->last_combiner->next_combiner_on_this_exec_ctx = lock; |
||||
exec_ctx->last_combiner = lock; |
||||
} |
||||
} |
||||
|
||||
static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx, |
||||
grpc_combiner *lock) { |
||||
lock->next_combiner_on_this_exec_ctx = exec_ctx->active_combiner; |
||||
exec_ctx->active_combiner = lock; |
||||
if (lock->next_combiner_on_this_exec_ctx == NULL) { |
||||
exec_ctx->last_combiner = lock; |
||||
} |
||||
} |
||||
|
||||
void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, |
||||
grpc_closure *cl, grpc_error *error, |
||||
bool covered_by_poller) { |
||||
GPR_TIMER_BEGIN("combiner.execute", 0); |
||||
gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2); |
||||
GRPC_COMBINER_TRACE(gpr_log( |
||||
GPR_DEBUG, "C:%p grpc_combiner_execute c=%p cov=%d last=%" PRIdPTR, lock, |
||||
cl, covered_by_poller, last)); |
||||
GPR_ASSERT(last & 1); // ensure lock has not been destroyed
|
||||
cl->error_data.scratch = |
||||
pack_error_data((error_data){error, covered_by_poller}); |
||||
if (covered_by_poller) { |
||||
gpr_atm_no_barrier_fetch_add(&lock->covered_by_poller, 1); |
||||
} |
||||
gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next); |
||||
if (last == 1) { |
||||
// code will be written when the exec_ctx calls
|
||||
// grpc_combiner_continue_exec_ctx
|
||||
push_last_on_exec_ctx(exec_ctx, lock); |
||||
} |
||||
GPR_TIMER_END("combiner.execute", 0); |
||||
} |
||||
|
||||
static void move_next(grpc_exec_ctx *exec_ctx) { |
||||
exec_ctx->active_combiner = |
||||
exec_ctx->active_combiner->next_combiner_on_this_exec_ctx; |
||||
if (exec_ctx->active_combiner == NULL) { |
||||
exec_ctx->last_combiner = NULL; |
||||
} |
||||
} |
||||
|
||||
static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { |
||||
grpc_combiner *lock = arg; |
||||
push_last_on_exec_ctx(exec_ctx, lock); |
||||
} |
||||
|
||||
static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) { |
||||
move_next(exec_ctx); |
||||
GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload --> %p", lock, |
||||
lock->optional_workqueue)); |
||||
grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, &lock->offload, |
||||
GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) { |
||||
GPR_TIMER_BEGIN("combiner.continue_exec_ctx", 0); |
||||
grpc_combiner *lock = exec_ctx->active_combiner; |
||||
if (lock == NULL) { |
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return false; |
||||
} |
||||
|
||||
GRPC_COMBINER_TRACE( |
||||
gpr_log(GPR_DEBUG, |
||||
"C:%p grpc_combiner_continue_exec_ctx workqueue=%p " |
||||
"is_covered_by_poller=%d exec_ctx_ready_to_finish=%d " |
||||
"time_to_execute_final_list=%d", |
||||
lock, lock->optional_workqueue, is_covered_by_poller(lock), |
||||
grpc_exec_ctx_ready_to_finish(exec_ctx), |
||||
lock->time_to_execute_final_list)); |
||||
|
||||
if (lock->optional_workqueue != NULL && is_covered_by_poller(lock) && |
||||
grpc_exec_ctx_ready_to_finish(exec_ctx)) { |
||||
GPR_TIMER_MARK("offload_from_finished_exec_ctx", 0); |
||||
// this execution context wants to move on, and we have a workqueue (and
|
||||
// so can help the execution context out): schedule remaining work to be
|
||||
// picked up on the workqueue
|
||||
queue_offload(exec_ctx, lock); |
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return true; |
||||
} |
||||
|
||||
if (!lock->time_to_execute_final_list || |
||||
// peek to see if something new has shown up, and execute that with
|
||||
// priority
|
||||
(gpr_atm_acq_load(&lock->state) >> 1) > 1) { |
||||
gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue); |
||||
GRPC_COMBINER_TRACE( |
||||
gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n)); |
||||
if (n == NULL) { |
||||
// queue is in an inconsistant state: use this as a cue that we should
|
||||
// go off and do something else for a while (and come back later)
|
||||
GPR_TIMER_MARK("delay_busy", 0); |
||||
if (lock->optional_workqueue != NULL && is_covered_by_poller(lock)) { |
||||
queue_offload(exec_ctx, lock); |
||||
} |
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return true; |
||||
} |
||||
GPR_TIMER_BEGIN("combiner.exec1", 0); |
||||
grpc_closure *cl = (grpc_closure *)n; |
||||
error_data err = unpack_error_data(cl->error_data.scratch); |
||||
cl->cb(exec_ctx, cl->cb_arg, err.error); |
||||
if (err.covered_by_poller) { |
||||
gpr_atm_no_barrier_fetch_add(&lock->covered_by_poller, -1); |
||||
} |
||||
GRPC_ERROR_UNREF(err.error); |
||||
GPR_TIMER_END("combiner.exec1", 0); |
||||
} else { |
||||
grpc_closure *c = lock->final_list.head; |
||||
GPR_ASSERT(c != NULL); |
||||
grpc_closure_list_init(&lock->final_list); |
||||
lock->final_list_covered_by_poller = false; |
||||
int loops = 0; |
||||
while (c != NULL) { |
||||
GPR_TIMER_BEGIN("combiner.exec_1final", 0); |
||||
GRPC_COMBINER_TRACE( |
||||
gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c)); |
||||
grpc_closure *next = c->next_data.next; |
||||
grpc_error *error = c->error_data.error; |
||||
c->cb(exec_ctx, c->cb_arg, error); |
||||
GRPC_ERROR_UNREF(error); |
||||
c = next; |
||||
GPR_TIMER_END("combiner.exec_1final", 0); |
||||
} |
||||
} |
||||
|
||||
GPR_TIMER_MARK("unref", 0); |
||||
move_next(exec_ctx); |
||||
lock->time_to_execute_final_list = false; |
||||
gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2); |
||||
GRPC_COMBINER_TRACE( |
||||
gpr_log(GPR_DEBUG, "C:%p finish old_state=%" PRIdPTR, lock, old_state)); |
||||
switch (old_state) { |
||||
default: |
||||
// we have multiple queued work items: just continue executing them
|
||||
break; |
||||
case 5: // we're down to one queued item: if it's the final list we
|
||||
case 4: // should do that
|
||||
if (!grpc_closure_list_empty(lock->final_list)) { |
||||
lock->time_to_execute_final_list = true; |
||||
} |
||||
break; |
||||
case 3: // had one count, one unorphaned --> unlocked unorphaned
|
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return true; |
||||
case 2: // and one count, one orphaned --> unlocked and orphaned
|
||||
really_destroy(exec_ctx, lock); |
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return true; |
||||
case 1: |
||||
case 0: |
||||
// these values are illegal - representing an already unlocked or
|
||||
// deleted lock
|
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
GPR_UNREACHABLE_CODE(return true); |
||||
} |
||||
push_first_on_exec_ctx(exec_ctx, lock); |
||||
GPR_TIMER_END("combiner.continue_exec_ctx", 0); |
||||
return true; |
||||
} |
||||
|
||||
static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure, |
||||
grpc_error *error) { |
||||
grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure, |
||||
GRPC_ERROR_REF(error), false); |
||||
} |
||||
|
||||
void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, |
||||
grpc_closure *closure, grpc_error *error, |
||||
bool covered_by_poller) { |
||||
GRPC_COMBINER_TRACE(gpr_log( |
||||
GPR_DEBUG, "C:%p grpc_combiner_execute_finally c=%p; ac=%p; cov=%d", lock, |
||||
closure, exec_ctx->active_combiner, covered_by_poller)); |
||||
GPR_TIMER_BEGIN("combiner.execute_finally", 0); |
||||
if (exec_ctx->active_combiner != lock) { |
||||
GPR_TIMER_MARK("slowpath", 0); |
||||
grpc_combiner_execute(exec_ctx, lock, |
||||
grpc_closure_create(enqueue_finally, closure), error, |
||||
false); |
||||
GPR_TIMER_END("combiner.execute_finally", 0); |
||||
return; |
||||
} |
||||
|
||||
if (grpc_closure_list_empty(lock->final_list)) { |
||||
gpr_atm_full_fetch_add(&lock->state, 2); |
||||
} |
||||
if (covered_by_poller) { |
||||
lock->final_list_covered_by_poller = true; |
||||
} |
||||
grpc_closure_list_append(&lock->final_list, closure, error); |
||||
GPR_TIMER_END("combiner.execute_finally", 0); |
||||
} |
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2016, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_COMBINER_H |
||||
#define GRPC_CORE_LIB_IOMGR_COMBINER_H |
||||
|
||||
#include <stddef.h> |
||||
|
||||
#include <grpc/support/atm.h> |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
#include "src/core/lib/support/mpscq.h" |
||||
|
||||
// Provides serialized access to some resource.
|
||||
// Each action queued on a combiner is executed serially in a borrowed thread.
|
||||
// The actual thread executing actions may change over time (but there will only
|
||||
// every be one at a time).
|
||||
|
||||
// Initialize the lock, with an optional workqueue to shift load to when
|
||||
// necessary
|
||||
grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue); |
||||
// Destroy the lock
|
||||
void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock); |
||||
// Execute \a action within the lock.
|
||||
void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, |
||||
grpc_closure *closure, grpc_error *error, |
||||
bool covered_by_poller); |
||||
// Execute \a action within the lock just prior to unlocking.
|
||||
void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock, |
||||
grpc_closure *closure, grpc_error *error, |
||||
bool covered_by_poller); |
||||
|
||||
bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx); |
||||
|
||||
extern int grpc_combiner_trace; |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue