Merge branch 'master' of https://github.com/Vizerai/grpc into filter_port
commit
e501a3d3fd
888 changed files with 30241 additions and 14800 deletions
@ -0,0 +1,108 @@ |
||||
[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= |
||||
# These suppressions are specific to tests: |
||||
# |
||||
# TODO(https://github.com/grpc/grpc/issues/261): investigate |
||||
# each of the following one by one and consider eliminating |
||||
# the suppression category. |
||||
# Eventually, the hope is to eliminate the .pylintrc-tests |
||||
# altogether and rely on .pylintrc for everything. |
||||
pointless-statement, |
||||
no-member, |
||||
no-self-use, |
||||
attribute-defined-outside-init, |
||||
unused-argument, |
||||
unused-variable, |
||||
unused-import, |
||||
redefined-builtin, |
||||
too-many-public-methods, |
||||
too-many-locals, |
||||
redefined-variable-type, |
||||
redefined-outer-name, |
||||
ungrouped-imports, |
||||
too-many-branches, |
||||
too-many-arguments, |
||||
too-many-format-args, |
||||
too-many-return-statements, |
||||
too-many-statements, |
||||
line-too-long, |
||||
wrong-import-position, |
||||
wrong-import-order, |
||||
# -- END OF TEST-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, |
||||
# NOTE(nathaniel): I have disputed the premise of this inspection from |
||||
# the beginning and will continue to do so until it goes away for good. |
||||
useless-else-on-loop, |
@ -0,0 +1,46 @@ |
||||
# Background # |
||||
|
||||
In Python, multithreading is ineffective at concurrency for CPU bound tasks |
||||
due to the GIL (global interpreter lock). Extension modules can release |
||||
the GIL in CPU bound tasks, but that isn't an option in pure Python. |
||||
Users use libraries such as multiprocessing, subprocess, concurrent.futures.ProcessPoolExecutor, |
||||
etc, to work around the GIL. These modules call ```fork()``` underneath the hood. Various issues have |
||||
been reported when using these modules with gRPC Python. gRPC Python wraps |
||||
gRPC core, which uses multithreading for performance, and hence doesn't support ```fork()```. |
||||
Historically, we didn't support forking in gRPC, but some users seemed |
||||
to be doing fine until their code started to break on version 1.6. This was |
||||
likely caused by the addition of background c-threads and a background |
||||
Python thread. |
||||
|
||||
# Current Status # |
||||
|
||||
## 1.11 ## |
||||
The background Python thread was removed entirely. This allows forking |
||||
after creating a channel. However, the channel must not have issued any |
||||
RPCs prior to the fork. Attempting to fork with an active channel that |
||||
has been used can result in deadlocks/corrupted wire data. |
||||
|
||||
## 1.9 ## |
||||
A regression was noted in cases where users are doing fork/exec. This |
||||
was due to ```pthread_atfork()``` handler that was added in 1.7 to partially |
||||
support forking in gRPC. A deadlock can happen when pthread_atfork |
||||
handler is running, and an application thread is calling into gRPC. |
||||
We have provided a workaround for this issue by allowing users to turn |
||||
off the handler using env flag ```GRPC_ENABLE_FORK_SUPPORT=False```. |
||||
This should be set whenever a user expects to always call exec |
||||
immediately following fork. It will disable the fork handlers. |
||||
|
||||
## 1.7 ## |
||||
A ```pthread_atfork()``` handler was added in 1.7 to automatically shut down |
||||
the background c-threads when fork was called. This does not shut down the |
||||
background Python thread, so users could not have any open channels when |
||||
forking. |
||||
|
||||
# Future Work # |
||||
|
||||
## 1.13 ## |
||||
The workaround when using fork/exec by setting |
||||
```GRPC_ENABLE_FORK_SUPPORT=False``` should no longer be needed. Following |
||||
[this PR](https://github.com/grpc/grpc/pull/14647), fork |
||||
handlers will not automatically run when multiple threads are calling |
||||
into gRPC. |
@ -1,18 +1,15 @@ |
||||
Each version of gRPC gets a new description of what the 'g' stands for, since |
||||
we've never really been able to figure it out. |
||||
'g' stands for something different every gRPC release: |
||||
|
||||
Below is a list of already-used definitions (that should not be repeated in the |
||||
future), and the corresponding version numbers that used them: |
||||
|
||||
- 1.0 'g' stands for 'gRPC' |
||||
- 1.1 'g' stands for 'good' |
||||
- 1.2 'g' stands for 'green' |
||||
- 1.3 'g' stands for 'gentle' |
||||
- 1.4 'g' stands for 'gregarious' |
||||
- 1.6 'g' stands for 'garcia' |
||||
- 1.7 'g' stands for 'gambit' |
||||
- 1.8 'g' stands for 'generous' |
||||
- 1.9 'g' stands for 'glossy' |
||||
- 1.10 'g' stands for 'glamorous' |
||||
- 1.11 'g' stands for 'gorgeous' |
||||
- 1.12 'g' stands for 'glorious' |
||||
- 1.0 'g' stands for ['gRPC'](https://github.com/grpc/grpc/tree/v1.0.x) |
||||
- 1.1 'g' stands for ['good'](https://github.com/grpc/grpc/tree/v1.1.x) |
||||
- 1.2 'g' stands for ['green'](https://github.com/grpc/grpc/tree/v1.2.x) |
||||
- 1.3 'g' stands for ['gentle'](https://github.com/grpc/grpc/tree/v1.3.x) |
||||
- 1.4 'g' stands for ['gregarious'](https://github.com/grpc/grpc/tree/v1.4.x) |
||||
- 1.6 'g' stands for ['garcia'](https://github.com/grpc/grpc/tree/v1.6.x) |
||||
- 1.7 'g' stands for ['gambit'](https://github.com/grpc/grpc/tree/v1.7.x) |
||||
- 1.8 'g' stands for ['generous'](https://github.com/grpc/grpc/tree/v1.8.x) |
||||
- 1.9 'g' stands for ['glossy'](https://github.com/grpc/grpc/tree/v1.9.x) |
||||
- 1.10 'g' stands for ['glamorous'](https://github.com/grpc/grpc/tree/v1.10.x) |
||||
- 1.11 'g' stands for ['gorgeous'](https://github.com/grpc/grpc/tree/v1.11.x) |
||||
- 1.12 'g' stands for ['glorious'](https://github.com/grpc/grpc/tree/v1.12.x) |
||||
- 1.13 'g' stands for ['gloriosa'](https://github.com/grpc/grpc/tree/master) |
||||
|
@ -1,92 +0,0 @@ |
||||
# Stress Test framework for gRPC |
||||
|
||||
(Sree Kuchibhotla - sreek@) |
||||
|
||||
Status: This is implemented. More details at [README.md](https://github.com/grpc/grpc/blob/master/tools/run_tests/stress_test/README.md) |
||||
|
||||
|
||||
**I. GOALS** |
||||
|
||||
1) Build a stress test suite for gRPC: |
||||
|
||||
* Build a stress test suite that can Identify bugs by testing the system (gRPC server/client) under extreme conditions: |
||||
* High load |
||||
* High concurrency |
||||
* Limited resources |
||||
* Intermittent failures |
||||
* Should be integrated with Jenkins CI |
||||
|
||||
2) Make it generic enough (i.e build a generic test framework) that can be used for: |
||||
|
||||
* Executing M instances of a client against N instances of a server with an arbitrarily defined connection matrix |
||||
* Execute heterogenous test configurations - for example: Java stress test clients against C++ servers or Node clients against Python servers or TSAN C++ clients vs ASAN C++ Servers etc. |
||||
* Easy and Flexible enough that Devs can use it to recreate complex test scenarios |
||||
|
||||
The implementation effort is divided into two parts: |
||||
|
||||
* Building a "Stress Test Framework" to run the stress test suites- More details in **Section II** (The idea is that the Stress Test framework is generic enough that it would be easier to modify it to run other suites like interop-tests or custom test scenarios) |
||||
* Building a 'Stress test suite' - More details in **section III** |
||||
|
||||
**Terminology:** |
||||
|
||||
GCE - Google compute engine |
||||
GKE - Google Container engine |
||||
Kubernetes - Google's open source service scheduler / orchestrator. |
||||
|
||||
**Note:** The terms GKE and Kubernetes are used interchangeably in this document |
||||
|
||||
# II. STRESS TEST FRAMEWORK |
||||
|
||||
(The details of each step are explained below)) |
||||
 |
||||
**Figure 1** |
||||
|
||||
### Step 1 Read the test config, generate base docker images |
||||
|
||||
**_Test Config:_** The test configuration contains the following information: |
||||
|
||||
* _GKE info:_ GKE project and cluster info |
||||
* _Docker images:_ Instructions to build docker images |
||||
* _Client templates:_ One or more client templates each containing the following information: |
||||
* Which docker image to use |
||||
* Path to the client program to launch (within the docker image) |
||||
* Parameters to the client program |
||||
* _Server templates:_ Similar to Client templates - except that these are for servers |
||||
* Test matrix containing the following: |
||||
* _Server groups:_ One or more groups of servers containing the following info for each group |
||||
* Which server template to use |
||||
* How many instances to launch |
||||
* _Client groups:_ One or more groups of clients containing the following (for each group): |
||||
* Which client template to use |
||||
* How many instances to launch |
||||
* Which server group to talk to (all clients in this group will talk to all servers in the server group) |
||||
|
||||
The first step is to read the test config and build the docker images |
||||
|
||||
**_Stress server docker image:_** The following are the main files in the server docker images |
||||
|
||||
* _Interop_server:_ The server program |
||||
* `run_server.py`: This is a python script which is the entry point of the docker image (i.e this is the script that is called when the docker image is run in GKE). This script launches the interop server and also updates the status in BigQuery. If the interop_server fails for whatever reason, the script launch_server.py logs that status in BigQuery |
||||
|
||||
**_Stress client docker image:_** |
||||
|
||||
* Stress client: The stress test client. In addition to talking to the interop_server, the stress client also exports metrics (which can be queried by the metrics_client described below) |
||||
* Metrics client: Metrics client connects to the stress_client to get the current qps metrics. |
||||
* `run_client.py`: This is a python script which is the entry point of the docker image (i.e this is the script that is called when the docker image is run in GKE). This script launches the stress client and also updates the status in BigQuery. The script then periodically launches metrics client to query the qps from the stress client and then uploads the qps to BigQuery. |
||||
|
||||
### Step 2) Upload the docker images to GKE |
||||
The docker images are uploaded to the GKE registry |
||||
|
||||
### Step 3) Launch the tests in GKE |
||||
The test driver reads the test matrix (described in step 1) and creates the necessary server and client pods in GKE. |
||||
|
||||
### Step 4) Tests are run in GKE |
||||
GKE starts running the tests by calling the entry points in *each* docker image (i.e `run_server.py` or `run_client.py` depending on whcih docker image it is) |
||||
|
||||
### Step 5) Upload the status to GKE and Monitor the status in GKE |
||||
* 5.1 The tests periodically update their status in BigQuery |
||||
* 5.2 The test driver periodically checks the status in Bigquery to see if any tests failed. If any tests failed, the driver immediately stops the tests. If not, the driver continues to run the tests for a configurable amount of time. |
||||
|
||||
### Step 6) Create a summary report |
||||
The test driver creates a final summary report containing details about any test failures and information about how to connect the failed pods in GKE for debugging. |
||||
|
@ -1,5 +0,0 @@ |
||||
{ |
||||
"sdk": { |
||||
"version": "1.0.0" |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
*.iml |
||||
.gradle |
||||
/local.properties |
||||
/.idea/workspace.xml |
||||
/.idea/libraries |
||||
.DS_Store |
||||
/build |
||||
/captures |
||||
.externalNativeBuild |
@ -0,0 +1,37 @@ |
||||
gRPC on Android |
||||
============== |
||||
|
||||
Note: Building the protobuf dependency for Android requires |
||||
https://github.com/google/protobuf/pull/3878. This fix will be in the next |
||||
protobuf release, but until then must be manually patched in to |
||||
`third_party/protobuf` to build gRPC for Android. |
||||
|
||||
PREREQUISITES |
||||
------------- |
||||
|
||||
- Android SDK |
||||
- Android NDK |
||||
- `protoc` and `grpc_cpp_plugin` binaries on the host system |
||||
|
||||
INSTALL |
||||
------- |
||||
|
||||
The example application can be built via Android Studio or on the command line |
||||
using `gradle`: |
||||
|
||||
```sh |
||||
$ ./gradlew installDebug |
||||
``` |
||||
|
||||
INSTRUMENTATION TESTS |
||||
--------------------- |
||||
|
||||
The instrumentation tests can be run via the following `gradle` command. This |
||||
requires an emulator already running on your computer. |
||||
|
||||
``` |
||||
$ ./gradlew connectedAndroidTest \ |
||||
-Pandroid.testInstrumentationRunnerArguments.server_host=grpc-test.sandbox.googleapis.com \ |
||||
-Pandroid.testInstrumentationRunnerArguments.server_port=443 \ |
||||
-Pandroid.testInstrumentationRunnerArguments.use_tls=true |
||||
``` |
@ -0,0 +1 @@ |
||||
/build |
@ -0,0 +1,119 @@ |
||||
cmake_minimum_required(VERSION 3.4.1) |
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") |
||||
|
||||
set(PROTOBUF_PROTOC_EXECUTABLE "/usr/local/bin/protoc" CACHE STRING "Protoc binary on host") |
||||
set(gRPC_CPP_PLUGIN_EXECUTABLE "/usr/local/bin/grpc_cpp_plugin" CACHE STRING "gRPC CPP plugin binary on host") |
||||
|
||||
set(GRPC_SRC_DIR ../../../../../) |
||||
|
||||
set(GRPC_BUILD_DIR ../grpc/outputs/${ANDROID_ABI}) |
||||
file(MAKE_DIRECTORY ${GRPC_BUILD_DIR}) |
||||
|
||||
add_subdirectory(${GRPC_SRC_DIR} ${GRPC_BUILD_DIR}) |
||||
|
||||
#include_directories(${GRPC_SRC_DIR}/include) |
||||
include_directories(${GRPC_SRC_DIR}) |
||||
|
||||
set(GRPC_PROTO_GENS_DIR ${CMAKE_BINARY_DIR}/gens) |
||||
file(MAKE_DIRECTORY ${GRPC_PROTO_GENS_DIR}) |
||||
include_directories(${GRPC_PROTO_GENS_DIR}) |
||||
|
||||
function(android_protobuf_grpc_generate_cpp SRC_FILES HDR_FILES INCLUDE_ROOT) |
||||
if(NOT ARGN) |
||||
message(SEND_ERROR "Error: android_protobuf_grpc_generate_cpp() called without any proto files") |
||||
return() |
||||
endif() |
||||
|
||||
set(${SRC_FILES}) |
||||
set(${HDR_FILES}) |
||||
set(PROTOBUF_INCLUDE_PATH -I ${INCLUDE_ROOT}) |
||||
foreach(FIL ${ARGN}) |
||||
get_filename_component(ABS_FIL ${FIL} ABSOLUTE) |
||||
get_filename_component(FIL_WE ${FIL} NAME_WE) |
||||
file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR}/${INCLUDE_ROOT} ${ABS_FIL}) |
||||
get_filename_component(REL_DIR ${REL_FIL} DIRECTORY) |
||||
set(RELFIL_WE "${REL_DIR}/${FIL_WE}") |
||||
|
||||
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc") |
||||
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h") |
||||
list(APPEND ${SRC_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc") |
||||
list(APPEND ${HDR_FILES} "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h") |
||||
|
||||
add_custom_command( |
||||
OUTPUT "${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.cc" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.grpc.pb.h" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.cc" |
||||
"${GRPC_PROTO_GENS_DIR}/${RELFIL_WE}.pb.h" |
||||
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} |
||||
ARGS --grpc_out=${GRPC_PROTO_GENS_DIR} |
||||
--cpp_out=${GRPC_PROTO_GENS_DIR} |
||||
--plugin=protoc-gen-grpc=${gRPC_CPP_PLUGIN_EXECUTABLE} |
||||
${PROTOBUF_INCLUDE_PATH} |
||||
${REL_FIL} |
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |
||||
DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE} ${gRPC_CPP_PLUGIN_EXECUTABLE} ${ABS_FIL} ) |
||||
endforeach() |
||||
|
||||
set_source_files_properties(${${SRC_FILES}} ${${HDR_FILES}} PROPERTIES GENERATED TRUE) |
||||
set(${SRC_FILES} ${${SRC_FILES}} PARENT_SCOPE) |
||||
set(${HDR_FILES} ${${HDR_FILES}} PARENT_SCOPE) |
||||
endfunction() |
||||
|
||||
set(PROTO_BASE_DIR ${GRPC_SRC_DIR}/examples/protos) |
||||
|
||||
android_protobuf_grpc_generate_cpp( |
||||
MESSAGES_PROTO_SRCS MESSAGES_PROTO_HDRS |
||||
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/messages.proto) |
||||
|
||||
add_library(messages_proto_lib |
||||
SHARED ${MESSAGES_PROTO_SRCS} ${MESSAGES_PROTO_HDRS}) |
||||
|
||||
target_link_libraries(messages_proto_lib |
||||
libprotobuf |
||||
grpc++ |
||||
android |
||||
log) |
||||
|
||||
android_protobuf_grpc_generate_cpp( |
||||
EMPTY_PROTO_SRCS EMPTY_PROTO_HDRS |
||||
${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/empty.proto) |
||||
|
||||
add_library(empty_proto_lib |
||||
SHARED ${EMPTY_PROTO_SRCS} ${EMPTY_PROTO_HDRS}) |
||||
|
||||
target_link_libraries(empty_proto_lib |
||||
libprotobuf |
||||
grpc++ |
||||
android |
||||
log) |
||||
|
||||
android_protobuf_grpc_generate_cpp( |
||||
TEST_PROTO_SRCS TEST_PROTO_HDRS ${GRPC_SRC_DIR} ${GRPC_SRC_DIR}/src/proto/grpc/testing/test.proto) |
||||
|
||||
add_library(test_proto_lib |
||||
SHARED ${TEST_PROTO_SRCS} ${TEST_PROTO_HDRS}) |
||||
|
||||
target_link_libraries(test_proto_lib |
||||
libprotobuf |
||||
grpc++ |
||||
empty_proto_lib |
||||
messages_proto_lib |
||||
android |
||||
log) |
||||
|
||||
find_library(log-lib |
||||
log) |
||||
|
||||
add_library(grpc-interop |
||||
SHARED |
||||
src/main/cpp/grpc-interop.cc |
||||
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.h |
||||
${GRPC_SRC_DIR}/test/cpp/interop/interop_client.cc) |
||||
|
||||
target_link_libraries(grpc-interop |
||||
messages_proto_lib |
||||
empty_proto_lib |
||||
test_proto_lib |
||||
android |
||||
${log-lib}) |
@ -0,0 +1,56 @@ |
||||
apply plugin: 'com.android.application' |
||||
|
||||
android { |
||||
compileSdkVersion 26 |
||||
defaultConfig { |
||||
applicationId "io.grpc.android.interop.cpp" |
||||
minSdkVersion 14 |
||||
targetSdkVersion 26 |
||||
versionCode 1 |
||||
versionName "1.0" |
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||
externalNativeBuild { |
||||
cmake { |
||||
// The paths to the protoc and grpc_cpp_plugin binaries on the host system (codegen |
||||
// is not cross-compiled to Android) |
||||
def protoc = project.hasProperty('protoc') ? |
||||
project.property('protoc') : '/usr/local/bin/protoc' |
||||
def grpc_cpp_plugin = project.hasProperty('grpc_cpp_plugin') ? |
||||
project.property('grpc_cpp_plugin') : '/usr/local/bin/grpc_cpp_plugin' |
||||
|
||||
cppFlags "-std=c++14 -frtti -fexceptions" |
||||
arguments '-DANDROID_STL=c++_shared' |
||||
arguments '-DRUN_HAVE_POSIX_REGEX=0' |
||||
arguments '-DRUN_HAVE_STD_REGEX=0' |
||||
arguments '-DRUN_HAVE_STEADY_CLOCK=0' |
||||
arguments '-Dprotobuf_BUILD_PROTOC_BINARIES=off' |
||||
arguments '-DgRPC_BUILD_CODEGEN=off' |
||||
arguments '-DPROTOBUF_PROTOC_EXECUTABLE=' + protoc |
||||
arguments '-DgRPC_CPP_PLUGIN_EXECUTABLE=' + grpc_cpp_plugin |
||||
} |
||||
} |
||||
ndk.abiFilters 'x86' |
||||
} |
||||
buildTypes { |
||||
debug { |
||||
minifyEnabled false |
||||
} |
||||
release { |
||||
minifyEnabled true |
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||||
} |
||||
} |
||||
externalNativeBuild { |
||||
cmake { |
||||
path "CMakeLists.txt" |
||||
} |
||||
} |
||||
} |
||||
|
||||
dependencies { |
||||
implementation fileTree(dir: 'libs', include: ['*.jar']) |
||||
implementation 'com.android.support:appcompat-v7:26.1.0' |
||||
testImplementation 'junit:junit:4.12' |
||||
androidTestImplementation 'com.android.support.test:runner:1.0.1' |
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' |
||||
} |
@ -0,0 +1,21 @@ |
||||
# Add project specific ProGuard rules here. |
||||
# You can control the set of applied configuration files using the |
||||
# proguardFiles setting in build.gradle. |
||||
# |
||||
# For more details, see |
||||
# http://developer.android.com/guide/developing/tools/proguard.html |
||||
|
||||
# If your project uses WebView with JS, uncomment the following |
||||
# and specify the fully qualified class name to the JavaScript interface |
||||
# class: |
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||
# public *; |
||||
#} |
||||
|
||||
# Uncomment this to preserve the line number information for |
||||
# debugging stack traces. |
||||
#-keepattributes SourceFile,LineNumberTable |
||||
|
||||
# If you keep the line number information, uncomment this to |
||||
# hide the original source file name. |
||||
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,93 @@ |
||||
/* |
||||
* Copyright 2018, gRPC Authors All rights reserved. |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
package io.grpc.interop.cpp; |
||||
|
||||
import static junit.framework.Assert.assertTrue; |
||||
|
||||
import android.content.Context; |
||||
import android.support.test.InstrumentationRegistry; |
||||
import android.support.test.runner.AndroidJUnit4; |
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
@RunWith(AndroidJUnit4.class) |
||||
public class InteropTest { |
||||
private String host; |
||||
private int port; |
||||
private boolean useTls; |
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
host = |
||||
InstrumentationRegistry.getArguments() |
||||
.getString("server_host", "grpc-test.sandbox.googleapis.com"); |
||||
port = Integer.parseInt(InstrumentationRegistry.getArguments().getString("server_port", "443")); |
||||
useTls = |
||||
Boolean.parseBoolean(InstrumentationRegistry.getArguments().getString("use_tls", "true")); |
||||
|
||||
if (useTls) { |
||||
Context ctx = InstrumentationRegistry.getTargetContext(); |
||||
String sslRootsFile = "roots.pem"; |
||||
InputStream in = ctx.getAssets().open(sslRootsFile); |
||||
File outFile = new File(ctx.getExternalFilesDir(null), sslRootsFile); |
||||
OutputStream out = new FileOutputStream(outFile); |
||||
byte[] buffer = new byte[1024]; |
||||
int bytesRead; |
||||
while ((bytesRead = in.read(buffer)) != -1) { |
||||
out.write(buffer, 0, bytesRead); |
||||
} |
||||
in.close(); |
||||
out.close(); |
||||
InteropActivity.configureSslRoots(outFile.getCanonicalPath()); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void emptyUnary() { |
||||
assertTrue(InteropActivity.doEmpty(host, port, useTls)); |
||||
} |
||||
|
||||
@Test |
||||
public void largeUnary() { |
||||
assertTrue(InteropActivity.doLargeUnary(host, port, useTls)); |
||||
} |
||||
|
||||
@Test |
||||
public void emptyStream() { |
||||
assertTrue(InteropActivity.doEmptyStream(host, port, useTls)); |
||||
} |
||||
|
||||
@Test |
||||
public void requestStreaming() { |
||||
assertTrue(InteropActivity.doRequestStreaming(host, port, useTls)); |
||||
} |
||||
|
||||
@Test |
||||
public void responseStreaming() { |
||||
assertTrue(InteropActivity.doResponseStreaming(host, port, useTls)); |
||||
} |
||||
|
||||
@Test |
||||
public void pingPong() { |
||||
assertTrue(InteropActivity.doPingPong(host, port, useTls)); |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="io.grpc.interop.cpp" > |
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" /> |
||||
|
||||
<application |
||||
android:allowBackup="false" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:theme="@style/Base.V7.Theme.AppCompat.Light" > |
||||
<activity |
||||
android:name=".InteropActivity" |
||||
android:label="@string/app_name" > |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
</application> |
||||
|
||||
</manifest> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,124 @@ |
||||
/*
|
||||
* |
||||
* 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 <grpcpp/grpcpp.h> |
||||
#include <jni.h> |
||||
#include <src/core/lib/gpr/env.h> |
||||
|
||||
#include "test/cpp/interop/interop_client.h" |
||||
|
||||
extern "C" JNIEXPORT void JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_configureSslRoots(JNIEnv* env, |
||||
jobject obj_this, |
||||
jstring path_raw) { |
||||
const char* path = env->GetStringUTFChars(path_raw, (jboolean*)0); |
||||
|
||||
gpr_setenv("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH", path); |
||||
} |
||||
|
||||
std::shared_ptr<grpc::testing::InteropClient> GetClient(const char* host, |
||||
int port, |
||||
bool use_tls) { |
||||
const int host_port_buf_size = 1024; |
||||
char host_port[host_port_buf_size]; |
||||
snprintf(host_port, host_port_buf_size, "%s:%d", host, port); |
||||
|
||||
std::shared_ptr<grpc::ChannelCredentials> credentials; |
||||
if (use_tls) { |
||||
credentials = grpc::SslCredentials(grpc::SslCredentialsOptions()); |
||||
} else { |
||||
credentials = grpc::InsecureChannelCredentials(); |
||||
} |
||||
|
||||
return std::shared_ptr<grpc::testing::InteropClient>( |
||||
new grpc::testing::InteropClient( |
||||
grpc::CreateChannel(host_port, credentials), true, false)); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doEmpty(JNIEnv* env, jobject obj_this, |
||||
jstring host_raw, |
||||
jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoEmpty(); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doLargeUnary(JNIEnv* env, |
||||
jobject obj_this, |
||||
jstring host_raw, |
||||
jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoLargeUnary(); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doEmptyStream(JNIEnv* env, |
||||
jobject obj_this, |
||||
jstring host_raw, |
||||
jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoEmptyStream(); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doRequestStreaming( |
||||
JNIEnv* env, jobject obj_this, jstring host_raw, jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoRequestStreaming(); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doResponseStreaming( |
||||
JNIEnv* env, jobject obj_this, jstring host_raw, jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoResponseStreaming(); |
||||
} |
||||
|
||||
extern "C" JNIEXPORT jboolean JNICALL |
||||
Java_io_grpc_interop_cpp_InteropActivity_doPingPong(JNIEnv* env, |
||||
jobject obj_this, |
||||
jstring host_raw, |
||||
jint port_raw, |
||||
jboolean use_tls_raw) { |
||||
const char* host = env->GetStringUTFChars(host_raw, (jboolean*)0); |
||||
int port = static_cast<int>(port_raw); |
||||
bool use_tls = static_cast<bool>(use_tls_raw); |
||||
|
||||
return GetClient(host, port, use_tls)->DoPingPong(); |
||||
} |
@ -0,0 +1,122 @@ |
||||
/* |
||||
* Copyright 2018, gRPC Authors All rights reserved. |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
package io.grpc.interop.cpp; |
||||
|
||||
import android.content.Context; |
||||
import android.os.AsyncTask; |
||||
import android.os.Bundle; |
||||
import android.support.v7.app.AppCompatActivity; |
||||
import android.text.TextUtils; |
||||
import android.text.method.ScrollingMovementMethod; |
||||
import android.view.View; |
||||
import android.view.inputmethod.InputMethodManager; |
||||
import android.widget.Button; |
||||
import android.widget.EditText; |
||||
import android.widget.TextView; |
||||
import java.lang.ref.WeakReference; |
||||
|
||||
public class InteropActivity extends AppCompatActivity { |
||||
|
||||
static { |
||||
System.loadLibrary("grpc-interop"); |
||||
} |
||||
|
||||
private Button sendButton; |
||||
private EditText hostEdit; |
||||
private EditText portEdit; |
||||
private TextView resultText; |
||||
private GrpcTask grpcTask; |
||||
|
||||
@Override |
||||
protected void onCreate(Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
setContentView(R.layout.activity_interop); |
||||
sendButton = (Button) findViewById(R.id.ping_pong_button); |
||||
hostEdit = (EditText) findViewById(R.id.host_edit_text); |
||||
portEdit = (EditText) findViewById(R.id.port_edit_text); |
||||
resultText = (TextView) findViewById(R.id.grpc_result_text); |
||||
resultText.setMovementMethod(new ScrollingMovementMethod()); |
||||
} |
||||
|
||||
@Override |
||||
protected void onPause() { |
||||
super.onPause(); |
||||
if (grpcTask != null) { |
||||
grpcTask.cancel(true); |
||||
grpcTask = null; |
||||
} |
||||
} |
||||
|
||||
public void doPingPong(View view) { |
||||
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) |
||||
.hideSoftInputFromWindow(hostEdit.getWindowToken(), 0); |
||||
sendButton.setEnabled(false); |
||||
resultText.setText(""); |
||||
grpcTask = new GrpcTask(this); |
||||
grpcTask.executeOnExecutor( |
||||
AsyncTask.THREAD_POOL_EXECUTOR, |
||||
hostEdit.getText().toString(), |
||||
portEdit.getText().toString()); |
||||
} |
||||
|
||||
private static class GrpcTask extends AsyncTask<String, Void, String> { |
||||
private final WeakReference<InteropActivity> activityReference; |
||||
|
||||
private GrpcTask(InteropActivity activity) { |
||||
this.activityReference = new WeakReference<InteropActivity>(activity); |
||||
} |
||||
|
||||
@Override |
||||
protected String doInBackground(String... params) { |
||||
String host = params[0]; |
||||
String portStr = params[1]; |
||||
int port = TextUtils.isEmpty(portStr) ? 50051 : Integer.valueOf(portStr); |
||||
// TODO(ericgribkoff) Support other test cases in the app UI
|
||||
if (doPingPong(host, port, false)) { |
||||
return "Success"; |
||||
} else { |
||||
return "Failure"; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected void onPostExecute(String result) { |
||||
InteropActivity activity = activityReference.get(); |
||||
if (activity == null || isCancelled()) { |
||||
return; |
||||
} |
||||
TextView resultText = (TextView) activity.findViewById(R.id.grpc_result_text); |
||||
Button sendButton = (Button) activity.findViewById(R.id.ping_pong_button); |
||||
resultText.setText(result); |
||||
sendButton.setEnabled(true); |
||||
} |
||||
} |
||||
|
||||
public static native void configureSslRoots(String path); |
||||
|
||||
public static native boolean doEmpty(String host, int port, boolean useTls); |
||||
|
||||
public static native boolean doLargeUnary(String host, int port, boolean useTls); |
||||
|
||||
public static native boolean doEmptyStream(String host, int port, boolean useTls); |
||||
|
||||
public static native boolean doRequestStreaming(String host, int port, boolean useTls); |
||||
|
||||
public static native boolean doResponseStreaming(String host, int port, boolean useTls); |
||||
|
||||
public static native boolean doPingPong(String host, int port, boolean useTls); |
||||
} |
@ -0,0 +1,48 @@ |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
tools:context=".InteropActivity" |
||||
android:orientation="vertical" > |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="horizontal"> |
||||
<EditText |
||||
android:id="@+id/host_edit_text" |
||||
android:layout_weight="2" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:hint="Enter Host" /> |
||||
<EditText |
||||
android:id="@+id/port_edit_text" |
||||
android:layout_weight="1" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:inputType="numberDecimal" |
||||
android:hint="Enter Port" /> |
||||
</LinearLayout> |
||||
|
||||
<Button |
||||
android:id="@+id/ping_pong_button" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:onClick="doPingPong" |
||||
android:text="Ping Pong" /> |
||||
|
||||
<TextView |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:paddingTop="12dp" |
||||
android:paddingBottom="12dp" |
||||
android:textSize="16sp" |
||||
android:text="Result:" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/grpc_result_text" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:scrollbars = "vertical" |
||||
android:textSize="16sp" /> |
||||
|
||||
</LinearLayout> |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 7.5 KiB |
@ -0,0 +1,3 @@ |
||||
<resources> |
||||
<string name="app_name">gRPC C++ Interop App</string> |
||||
</resources> |
@ -0,0 +1,24 @@ |
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. |
||||
|
||||
buildscript { |
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
dependencies { |
||||
classpath 'com.android.tools.build:gradle:3.0.1' |
||||
// NOTE: Do not place your application dependencies here; they belong |
||||
// in the individual module build.gradle files |
||||
} |
||||
} |
||||
|
||||
allprojects { |
||||
repositories { |
||||
google() |
||||
jcenter() |
||||
} |
||||
} |
||||
|
||||
task clean(type: Delete) { |
||||
delete rootProject.buildDir |
||||
} |
@ -0,0 +1,17 @@ |
||||
# Project-wide Gradle settings. |
||||
|
||||
# IDE (e.g. Android Studio) users: |
||||
# Gradle settings configured through the IDE *will override* |
||||
# any settings specified in this file. |
||||
|
||||
# For more details on how to configure your build environment visit |
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
||||
|
||||
# Specifies the JVM arguments used for the daemon process. |
||||
# The setting is particularly useful for tweaking memory settings. |
||||
org.gradle.jvmargs=-Xmx1536m |
||||
|
||||
# When configured, Gradle will run in incubating parallel mode. |
||||
# This option should only be used with decoupled projects. More details, visit |
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
||||
# org.gradle.parallel=true |
Binary file not shown.
@ -0,0 +1,6 @@ |
||||
#Thu Jan 25 11:45:30 PST 2018 |
||||
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip |
@ -0,0 +1,160 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
############################################################################## |
||||
## |
||||
## Gradle start up script for UN*X |
||||
## |
||||
############################################################################## |
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
DEFAULT_JVM_OPTS="" |
||||
|
||||
APP_NAME="Gradle" |
||||
APP_BASE_NAME=`basename "$0"` |
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
||||
MAX_FD="maximum" |
||||
|
||||
warn ( ) { |
||||
echo "$*" |
||||
} |
||||
|
||||
die ( ) { |
||||
echo |
||||
echo "$*" |
||||
echo |
||||
exit 1 |
||||
} |
||||
|
||||
# OS specific support (must be 'true' or 'false'). |
||||
cygwin=false |
||||
msys=false |
||||
darwin=false |
||||
case "`uname`" in |
||||
CYGWIN* ) |
||||
cygwin=true |
||||
;; |
||||
Darwin* ) |
||||
darwin=true |
||||
;; |
||||
MINGW* ) |
||||
msys=true |
||||
;; |
||||
esac |
||||
|
||||
# Attempt to set APP_HOME |
||||
# Resolve links: $0 may be a link |
||||
PRG="$0" |
||||
# Need this for relative symlinks. |
||||
while [ -h "$PRG" ] ; do |
||||
ls=`ls -ld "$PRG"` |
||||
link=`expr "$ls" : '.*-> \(.*\)$'` |
||||
if expr "$link" : '/.*' > /dev/null; then |
||||
PRG="$link" |
||||
else |
||||
PRG=`dirname "$PRG"`"/$link" |
||||
fi |
||||
done |
||||
SAVED="`pwd`" |
||||
cd "`dirname \"$PRG\"`/" >/dev/null |
||||
APP_HOME="`pwd -P`" |
||||
cd "$SAVED" >/dev/null |
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
||||
|
||||
# Determine the Java command to use to start the JVM. |
||||
if [ -n "$JAVA_HOME" ] ; then |
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
||||
# IBM's JDK on AIX uses strange locations for the executables |
||||
JAVACMD="$JAVA_HOME/jre/sh/java" |
||||
else |
||||
JAVACMD="$JAVA_HOME/bin/java" |
||||
fi |
||||
if [ ! -x "$JAVACMD" ] ; then |
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
else |
||||
JAVACMD="java" |
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the |
||||
location of your Java installation." |
||||
fi |
||||
|
||||
# Increase the maximum file descriptors if we can. |
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then |
||||
MAX_FD_LIMIT=`ulimit -H -n` |
||||
if [ $? -eq 0 ] ; then |
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
||||
MAX_FD="$MAX_FD_LIMIT" |
||||
fi |
||||
ulimit -n $MAX_FD |
||||
if [ $? -ne 0 ] ; then |
||||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
||||
fi |
||||
else |
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
||||
fi |
||||
fi |
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock |
||||
if $darwin; then |
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
||||
fi |
||||
|
||||
# For Cygwin, switch paths to Windows format before running java |
||||
if $cygwin ; then |
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
||||
JAVACMD=`cygpath --unix "$JAVACMD"` |
||||
|
||||
# We build the pattern for arguments to be converted via cygpath |
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
||||
SEP="" |
||||
for dir in $ROOTDIRSRAW ; do |
||||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
||||
SEP="|" |
||||
done |
||||
OURCYGPATTERN="(^($ROOTDIRS))" |
||||
# Add a user-defined pattern to the cygpath arguments |
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
||||
fi |
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
||||
i=0 |
||||
for arg in "$@" ; do |
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
||||
else |
||||
eval `echo args$i`="\"$arg\"" |
||||
fi |
||||
i=$((i+1)) |
||||
done |
||||
case $i in |
||||
(0) set -- ;; |
||||
(1) set -- "$args0" ;; |
||||
(2) set -- "$args0" "$args1" ;; |
||||
(3) set -- "$args0" "$args1" "$args2" ;; |
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
||||
esac |
||||
fi |
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules |
||||
function splitJvmOpts() { |
||||
JVM_OPTS=("$@") |
||||
} |
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS |
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" |
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@ -0,0 +1,90 @@ |
||||
@if "%DEBUG%" == "" @echo off |
||||
@rem ########################################################################## |
||||
@rem |
||||
@rem Gradle startup script for Windows |
||||
@rem |
||||
@rem ########################################################################## |
||||
|
||||
@rem Set local scope for the variables with windows NT shell |
||||
if "%OS%"=="Windows_NT" setlocal |
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
||||
set DEFAULT_JVM_OPTS= |
||||
|
||||
set DIRNAME=%~dp0 |
||||
if "%DIRNAME%" == "" set DIRNAME=. |
||||
set APP_BASE_NAME=%~n0 |
||||
set APP_HOME=%DIRNAME% |
||||
|
||||
@rem Find java.exe |
||||
if defined JAVA_HOME goto findJavaFromJavaHome |
||||
|
||||
set JAVA_EXE=java.exe |
||||
%JAVA_EXE% -version >NUL 2>&1 |
||||
if "%ERRORLEVEL%" == "0" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:findJavaFromJavaHome |
||||
set JAVA_HOME=%JAVA_HOME:"=% |
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
||||
|
||||
if exist "%JAVA_EXE%" goto init |
||||
|
||||
echo. |
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
||||
echo. |
||||
echo Please set the JAVA_HOME variable in your environment to match the |
||||
echo location of your Java installation. |
||||
|
||||
goto fail |
||||
|
||||
:init |
||||
@rem Get command-line arguments, handling Windowz variants |
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args |
||||
if "%@eval[2+2]" == "4" goto 4NT_args |
||||
|
||||
:win9xME_args |
||||
@rem Slurp the command line arguments. |
||||
set CMD_LINE_ARGS= |
||||
set _SKIP=2 |
||||
|
||||
:win9xME_args_slurp |
||||
if "x%~1" == "x" goto execute |
||||
|
||||
set CMD_LINE_ARGS=%* |
||||
goto execute |
||||
|
||||
:4NT_args |
||||
@rem Get arguments from the 4NT Shell from JP Software |
||||
set CMD_LINE_ARGS=%$ |
||||
|
||||
:execute |
||||
@rem Setup the command line |
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
||||
|
||||
@rem Execute Gradle |
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
||||
|
||||
:end |
||||
@rem End local scope for the variables with windows NT shell |
||||
if "%ERRORLEVEL%"=="0" goto mainEnd |
||||
|
||||
:fail |
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
||||
rem the _cmd.exe /c_ return code! |
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
||||
exit /b 1 |
||||
|
||||
:mainEnd |
||||
if "%OS%"=="Windows_NT" endlocal |
||||
|
||||
:omega |
@ -0,0 +1 @@ |
||||
include ':app' |
@ -1,4 +1,4 @@ |
||||
set noparent |
||||
@markdroth |
||||
@dgquintas |
||||
@a11r |
||||
@AspirinSJL |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,36 @@ |
||||
/*
|
||||
* |
||||
* 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_LB_POLICY_GRPCLB_GRPCLB_H |
||||
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
/** Channel arg indicating if a target corresponding to the address is grpclb
|
||||
* loadbalancer. The type of this arg is an integer and the value is treated as |
||||
* a bool. */ |
||||
#define GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER \ |
||||
"grpc.address_is_grpclb_load_balancer" |
||||
/** Channel arg indicating if a target corresponding to the address is a backend
|
||||
* received from a balancer. The type of this arg is an integer and the value is |
||||
* treated as a bool. */ |
||||
#define GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER \ |
||||
"grpc.address_is_backend_from_grpclb_load_balancer" |
||||
|
||||
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H \ |
||||
*/ |
@ -1,253 +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 <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" |
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/combiner.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/transport/connectivity_state.h" |
||||
|
||||
void grpc_lb_subchannel_data_unref_subchannel(grpc_lb_subchannel_data* sd, |
||||
const char* reason) { |
||||
if (sd->subchannel != nullptr) { |
||||
if (sd->subchannel_list->tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR |
||||
" (subchannel %p): unreffing subchannel", |
||||
sd->subchannel_list->tracer->name(), sd->subchannel_list->policy, |
||||
sd->subchannel_list, |
||||
static_cast<size_t>(sd - sd->subchannel_list->subchannels), |
||||
sd->subchannel_list->num_subchannels, sd->subchannel); |
||||
} |
||||
GRPC_SUBCHANNEL_UNREF(sd->subchannel, reason); |
||||
sd->subchannel = nullptr; |
||||
sd->connected_subchannel.reset(); |
||||
if (sd->user_data != nullptr) { |
||||
GPR_ASSERT(sd->user_data_vtable != nullptr); |
||||
sd->user_data_vtable->destroy(sd->user_data); |
||||
sd->user_data = nullptr; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void grpc_lb_subchannel_data_start_connectivity_watch( |
||||
grpc_lb_subchannel_data* sd) { |
||||
if (sd->subchannel_list->tracer->enabled()) { |
||||
gpr_log( |
||||
GPR_DEBUG, |
||||
"[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR |
||||
" (subchannel %p): requesting connectivity change " |
||||
"notification (from %s)", |
||||
sd->subchannel_list->tracer->name(), sd->subchannel_list->policy, |
||||
sd->subchannel_list, |
||||
static_cast<size_t>(sd - sd->subchannel_list->subchannels), |
||||
sd->subchannel_list->num_subchannels, sd->subchannel, |
||||
grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe)); |
||||
} |
||||
sd->connectivity_notification_pending = true; |
||||
grpc_subchannel_notify_on_state_change( |
||||
sd->subchannel, sd->subchannel_list->policy->interested_parties(), |
||||
&sd->pending_connectivity_state_unsafe, |
||||
&sd->connectivity_changed_closure); |
||||
} |
||||
|
||||
void grpc_lb_subchannel_data_stop_connectivity_watch( |
||||
grpc_lb_subchannel_data* sd) { |
||||
if (sd->subchannel_list->tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR |
||||
" (subchannel %p): stopping connectivity watch", |
||||
sd->subchannel_list->tracer->name(), sd->subchannel_list->policy, |
||||
sd->subchannel_list, |
||||
static_cast<size_t>(sd - sd->subchannel_list->subchannels), |
||||
sd->subchannel_list->num_subchannels, sd->subchannel); |
||||
} |
||||
GPR_ASSERT(sd->connectivity_notification_pending); |
||||
sd->connectivity_notification_pending = false; |
||||
} |
||||
|
||||
grpc_lb_subchannel_list* grpc_lb_subchannel_list_create( |
||||
grpc_core::LoadBalancingPolicy* p, grpc_core::TraceFlag* tracer, |
||||
const grpc_lb_addresses* addresses, grpc_combiner* combiner, |
||||
grpc_client_channel_factory* client_channel_factory, |
||||
const grpc_channel_args& args, grpc_iomgr_cb_func connectivity_changed_cb) { |
||||
grpc_lb_subchannel_list* subchannel_list = |
||||
static_cast<grpc_lb_subchannel_list*>( |
||||
gpr_zalloc(sizeof(*subchannel_list))); |
||||
if (tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", |
||||
tracer->name(), p, subchannel_list, addresses->num_addresses); |
||||
} |
||||
subchannel_list->policy = p; |
||||
subchannel_list->tracer = tracer; |
||||
gpr_ref_init(&subchannel_list->refcount, 1); |
||||
subchannel_list->subchannels = static_cast<grpc_lb_subchannel_data*>( |
||||
gpr_zalloc(sizeof(grpc_lb_subchannel_data) * addresses->num_addresses)); |
||||
// We need to remove the LB addresses in order to be able to compare the
|
||||
// subchannel keys of subchannels from a different batch of addresses.
|
||||
static const char* keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, |
||||
GRPC_ARG_LB_ADDRESSES}; |
||||
// Create a subchannel for each address.
|
||||
grpc_subchannel_args sc_args; |
||||
size_t subchannel_index = 0; |
||||
for (size_t i = 0; i < addresses->num_addresses; i++) { |
||||
// If there were any balancer, we would have chosen grpclb policy instead.
|
||||
GPR_ASSERT(!addresses->addresses[i].is_balancer); |
||||
memset(&sc_args, 0, sizeof(grpc_subchannel_args)); |
||||
grpc_arg addr_arg = |
||||
grpc_create_subchannel_address_arg(&addresses->addresses[i].address); |
||||
grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove( |
||||
&args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, 1); |
||||
gpr_free(addr_arg.value.string); |
||||
sc_args.args = new_args; |
||||
grpc_subchannel* subchannel = grpc_client_channel_factory_create_subchannel( |
||||
client_channel_factory, &sc_args); |
||||
grpc_channel_args_destroy(new_args); |
||||
if (subchannel == nullptr) { |
||||
// Subchannel could not be created.
|
||||
if (tracer->enabled()) { |
||||
char* address_uri = |
||||
grpc_sockaddr_to_uri(&addresses->addresses[i].address); |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] could not create subchannel for address uri %s, " |
||||
"ignoring", |
||||
tracer->name(), subchannel_list->policy, address_uri); |
||||
gpr_free(address_uri); |
||||
} |
||||
continue; |
||||
} |
||||
if (tracer->enabled()) { |
||||
char* address_uri = |
||||
grpc_sockaddr_to_uri(&addresses->addresses[i].address); |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] subchannel list %p index %" PRIuPTR |
||||
": Created subchannel %p for address uri %s", |
||||
tracer->name(), p, subchannel_list, subchannel_index, subchannel, |
||||
address_uri); |
||||
gpr_free(address_uri); |
||||
} |
||||
grpc_lb_subchannel_data* sd = |
||||
&subchannel_list->subchannels[subchannel_index++]; |
||||
sd->subchannel_list = subchannel_list; |
||||
sd->subchannel = subchannel; |
||||
GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, |
||||
connectivity_changed_cb, sd, |
||||
grpc_combiner_scheduler(combiner)); |
||||
// We assume that the current state is IDLE. If not, we'll get a
|
||||
// callback telling us that.
|
||||
sd->prev_connectivity_state = GRPC_CHANNEL_IDLE; |
||||
sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; |
||||
sd->pending_connectivity_state_unsafe = GRPC_CHANNEL_IDLE; |
||||
sd->user_data_vtable = addresses->user_data_vtable; |
||||
if (sd->user_data_vtable != nullptr) { |
||||
sd->user_data = |
||||
sd->user_data_vtable->copy(addresses->addresses[i].user_data); |
||||
} |
||||
} |
||||
subchannel_list->num_subchannels = subchannel_index; |
||||
subchannel_list->num_idle = subchannel_index; |
||||
return subchannel_list; |
||||
} |
||||
|
||||
static void subchannel_list_destroy(grpc_lb_subchannel_list* subchannel_list) { |
||||
if (subchannel_list->tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, "[%s %p] Destroying subchannel_list %p", |
||||
subchannel_list->tracer->name(), subchannel_list->policy, |
||||
subchannel_list); |
||||
} |
||||
for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { |
||||
grpc_lb_subchannel_data* sd = &subchannel_list->subchannels[i]; |
||||
grpc_lb_subchannel_data_unref_subchannel(sd, "subchannel_list_destroy"); |
||||
} |
||||
gpr_free(subchannel_list->subchannels); |
||||
gpr_free(subchannel_list); |
||||
} |
||||
|
||||
void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list* subchannel_list, |
||||
const char* reason) { |
||||
gpr_ref_non_zero(&subchannel_list->refcount); |
||||
if (subchannel_list->tracer->enabled()) { |
||||
const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); |
||||
gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p REF %lu->%lu (%s)", |
||||
subchannel_list->tracer->name(), subchannel_list->policy, |
||||
subchannel_list, static_cast<unsigned long>(count - 1), |
||||
static_cast<unsigned long>(count), reason); |
||||
} |
||||
} |
||||
|
||||
void grpc_lb_subchannel_list_unref(grpc_lb_subchannel_list* subchannel_list, |
||||
const char* reason) { |
||||
const bool done = gpr_unref(&subchannel_list->refcount); |
||||
if (subchannel_list->tracer->enabled()) { |
||||
const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); |
||||
gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p UNREF %lu->%lu (%s)", |
||||
subchannel_list->tracer->name(), subchannel_list->policy, |
||||
subchannel_list, static_cast<unsigned long>(count + 1), |
||||
static_cast<unsigned long>(count), reason); |
||||
} |
||||
if (done) { |
||||
subchannel_list_destroy(subchannel_list); |
||||
} |
||||
} |
||||
|
||||
static void subchannel_data_cancel_connectivity_watch( |
||||
grpc_lb_subchannel_data* sd, const char* reason) { |
||||
if (sd->subchannel_list->tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, |
||||
"[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR |
||||
" (subchannel %p): canceling connectivity watch (%s)", |
||||
sd->subchannel_list->tracer->name(), sd->subchannel_list->policy, |
||||
sd->subchannel_list, |
||||
static_cast<size_t>(sd - sd->subchannel_list->subchannels), |
||||
sd->subchannel_list->num_subchannels, sd->subchannel, reason); |
||||
} |
||||
grpc_subchannel_notify_on_state_change(sd->subchannel, nullptr, nullptr, |
||||
&sd->connectivity_changed_closure); |
||||
} |
||||
|
||||
void grpc_lb_subchannel_list_shutdown_and_unref( |
||||
grpc_lb_subchannel_list* subchannel_list, const char* reason) { |
||||
if (subchannel_list->tracer->enabled()) { |
||||
gpr_log(GPR_DEBUG, "[%s %p] Shutting down subchannel_list %p (%s)", |
||||
subchannel_list->tracer->name(), subchannel_list->policy, |
||||
subchannel_list, reason); |
||||
} |
||||
GPR_ASSERT(!subchannel_list->shutting_down); |
||||
subchannel_list->shutting_down = true; |
||||
for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { |
||||
grpc_lb_subchannel_data* sd = &subchannel_list->subchannels[i]; |
||||
// If there's a pending notification for this subchannel, cancel it;
|
||||
// the callback is responsible for unreffing the subchannel.
|
||||
// Otherwise, unref the subchannel directly.
|
||||
if (sd->connectivity_notification_pending) { |
||||
subchannel_data_cancel_connectivity_watch(sd, reason); |
||||
} else if (sd->subchannel != nullptr) { |
||||
grpc_lb_subchannel_data_unref_subchannel(sd, reason); |
||||
} |
||||
} |
||||
grpc_lb_subchannel_list_unref(subchannel_list, reason); |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue