aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--BUILD3
-rw-r--r--CMakeLists.txt35
-rw-r--r--CONTRIBUTING.md106
-rw-r--r--Makefile39
-rw-r--r--binding.gyp1
-rw-r--r--build.yaml13
-rw-r--r--config.m41
-rw-r--r--config.w321
-rw-r--r--doc/PROTOCOL-WEB.md4
-rw-r--r--gRPC-Core.podspec5
-rwxr-xr-xgrpc.gemspec3
-rw-r--r--package.xml3
-rw-r--r--src/core/ext/census/intrusive_hash_map.c319
-rw-r--r--src/core/ext/census/intrusive_hash_map.h167
-rw-r--r--src/core/ext/census/intrusive_hash_map_internal.h63
-rw-r--r--src/core/ext/transport/chttp2/server/chttp2_server.c1
-rw-r--r--src/core/lib/http/httpcli.c4
-rw-r--r--src/core/lib/http/httpcli_security_connector.c4
-rw-r--r--src/core/lib/security/transport/security_connector.c19
-rw-r--r--src/core/lib/security/transport/security_handshaker.c220
-rw-r--r--src/csharp/.editorconfig7
-rw-r--r--src/csharp/Grpc.Core/Internal/CallSafeHandle.cs11
-rw-r--r--src/csharp/Grpc.Core/Internal/CompletionRegistry.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/NativeMethods.cs4
-rw-r--r--src/csharp/Grpc.Core/Properties/AssemblyInfo.cs6
-rw-r--r--src/csharp/Grpc.Microbenchmarks/.gitignore2
-rw-r--r--src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj28
-rw-r--r--src/csharp/Grpc.Microbenchmarks/Program.cs55
-rw-r--r--src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs106
-rw-r--r--src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs79
-rw-r--r--src/csharp/Grpc.sln8
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c86
-rw-r--r--src/node/README.md64
-rw-r--r--src/node/index.js138
-rw-r--r--src/node/src/client.js254
-rw-r--r--src/node/src/common.js64
-rw-r--r--src/node/src/constants.js24
-rw-r--r--src/node/src/credentials.js63
-rw-r--r--src/node/src/grpc_extension.js4
-rw-r--r--src/node/src/metadata.js15
-rw-r--r--src/node/src/protobuf_js_5_common.js9
-rw-r--r--src/node/src/protobuf_js_6_common.js9
-rw-r--r--src/node/src/server.js445
-rw-r--r--src/node/test/surface_test.js8
-rw-r--r--src/python/grpcio/grpc_core_dependencies.py1
-rw-r--r--src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py2
-rw-r--r--templates/README.md9
-rw-r--r--test/core/census/intrusive_hash_map_test.c299
-rw-r--r--tools/doxygen/Doxyfile.core.internal3
-rw-r--r--tools/run_tests/generated/sources_and_headers.json22
-rw-r--r--tools/run_tests/generated/tests.json22
-rwxr-xr-xtools/run_tests/python_utils/jobset.py62
-rw-r--r--vsprojects/buildtests_c.sln27
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj4
-rw-r--r--vsprojects/vcxproj/grpc/grpc.vcxproj.filters9
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj4
-rw-r--r--vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters9
-rw-r--r--vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj199
-rw-r--r--vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters21
59 files changed, 2536 insertions, 667 deletions
diff --git a/BUILD b/BUILD
index cc5fd3eb47..bdea522ad1 100644
--- a/BUILD
+++ b/BUILD
@@ -282,6 +282,7 @@ grpc_cc_library(
"src/core/ext/census/grpc_filter.c",
"src/core/ext/census/grpc_plugin.c",
"src/core/ext/census/initialize.c",
+ "src/core/ext/census/intrusive_hash_map.c",
"src/core/ext/census/mlog.c",
"src/core/ext/census/operation.c",
"src/core/ext/census/placeholders.c",
@@ -297,6 +298,8 @@ grpc_cc_library(
"src/core/ext/census/gen/census.pb.h",
"src/core/ext/census/gen/trace_context.pb.h",
"src/core/ext/census/grpc_filter.h",
+ "src/core/ext/census/intrusive_hash_map.h",
+ "src/core/ext/census/intrusive_hash_map_internal.h",
"src/core/ext/census/mlog.h",
"src/core/ext/census/resource.h",
"src/core/ext/census/rpc_metric_id.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1a23545602..1635d5dc2d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -375,6 +375,7 @@ add_dependencies(buildtests_c bdp_estimator_test)
add_dependencies(buildtests_c bin_decoder_test)
add_dependencies(buildtests_c bin_encoder_test)
add_dependencies(buildtests_c census_context_test)
+add_dependencies(buildtests_c census_intrusive_hash_map_test)
add_dependencies(buildtests_c census_resource_test)
add_dependencies(buildtests_c census_trace_context_test)
add_dependencies(buildtests_c channel_create_test)
@@ -1157,6 +1158,7 @@ add_library(grpc
src/core/ext/census/grpc_filter.c
src/core/ext/census/grpc_plugin.c
src/core/ext/census/initialize.c
+ src/core/ext/census/intrusive_hash_map.c
src/core/ext/census/mlog.c
src/core/ext/census/operation.c
src/core/ext/census/placeholders.c
@@ -2048,6 +2050,7 @@ add_library(grpc_unsecure
src/core/ext/census/grpc_filter.c
src/core/ext/census/grpc_plugin.c
src/core/ext/census/initialize.c
+ src/core/ext/census/intrusive_hash_map.c
src/core/ext/census/mlog.c
src/core/ext/census/operation.c
src/core/ext/census/placeholders.c
@@ -2659,6 +2662,7 @@ add_library(grpc++_cronet
src/core/ext/census/grpc_filter.c
src/core/ext/census/grpc_plugin.c
src/core/ext/census/initialize.c
+ src/core/ext/census/intrusive_hash_map.c
src/core/ext/census/mlog.c
src/core/ext/census/operation.c
src/core/ext/census/placeholders.c
@@ -4769,6 +4773,37 @@ target_link_libraries(census_context_test
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
+add_executable(census_intrusive_hash_map_test
+ test/core/census/intrusive_hash_map_test.c
+)
+
+
+target_include_directories(census_intrusive_hash_map_test
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+ PRIVATE ${BORINGSSL_ROOT_DIR}/include
+ PRIVATE ${PROTOBUF_ROOT_DIR}/src
+ PRIVATE ${BENCHMARK_ROOT_DIR}/include
+ PRIVATE ${ZLIB_ROOT_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+ PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+ PRIVATE ${CARES_INCLUDE_DIR}
+ PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+ PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(census_intrusive_hash_map_test
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+ grpc
+ gpr_test_util
+ gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
add_executable(census_resource_test
test/core/census/resource_test.c
)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 56bb4b6eb9..e9c5fe2014 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,74 +1,54 @@
# How to contribute
-We definitely welcome patches and contribution to grpc! Here is some guideline
-and information about how to do so.
+We definitely welcome your patches and contributions to gRPC!
-## Getting started
+If you are new to github, please start by reading [Pull Request howto](https://help.github.com/articles/about-pull-requests/)
-### Legal requirements
+## Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
-### Technical requirements
+## Running tests
+
+Use `tools/run_tests/run_tests.py` script to run the unit tests.
+See [tools/run_tests](tools/run_tests) for how to run tests for a given language.
+
+Prerequisites for building and running tests are listed in [INSTALL.md](INSTALL.md)
+and in `src/YOUR-LANGUAGE` (e.g. `src/csharp`)
+
+## Generated project files
+
+To ease maintenance of language- and platform- specific build systems,
+many projects files are generated using templates and should not be edited
+by hand.
+Run `tools/buildgen/generate_projects.sh` to regenerate.
+See [templates](templates) for details.
+
+As a rule of thumb, if you see the "sanity tests" failing you've most likely edited generated files or you didn't regenerate the projects properly (or your code formatting doesn't match our code style).
+
+## Guidelines for Pull Requests
+How to get your contributions merged smoothly and quickly.
+
+- Create **small PRs** that are narrowly focused on **addressing a single concern**. We often times receive PRs that are trying to fix several things at a time, but only one fix is considered acceptable, nothing gets merged and both author's & review's time is wasted. Create more PRs to address different concerns and everyone will be happy.
+
+- For speculative changes, consider opening an issue and discussing it first. If you are suggesting a behavioral or API change, consider starting with a [gRFC proposal](https://github.com/grpc/proposal).
+
+- Provide a good **PR description** as a record of **what** change is being made and **why** it was made. Link to a github issue if it exists.
+
+- Don't fix code style and formatting unless you are already changing that line to address an issue. PRs with irrelevant changes won't be merged. If you do want to fix formatting or style, do that in a separate PR.
+
+- Unless your PR is trivial, you should expect there will be reviewer comments that you'll need to address before merging. We expect you to be reasonably responsive to those comments, otherwise the PR will be closed after 2-3 weeks of inactivity.
+
+- Maintain **clean commit history** and use **meaningful commit messages**. PRs with messy commit history are difficult to review and won't be merged. Use `rebase -i upstream/master` to curate your commit history and/or to bring in latest changes from master (but avoid rebasing in the middle of a code review).
+
+- Keep your PR up to date with upstream/master (if there are merge conflicts, we can't really merge your change).
+
+- if you are regenerating the projects using `tools/buildgen/generate_projects.sh`, make changes to generated files a separate commit with commit message `regenerate projects`. Mixing changes to generated and hand-written files make your PR difficult to review.
+
+- **All tests need to be passing** before your change can be merged. We recommend you **run tests locally** before creating your PR to catch breakages early on (see [tools/run_tests](tools/run_tests). Ultimately, the green signal will be provided by our testing infrastructure. The reviewer will help you if there are test failures that seem not related to the change you are making.
+
+- Exceptions to the rules can be made if there's a compelling reason for doing so.
-You will need several tools to work with this repository. In addition to all of
-the packages described in the [INSTALL](INSTALL.md) file, you will also need
-python, and the mako template renderer. To install the latter, using pip, one
-should simply be able to do `pip install mako`.
-In order to run all of the tests we provide, you will need valgrind and clang.
-More specifically, under debian, you will need the package libc++-dev to
-properly run all the tests.
-Compiling and running grpc C++ tests depend on protobuf 3.0.0, gtest and gflags.
-Although gflags is provided in third_party, you will need to manually install
-that dependency on your system to run these tests. Under a Debian or Ubuntu
-system, you can install the gtests and gflags packages using apt-get:
-
-```sh
- $ [sudo] apt-get install libgflags-dev libgtest-dev
-```
-
-If you are planning to work on any of the languages other than C and C++, you
-will also need their appropriate development environments.
-
-If you want to work under Windows, we recommend the use of Visual Studio 2013.
-The [Community or Express editions](http://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx)
-are free and suitable for developing with grpc. Note however that our test
-environment and tools are available for Unix environments only at the moment.
-
-## Testing your changes
-
-We provide a tool to help run the suite of tests in various environments.
-In order to run most of the available tests, one would need to run:
-
-`./tools/run_tests/run_tests.py`
-
-If you want to run tests for any of the languages {c, c++, csharp, node, objc, php, python, ruby}, do this:
-
-`./tools/run_tests/run_tests.py -l <lang>`
-
-To know about the list of available commands, do this:
-
-`./tools/run_tests/run_tests.py -h`
-
-If you are running tests for ObjC on osx, follow these steps before running tests:
-* install Xcode command-line tools by running
-`sudo xcode-select --install`
-* install macports from https://www.macports.org/install.php
-* install autoconf, automake, libtool, gflags, cmake using macports
-* restart your terminal window or run source ~/.bash_profile to pick up the new PATH changes.
-
-## Adding or removing source code
-
-Each language uses its own build system to work. Currently, the root's Makefile
-and the Visual Studio project files are building only the C and C++ source code.
-In order to ease the maintenance of these files, we have a
-template system. Please do not contribute manual changes to any of the generated
-files. Instead, modify the template files, or the build.yaml file, and
-re-generate the project files using the following command:
-
-`./tools/buildgen/generate_projects.sh`
-
-You'll find more information about this in the [templates](templates) folder.
diff --git a/Makefile b/Makefile
index 5e5cd956bb..188ca8b268 100644
--- a/Makefile
+++ b/Makefile
@@ -967,6 +967,7 @@ bdp_estimator_test: $(BINDIR)/$(CONFIG)/bdp_estimator_test
bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
census_context_test: $(BINDIR)/$(CONFIG)/census_context_test
+census_intrusive_hash_map_test: $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test
census_resource_test: $(BINDIR)/$(CONFIG)/census_resource_test
census_trace_context_test: $(BINDIR)/$(CONFIG)/census_trace_context_test
channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test
@@ -1360,6 +1361,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/bin_decoder_test \
$(BINDIR)/$(CONFIG)/bin_encoder_test \
$(BINDIR)/$(CONFIG)/census_context_test \
+ $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test \
$(BINDIR)/$(CONFIG)/census_resource_test \
$(BINDIR)/$(CONFIG)/census_trace_context_test \
$(BINDIR)/$(CONFIG)/channel_create_test \
@@ -1763,6 +1765,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 )
$(E) "[RUN] Testing census_context_test"
$(Q) $(BINDIR)/$(CONFIG)/census_context_test || ( echo test census_context_test failed ; exit 1 )
+ $(E) "[RUN] Testing census_intrusive_hash_map_test"
+ $(Q) $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test || ( echo test census_intrusive_hash_map_test failed ; exit 1 )
$(E) "[RUN] Testing census_resource_test"
$(Q) $(BINDIR)/$(CONFIG)/census_resource_test || ( echo test census_resource_test failed ; exit 1 )
$(E) "[RUN] Testing census_trace_context_test"
@@ -3134,6 +3138,7 @@ LIBGRPC_SRC = \
src/core/ext/census/grpc_filter.c \
src/core/ext/census/grpc_plugin.c \
src/core/ext/census/initialize.c \
+ src/core/ext/census/intrusive_hash_map.c \
src/core/ext/census/mlog.c \
src/core/ext/census/operation.c \
src/core/ext/census/placeholders.c \
@@ -3994,6 +3999,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/census/grpc_filter.c \
src/core/ext/census/grpc_plugin.c \
src/core/ext/census/initialize.c \
+ src/core/ext/census/intrusive_hash_map.c \
src/core/ext/census/mlog.c \
src/core/ext/census/operation.c \
src/core/ext/census/placeholders.c \
@@ -4591,6 +4597,7 @@ LIBGRPC++_CRONET_SRC = \
src/core/ext/census/grpc_filter.c \
src/core/ext/census/grpc_plugin.c \
src/core/ext/census/initialize.c \
+ src/core/ext/census/intrusive_hash_map.c \
src/core/ext/census/mlog.c \
src/core/ext/census/operation.c \
src/core/ext/census/placeholders.c \
@@ -8687,6 +8694,38 @@ endif
endif
+CENSUS_INTRUSIVE_HASH_MAP_TEST_SRC = \
+ test/core/census/intrusive_hash_map_test.c \
+
+CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CENSUS_INTRUSIVE_HASH_MAP_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test: $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+ $(E) "[LD] Linking $@"
+ $(Q) mkdir -p `dirname $@`
+ $(Q) $(LD) $(LDFLAGS) $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/census_intrusive_hash_map_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/census/intrusive_hash_map_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_census_intrusive_hash_map_test: $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CENSUS_INTRUSIVE_HASH_MAP_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
CENSUS_RESOURCE_TEST_SRC = \
test/core/census/resource_test.c \
diff --git a/binding.gyp b/binding.gyp
index 8aafdaa62b..e617485134 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -890,6 +890,7 @@
'src/core/ext/census/grpc_filter.c',
'src/core/ext/census/grpc_plugin.c',
'src/core/ext/census/initialize.c',
+ 'src/core/ext/census/intrusive_hash_map.c',
'src/core/ext/census/mlog.c',
'src/core/ext/census/operation.c',
'src/core/ext/census/placeholders.c',
diff --git a/build.yaml b/build.yaml
index 98401b84c5..d2ea16c8c2 100644
--- a/build.yaml
+++ b/build.yaml
@@ -27,6 +27,8 @@ filegroups:
- src/core/ext/census/gen/census.pb.h
- src/core/ext/census/gen/trace_context.pb.h
- src/core/ext/census/grpc_filter.h
+ - src/core/ext/census/intrusive_hash_map.h
+ - src/core/ext/census/intrusive_hash_map_internal.h
- src/core/ext/census/mlog.h
- src/core/ext/census/resource.h
- src/core/ext/census/rpc_metric_id.h
@@ -45,6 +47,7 @@ filegroups:
- src/core/ext/census/grpc_filter.c
- src/core/ext/census/grpc_plugin.c
- src/core/ext/census/initialize.c
+ - src/core/ext/census/intrusive_hash_map.c
- src/core/ext/census/mlog.c
- src/core/ext/census/operation.c
- src/core/ext/census/placeholders.c
@@ -1676,6 +1679,16 @@ targets:
- grpc
- gpr_test_util
- gpr
+- name: census_intrusive_hash_map_test
+ build: test
+ language: c
+ src:
+ - test/core/census/intrusive_hash_map_test.c
+ deps:
+ - grpc_test_util
+ - grpc
+ - gpr_test_util
+ - gpr
- name: census_resource_test
build: test
language: c
diff --git a/config.m4 b/config.m4
index ec463b2243..3b9cac1abe 100644
--- a/config.m4
+++ b/config.m4
@@ -322,6 +322,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/census/grpc_filter.c \
src/core/ext/census/grpc_plugin.c \
src/core/ext/census/initialize.c \
+ src/core/ext/census/intrusive_hash_map.c \
src/core/ext/census/mlog.c \
src/core/ext/census/operation.c \
src/core/ext/census/placeholders.c \
diff --git a/config.w32 b/config.w32
index 0d82f9d757..7c407e848a 100644
--- a/config.w32
+++ b/config.w32
@@ -299,6 +299,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\census\\grpc_filter.c " +
"src\\core\\ext\\census\\grpc_plugin.c " +
"src\\core\\ext\\census\\initialize.c " +
+ "src\\core\\ext\\census\\intrusive_hash_map.c " +
"src\\core\\ext\\census\\mlog.c " +
"src\\core\\ext\\census\\operation.c " +
"src\\core\\ext\\census\\placeholders.c " +
diff --git a/doc/PROTOCOL-WEB.md b/doc/PROTOCOL-WEB.md
index 10998899c4..912dbe6d8f 100644
--- a/doc/PROTOCOL-WEB.md
+++ b/doc/PROTOCOL-WEB.md
@@ -103,10 +103,6 @@ to security policies with XHR
* While the server runtime will always base64-encode and flush gRPC messages
atomically the client library should not assume base64 padding always
happens at the boundary of message frames. That is, the implementation may send base64-encoded "chunks" with potential padding whenever the runtime needs to flush a byte buffer.
-3. For binary trailers, when the content-type is set to
-application/grpc-web-text, the extra base64 encoding specified
-in [gRPC over HTTP2](http://www.grpc.io/docs/guides/wire.html)
-for binary custom metadata is skipped.
# Other features
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 1176a15f2b..d9de2d78a0 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -463,6 +463,8 @@ Pod::Spec.new do |s|
'src/core/ext/census/gen/census.pb.h',
'src/core/ext/census/gen/trace_context.pb.h',
'src/core/ext/census/grpc_filter.h',
+ 'src/core/ext/census/intrusive_hash_map.h',
+ 'src/core/ext/census/intrusive_hash_map_internal.h',
'src/core/ext/census/mlog.h',
'src/core/ext/census/resource.h',
'src/core/ext/census/rpc_metric_id.h',
@@ -713,6 +715,7 @@ Pod::Spec.new do |s|
'src/core/ext/census/grpc_filter.c',
'src/core/ext/census/grpc_plugin.c',
'src/core/ext/census/initialize.c',
+ 'src/core/ext/census/intrusive_hash_map.c',
'src/core/ext/census/mlog.c',
'src/core/ext/census/operation.c',
'src/core/ext/census/placeholders.c',
@@ -946,6 +949,8 @@ Pod::Spec.new do |s|
'src/core/ext/census/gen/census.pb.h',
'src/core/ext/census/gen/trace_context.pb.h',
'src/core/ext/census/grpc_filter.h',
+ 'src/core/ext/census/intrusive_hash_map.h',
+ 'src/core/ext/census/intrusive_hash_map_internal.h',
'src/core/ext/census/mlog.h',
'src/core/ext/census/resource.h',
'src/core/ext/census/rpc_metric_id.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 32c1164456..b334efb0b5 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -379,6 +379,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/census/gen/census.pb.h )
s.files += %w( src/core/ext/census/gen/trace_context.pb.h )
s.files += %w( src/core/ext/census/grpc_filter.h )
+ s.files += %w( src/core/ext/census/intrusive_hash_map.h )
+ s.files += %w( src/core/ext/census/intrusive_hash_map_internal.h )
s.files += %w( src/core/ext/census/mlog.h )
s.files += %w( src/core/ext/census/resource.h )
s.files += %w( src/core/ext/census/rpc_metric_id.h )
@@ -629,6 +631,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/census/grpc_filter.c )
s.files += %w( src/core/ext/census/grpc_plugin.c )
s.files += %w( src/core/ext/census/initialize.c )
+ s.files += %w( src/core/ext/census/intrusive_hash_map.c )
s.files += %w( src/core/ext/census/mlog.c )
s.files += %w( src/core/ext/census/operation.c )
s.files += %w( src/core/ext/census/placeholders.c )
diff --git a/package.xml b/package.xml
index 5bcffd6eed..9179ef238c 100644
--- a/package.xml
+++ b/package.xml
@@ -393,6 +393,8 @@
<file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/gen/trace_context.pb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/grpc_filter.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/census/intrusive_hash_map.h" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/census/intrusive_hash_map_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/mlog.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/resource.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/rpc_metric_id.h" role="src" />
@@ -643,6 +645,7 @@
<file baseinstalldir="/" name="src/core/ext/census/grpc_filter.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/grpc_plugin.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/initialize.c" role="src" />
+ <file baseinstalldir="/" name="src/core/ext/census/intrusive_hash_map.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/mlog.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/operation.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/census/placeholders.c" role="src" />
diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c
new file mode 100644
index 0000000000..77512a3aac
--- /dev/null
+++ b/src/core/ext/census/intrusive_hash_map.c
@@ -0,0 +1,319 @@
+/*
+ *
+ * Copyright 2017, 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/intrusive_hash_map.h"
+#include <string.h>
+
+extern bool hm_index_compare(const hm_index *A, const hm_index *B);
+
+/* Simple hashing function that takes lower 32 bits. */
+static inline uint32_t chunked_vector_hasher(uint64_t key) {
+ return (uint32_t)key;
+}
+
+/* Vector chunks are 1MiB divided by pointer size. */
+static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *);
+
+/* Helper functions which return buckets from the chunked vector. */
+static inline void **get_mutable_bucket(const chunked_vector *buckets,
+ uint32_t index) {
+ if (index < VECTOR_CHUNK_SIZE) {
+ return &buckets->first_[index];
+ }
+ size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE;
+ return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE];
+}
+
+static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) {
+ if (index < VECTOR_CHUNK_SIZE) {
+ return buckets->first_[index];
+ }
+ size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE;
+ return buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE];
+}
+
+/* Helper function. */
+static inline size_t RestSize(const chunked_vector *vec) {
+ return (vec->size_ <= VECTOR_CHUNK_SIZE)
+ ? 0
+ : (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1;
+}
+
+/* Initialize chunked vector to size of 0. */
+static void chunked_vector_init(chunked_vector *vec) {
+ vec->size_ = 0;
+ vec->first_ = NULL;
+ vec->rest_ = NULL;
+}
+
+/* Clear chunked vector and free all memory that has been allocated then
+ initialize chunked vector. */
+static void chunked_vector_clear(chunked_vector *vec) {
+ if (vec->first_ != NULL) {
+ gpr_free(vec->first_);
+ }
+ if (vec->rest_ != NULL) {
+ size_t rest_size = RestSize(vec);
+ for (size_t i = 0; i < rest_size; ++i) {
+ if (vec->rest_[i] != NULL) {
+ gpr_free(vec->rest_[i]);
+ }
+ }
+ gpr_free(vec->rest_);
+ }
+ chunked_vector_init(vec);
+}
+
+/* Clear chunked vector and then resize it to n entries. Allow the first 1MB to
+ be read w/o an extra cache miss. The rest of the elements are stored in an
+ array of arrays to avoid large mallocs. */
+static void chunked_vector_reset(chunked_vector *vec, size_t n) {
+ chunked_vector_clear(vec);
+ vec->size_ = n;
+ if (n <= VECTOR_CHUNK_SIZE) {
+ vec->first_ = (void **)gpr_malloc(sizeof(void *) * n);
+ memset(vec->first_, 0, sizeof(void *) * n);
+ } else {
+ vec->first_ = (void **)gpr_malloc(sizeof(void *) * VECTOR_CHUNK_SIZE);
+ memset(vec->first_, 0, sizeof(void *) * VECTOR_CHUNK_SIZE);
+ size_t rest_size = RestSize(vec);
+ vec->rest_ = (void ***)gpr_malloc(sizeof(void **) * rest_size);
+ memset(vec->rest_, 0, sizeof(void **) * rest_size);
+ int i = 0;
+ n -= VECTOR_CHUNK_SIZE;
+ while (n > 0) {
+ size_t this_size = GPR_MIN(n, VECTOR_CHUNK_SIZE);
+ vec->rest_[i] = (void **)gpr_malloc(sizeof(void *) * this_size);
+ memset(vec->rest_[i], 0, sizeof(void *) * this_size);
+ n -= this_size;
+ ++i;
+ }
+ }
+}
+
+void intrusive_hash_map_init(intrusive_hash_map *hash_map,
+ uint32_t initial_log2_table_size) {
+ hash_map->log2_num_buckets = initial_log2_table_size;
+ hash_map->num_items = 0;
+ uint32_t num_buckets = (uint32_t)1 << hash_map->log2_num_buckets;
+ hash_map->extend_threshold = num_buckets >> 1;
+ chunked_vector_init(&hash_map->buckets);
+ chunked_vector_reset(&hash_map->buckets, num_buckets);
+ hash_map->hash_mask = num_buckets - 1;
+}
+
+bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map) {
+ return hash_map->num_items == 0;
+}
+
+size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map) {
+ return hash_map->num_items;
+}
+
+void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx) {
+ idx->bucket_index = (uint32_t)hash_map->buckets.size_;
+ GPR_ASSERT(idx->bucket_index <= UINT32_MAX);
+ idx->item = NULL;
+}
+
+void intrusive_hash_map_next(const intrusive_hash_map *hash_map,
+ hm_index *idx) {
+ idx->item = idx->item->hash_link;
+ while (idx->item == NULL) {
+ idx->bucket_index++;
+ if (idx->bucket_index >= hash_map->buckets.size_) {
+ /* Reached end of table. */
+ idx->item = NULL;
+ return;
+ }
+ idx->item = (hm_item *)get_bucket(&hash_map->buckets, idx->bucket_index);
+ }
+}
+
+void intrusive_hash_map_begin(const intrusive_hash_map *hash_map,
+ hm_index *idx) {
+ for (uint32_t i = 0; i < hash_map->buckets.size_; ++i) {
+ if (get_bucket(&hash_map->buckets, i) != NULL) {
+ idx->bucket_index = i;
+ idx->item = (hm_item *)get_bucket(&hash_map->buckets, i);
+ return;
+ }
+ }
+ intrusive_hash_map_end(hash_map, idx);
+}
+
+hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map,
+ uint64_t key) {
+ uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask;
+
+ hm_item *p = (hm_item *)get_bucket(&hash_map->buckets, index);
+ while (p != NULL) {
+ if (key == p->key) {
+ return p;
+ }
+ p = p->hash_link;
+ }
+ return NULL;
+}
+
+hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) {
+ uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask;
+
+ hm_item **slot = (hm_item **)get_mutable_bucket(&hash_map->buckets, index);
+ hm_item *p = *slot;
+ if (p == NULL) {
+ return NULL;
+ }
+
+ if (key == p->key) {
+ *slot = p->hash_link;
+ p->hash_link = NULL;
+ hash_map->num_items--;
+ return p;
+ }
+
+ hm_item *prev = p;
+ p = p->hash_link;
+
+ while (p) {
+ if (key == p->key) {
+ prev->hash_link = p->hash_link;
+ p->hash_link = NULL;
+ hash_map->num_items--;
+ return p;
+ }
+ prev = p;
+ p = p->hash_link;
+ }
+ return NULL;
+}
+
+/* Insert an hm_item* into the underlying chunked vector. hash_mask is
+ * array_size-1. Returns true if it is a new hm_item and false if the hm_item
+ * already existed.
+ */
+static inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets,
+ uint32_t hash_mask,
+ hm_item *item) {
+ const uint64_t key = item->key;
+ uint32_t index = chunked_vector_hasher(key) & hash_mask;
+ hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index);
+ hm_item *p = *slot;
+ item->hash_link = p;
+
+ /* Check to see if key already exists. */
+ while (p) {
+ if (p->key == key) {
+ return false;
+ }
+ p = p->hash_link;
+ }
+
+ /* Otherwise add new entry. */
+ *slot = item;
+ return true;
+}
+
+/* Extend the allocated number of elements in the hash map by a factor of 2. */
+void intrusive_hash_map_extend(intrusive_hash_map *hash_map) {
+ uint32_t new_log2_num_buckets = 1 + hash_map->log2_num_buckets;
+ uint32_t new_num_buckets = (uint32_t)1 << new_log2_num_buckets;
+ GPR_ASSERT(new_num_buckets <= UINT32_MAX && new_num_buckets > 0);
+ chunked_vector new_buckets;
+ chunked_vector_init(&new_buckets);
+ chunked_vector_reset(&new_buckets, new_num_buckets);
+ uint32_t new_hash_mask = new_num_buckets - 1;
+
+ hm_index cur_idx;
+ hm_index end_idx;
+ intrusive_hash_map_end(hash_map, &end_idx);
+ intrusive_hash_map_begin(hash_map, &cur_idx);
+ while (!hm_index_compare(&cur_idx, &end_idx)) {
+ hm_item *new_item = cur_idx.item;
+ intrusive_hash_map_next(hash_map, &cur_idx);
+ intrusive_hash_map_internal_insert(&new_buckets, new_hash_mask, new_item);
+ }
+
+ /* Set values for new chunked_vector. extend_threshold is set to half of
+ * new_num_buckets. */
+ hash_map->log2_num_buckets = new_log2_num_buckets;
+ chunked_vector_clear(&hash_map->buckets);
+ hash_map->buckets = new_buckets;
+ hash_map->hash_mask = new_hash_mask;
+ hash_map->extend_threshold = new_num_buckets >> 1;
+}
+
+/* Insert a hm_item. The hm_item must remain live until it is removed from the
+ table. This object does not take the ownership of hm_item. The caller must
+ remove this hm_item from the table and delete it before this table is
+ deleted. If hm_item exists already num_items is not changed. */
+bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item) {
+ if (hash_map->num_items >= hash_map->extend_threshold) {
+ intrusive_hash_map_extend(hash_map);
+ }
+ if (intrusive_hash_map_internal_insert(&hash_map->buckets,
+ hash_map->hash_mask, item)) {
+ hash_map->num_items++;
+ return true;
+ }
+ return false;
+}
+
+void intrusive_hash_map_clear(intrusive_hash_map *hash_map,
+ void (*free_object)(void *)) {
+ hm_index cur;
+ hm_index end;
+ intrusive_hash_map_end(hash_map, &end);
+ intrusive_hash_map_begin(hash_map, &cur);
+
+ while (!hm_index_compare(&cur, &end)) {
+ hm_index next = cur;
+ intrusive_hash_map_next(hash_map, &next);
+ if (cur.item != NULL) {
+ hm_item *item = intrusive_hash_map_erase(hash_map, cur.item->key);
+ (*free_object)((void *)item);
+ gpr_free(item);
+ }
+ cur = next;
+ }
+}
+
+void intrusive_hash_map_free(intrusive_hash_map *hash_map,
+ void (*free_object)(void *)) {
+ intrusive_hash_map_clear(hash_map, (*free_object));
+ hash_map->num_items = 0;
+ hash_map->extend_threshold = 0;
+ hash_map->log2_num_buckets = 0;
+ hash_map->hash_mask = 0;
+ chunked_vector_clear(&hash_map->buckets);
+}
diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h
new file mode 100644
index 0000000000..a8405517b8
--- /dev/null
+++ b/src/core/ext/census/intrusive_hash_map.h
@@ -0,0 +1,167 @@
+/*
+ *
+ * Copyright 2017, 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_CENSUS_INTRUSIVE_HASH_MAP_H
+#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H
+
+#include "src/core/ext/census/intrusive_hash_map_internal.h"
+
+/* intrusive_hash_map is a fast chained hash table. This hash map is faster than
+ * a dense hash map when the application calls insert and erase more often than
+ * find. When the workload is dominated by find() a dense hash map may be
+ * faster.
+ *
+ * intrusive_hash_map uses an intrusive header placed within a user defined
+ * struct. The header field IHM_key MUST be set to a valid value before
+ * insertion into the hash map or undefined behavior may occur. The header field
+ * IHM_hash_link MUST to be set to NULL initially.
+ *
+ * EXAMPLE USAGE:
+ *
+ * typedef struct string_item {
+ * INTRUSIVE_HASH_MAP_HEADER;
+ * // User data.
+ * char *str_buf;
+ * uint16_t len;
+ * } string_item;
+ *
+ * static string_item *make_string_item(uint64_t key, const char *buf,
+ * uint16_t len) {
+ * string_item *item = (string_item *)gpr_malloc(sizeof(string_item));
+ * item->IHM_key = key;
+ * item->IHM_hash_link = NULL;
+ * item->len = len;
+ * item->str_buf = (char *)malloc(len);
+ * memcpy(item->str_buf, buf, len);
+ * return item;
+ * }
+ *
+ * intrusive_hash_map hash_map;
+ * intrusive_hash_map_init(&hash_map, 4);
+ * string_item *new_item1 = make_string_item(10, "test1", 5);
+ * bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1);
+ *
+ * string_item *item1 =
+ * (string_item *)intrusive_hash_map_find(&hash_map, 10);
+ */
+
+/* Hash map item. Stores key and a pointer to the actual object. A user defined
+ * version of this can be passed in provided the first 2 entries (key and
+ * hash_link) are the same. These entries must be first in the user defined
+ * struct. Pointer to struct will need to be cast as (hm_item *) when passed to
+ * hash map. This allows it to be intrusive. */
+typedef struct hm_item {
+ uint64_t key;
+ struct hm_item *hash_link;
+ /* Optional user defined data after this. */
+} hm_item;
+
+/* Macro provided for ease of use. This must be first in the user defined
+ * struct (i.e. uint64_t key and hm_item * must be the first two elements in
+ * that order). */
+#define INTRUSIVE_HASH_MAP_HEADER \
+ uint64_t IHM_key; \
+ struct hm_item *IHM_hash_link
+
+/* Index struct which acts as a pseudo-iterator within the hash map. */
+typedef struct hm_index {
+ uint32_t bucket_index; // hash map bucket index.
+ hm_item *item; // Pointer to hm_item within the hash map.
+} hm_index;
+
+/* Returns true if two hm_indices point to the same object within the hash map
+ * and false otherwise. */
+inline bool hm_index_compare(const hm_index *A, const hm_index *B) {
+ return (A->item == B->item && A->bucket_index == B->bucket_index);
+}
+
+/*
+ * Helper functions for iterating over the hash map.
+ */
+
+/* On return idx will contain an invalid index which is always equal to
+ * hash_map->buckets.size_ */
+void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx);
+
+/* Iterates index to the next valid entry in the hash map and stores the
+ * index within idx. If end of table is reached, idx will contain the same
+ * values as if intrusive_hash_map_end() was called. */
+void intrusive_hash_map_next(const intrusive_hash_map *hash_map, hm_index *idx);
+
+/* On return, idx will contain the index of the first non-null entry in the hash
+ * map. If the hash map is empty, idx will contain the same values as if
+ * intrusive_hash_map_end() was called. */
+void intrusive_hash_map_begin(const intrusive_hash_map *hash_map,
+ hm_index *idx);
+
+/* Initialize intrusive hash map data structure. This must be called before
+ * the hash map can be used. The initial size of an intrusive hash map will be
+ * 2^initial_log2_map_size (valid range is [0, 31]). */
+void intrusive_hash_map_init(intrusive_hash_map *hash_map,
+ uint32_t initial_log2_map_size);
+
+/* Returns true if the hash map is empty and false otherwise. */
+bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map);
+
+/* Returns the number of elements currently in the hash map. */
+size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map);
+
+/* Find a hm_item within the hash map by key. Returns NULL if item was not
+ * found. */
+hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map,
+ uint64_t key);
+
+/* Erase the hm_item that corresponds with key. If the hm_item is found, return
+ * the pointer to the hm_item. Else returns NULL. */
+hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key);
+
+/* Attempts to insert a new hm_item into the hash map. If an element with the
+ * same key already exists, it will not insert the new item and return false.
+ * Otherwise, it will insert the new item and return true. */
+bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item);
+
+/* Clears entire contents of the hash map, but leaves internal data structure
+ * untouched. Second argument takes a function pointer to a function that will
+ * free the object designated by the user and pointed to by hash_map->value. */
+void intrusive_hash_map_clear(intrusive_hash_map *hash_map,
+ void (*free_object)(void *));
+
+/* Erase all contents of hash map and free the memory. Hash map is invalid
+ * after calling this function and cannot be used until it has been
+ * reinitialized (intrusive_hash_map_init()). This function takes a function
+ * pointer to a function that will free the object designated by the user and
+ * pointed to by hash_map->value. */
+void intrusive_hash_map_free(intrusive_hash_map *hash_map,
+ void (*free_object)(void *));
+
+#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H */
diff --git a/src/core/ext/census/intrusive_hash_map_internal.h b/src/core/ext/census/intrusive_hash_map_internal.h
new file mode 100644
index 0000000000..76a9a3a722
--- /dev/null
+++ b/src/core/ext/census/intrusive_hash_map_internal.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2017, 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_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H
+#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include <stdbool.h>
+
+/* The chunked vector is a data structure that allocates buckets for use in the
+ * hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as
+ * T*). It's internally implemented as an array of 1MB arrays to avoid
+ * allocating large consecutive memory chunks. This is an internal data
+ * structure that should never be accessed directly. */
+typedef struct chunked_vector {
+ size_t size_;
+ void **first_;
+ void ***rest_;
+} chunked_vector;
+
+/* Core intrusive hash map data structure. All internal elements are managed by
+ * functions and should not be altered manually. */
+typedef struct intrusive_hash_map {
+ uint32_t num_items;
+ uint32_t extend_threshold;
+ uint32_t log2_num_buckets;
+ uint32_t hash_mask;
+ chunked_vector buckets;
+} intrusive_hash_map;
+
+#endif /* GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
index b9c62c376a..2c076e821c 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.c
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -127,6 +127,7 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_endpoint *tcp,
gpr_mu_lock(&state->mu);
if (state->shutdown) {
gpr_mu_unlock(&state->mu);
+ grpc_endpoint_shutdown(exec_ctx, tcp, GRPC_ERROR_NONE);
grpc_endpoint_destroy(exec_ctx, tcp);
gpr_free(acceptor);
return;
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index 0ac2c2ad52..7012ffe568 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -105,7 +105,7 @@ static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
grpc_error *error) {
grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent,
req->context->pollset_set);
- grpc_closure_sched(exec_ctx, req->on_done, GRPC_ERROR_REF(error));
+ grpc_closure_sched(exec_ctx, req->on_done, error);
grpc_http_parser_destroy(&req->parser);
if (req->addresses != NULL) {
grpc_resolved_addresses_destroy(req->addresses);
@@ -244,7 +244,7 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req,
static void on_resolved(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
internal_request *req = arg;
if (error != GRPC_ERROR_NONE) {
- finish(exec_ctx, req, error);
+ finish(exec_ctx, req, GRPC_ERROR_REF(error));
return;
}
req->next_address = 0;
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 76946434f0..ea7c1122c1 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -44,6 +44,7 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/support/string.h"
#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security_adapter.h"
typedef struct {
grpc_channel_security_connector base;
@@ -78,7 +79,8 @@ static void httpcli_ssl_add_handshakers(grpc_exec_ctx *exec_ctx,
}
grpc_handshake_manager_add(
handshake_mgr,
- grpc_security_handshaker_create(exec_ctx, handshaker, &sc->base));
+ grpc_security_handshaker_create(
+ exec_ctx, tsi_create_adapter_handshaker(handshaker), &sc->base));
}
static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index 30431a4e4a..416a3bdb35 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -56,6 +56,7 @@
#include "src/core/lib/support/string.h"
#include "src/core/tsi/fake_transport_security.h"
#include "src/core/tsi/ssl_transport_security.h"
+#include "src/core/tsi/transport_security_adapter.h"
/* -- Constants. -- */
@@ -390,7 +391,8 @@ static void fake_channel_add_handshakers(
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
- exec_ctx, tsi_create_fake_handshaker(true /* is_client */),
+ exec_ctx, tsi_create_adapter_handshaker(
+ tsi_create_fake_handshaker(true /* is_client */)),
&sc->base));
}
@@ -400,7 +402,8 @@ static void fake_server_add_handshakers(grpc_exec_ctx *exec_ctx,
grpc_handshake_manager_add(
handshake_mgr,
grpc_security_handshaker_create(
- exec_ctx, tsi_create_fake_handshaker(false /* is_client */),
+ exec_ctx, tsi_create_adapter_handshaker(
+ tsi_create_fake_handshaker(false /* is_client */)),
&sc->base));
}
@@ -495,8 +498,10 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx,
}
// Create handshakers.
- grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create(
- exec_ctx, tsi_hs, &sc->base));
+ grpc_handshake_manager_add(
+ handshake_mgr,
+ grpc_security_handshaker_create(
+ exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base));
}
static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx,
@@ -515,8 +520,10 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx,
}
// Create handshakers.
- grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create(
- exec_ctx, tsi_hs, &sc->base));
+ grpc_handshake_manager_add(
+ handshake_mgr,
+ grpc_security_handshaker_create(
+ exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base));
}
static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) {
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
index 509b4b556d..3bc113e20f 100644
--- a/src/core/lib/security/transport/security_handshaker.c
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -71,12 +71,12 @@ typedef struct {
unsigned char *handshake_buffer;
size_t handshake_buffer_size;
- grpc_slice_buffer left_overs;
grpc_slice_buffer outgoing;
grpc_closure on_handshake_data_sent_to_peer;
grpc_closure on_handshake_data_received_from_peer;
grpc_closure on_peer_checked;
grpc_auth_context *auth_context;
+ tsi_handshaker_result *handshaker_result;
} security_handshaker;
static void security_handshaker_unref(grpc_exec_ctx *exec_ctx,
@@ -84,6 +84,7 @@ static void security_handshaker_unref(grpc_exec_ctx *exec_ctx,
if (gpr_unref(&h->refs)) {
gpr_mu_destroy(&h->mu);
tsi_handshaker_destroy(h->handshaker);
+ tsi_handshaker_result_destroy(h->handshaker_result);
if (h->endpoint_to_destroy != NULL) {
grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy);
}
@@ -92,7 +93,6 @@ static void security_handshaker_unref(grpc_exec_ctx *exec_ctx,
gpr_free(h->read_buffer_to_destroy);
}
gpr_free(h->handshake_buffer);
- grpc_slice_buffer_destroy_internal(exec_ctx, &h->left_overs);
grpc_slice_buffer_destroy_internal(exec_ctx, &h->outgoing);
GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, h->connector, "handshake");
@@ -150,10 +150,10 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg,
security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error));
goto done;
}
- // Get frame protector.
+ // Create frame protector.
tsi_frame_protector *protector;
- tsi_result result =
- tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
+ tsi_result result = tsi_handshaker_result_create_frame_protector(
+ h->handshaker_result, NULL, &protector);
if (result != TSI_OK) {
error = grpc_set_tsi_error_result(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Frame protector creation failed"),
@@ -161,14 +161,25 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg,
security_handshake_failed_locked(exec_ctx, h, error);
goto done;
}
- // Success.
+ // Get unused bytes.
+ unsigned char *unused_bytes = NULL;
+ size_t unused_bytes_size = 0;
+ result = tsi_handshaker_result_get_unused_bytes(
+ h->handshaker_result, &unused_bytes, &unused_bytes_size);
// Create secure endpoint.
- h->args->endpoint = grpc_secure_endpoint_create(
- protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count);
- h->left_overs.count = 0;
- h->left_overs.length = 0;
- // Clear out the read buffer before it gets passed to the transport,
- // since any excess bytes were already copied to h->left_overs.
+ if (unused_bytes_size > 0) {
+ grpc_slice slice =
+ grpc_slice_from_copied_buffer((char *)unused_bytes, unused_bytes_size);
+ h->args->endpoint =
+ grpc_secure_endpoint_create(protector, h->args->endpoint, &slice, 1);
+ grpc_slice_unref_internal(exec_ctx, slice);
+ } else {
+ h->args->endpoint =
+ grpc_secure_endpoint_create(protector, h->args->endpoint, NULL, 0);
+ }
+ tsi_handshaker_result_destroy(h->handshaker_result);
+ h->handshaker_result = NULL;
+ // Clear out the read buffer before it gets passed to the transport.
grpc_slice_buffer_reset_and_unref_internal(exec_ctx, h->args->read_buffer);
// Add auth context to channel args.
grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context);
@@ -189,7 +200,8 @@ done:
static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx,
security_handshaker *h) {
tsi_peer peer;
- tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
+ tsi_result result =
+ tsi_handshaker_result_extract_peer(h->handshaker_result, &peer);
if (result != TSI_OK) {
return grpc_set_tsi_error_result(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Peer extraction failed"), result);
@@ -199,34 +211,87 @@ static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx,
return GRPC_ERROR_NONE;
}
-static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx,
- security_handshaker *h) {
- // Get data to send.
- tsi_result result = TSI_OK;
- size_t offset = 0;
- do {
- size_t to_send_size = h->handshake_buffer_size - offset;
- result = tsi_handshaker_get_bytes_to_send_to_peer(
- h->handshaker, h->handshake_buffer + offset, &to_send_size);
- offset += to_send_size;
- if (result == TSI_INCOMPLETE_DATA) {
- h->handshake_buffer_size *= 2;
- h->handshake_buffer =
- gpr_realloc(h->handshake_buffer, h->handshake_buffer_size);
- }
- } while (result == TSI_INCOMPLETE_DATA);
+static grpc_error *on_handshake_next_done_locked(
+ grpc_exec_ctx *exec_ctx, security_handshaker *h, tsi_result result,
+ const unsigned char *bytes_to_send, size_t bytes_to_send_size,
+ tsi_handshaker_result *handshaker_result) {
+ grpc_error *error = GRPC_ERROR_NONE;
+ // Read more if we need to.
+ if (result == TSI_INCOMPLETE_DATA) {
+ GPR_ASSERT(bytes_to_send_size == 0);
+ grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
+ &h->on_handshake_data_received_from_peer);
+ return error;
+ }
if (result != TSI_OK) {
return grpc_set_tsi_error_result(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result);
}
- // Send data.
- grpc_slice to_send =
- grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
- grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing);
- grpc_slice_buffer_add(&h->outgoing, to_send);
- grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing,
- &h->on_handshake_data_sent_to_peer);
- return GRPC_ERROR_NONE;
+ // Update handshaker result.
+ if (handshaker_result != NULL) {
+ GPR_ASSERT(h->handshaker_result == NULL);
+ h->handshaker_result = handshaker_result;
+ }
+ if (bytes_to_send_size > 0) {
+ // Send data to peer, if needed.
+ grpc_slice to_send = grpc_slice_from_copied_buffer(
+ (const char *)bytes_to_send, bytes_to_send_size);
+ grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing);
+ grpc_slice_buffer_add(&h->outgoing, to_send);
+ grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing,
+ &h->on_handshake_data_sent_to_peer);
+ } else if (handshaker_result == NULL) {
+ // There is nothing to send, but need to read from peer.
+ grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
+ &h->on_handshake_data_received_from_peer);
+ } else {
+ // Handshake has finished, check peer and so on.
+ error = check_peer_locked(exec_ctx, h);
+ }
+ return error;
+}
+
+static void on_handshake_next_done_grpc_wrapper(
+ tsi_result result, void *user_data, const unsigned char *bytes_to_send,
+ size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) {
+ security_handshaker *h = user_data;
+ // This callback will be invoked by TSI in a non-grpc thread, so it's
+ // safe to create our own exec_ctx here.
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ gpr_mu_lock(&h->mu);
+ grpc_error *error =
+ on_handshake_next_done_locked(&exec_ctx, h, result, bytes_to_send,
+ bytes_to_send_size, handshaker_result);
+ if (error != GRPC_ERROR_NONE) {
+ security_handshake_failed_locked(&exec_ctx, h, error);
+ gpr_mu_unlock(&h->mu);
+ security_handshaker_unref(&exec_ctx, h);
+ } else {
+ gpr_mu_unlock(&h->mu);
+ }
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static grpc_error *do_handshaker_next_locked(
+ grpc_exec_ctx *exec_ctx, security_handshaker *h,
+ const unsigned char *bytes_received, size_t bytes_received_size) {
+ // Invoke TSI handshaker.
+ unsigned char *bytes_to_send = NULL;
+ size_t bytes_to_send_size = 0;
+ tsi_handshaker_result *handshaker_result = NULL;
+ tsi_result result = tsi_handshaker_next(
+ h->handshaker, bytes_received, bytes_received_size, &bytes_to_send,
+ &bytes_to_send_size, &handshaker_result,
+ &on_handshake_next_done_grpc_wrapper, h);
+ if (result == TSI_ASYNC) {
+ // Handshaker operating asynchronously. Nothing else to do here;
+ // callback will be invoked in a TSI thread.
+ return GRPC_ERROR_NONE;
+ }
+ // Handshaker returned synchronously. Invoke callback directly in
+ // this thread with our existing exec_ctx.
+ return on_handshake_next_done_locked(exec_ctx, h, result, bytes_to_send,
+ bytes_to_send_size, handshaker_result);
}
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
@@ -241,72 +306,34 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
security_handshaker_unref(exec_ctx, h);
return;
}
- // Process received data.
- tsi_result result = TSI_OK;
- size_t consumed_slice_size = 0;
+ // Copy all slices received.
size_t i;
+ size_t bytes_received_size = 0;
for (i = 0; i < h->args->read_buffer->count; i++) {
- consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]);
- result = tsi_handshaker_process_bytes_from_peer(
- h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]),
- &consumed_slice_size);
- if (!tsi_handshaker_is_in_progress(h->handshaker)) break;
+ bytes_received_size += GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]);
}
- if (tsi_handshaker_is_in_progress(h->handshaker)) {
- /* We may need more data. */
- if (result == TSI_INCOMPLETE_DATA) {
- grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
- &h->on_handshake_data_received_from_peer);
- goto done;
- } else {
- error = send_handshake_bytes_to_peer_locked(exec_ctx, h);
- if (error != GRPC_ERROR_NONE) {
- security_handshake_failed_locked(exec_ctx, h, error);
- gpr_mu_unlock(&h->mu);
- security_handshaker_unref(exec_ctx, h);
- return;
- }
- goto done;
- }
+ if (bytes_received_size > h->handshake_buffer_size) {
+ h->handshake_buffer = gpr_realloc(h->handshake_buffer, bytes_received_size);
+ h->handshake_buffer_size = bytes_received_size;
}
- if (result != TSI_OK) {
- security_handshake_failed_locked(
- exec_ctx, h,
- grpc_set_tsi_error_result(
- GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result));
- gpr_mu_unlock(&h->mu);
- security_handshaker_unref(exec_ctx, h);
- return;
- }
- /* Handshake is done and successful this point. */
- bool has_left_overs_in_current_slice =
- (consumed_slice_size <
- GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]));
- size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) +
- h->args->read_buffer->count - i - 1;
- if (num_left_overs > 0) {
- /* Put the leftovers in our buffer (ownership transfered). */
- if (has_left_overs_in_current_slice) {
- grpc_slice tail = grpc_slice_split_tail(&h->args->read_buffer->slices[i],
- consumed_slice_size);
- grpc_slice_buffer_add(&h->left_overs, tail);
- /* split_tail above increments refcount. */
- grpc_slice_unref_internal(exec_ctx, tail);
- }
- grpc_slice_buffer_addn(
- &h->left_overs, &h->args->read_buffer->slices[i + 1],
- num_left_overs - (size_t)has_left_overs_in_current_slice);
+ size_t offset = 0;
+ for (i = 0; i < h->args->read_buffer->count; i++) {
+ size_t slice_size = GPR_SLICE_LENGTH(h->args->read_buffer->slices[i]);
+ memcpy(h->handshake_buffer + offset,
+ GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), slice_size);
+ offset += slice_size;
}
- // Check peer.
- error = check_peer_locked(exec_ctx, h);
+ // Call TSI handshaker.
+ error = do_handshaker_next_locked(exec_ctx, h, h->handshake_buffer,
+ bytes_received_size);
+
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
security_handshaker_unref(exec_ctx, h);
- return;
+ } else {
+ gpr_mu_unlock(&h->mu);
}
-done:
- gpr_mu_unlock(&h->mu);
}
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg,
@@ -321,8 +348,8 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg,
security_handshaker_unref(exec_ctx, h);
return;
}
- /* We may be done. */
- if (tsi_handshaker_is_in_progress(h->handshaker)) {
+ // We may be done.
+ if (h->handshaker_result == NULL) {
grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer,
&h->on_handshake_data_received_from_peer);
} else {
@@ -371,7 +398,7 @@ static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx,
h->args = args;
h->on_handshake_done = on_handshake_done;
gpr_ref(&h->refs);
- grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h);
+ grpc_error *error = do_handshaker_next_locked(exec_ctx, h, NULL, 0);
if (error != GRPC_ERROR_NONE) {
security_handshake_failed_locked(exec_ctx, h, error);
gpr_mu_unlock(&h->mu);
@@ -404,7 +431,6 @@ static grpc_handshaker *security_handshaker_create(
grpc_schedule_on_exec_ctx);
grpc_closure_init(&h->on_peer_checked, on_peer_checked, h,
grpc_schedule_on_exec_ctx);
- grpc_slice_buffer_init(&h->left_overs);
grpc_slice_buffer_init(&h->outgoing);
return &h->base;
}
diff --git a/src/csharp/.editorconfig b/src/csharp/.editorconfig
new file mode 100644
index 0000000000..7bc2bcce18
--- /dev/null
+++ b/src/csharp/.editorconfig
@@ -0,0 +1,7 @@
+root = true
+[**]
+end_of_line = LF
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+tab_width = 4
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 8ed0c0b92f..bc74e212b1 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -218,5 +218,16 @@ namespace Grpc.Core.Internal
{
return buffered ? 0 : GRPC_WRITE_BUFFER_HINT;
}
+
+ /// <summary>
+ /// Only for testing.
+ /// </summary>
+ public static CallSafeHandle CreateFake(IntPtr ptr, CompletionQueueSafeHandle cq)
+ {
+ var call = new CallSafeHandle();
+ call.SetHandle(ptr);
+ call.Initialize(cq);
+ return call;
+ }
}
}
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index a4aa8d3ffe..075286d33e 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -52,6 +52,7 @@ namespace Grpc.Core.Internal
readonly GrpcEnvironment environment;
readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(new IntPtrComparer());
+ IntPtr lastRegisteredKey; // only for testing
public CompletionRegistry(GrpcEnvironment environment)
{
@@ -62,6 +63,7 @@ namespace Grpc.Core.Internal
{
environment.DebugStats.PendingBatchCompletions.Increment();
GrpcPreconditions.CheckState(dict.TryAdd(key, callback));
+ this.lastRegisteredKey = key;
}
public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
@@ -84,6 +86,14 @@ namespace Grpc.Core.Internal
return value;
}
+ /// <summary>
+ /// For testing purposes only.
+ /// </summary>
+ public IntPtr LastRegisteredKey
+ {
+ get { return this.lastRegisteredKey; }
+ }
+
private static void HandleBatchCompletion(bool success, BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
{
try
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 696987d2a8..e703e3e6ce 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -164,6 +164,8 @@ namespace Grpc.Core.Internal
public readonly Delegates.grpcsharp_test_callback_delegate grpcsharp_test_callback;
public readonly Delegates.grpcsharp_test_nop_delegate grpcsharp_test_nop;
+ public readonly Delegates.grpcsharp_test_override_method_delegate grpcsharp_test_override_method;
+
#endregion
public NativeMethods(UnmanagedLibrary library)
@@ -278,6 +280,7 @@ namespace Grpc.Core.Internal
this.grpcsharp_test_callback = GetMethodDelegate<Delegates.grpcsharp_test_callback_delegate>(library);
this.grpcsharp_test_nop = GetMethodDelegate<Delegates.grpcsharp_test_nop_delegate>(library);
+ this.grpcsharp_test_override_method = GetMethodDelegate<Delegates.grpcsharp_test_override_method_delegate>(library);
}
/// <summary>
@@ -434,6 +437,7 @@ namespace Grpc.Core.Internal
public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
+ public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant);
}
}
}
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 77ac347c7d..fe757820fd 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -59,8 +59,14 @@ using System.Runtime.CompilerServices;
"0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
"27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
"71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
+[assembly: InternalsVisibleTo("Grpc.Microbenchmarks,PublicKey=" +
+ "00240000048000009400000006020000002400005253413100040000010001002f5797a92c6fcde81bd4098f43" +
+ "0442bb8e12768722de0b0cb1b15e955b32a11352740ee59f2c94c48edc8e177d1052536b8ac651bce11ce5da3a" +
+ "27fc95aff3dc604a6971417453f9483c7b5e836756d5b271bf8f2403fe186e31956148c03d804487cf642f8cc0" +
+ "71394ee9672dfe5b55ea0f95dfd5a7f77d22c962ccf51320d3")]
#else
[assembly: InternalsVisibleTo("Grpc.Core.Tests")]
[assembly: InternalsVisibleTo("Grpc.Core.Testing")]
[assembly: InternalsVisibleTo("Grpc.IntegrationTesting")]
+[assembly: InternalsVisibleTo("Grpc.Microbenchmarks")]
#endif
diff --git a/src/csharp/Grpc.Microbenchmarks/.gitignore b/src/csharp/Grpc.Microbenchmarks/.gitignore
new file mode 100644
index 0000000000..1746e3269e
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
new file mode 100644
index 0000000000..26a940e488
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
@@ -0,0 +1,28 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <Import Project="..\Grpc.Core\Version.csproj.include" />
+ <Import Project="..\Grpc.Core\Common.csproj.include" />
+
+ <PropertyGroup>
+ <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+ <AssemblyName>Grpc.Microbenchmarks</AssemblyName>
+ <OutputType>Exe</OutputType>
+ <PackageId>Grpc.Microbenchmarks</PackageId>
+ <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+ <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
+ </ItemGroup>
+
+ <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+ <Reference Include="System" />
+ <Reference Include="Microsoft.CSharp" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="..\Grpc.Core\Version.cs" />
+ </ItemGroup>
+
+</Project>
diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs
new file mode 100644
index 0000000000..a0ca1f75ae
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/Program.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Logging;
+
+namespace Grpc.Microbenchmarks
+{
+ class Program
+ {
+ public static void Main(string[] args)
+ {
+ GrpcEnvironment.SetLogger(new TextWriterLogger(Console.Error));
+ var benchmark = new SendMessageBenchmark();
+ benchmark.Init();
+ foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
+ {
+ benchmark.Run(threadCount, 4 * 1000 * 1000, 0);
+ }
+ benchmark.Cleanup();
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
new file mode 100644
index 0000000000..eea375824f
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
@@ -0,0 +1,106 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Threading;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Grpc.Microbenchmarks
+{
+ public class SendMessageBenchmark
+ {
+ static readonly NativeMethods Native = NativeMethods.Get();
+
+ GrpcEnvironment environment;
+
+ public void Init()
+ {
+ Native.grpcsharp_test_override_method("grpcsharp_call_start_batch", "nop");
+ environment = GrpcEnvironment.AddRef();
+ }
+
+ public void Cleanup()
+ {
+ GrpcEnvironment.ReleaseAsync().Wait();
+ // TODO(jtattermusch): track GC stats
+ }
+
+ public void Run(int threadCount, int iterations, int payloadSize)
+ {
+ Console.WriteLine(string.Format("SendMessageBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize));
+ var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize));
+ threadedBenchmark.Run();
+ }
+
+ private void ThreadBody(int iterations, int payloadSize)
+ {
+ // TODO(jtattermusch): parametrize by number of pending completions.
+ // TODO(jtattermusch): parametrize by cached/non-cached BatchContextSafeHandle
+
+ var completionRegistry = new CompletionRegistry(environment);
+ var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry);
+ var call = CreateFakeCall(cq);
+
+ var sendCompletionHandler = new SendCompletionHandler((success) => { });
+ var payload = new byte[payloadSize];
+ var writeFlags = default(WriteFlags);
+
+ var stopwatch = Stopwatch.StartNew();
+ for (int i = 0; i < iterations; i++)
+ {
+ call.StartSendMessage(sendCompletionHandler, payload, writeFlags, false);
+ var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey);
+ callback(true);
+ }
+ stopwatch.Stop();
+ Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
+
+ cq.Dispose();
+ }
+
+ private static CallSafeHandle CreateFakeCall(CompletionQueueSafeHandle cq)
+ {
+ var call = CallSafeHandle.CreateFake(new IntPtr(0xdead), cq);
+ bool success = false;
+ while (!success)
+ {
+ // avoid calling destroy on a nonexistent grpc_call pointer
+ call.DangerousAddRef(ref success);
+ }
+ return call;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
new file mode 100644
index 0000000000..1c54624034
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+
+// 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.
+
+#endregion
+
+using System;
+using System.Threading;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Grpc.Microbenchmarks
+{
+ public class ThreadedBenchmark
+ {
+ List<ThreadStart> runners;
+
+ public ThreadedBenchmark(IEnumerable<ThreadStart> runners)
+ {
+ this.runners = new List<ThreadStart>(runners);
+ }
+
+ public ThreadedBenchmark(int threadCount, Action threadBody)
+ {
+ this.runners = new List<ThreadStart>();
+ for (int i = 0; i < threadCount; i++)
+ {
+ this.runners.Add(new ThreadStart(() => threadBody()));
+ }
+ }
+
+ public void Run()
+ {
+ Console.WriteLine("Running threads.");
+ var threads = new List<Thread>();
+ for (int i = 0; i < runners.Count; i++)
+ {
+ var thread = new Thread(runners[i]);
+ thread.Start();
+ threads.Add(thread);
+ }
+
+ foreach (var thread in threads)
+ {
+ thread.Join();
+ }
+ Console.WriteLine("All threads finished.");
+ }
+ }
+}
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index beab3ccb36..d9a7b8d556 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
+VisualStudioVersion = 15.0.26430.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}"
EndProject
@@ -37,6 +37,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection", "Grpc.Ref
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{335AD0A2-F2CC-4C2E-853C-26174206BEE7}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Microbenchmarks", "Grpc.Microbenchmarks\Grpc.Microbenchmarks.csproj", "{84C17746-4727-4290-8E8B-A380793DAE1E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -111,6 +113,10 @@ Global
{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {84C17746-4727-4290-8E8B-A380793DAE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {84C17746-4727-4290-8E8B-A380793DAE1E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index f6cff454bd..a56113eca3 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -529,6 +529,38 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_destroy(grpc_call *call) {
grpc_call_unref(call);
}
+typedef grpc_call_error (*grpcsharp_call_start_batch_func)(grpc_call *call,
+ const grpc_op *ops,
+ size_t nops,
+ void *tag,
+ void *reserved);
+
+/* Only for testing */
+static grpc_call_error grpcsharp_call_start_batch_nop(grpc_call *call,
+ const grpc_op *ops,
+ size_t nops, void *tag,
+ void *reserved) {
+ return GRPC_CALL_OK;
+}
+
+static grpc_call_error grpcsharp_call_start_batch_default(grpc_call *call,
+ const grpc_op *ops,
+ size_t nops,
+ void *tag,
+ void *reserved) {
+ return grpc_call_start_batch(call, ops, nops, tag, reserved);
+}
+
+static grpcsharp_call_start_batch_func g_call_start_batch_func =
+ grpcsharp_call_start_batch_default;
+
+static grpc_call_error grpcsharp_call_start_batch(grpc_call *call,
+ const grpc_op *ops,
+ size_t nops, void *tag,
+ void *reserved) {
+ return g_call_start_batch_func(call, ops, nops, tag, reserved);
+}
+
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(
grpc_call *call, grpcsharp_batch_context *ctx, const char *send_buffer,
size_t send_buffer_len, uint32_t write_flags,
@@ -576,8 +608,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_unary(
ops[5].flags = 0;
ops[5].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(
@@ -616,8 +648,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_client_streaming(
ops[3].flags = 0;
ops[3].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
@@ -656,8 +688,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_server_streaming(
ops[3].flags = 0;
ops[3].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(
@@ -685,8 +717,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_start_duplex_streaming(
ops[1].flags = 0;
ops[1].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
@@ -699,8 +731,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_recv_initial_metadata(
ops[0].flags = 0;
ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(
@@ -720,7 +752,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_message(
ops[1].flags = 0;
ops[1].reserved = NULL;
- return grpc_call_start_batch(call, ops, nops, ctx, NULL);
+ return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(
@@ -731,8 +763,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_close_from_client(
ops[0].flags = 0;
ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
@@ -773,7 +805,7 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_status_from_server(
ops[nops].reserved = NULL;
nops++;
}
- return grpc_call_start_batch(call, ops, nops, ctx, NULL);
+ return grpcsharp_call_start_batch(call, ops, nops, ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -784,8 +816,8 @@ grpcsharp_call_recv_message(grpc_call *call, grpcsharp_batch_context *ctx) {
ops[0].data.recv_message.recv_message = &(ctx->recv_message);
ops[0].flags = 0;
ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -798,8 +830,8 @@ grpcsharp_call_start_serverside(grpc_call *call, grpcsharp_batch_context *ctx) {
ops[0].flags = 0;
ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(
@@ -817,8 +849,8 @@ GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_send_initial_metadata(
ops[0].flags = 0;
ops[0].reserved = NULL;
- return grpc_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]), ctx,
- NULL);
+ return grpcsharp_call_start_batch(call, ops, sizeof(ops) / sizeof(ops[0]),
+ ctx, NULL);
}
GPR_EXPORT grpc_call_error GPR_CALLTYPE
@@ -1092,3 +1124,17 @@ GPR_EXPORT void *GPR_CALLTYPE grpcsharp_test_nop(void *ptr) { return ptr; }
GPR_EXPORT int32_t GPR_CALLTYPE grpcsharp_sizeof_grpc_event(void) {
return sizeof(grpc_event);
}
+
+/* Override a method for testing */
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_test_override_method(const char *method_name, const char *variant) {
+ if (strcmp("grpcsharp_call_start_batch", method_name) == 0) {
+ if (strcmp("nop", variant) == 0) {
+ g_call_start_batch_func = grpcsharp_call_start_batch_nop;
+ } else {
+ GPR_ASSERT(0);
+ }
+ } else {
+ GPR_ASSERT(0);
+ }
+}
diff --git a/src/node/README.md b/src/node/README.md
index 4b906643bc..3b98b97879 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -2,9 +2,9 @@
# Node.js gRPC Library
## PREREQUISITES
-- `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
+- `node`: This requires `node` to be installed, version `4.0` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
-- **Note:** If you installed `node` via a package manager and the version is still less than `0.12`, try directly installing it from [nodejs.org](https://nodejs.org).
+- **Note:** If you installed `node` via a package manager and the version is still less than `4.0`, try directly installing it from [nodejs.org](https://nodejs.org).
## INSTALLATION
@@ -16,7 +16,7 @@ npm install grpc
## BUILD FROM SOURCE
1. Clone [the grpc Git Repository](https://github.com/grpc/grpc).
- 2. Run `npm install` from the repository root.
+ 2. Run `npm install --build-from-source` from the repository root.
- **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning):
@@ -34,61 +34,3 @@ npm install grpc
## TESTING
To run the test suite, simply run `npm test` in the install location.
-
-## API
-This library internally uses [ProtoBuf.js](https://github.com/dcodeIO/ProtoBuf.js), and some structures it exports match those exported by that library.
-
-If you require this module, you will get an object with the following members
-
-```javascript
-function load(filename)
-```
-
-Takes a filename of a [Protocol Buffer](https://developers.google.com/protocol-buffers/) file, and returns an object representing the structure of the protocol buffer in the following way:
-
- - Namespaces become maps from the names of their direct members to those member objects
- - Service definitions become client constructors for clients for that service. They also have a `service` member that can be used for constructing servers.
- - Message definitions become Message constructors like those that ProtoBuf.js would create
- - Enum definitions become Enum objects like those that ProtoBuf.js would create
- - Anything else becomes the relevant reflection object that ProtoBuf.js would create
-
-
-```javascript
-function loadObject(reflectionObject)
-```
-
-Returns the same structure that `load` returns, but takes a reflection object from `ProtoBuf.js` instead of a file name.
-
-```javascript
-function Server([serverOptions])
-```
-
-Constructs a server to which service/implementation pairs can be added.
-
-
-```javascript
-status
-```
-
-An object mapping status names to status code numbers.
-
-
-```javascript
-callError
-```
-
-An object mapping call error names to codes. This is primarily useful for tracking down certain kinds of internal errors.
-
-
-```javascript
-Credentials
-```
-
-An object with factory methods for creating credential objects for clients.
-
-
-```javascript
-ServerCredentials
-```
-
-An object with factory methods for creating credential objects for servers.
diff --git a/src/node/index.js b/src/node/index.js
index 2da77c3eae..177628e22d 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -31,10 +31,6 @@
*
*/
-/**
- * @module
- */
-
'use strict';
var path = require('path');
@@ -64,24 +60,30 @@ var constants = require('./src/constants.js');
grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
/**
- * Load a ProtoBuf.js object as a gRPC object. The options object can provide
- * the following options:
- * - binaryAsBase64: deserialize bytes values as base64 strings instead of
- * Buffers. Defaults to false
- * - longsAsStrings: deserialize long values as strings instead of objects.
- * Defaults to true
- * - deprecatedArgumentOrder: Use the beta method argument order for client
- * methods, with optional arguments after the callback. Defaults to false.
- * This option is only a temporary stopgap measure to smooth an API breakage.
- * It is deprecated, and new code should not use it.
- * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6
- * respectively indicate that an object from the corresponding version of
- * ProtoBuf.js is provided in the value argument. If the option is 'detect',
- * gRPC will guess what the version is based on the structure of the value.
- * Defaults to 'detect'.
+ * @namespace grpc
+ */
+
+/**
+ * Load a ProtoBuf.js object as a gRPC object.
+ * @memberof grpc
+ * @alias grpc.loadObject
* @param {Object} value The ProtoBuf.js reflection object to load
* @param {Object=} options Options to apply to the loaded file
- * @return {Object<string, *>} The resulting gRPC object
+ * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as
+ * base64 strings instead of Buffers
+ * @param {bool=} [options.longsAsStrings=true] deserialize long values as
+ * strings instead of objects
+ * @param {bool=} [options.enumsAsStrings=true] deserialize enum values as
+ * strings instead of numbers. Only works with Protobuf.js 6 values.
+ * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method
+ * argument order for client methods, with optional arguments after the
+ * callback. This option is only a temporary stopgap measure to smooth an
+ * API breakage. It is deprecated, and new code should not use it.
+ * @param {(number|string)=} [options.protobufjsVersion='detect'] 5 and 6
+ * respectively indicate that an object from the corresponding version of
+ * Protobuf.js is provided in the value argument. If the option is 'detect',
+ * gRPC wll guess what the version is based on the structure of the value.
+ * @return {Object<string, *>} The resulting gRPC object.
*/
exports.loadObject = function loadObject(value, options) {
options = _.defaults(options, common.defaultGrpcOptions);
@@ -112,22 +114,23 @@ exports.loadObject = function loadObject(value, options) {
var loadObject = exports.loadObject;
/**
- * Load a gRPC object from a .proto file. The options object can provide the
- * following options:
- * - convertFieldsToCamelCase: Load this file with field names in camel case
- * instead of their original case
- * - binaryAsBase64: deserialize bytes values as base64 strings instead of
- * Buffers. Defaults to false
- * - longsAsStrings: deserialize long values as strings instead of objects.
- * Defaults to true
- * - deprecatedArgumentOrder: Use the beta method argument order for client
- * methods, with optional arguments after the callback. Defaults to false.
- * This option is only a temporary stopgap measure to smooth an API breakage.
- * It is deprecated, and new code should not use it.
+ * Load a gRPC object from a .proto file.
+ * @memberof grpc
+ * @alias grpc.load
* @param {string|{root: string, file: string}} filename The file to load
* @param {string=} format The file format to expect. Must be either 'proto' or
* 'json'. Defaults to 'proto'
* @param {Object=} options Options to apply to the loaded file
+ * @param {bool=} [options.convertFieldsToCamelCase=false] Load this file with
+ * field names in camel case instead of their original case
+ * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as
+ * base64 strings instead of Buffers
+ * @param {bool=} [options.longsAsStrings=true] deserialize long values as
+ * strings instead of objects
+ * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method
+ * argument order for client methods, with optional arguments after the
+ * callback. This option is only a temporary stopgap measure to smooth an
+ * API breakage. It is deprecated, and new code should not use it.
* @return {Object<string, *>} The resulting gRPC object
*/
exports.load = function load(filename, format, options) {
@@ -168,6 +171,8 @@ var log_template = _.template(
* called. Note: the output format here is intended to be informational, and
* is not guaranteed to stay the same in the future.
* Logs will be directed to logger.error.
+ * @memberof grpc
+ * @alias grpc.setLogger
* @param {Console} logger A Console-like object.
*/
exports.setLogger = function setLogger(logger) {
@@ -187,6 +192,8 @@ exports.setLogger = function setLogger(logger) {
/**
* Sets the logger verbosity for gRPC module logging. The options are members
* of the grpc.logVerbosity map.
+ * @memberof grpc
+ * @alias grpc.setLogVerbosity
* @param {Number} verbosity The minimum severity to log
*/
exports.setLogVerbosity = function setLogVerbosity(verbosity) {
@@ -194,71 +201,70 @@ exports.setLogVerbosity = function setLogVerbosity(verbosity) {
grpc.setLogVerbosity(verbosity);
};
-/**
- * @see module:src/server.Server
- */
exports.Server = server.Server;
-/**
- * @see module:src/metadata
- */
exports.Metadata = Metadata;
-/**
- * Status name to code number mapping
- */
exports.status = constants.status;
-/**
- * Propagate flag name to number mapping
- */
exports.propagate = constants.propagate;
-/**
- * Call error name to code number mapping
- */
exports.callError = constants.callError;
-/**
- * Write flag name to code number mapping
- */
exports.writeFlags = constants.writeFlags;
-/**
- * Log verbosity setting name to code number mapping
- */
exports.logVerbosity = constants.logVerbosity;
-/**
- * Credentials factories
- */
exports.credentials = require('./src/credentials.js');
/**
* ServerCredentials factories
+ * @constructor ServerCredentials
+ * @memberof grpc
*/
exports.ServerCredentials = grpc.ServerCredentials;
/**
- * @see module:src/client.makeClientConstructor
+ * Create insecure server credentials
+ * @name grpc.ServerCredentials.createInsecure
+ * @kind function
+ * @return grpc.ServerCredentials
*/
-exports.makeGenericClientConstructor = client.makeClientConstructor;
/**
- * @see module:src/client.getClientChannel
+ * A private key and certificate pair
+ * @typedef {Object} grpc.ServerCredentials~keyCertPair
+ * @property {Buffer} privateKey The server's private key
+ * @property {Buffer} certChain The server's certificate chain
*/
-exports.getClientChannel = client.getClientChannel;
/**
- * @see module:src/client.waitForClientReady
+ * Create SSL server credentials
+ * @name grpc.ServerCredentials.createInsecure
+ * @kind function
+ * @param {?Buffer} rootCerts Root CA certificates for validating client
+ * certificates
+ * @param {Array<grpc.ServerCredentials~keyCertPair>} keyCertPairs A list of
+ * private key and certificate chain pairs to be used for authenticating
+ * the server
+ * @param {boolean} [checkClientCertificate=false] Indicates that the server
+ * should request and verify the client's certificates
+ * @return grpc.ServerCredentials
*/
+
+exports.makeGenericClientConstructor = client.makeClientConstructor;
+
+exports.getClientChannel = client.getClientChannel;
+
exports.waitForClientReady = client.waitForClientReady;
+/**
+ * @memberof grpc
+ * @alias grpc.closeClient
+ * @param {grpc.Client} client_obj The client to close
+ */
exports.closeClient = function closeClient(client_obj) {
client.Client.prototype.close.apply(client_obj);
};
-/**
- * @see module:src/client.Client
- */
exports.Client = client.Client;
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 16fe06a54d..cf4c104144 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -43,8 +43,6 @@
* var Client = proto_obj.package.subpackage.ServiceName;
* var client = new Client(server_address, client_credentials);
* var call = client.unaryMethod(arguments, callback);
- *
- * @module
*/
'use strict';
@@ -70,13 +68,26 @@ var Duplex = stream.Duplex;
var util = require('util');
var version = require('../../../package.json').version;
+/**
+ * Initial response metadata sent by the server when it starts processing the
+ * call
+ * @event grpc~ClientUnaryCall#metadata
+ * @type {grpc.Metadata}
+ */
+
+/**
+ * Status of the call when it has completed.
+ * @event grpc~ClientUnaryCall#status
+ * @type grpc~StatusObject
+ */
+
util.inherits(ClientUnaryCall, EventEmitter);
/**
- * An EventEmitter. Used for unary calls
- * @constructor
+ * An EventEmitter. Used for unary calls.
+ * @constructor grpc~ClientUnaryCall
* @extends external:EventEmitter
- * @param {grpc.Call} call The call object associated with the request
+ * @param {grpc.internal~Call} call The call object associated with the request
*/
function ClientUnaryCall(call) {
EventEmitter.call(this);
@@ -88,14 +99,16 @@ util.inherits(ClientWritableStream, Writable);
/**
* A stream that the client can write to. Used for calls that are streaming from
* the client side.
- * @constructor
+ * @constructor grpc~ClientWritableStream
* @extends external:Writable
- * @borrows module:src/client~ClientUnaryCall#cancel as
- * module:src/client~ClientWritableStream#cancel
- * @borrows module:src/client~ClientUnaryCall#getPeer as
- * module:src/client~ClientWritableStream#getPeer
- * @param {grpc.Call} call The call object to send data with
- * @param {module:src/common~serialize=} [serialize=identity] Serialization
+ * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientWritableStream#cancel
+ * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientWritableStream#getPeer
+ * @borrows grpc~ClientUnaryCall#event:metadata as
+ * grpc~ClientWritableStream#metadata
+ * @borrows grpc~ClientUnaryCall#event:status as
+ * grpc~ClientWritableStream#status
+ * @param {grpc.internal~Call} call The call object to send data with
+ * @param {grpc~serialize=} [serialize=identity] Serialization
* function for writes.
*/
function ClientWritableStream(call, serialize) {
@@ -110,11 +123,24 @@ function ClientWritableStream(call, serialize) {
}
/**
+ * Write a message to the request stream. If serializing the argument fails,
+ * the call will be cancelled and the stream will end with an error.
+ * @name grpc~ClientWritableStream#write
+ * @kind function
+ * @override
+ * @param {*} message The message to write. Must be a valid argument to the
+ * serialize function of the corresponding method
+ * @param {grpc.writeFlags} flags Flags to modify how the message is written
+ * @param {Function} callback Callback for when this chunk of data is flushed
+ * @return {boolean} As defined for [Writable]{@link external:Writable}
+ */
+
+/**
* Attempt to write the given chunk. Calls the callback when done. This is an
* implementation of a method needed for implementing stream.Writable.
- * @access private
- * @param {Buffer} chunk The chunk to write
- * @param {string} encoding Used to pass write flags
+ * @private
+ * @param {*} chunk The chunk to write
+ * @param {grpc.writeFlags} encoding Used to pass write flags
* @param {function(Error=)} callback Called when the write is complete
*/
function _write(chunk, encoding, callback) {
@@ -155,14 +181,16 @@ util.inherits(ClientReadableStream, Readable);
/**
* A stream that the client can read from. Used for calls that are streaming
* from the server side.
- * @constructor
+ * @constructor grpc~ClientReadableStream
* @extends external:Readable
- * @borrows module:src/client~ClientUnaryCall#cancel as
- * module:src/client~ClientReadableStream#cancel
- * @borrows module:src/client~ClientUnaryCall#getPeer as
- * module:src/client~ClientReadableStream#getPeer
- * @param {grpc.Call} call The call object to read data with
- * @param {module:src/common~deserialize=} [deserialize=identity]
+ * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientReadableStream#cancel
+ * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientReadableStream#getPeer
+ * @borrows grpc~ClientUnaryCall#event:metadata as
+ * grpc~ClientReadableStream#metadata
+ * @borrows grpc~ClientUnaryCall#event:status as
+ * grpc~ClientReadableStream#status
+ * @param {grpc.internal~Call} call The call object to read data with
+ * @param {grpc~deserialize=} [deserialize=identity]
* Deserialization function for reads
*/
function ClientReadableStream(call, deserialize) {
@@ -183,7 +211,7 @@ function ClientReadableStream(call, deserialize) {
* parameter indicates that the call should end with that status. status
* defaults to OK if not provided.
* @param {Object!} status The status that the call should end with
- * @access private
+ * @private
*/
function _readsDone(status) {
/* jshint validthis: true */
@@ -202,7 +230,7 @@ ClientReadableStream.prototype._readsDone = _readsDone;
/**
* Called to indicate that we have received a status from the server.
- * @access private
+ * @private
*/
function _receiveStatus(status) {
/* jshint validthis: true */
@@ -215,7 +243,7 @@ ClientReadableStream.prototype._receiveStatus = _receiveStatus;
/**
* If we have both processed all incoming messages and received the status from
* the server, emit the status. Otherwise, do nothing.
- * @access private
+ * @private
*/
function _emitStatusIfDone() {
/* jshint validthis: true */
@@ -242,7 +270,7 @@ ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone;
/**
* Read the next object from the stream.
- * @access private
+ * @private
* @param {*} size Ignored because we use objectMode=true
*/
function _read(size) {
@@ -300,16 +328,19 @@ util.inherits(ClientDuplexStream, Duplex);
/**
* A stream that the client can read from or write to. Used for calls with
* duplex streaming.
- * @constructor
+ * @constructor grpc~ClientDuplexStream
* @extends external:Duplex
- * @borrows module:src/client~ClientUnaryCall#cancel as
- * module:src/client~ClientDuplexStream#cancel
- * @borrows module:src/client~ClientUnaryCall#getPeer as
- * module:src/client~ClientDuplexStream#getPeer
- * @param {grpc.Call} call Call object to proxy
- * @param {module:src/common~serialize=} [serialize=identity] Serialization
+ * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientDuplexStream#cancel
+ * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientDuplexStream#getPeer
+ * @borrows grpc~ClientWritableStream#write as grpc~ClientDuplexStream#write
+ * @borrows grpc~ClientUnaryCall#event:metadata as
+ * grpc~ClientDuplexStream#metadata
+ * @borrows grpc~ClientUnaryCall#event:status as
+ * grpc~ClientDuplexStream#status
+ * @param {grpc.internal~Call} call Call object to proxy
+ * @param {grpc~serialize=} [serialize=identity] Serialization
* function for requests
- * @param {module:src/common~deserialize=} [deserialize=identity]
+ * @param {grpc~deserialize=} [deserialize=identity]
* Deserialization function for responses
*/
function ClientDuplexStream(call, serialize, deserialize) {
@@ -336,8 +367,9 @@ ClientDuplexStream.prototype._read = _read;
ClientDuplexStream.prototype._write = _write;
/**
- * Cancel the ongoing call
- * @alias module:src/client~ClientUnaryCall#cancel
+ * Cancel the ongoing call. Results in the call ending with a CANCELLED status,
+ * unless it has already ended with some other status.
+ * @alias grpc~ClientUnaryCall#cancel
*/
function cancel() {
/* jshint validthis: true */
@@ -352,7 +384,7 @@ ClientDuplexStream.prototype.cancel = cancel;
/**
* Get the endpoint this call/stream is connected to.
* @return {string} The URI of the endpoint
- * @alias module:src/client~ClientUnaryCall#getPeer
+ * @alias grpc~ClientUnaryCall#getPeer
*/
function getPeer() {
/* jshint validthis: true */
@@ -368,33 +400,31 @@ ClientDuplexStream.prototype.getPeer = getPeer;
* Any client call type
* @typedef {(ClientUnaryCall|ClientReadableStream|
* ClientWritableStream|ClientDuplexStream)}
- * module:src/client~Call
+ * grpc.Client~Call
*/
/**
* Options that can be set on a call.
- * @typedef {Object} module:src/client~CallOptions
- * @property {(date|number)} deadline The deadline for the entire call to
- * complete. A value of Infinity indicates that no deadline should be set.
- * @property {(string)} host Server hostname to set on the call. Only meaningful
+ * @typedef {Object} grpc.Client~CallOptions
+ * @property {grpc~Deadline} deadline The deadline for the entire call to
+ * complete.
+ * @property {string} host Server hostname to set on the call. Only meaningful
* if different from the server address used to construct the client.
- * @property {module:src/client~Call} parent Parent call. Used in servers when
+ * @property {grpc.Client~Call} parent Parent call. Used in servers when
* making a call as part of the process of handling a call. Used to
* propagate some information automatically, as specified by
* propagate_flags.
* @property {number} propagate_flags Indicates which properties of a parent
* call should propagate to this call. Bitwise combination of flags in
- * [grpc.propagate]{@link module:index.propagate}.
- * @property {module:src/credentials~CallCredentials} credentials The
- * credentials that should be used to make this particular call.
+ * {@link grpc.propagate}.
+ * @property {grpc.credentials~CallCredentials} credentials The credentials that
+ * should be used to make this particular call.
*/
/**
- * Get a call object built with the provided options. Keys for options are
- * 'deadline', which takes a date or number, and 'host', which takes a string
- * and overrides the hostname to connect to.
+ * Get a call object built with the provided options.
* @access private
- * @param {module:src/client~CallOptions=} options Options object.
+ * @param {grpc.Client~CallOptions=} options Options object.
*/
function getCall(channel, method, options) {
var deadline;
@@ -422,14 +452,14 @@ function getCall(channel, method, options) {
/**
* A generic gRPC client. Primarily useful as a base class for generated clients
- * @alias module:src/client.Client
+ * @memberof grpc
* @constructor
* @param {string} address Server address to connect to
- * @param {module:src/credentials~ChannelCredentials} credentials Credentials to
- * use to connect to the server
+ * @param {grpc~ChannelCredentials} credentials Credentials to use to connect to
+ * the server
* @param {Object} options Options to apply to channel creation
*/
-var Client = exports.Client = function Client(address, credentials, options) {
+function Client(address, credentials, options) {
if (!options) {
options = {};
}
@@ -445,19 +475,13 @@ var Client = exports.Client = function Client(address, credentials, options) {
/* Private fields use $ as a prefix instead of _ because it is an invalid
* prefix of a method name */
this.$channel = new grpc.Channel(address, credentials, options);
-};
+}
-/**
- * @typedef {Error} module:src/client.Client~ServiceError
- * @property {number} code The error code, a key of
- * [grpc.status]{@link module:src/client.status}
- * @property {module:metadata.Metadata} metadata Metadata sent with the status
- * by the server, if any
- */
+exports.Client = Client;
/**
- * @callback module:src/client.Client~requestCallback
- * @param {?module:src/client.Client~ServiceError} error The error, if the call
+ * @callback grpc.Client~requestCallback
+ * @param {?grpc~ServiceError} error The error, if the call
* failed
* @param {*} value The response value, if the call succeeded
*/
@@ -466,17 +490,17 @@ var Client = exports.Client = function Client(address, credentials, options) {
* Make a unary request to the given method, using the given serialize
* and deserialize functions, with the given argument.
* @param {string} method The name of the method to request
- * @param {module:src/common~serialize} serialize The serialization function for
+ * @param {grpc~serialize} serialize The serialization function for
* inputs
- * @param {module:src/common~deserialize} deserialize The deserialization
+ * @param {grpc~deserialize} deserialize The deserialization
* function for outputs
* @param {*} argument The argument to the call. Should be serializable with
* serialize
- * @param {module:src/metadata.Metadata=} metadata Metadata to add to the call
- * @param {module:src/client~CallOptions=} options Options map
- * @param {module:src/client.Client~requestCallback} callback The callback to
+ * @param {grpc.Metadata=} metadata Metadata to add to the call
+ * @param {grpc.Client~CallOptions=} options Options map
+ * @param {grpc.Client~requestCallback} callback The callback to
* for when the response is received
- * @return {EventEmitter} An event emitter for stream related events
+ * @return {grpc~ClientUnaryCall} An event emitter for stream related events
*/
Client.prototype.makeUnaryRequest = function(method, serialize, deserialize,
argument, metadata, options,
@@ -548,17 +572,17 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize,
* Make a client stream request to the given method, using the given serialize
* and deserialize functions, with the given argument.
* @param {string} method The name of the method to request
- * @param {module:src/common~serialize} serialize The serialization function for
+ * @param {grpc~serialize} serialize The serialization function for
* inputs
- * @param {module:src/common~deserialize} deserialize The deserialization
+ * @param {grpc~deserialize} deserialize The deserialization
* function for outputs
- * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value
- * pairs to add to the call
- * @param {module:src/client~CallOptions=} options Options map
- * @param {Client~requestCallback} callback The callback to for when the
+ * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to
+ * the call
+ * @param {grpc.Client~CallOptions=} options Options map
+ * @param {grpc.Client~requestCallback} callback The callback to for when the
* response is received
- * @return {module:src/client~ClientWritableStream} An event emitter for stream
- * related events
+ * @return {grpc~ClientWritableStream} An event emitter for stream related
+ * events
*/
Client.prototype.makeClientStreamRequest = function(method, serialize,
deserialize, metadata,
@@ -631,17 +655,16 @@ Client.prototype.makeClientStreamRequest = function(method, serialize,
* Make a server stream request to the given method, with the given serialize
* and deserialize function, using the given argument
* @param {string} method The name of the method to request
- * @param {module:src/common~serialize} serialize The serialization function for
- * inputs
- * @param {module:src/common~deserialize} deserialize The deserialization
+ * @param {grpc~serialize} serialize The serialization function for inputs
+ * @param {grpc~deserialize} deserialize The deserialization
* function for outputs
* @param {*} argument The argument to the call. Should be serializable with
* serialize
- * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value
- * pairs to add to the call
- * @param {module:src/client~CallOptions=} options Options map
- * @return {module:src/client~ClientReadableStream} An event emitter for stream
- * related events
+ * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to
+ * the call
+ * @param {grpc.Client~CallOptions=} options Options map
+ * @return {grpc~ClientReadableStream} An event emitter for stream related
+ * events
*/
Client.prototype.makeServerStreamRequest = function(method, serialize,
deserialize, argument,
@@ -693,15 +716,13 @@ Client.prototype.makeServerStreamRequest = function(method, serialize,
/**
* Make a bidirectional stream request with this method on the given channel.
* @param {string} method The name of the method to request
- * @param {module:src/common~serialize} serialize The serialization function for
- * inputs
- * @param {module:src/common~deserialize} deserialize The deserialization
+ * @param {grpc~serialize} serialize The serialization function for inputs
+ * @param {grpc~deserialize} deserialize The deserialization
* function for outputs
- * @param {module:src/metadata.Metadata=} metadata Array of metadata key/value
+ * @param {grpc.Metadata=} metadata Array of metadata key/value
* pairs to add to the call
- * @param {module:src/client~CallOptions=} options Options map
- * @return {module:src/client~ClientDuplexStream} An event emitter for stream
- * related events
+ * @param {grpc.Client~CallOptions=} options Options map
+ * @return {grpc~ClientDuplexStream} An event emitter for stream related events
*/
Client.prototype.makeBidiStreamRequest = function(method, serialize,
deserialize, metadata,
@@ -743,6 +764,9 @@ Client.prototype.makeBidiStreamRequest = function(method, serialize,
return stream;
};
+/**
+ * Close this client.
+ */
Client.prototype.close = function() {
this.$channel.close();
};
@@ -761,8 +785,7 @@ Client.prototype.getChannel = function() {
* with an error if the attempt to connect to the server has unrecoverablly
* failed or if the deadline expires. This function will make the channel
* start connecting if it has not already done so.
- * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
- * Infinity to wait forever.
+ * @param {grpc~Deadline} deadline When to stop waiting for a connection.
* @param {function(Error)} callback The callback to call when done attempting
* to connect.
*/
@@ -788,7 +811,7 @@ Client.prototype.waitForReady = function(deadline, callback) {
/**
* Map with short names for each of the requester maker functions. Used in
* makeClientConstructor
- * @access private
+ * @private
*/
var requester_funcs = {
unary: Client.prototype.makeUnaryRequest,
@@ -834,9 +857,15 @@ var deprecated_request_wrap = {
/**
* Creates a constructor for a client with the given methods, as specified in
- * the methods argument.
- * @param {module:src/common~ServiceDefinition} methods An object mapping
- * method names to method attributes
+ * the methods argument. The resulting class will have an instance method for
+ * each method in the service, which is a partial application of one of the
+ * [Client]{@link grpc.Client} request methods, depending on `requestSerialize`
+ * and `responseSerialize`, with the `method`, `serialize`, and `deserialize`
+ * arguments predefined.
+ * @memberof grpc
+ * @alias grpc~makeGenericClientConstructor
+ * @param {grpc~ServiceDefinition} methods An object mapping method names to
+ * method attributes
* @param {string} serviceName The fully qualified name of the service
* @param {Object} class_options An options object.
* @param {boolean=} [class_options.deprecatedArgumentOrder=false] Indicates
@@ -844,9 +873,8 @@ var deprecated_request_wrap = {
* arguments at the end instead of the callback at the end. This option
* is only a temporary stopgap measure to smooth an API breakage.
* It is deprecated, and new code should not use it.
- * @return {function(string, Object)} New client constructor, which is a
- * subclass of [grpc.Client]{@link module:src/client.Client}, and has the
- * same arguments as that constructor.
+ * @return {function} New client constructor, which is a subclass of
+ * {@link grpc.Client}, and has the same arguments as that constructor.
*/
exports.makeClientConstructor = function(methods, serviceName,
class_options) {
@@ -898,8 +926,11 @@ exports.makeClientConstructor = function(methods, serviceName,
/**
* Return the underlying channel object for the specified client
+ * @memberof grpc
+ * @alias grpc~getClientChannel
* @param {Client} client
* @return {Channel} The channel
+ * @see grpc.Client#getChannel
*/
exports.getClientChannel = function(client) {
return Client.prototype.getChannel.call(client);
@@ -911,22 +942,15 @@ exports.getClientChannel = function(client) {
* with an error if the attempt to connect to the server has unrecoverablly
* failed or if the deadline expires. This function will make the channel
* start connecting if it has not already done so.
+ * @memberof grpc
+ * @alias grpc~waitForClientReady
* @param {Client} client The client to wait on
- * @param {(Date|Number)} deadline When to stop waiting for a connection. Pass
+ * @param {grpc~Deadline} deadline When to stop waiting for a connection. Pass
* Infinity to wait forever.
* @param {function(Error)} callback The callback to call when done attempting
* to connect.
+ * @see grpc.Client#waitForReady
*/
exports.waitForClientReady = function(client, deadline, callback) {
Client.prototype.waitForReady.call(client, deadline, callback);
};
-
-/**
- * Map of status code names to status codes
- */
-exports.status = constants.status;
-
-/**
- * See docs for client.callError
- */
-exports.callError = grpc.callError;
diff --git a/src/node/src/common.js b/src/node/src/common.js
index 4dad60e630..0f835317ea 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -31,12 +31,6 @@
*
*/
-/**
- * This module contains functions that are common to client and server
- * code. None of them should be used directly by gRPC users.
- * @module
- */
-
'use strict';
var _ = require('lodash');
@@ -62,16 +56,19 @@ exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
/**
* The logger object for the gRPC module. Defaults to console.
+ * @private
*/
exports.logger = console;
/**
* The current logging verbosity. 0 corresponds to logging everything
+ * @private
*/
exports.logVerbosity = 0;
/**
* Log a message if the severity is at least as high as the current verbosity
+ * @private
* @param {Number} severity A value of the grpc.logVerbosity map
* @param {String} message The message to log
*/
@@ -83,6 +80,7 @@ exports.log = function log(severity, message) {
/**
* Default options for loading proto files into gRPC
+ * @alias grpc~defaultLoadOptions
*/
exports.defaultGrpcOptions = {
convertFieldsToCamelCase: false,
@@ -95,6 +93,30 @@ exports.defaultGrpcOptions = {
// JSDoc definitions that are used in multiple other modules
/**
+ * Represents the status of a completed request. If `code` is
+ * {@link grpc.status}.OK, then the request has completed successfully.
+ * Otherwise, the request has failed, `details` will contain a description of
+ * the error. Either way, `metadata` contains the trailing response metadata
+ * sent by the server when it finishes processing the call.
+ * @typedef {object} grpc~StatusObject
+ * @property {number} code The error code, a key of {@link grpc.status}
+ * @property {string} details Human-readable description of the status
+ * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
+ * if applicable
+ */
+
+/**
+ * Describes how a request has failed. The member `message` will be the same as
+ * `details` in {@link grpc~StatusObject}, and `code` and `metadata` are the
+ * same as in that object.
+ * @typedef {Error} grpc~ServiceError
+ * @property {number} code The error code, a key of {@link grpc.status} that is
+ * not `grpc.status.OK`
+ * @property {grpc.Metadata} metadata Trailing metadata sent with the status,
+ * if applicable
+ */
+
+/**
* The EventEmitter class in the event standard module
* @external EventEmitter
* @see https://nodejs.org/api/events.html#events_class_eventemitter
@@ -120,38 +142,46 @@ exports.defaultGrpcOptions = {
/**
* A serialization function
- * @callback module:src/common~serialize
+ * @callback grpc~serialize
* @param {*} value The value to serialize
* @return {Buffer} The value serialized as a byte sequence
*/
/**
* A deserialization function
- * @callback module:src/common~deserialize
+ * @callback grpc~deserialize
* @param {Buffer} data The byte sequence to deserialize
* @return {*} The data deserialized as a value
*/
/**
+ * The deadline of an operation. If it is a date, the deadline is reached at
+ * the date and time specified. If it is a finite number, it is treated as
+ * a number of milliseconds since the Unix Epoch. If it is Infinity, the
+ * deadline will never be reached. If it is -Infinity, the deadline has already
+ * passed.
+ * @typedef {(number|date)} grpc~Deadline
+ */
+
+/**
* An object that completely defines a service method signature.
- * @typedef {Object} module:src/common~MethodDefinition
+ * @typedef {Object} grpc~MethodDefinition
* @property {string} path The method's URL path
* @property {boolean} requestStream Indicates whether the method accepts
* a stream of requests
* @property {boolean} responseStream Indicates whether the method returns
* a stream of responses
- * @property {module:src/common~serialize} requestSerialize Serialization
+ * @property {grpc~serialize} requestSerialize Serialization
* function for request values
- * @property {module:src/common~serialize} responseSerialize Serialization
+ * @property {grpc~serialize} responseSerialize Serialization
* function for response values
- * @property {module:src/common~deserialize} requestDeserialize Deserialization
+ * @property {grpc~deserialize} requestDeserialize Deserialization
* function for request data
- * @property {module:src/common~deserialize} responseDeserialize Deserialization
+ * @property {grpc~deserialize} responseDeserialize Deserialization
* function for repsonse data
*/
/**
* An object that completely defines a service.
- * @typedef {Object.<string, module:src/common~MethodDefinition>}
- * module:src/common~ServiceDefinition
+ * @typedef {Object.<string, grpc~MethodDefinition>} grpc~ServiceDefinition
*/
diff --git a/src/node/src/constants.js b/src/node/src/constants.js
index 528dab120e..c441ee740b 100644
--- a/src/node/src/constants.js
+++ b/src/node/src/constants.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2017, Google Inc.
* All rights reserved.
*
@@ -31,16 +31,14 @@
*
*/
-/**
- * @module
- */
-
/* The comments about status codes are copied verbatim (with some formatting
* modifications) from include/grpc/impl/codegen/status.h, for the purpose of
* including them in generated documentation.
*/
/**
* Enum of status codes that gRPC can return
+ * @memberof grpc
+ * @alias grpc.status
* @readonly
* @enum {number}
*/
@@ -178,6 +176,8 @@ exports.status = {
* Users are encouraged to write propagation masks as deltas from the default.
* i.e. write `grpc.propagate.DEFAULTS & ~grpc.propagate.DEADLINE` to disable
* deadline propagation.
+ * @memberof grpc
+ * @alias grpc.propagate
* @enum {number}
*/
exports.propagate = {
@@ -194,9 +194,11 @@ exports.propagate = {
/**
* Call error constants. Call errors almost always indicate bugs in the gRPC
* library, and these error codes are mainly useful for finding those bugs.
+ * @memberof grpc
+ * @readonly
* @enum {number}
*/
-exports.callError = {
+const callError = {
OK: 0,
ERROR: 1,
NOT_ON_SERVER: 2,
@@ -213,9 +215,14 @@ exports.callError = {
PAYLOAD_TYPE_MISMATCH: 14
};
+exports.callError = callError;
+
/**
* Write flags: these can be bitwise or-ed to form write options that modify
* how data is written.
+ * @memberof grpc
+ * @alias grpc.writeFlags
+ * @readonly
* @enum {number}
*/
exports.writeFlags = {
@@ -232,6 +239,9 @@ exports.writeFlags = {
};
/**
+ * @memberof grpc
+ * @alias grpc.logVerbosity
+ * @readonly
* @enum {number}
*/
exports.logVerbosity = {
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index b1e86bbd09..b1dbc1c450 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -48,6 +48,7 @@
* For example, to create a client secured with SSL that uses Google
* default application credentials to authenticate:
*
+ * @example
* var channel_creds = credentials.createSsl(root_certs);
* (new GoogleAuth()).getApplicationDefault(function(err, credential) {
* var call_creds = credentials.createFromGoogleCredential(credential);
@@ -56,15 +57,25 @@
* var client = new Client(address, combined_creds);
* });
*
- * @module
+ * @namespace grpc.credentials
*/
'use strict';
var grpc = require('./grpc_extension');
+/**
+ * This cannot be constructed directly. Instead, instances of this class should
+ * be created using the factory functions in {@link grpc.credentials}
+ * @constructor grpc.credentials~CallCredentials
+ */
var CallCredentials = grpc.CallCredentials;
+/**
+ * This cannot be constructed directly. Instead, instances of this class should
+ * be created using the factory functions in {@link grpc.credentials}
+ * @constructor grpc.credentials~ChannelCredentials
+ */
var ChannelCredentials = grpc.ChannelCredentials;
var Metadata = require('./metadata.js');
@@ -76,24 +87,48 @@ var constants = require('./constants');
var _ = require('lodash');
/**
+ * @external GoogleCredential
+ * @see https://github.com/google/google-auth-library-nodejs
+ */
+
+/**
* Create an SSL Credentials object. If using a client-side certificate, both
* the second and third arguments must be passed.
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.createSsl
+ * @kind function
* @param {Buffer} root_certs The root certificate data
* @param {Buffer=} private_key The client certificate private key, if
* applicable
* @param {Buffer=} cert_chain The client certificate cert chain, if applicable
- * @return {ChannelCredentials} The SSL Credentials object
+ * @return {grpc.credentials.ChannelCredentials} The SSL Credentials object
*/
exports.createSsl = ChannelCredentials.createSsl;
/**
+ * @callback grpc.credentials~metadataCallback
+ * @param {Error} error The error, if getting metadata failed
+ * @param {grpc.Metadata} metadata The metadata
+ */
+
+/**
+ * @callback grpc.credentials~generateMetadata
+ * @param {Object} params Parameters that can modify metadata generation
+ * @param {string} params.service_url The URL of the service that the call is
+ * going to
+ * @param {grpc.credentials~metadataCallback} callback
+ */
+
+/**
* Create a gRPC credentials object from a metadata generation function. This
* function gets the service URL and a callback as parameters. The error
* passed to the callback can optionally have a 'code' value attached to it,
* which corresponds to a status code that this library uses.
- * @param {function(String, function(Error, Metadata))} metadata_generator The
- * function that generates metadata
- * @return {CallCredentials} The credentials object
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.createFromMetadataGenerator
+ * @param {grpc.credentials~generateMetadata} metadata_generator The function
+ * that generates metadata
+ * @return {grpc.credentials.CallCredentials} The credentials object
*/
exports.createFromMetadataGenerator = function(metadata_generator) {
return CallCredentials.createFromPlugin(function(service_url, cb_data,
@@ -119,8 +154,11 @@ exports.createFromMetadataGenerator = function(metadata_generator) {
/**
* Create a gRPC credential from a Google credential object.
- * @param {Object} google_credential The Google credential object to use
- * @return {CallCredentials} The resulting credentials object
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.createFromGoogleCredential
+ * @param {external:GoogleCredential} google_credential The Google credential
+ * object to use
+ * @return {grpc.credentials.CallCredentials} The resulting credentials object
*/
exports.createFromGoogleCredential = function(google_credential) {
return exports.createFromMetadataGenerator(function(auth_context, callback) {
@@ -141,6 +179,8 @@ exports.createFromGoogleCredential = function(google_credential) {
/**
* Combine a ChannelCredentials with any number of CallCredentials into a single
* ChannelCredentials object.
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.combineChannelCredentials
* @param {ChannelCredentials} channel_credential The ChannelCredentials to
* start with
* @param {...CallCredentials} credentials The CallCredentials to compose
@@ -157,6 +197,8 @@ exports.combineChannelCredentials = function(channel_credential) {
/**
* Combine any number of CallCredentials into a single CallCredentials object
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.combineCallCredentials
* @param {...CallCredentials} credentials the CallCredentials to compose
* @return CallCredentials A credentials object that combines all of the input
* credentials
@@ -172,6 +214,9 @@ exports.combineCallCredentials = function() {
/**
* Create an insecure credentials object. This is used to create a channel that
* does not use SSL. This cannot be composed with anything.
+ * @memberof grpc.credentials
+ * @alias grpc.credentials.createInsecure
+ * @kind function
* @return {ChannelCredentials} The insecure credentials object
*/
exports.createInsecure = ChannelCredentials.createInsecure;
diff --git a/src/node/src/grpc_extension.js b/src/node/src/grpc_extension.js
index 63a281ddbc..864da97314 100644
--- a/src/node/src/grpc_extension.js
+++ b/src/node/src/grpc_extension.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2016, Google Inc.
* All rights reserved.
*
diff --git a/src/node/src/metadata.js b/src/node/src/metadata.js
index 92cf23998b..c757d520f8 100644
--- a/src/node/src/metadata.js
+++ b/src/node/src/metadata.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -31,15 +31,6 @@
*
*/
-/**
- * Metadata module
- *
- * This module defines the Metadata class, which represents header and trailer
- * metadata for gRPC calls.
- *
- * @module
- */
-
'use strict';
var _ = require('lodash');
@@ -48,8 +39,8 @@ var grpc = require('./grpc_extension');
/**
* Class for storing metadata. Keys are normalized to lowercase ASCII.
+ * @memberof grpc
* @constructor
- * @alias module:src/metadata.Metadata
* @example
* var metadata = new metadata_module.Metadata();
* metadata.set('key1', 'value1');
diff --git a/src/node/src/protobuf_js_5_common.js b/src/node/src/protobuf_js_5_common.js
index 4041e05390..1663a3a400 100644
--- a/src/node/src/protobuf_js_5_common.js
+++ b/src/node/src/protobuf_js_5_common.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2017, Google Inc.
* All rights reserved.
*
@@ -31,6 +31,11 @@
*
*/
+/**
+ * @module
+ * @private
+ */
+
'use strict';
var _ = require('lodash');
diff --git a/src/node/src/protobuf_js_6_common.js b/src/node/src/protobuf_js_6_common.js
index 00f11f2736..91a458aa20 100644
--- a/src/node/src/protobuf_js_6_common.js
+++ b/src/node/src/protobuf_js_6_common.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2017, Google Inc.
* All rights reserved.
*
@@ -31,6 +31,11 @@
*
*/
+/**
+ * @module
+ * @private
+ */
+
'use strict';
var _ = require('lodash');
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 1d9cc7d2c1..ae4fcb1dc4 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -1,5 +1,5 @@
-/*
- *
+/**
+ * @license
* Copyright 2015, Google Inc.
* All rights reserved.
*
@@ -31,22 +31,6 @@
*
*/
-/**
- * Server module
- *
- * This module contains all the server code for Node gRPC: both the Server
- * class itself and the method handler code for all types of methods.
- *
- * For example, to create a Server, add a service, and start it:
- *
- * var server = new server_module.Server();
- * server.addProtoService(protobuf_service_descriptor, service_implementation);
- * server.bind('address:port', server_credential);
- * server.start();
- *
- * @module
- */
-
'use strict';
var _ = require('lodash');
@@ -70,9 +54,9 @@ var EventEmitter = require('events').EventEmitter;
/**
* Handle an error on a call by sending it as a status
- * @access private
- * @param {grpc.Call} call The call to send the error on
- * @param {Object} error The error object
+ * @private
+ * @param {grpc.internal~Call} call The call to send the error on
+ * @param {(Object|Error)} error The error object
*/
function handleError(call, error) {
var statusMetadata = new Metadata();
@@ -104,14 +88,14 @@ function handleError(call, error) {
/**
* Send a response to a unary or client streaming call.
- * @access private
+ * @private
* @param {grpc.Call} call The call to respond on
* @param {*} value The value to respond with
- * @param {function(*):Buffer=} serialize Serialization function for the
+ * @param {grpc~serialize} serialize Serialization function for the
* response
- * @param {Metadata=} metadata Optional trailing metadata to send with status
- * @param {number=} flags Flags for modifying how the message is sent.
- * Defaults to 0.
+ * @param {grpc.Metadata=} metadata Optional trailing metadata to send with
+ * status
+ * @param {number=} [flags=0] Flags for modifying how the message is sent.
*/
function sendUnaryResponse(call, value, serialize, metadata, flags) {
var end_batch = {};
@@ -146,7 +130,7 @@ function sendUnaryResponse(call, value, serialize, metadata, flags) {
/**
* Initialize a writable stream. This is used for both the writable and duplex
* stream constructors.
- * @access private
+ * @private
* @param {Writable} stream The stream to set up
* @param {function(*):Buffer=} Serialization function for responses
*/
@@ -225,9 +209,9 @@ function setUpWritable(stream, serialize) {
/**
* Initialize a readable stream. This is used for both the readable and duplex
* stream constructors.
- * @access private
+ * @private
* @param {Readable} stream The stream to initialize
- * @param {function(Buffer):*=} deserialize Deserialization function for
+ * @param {grpc~deserialize} deserialize Deserialization function for
* incoming data.
*/
function setUpReadable(stream, deserialize) {
@@ -245,34 +229,88 @@ function setUpReadable(stream, deserialize) {
});
}
+/**
+ * Emitted when the call has been cancelled. After this has been emitted, the
+ * call's `cancelled` property will be set to `true`.
+ * @event grpc~ServerUnaryCall~cancelled
+ */
+
util.inherits(ServerUnaryCall, EventEmitter);
-function ServerUnaryCall(call) {
+/**
+ * An EventEmitter. Used for unary calls.
+ * @constructor grpc~ServerUnaryCall
+ * @extends external:EventEmitter
+ * @param {grpc.internal~Call} call The call object associated with the request
+ * @param {grpc.Metadata} metadata The request metadata from the client
+ */
+function ServerUnaryCall(call, metadata) {
EventEmitter.call(this);
this.call = call;
+ /**
+ * Indicates if the call has been cancelled
+ * @member {boolean} grpc~ServerUnaryCall#cancelled
+ */
+ this.cancelled = false;
+ /**
+ * The request metadata from the client
+ * @member {grpc.Metadata} grpc~ServerUnaryCall#metadata
+ */
+ this.metadata = metadata;
+ /**
+ * The request message from the client
+ * @member {*} grpc~ServerUnaryCall#request
+ */
+ this.request = undefined;
}
+/**
+ * Emitted when the call has been cancelled. After this has been emitted, the
+ * call's `cancelled` property will be set to `true`.
+ * @event grpc~ServerWritableStream~cancelled
+ */
+
util.inherits(ServerWritableStream, Writable);
/**
* A stream that the server can write to. Used for calls that are streaming from
* the server side.
- * @constructor
- * @param {grpc.Call} call The call object to send data with
- * @param {function(*):Buffer=} serialize Serialization function for writes
+ * @constructor grpc~ServerWritableStream
+ * @extends external:Writable
+ * @borrows grpc~ServerUnaryCall#sendMetadata as
+ * grpc~ServerWritableStream#sendMetadata
+ * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerWritableStream#getPeer
+ * @param {grpc.internal~Call} call The call object to send data with
+ * @param {grpc.Metadata} metadata The request metadata from the client
+ * @param {grpc~serialize} serialize Serialization function for writes
*/
-function ServerWritableStream(call, serialize) {
+function ServerWritableStream(call, metadata, serialize) {
Writable.call(this, {objectMode: true});
this.call = call;
this.finished = false;
setUpWritable(this, serialize);
+ /**
+ * Indicates if the call has been cancelled
+ * @member {boolean} grpc~ServerWritableStream#cancelled
+ */
+ this.cancelled = false;
+ /**
+ * The request metadata from the client
+ * @member {grpc.Metadata} grpc~ServerWritableStream#metadata
+ */
+ this.metadata = metadata;
+ /**
+ * The request message from the client
+ * @member {*} grpc~ServerWritableStream#request
+ */
+ this.request = undefined;
}
/**
* Start writing a chunk of data. This is an implementation of a method required
* for implementing stream.Writable.
- * @access private
+ * @private
* @param {Buffer} chunk The chunk of data to write
* @param {string} encoding Used to pass write flags
* @param {function(Error=)} callback Callback to indicate that the write is
@@ -312,19 +350,40 @@ function _write(chunk, encoding, callback) {
ServerWritableStream.prototype._write = _write;
+/**
+ * Emitted when the call has been cancelled. After this has been emitted, the
+ * call's `cancelled` property will be set to `true`.
+ * @event grpc~ServerReadableStream~cancelled
+ */
+
util.inherits(ServerReadableStream, Readable);
/**
* A stream that the server can read from. Used for calls that are streaming
* from the client side.
- * @constructor
- * @param {grpc.Call} call The call object to read data with
- * @param {function(Buffer):*=} deserialize Deserialization function for reads
+ * @constructor grpc~ServerReadableStream
+ * @extends external:Readable
+ * @borrows grpc~ServerUnaryCall#sendMetadata as
+ * grpc~ServerReadableStream#sendMetadata
+ * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerReadableStream#getPeer
+ * @param {grpc.internal~Call} call The call object to read data with
+ * @param {grpc.Metadata} metadata The request metadata from the client
+ * @param {grpc~deserialize} deserialize Deserialization function for reads
*/
-function ServerReadableStream(call, deserialize) {
+function ServerReadableStream(call, metadata, deserialize) {
Readable.call(this, {objectMode: true});
this.call = call;
setUpReadable(this, deserialize);
+ /**
+ * Indicates if the call has been cancelled
+ * @member {boolean} grpc~ServerReadableStream#cancelled
+ */
+ this.cancelled = false;
+ /**
+ * The request metadata from the client
+ * @member {grpc.Metadata} grpc~ServerReadableStream#metadata
+ */
+ this.metadata = metadata;
}
/**
@@ -381,22 +440,43 @@ function _read(size) {
ServerReadableStream.prototype._read = _read;
+/**
+ * Emitted when the call has been cancelled. After this has been emitted, the
+ * call's `cancelled` property will be set to `true`.
+ * @event grpc~ServerDuplexStream~cancelled
+ */
+
util.inherits(ServerDuplexStream, Duplex);
/**
* A stream that the server can read from or write to. Used for calls with
* duplex streaming.
- * @constructor
- * @param {grpc.Call} call Call object to proxy
- * @param {function(*):Buffer=} serialize Serialization function for requests
- * @param {function(Buffer):*=} deserialize Deserialization function for
+ * @constructor grpc~ServerDuplexStream
+ * @extends external:Duplex
+ * @borrows grpc~ServerUnaryCall#sendMetadata as
+ * grpc~ServerDuplexStream#sendMetadata
+ * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerDuplexStream#getPeer
+ * @param {grpc.internal~Call} call Call object to proxy
+ * @param {grpc.Metadata} metadata The request metadata from the client
+ * @param {grpc~serialize} serialize Serialization function for requests
+ * @param {grpc~deserialize} deserialize Deserialization function for
* responses
*/
-function ServerDuplexStream(call, serialize, deserialize) {
+function ServerDuplexStream(call, metadata, serialize, deserialize) {
Duplex.call(this, {objectMode: true});
this.call = call;
setUpWritable(this, serialize);
setUpReadable(this, deserialize);
+ /**
+ * Indicates if the call has been cancelled
+ * @member {boolean} grpc~ServerReadableStream#cancelled
+ */
+ this.cancelled = false;
+ /**
+ * The request metadata from the client
+ * @member {grpc.Metadata} grpc~ServerReadableStream#metadata
+ */
+ this.metadata = metadata;
}
ServerDuplexStream.prototype._read = _read;
@@ -404,6 +484,7 @@ ServerDuplexStream.prototype._write = _write;
/**
* Send the initial metadata for a writable stream.
+ * @alias grpc~ServerUnaryCall#sendMetadata
* @param {Metadata} responseMetadata Metadata to send
*/
function sendMetadata(responseMetadata) {
@@ -430,6 +511,7 @@ ServerDuplexStream.prototype.sendMetadata = sendMetadata;
/**
* Get the endpoint this call/stream is connected to.
+ * @alias grpc~ServerUnaryCall#getPeer
* @return {string} The URI of the endpoint
*/
function getPeer() {
@@ -445,6 +527,7 @@ ServerDuplexStream.prototype.getPeer = getPeer;
/**
* Wait for the client to close, then emit a cancelled event if the client
* cancelled.
+ * @private
*/
function waitForCancel() {
/* jshint validthis: true */
@@ -468,18 +551,41 @@ ServerWritableStream.prototype.waitForCancel = waitForCancel;
ServerDuplexStream.prototype.waitForCancel = waitForCancel;
/**
+ * Callback function passed to server handlers that handle methods with unary
+ * responses.
+ * @callback grpc.Server~sendUnaryData
+ * @param {grpc~ServiceError} error An error, if the call failed
+ * @param {*} value The response value. Must be a valid argument to the
+ * `responseSerialize` method of the method that is being handled
+ * @param {grpc.Metadata=} trailer Trailing metadata to send, if applicable
+ * @param {grpc.writeFlags=} flags Flags to modify writing the response
+ */
+
+/**
+ * User-provided method to handle unary requests on a server
+ * @callback grpc.Server~handleUnaryCall
+ * @param {grpc~ServerUnaryCall} call The call object
+ * @param {grpc.Server~sendUnaryData} callback The callback to call to respond
+ * to the request
+ */
+
+/**
* Fully handle a unary call
- * @access private
- * @param {grpc.Call} call The call to handle
+ * @private
+ * @param {grpc.internal~Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Metadata} metadata Metadata from the client
+ * @param {grpc~Server.handleUnaryCall} handler.func The handler function
+ * @param {grpc~deserialize} handler.deserialize The deserialization function
+ * for request data
+ * @param {grpc~serialize} handler.serialize The serialization function for
+ * response data
+ * @param {grpc.Metadata} metadata Metadata from the client
*/
function handleUnary(call, handler, metadata) {
- var emitter = new ServerUnaryCall(call);
+ var emitter = new ServerUnaryCall(call, metadata);
emitter.on('error', function(error) {
handleError(call, error);
});
- emitter.metadata = metadata;
emitter.waitForCancel();
var batch = {};
batch[grpc.opType.RECV_MESSAGE] = true;
@@ -512,16 +618,27 @@ function handleUnary(call, handler, metadata) {
}
/**
+ * User provided method to handle server streaming methods on the server.
+ * @callback grpc.Server~handleServerStreamingCall
+ * @param {grpc~ServerWritableStream} call The call object
+ */
+
+/**
* Fully handle a server streaming call
- * @access private
- * @param {grpc.Call} call The call to handle
+ * @private
+ * @param {grpc.internal~Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Metadata} metadata Metadata from the client
+ * @param {grpc~Server.handleServerStreamingCall} handler.func The handler
+ * function
+ * @param {grpc~deserialize} handler.deserialize The deserialization function
+ * for request data
+ * @param {grpc~serialize} handler.serialize The serialization function for
+ * response data
+ * @param {grpc.Metadata} metadata Metadata from the client
*/
function handleServerStreaming(call, handler, metadata) {
- var stream = new ServerWritableStream(call, handler.serialize);
+ var stream = new ServerWritableStream(call, metadata, handler.serialize);
stream.waitForCancel();
- stream.metadata = metadata;
var batch = {};
batch[grpc.opType.RECV_MESSAGE] = true;
call.startBatch(batch, function(err, result) {
@@ -541,19 +658,32 @@ function handleServerStreaming(call, handler, metadata) {
}
/**
+ * User provided method to handle client streaming methods on the server.
+ * @callback grpc.Server~handleClientStreamingCall
+ * @param {grpc~ServerReadableStream} call The call object
+ * @param {grpc.Server~sendUnaryData} callback The callback to call to respond
+ * to the request
+ */
+
+/**
* Fully handle a client streaming call
* @access private
- * @param {grpc.Call} call The call to handle
+ * @param {grpc.internal~Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
- * @param {Metadata} metadata Metadata from the client
+ * @param {grpc~Server.handleClientStreamingCall} handler.func The handler
+ * function
+ * @param {grpc~deserialize} handler.deserialize The deserialization function
+ * for request data
+ * @param {grpc~serialize} handler.serialize The serialization function for
+ * response data
+ * @param {grpc.Metadata} metadata Metadata from the client
*/
function handleClientStreaming(call, handler, metadata) {
- var stream = new ServerReadableStream(call, handler.deserialize);
+ var stream = new ServerReadableStream(call, metadata, handler.deserialize);
stream.on('error', function(error) {
handleError(call, error);
});
stream.waitForCancel();
- stream.metadata = metadata;
handler.func(stream, function(err, value, trailer, flags) {
stream.terminate();
if (err) {
@@ -568,17 +698,28 @@ function handleClientStreaming(call, handler, metadata) {
}
/**
+ * User provided method to handle bidirectional streaming calls on the server.
+ * @callback grpc.Server~handleBidiStreamingCall
+ * @param {grpc~ServerDuplexStream} call The call object
+ */
+
+/**
* Fully handle a bidirectional streaming call
- * @access private
- * @param {grpc.Call} call The call to handle
+ * @private
+ * @param {grpc.internal~Call} call The call to handle
* @param {Object} handler Request handler object for the method that was called
+ * @param {grpc~Server.handleBidiStreamingCall} handler.func The handler
+ * function
+ * @param {grpc~deserialize} handler.deserialize The deserialization function
+ * for request data
+ * @param {grpc~serialize} handler.serialize The serialization function for
+ * response data
* @param {Metadata} metadata Metadata from the client
*/
function handleBidiStreaming(call, handler, metadata) {
- var stream = new ServerDuplexStream(call, handler.serialize,
+ var stream = new ServerDuplexStream(call, metadata, handler.serialize,
handler.deserialize);
stream.waitForCancel();
- stream.metadata = metadata;
handler.func(stream);
}
@@ -592,96 +733,90 @@ var streamHandlers = {
/**
* Constructs a server object that stores request handlers and delegates
* incoming requests to those handlers
+ * @memberof grpc
* @constructor
* @param {Object=} options Options that should be passed to the internal server
* implementation
+ * @example
+ * var server = new grpc.Server();
+ * server.addProtoService(protobuf_service_descriptor, service_implementation);
+ * server.bind('address:port', server_credential);
+ * server.start();
*/
function Server(options) {
this.handlers = {};
- var handlers = this.handlers;
var server = new grpc.Server(options);
this._server = server;
this.started = false;
+}
+
+/**
+ * Start the server and begin handling requests
+ */
+Server.prototype.start = function() {
+ if (this.started) {
+ throw new Error('Server is already running');
+ }
+ var self = this;
+ this.started = true;
+ this._server.start();
/**
- * Start the server and begin handling requests
- * @this Server
+ * Handles the SERVER_RPC_NEW event. If there is a handler associated with
+ * the requested method, use that handler to respond to the request. Then
+ * wait for the next request
+ * @param {grpc.internal~Event} event The event to handle with tag
+ * SERVER_RPC_NEW
*/
- this.start = function() {
- if (this.started) {
- throw new Error('Server is already running');
+ function handleNewCall(err, event) {
+ if (err) {
+ return;
}
- this.started = true;
- server.start();
- /**
- * Handles the SERVER_RPC_NEW event. If there is a handler associated with
- * the requested method, use that handler to respond to the request. Then
- * wait for the next request
- * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
- */
- function handleNewCall(err, event) {
- if (err) {
- return;
- }
- var details = event.new_call;
- var call = details.call;
- var method = details.method;
- var metadata = Metadata._fromCoreRepresentation(details.metadata);
- if (method === null) {
- return;
- }
- server.requestCall(handleNewCall);
- var handler;
- if (handlers.hasOwnProperty(method)) {
- handler = handlers[method];
- } else {
- var batch = {};
- batch[grpc.opType.SEND_INITIAL_METADATA] =
- (new Metadata())._getCoreRepresentation();
- batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
- code: constants.status.UNIMPLEMENTED,
- details: '',
- metadata: {}
- };
- batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
- call.startBatch(batch, function() {});
- return;
- }
- streamHandlers[handler.type](call, handler, metadata);
+ var details = event.new_call;
+ var call = details.call;
+ var method = details.method;
+ var metadata = Metadata._fromCoreRepresentation(details.metadata);
+ if (method === null) {
+ return;
}
- server.requestCall(handleNewCall);
- };
-
- /**
- * Gracefully shuts down the server. The server will stop receiving new calls,
- * and any pending calls will complete. The callback will be called when all
- * pending calls have completed and the server is fully shut down. This method
- * is idempotent with itself and forceShutdown.
- * @param {function()} callback The shutdown complete callback
- */
- this.tryShutdown = function(callback) {
- server.tryShutdown(callback);
- };
+ self._server.requestCall(handleNewCall);
+ var handler;
+ if (self.handlers.hasOwnProperty(method)) {
+ handler = self.handlers[method];
+ } else {
+ var batch = {};
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
+ batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
+ code: constants.status.UNIMPLEMENTED,
+ details: '',
+ metadata: {}
+ };
+ batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
+ call.startBatch(batch, function() {});
+ return;
+ }
+ streamHandlers[handler.type](call, handler, metadata);
+ }
+ this._server.requestCall(handleNewCall);
+};
- /**
- * Forcibly shuts down the server. The server will stop receiving new calls
- * and cancel all pending calls. When it returns, the server has shut down.
- * This method is idempotent with itself and tryShutdown, and it will trigger
- * any outstanding tryShutdown callbacks.
- */
- this.forceShutdown = function() {
- server.forceShutdown();
- };
-}
+/**
+ * Unified type for application handlers for all types of calls
+ * @typedef {(grpc.Server~handleUnaryCall
+ * |grpc.Server~handleClientStreamingCall
+ * |grpc.Server~handleServerStreamingCall
+ * |grpc.Server~handleBidiStreamingCall)} grpc.Server~handleCall
+ */
/**
* Registers a handler to handle the named method. Fails if there already is
* a handler for the given method. Returns true on success
* @param {string} name The name of the method that the provided function should
* handle/respond to.
- * @param {function} handler Function that takes a stream of request values and
- * returns a stream of response values
- * @param {function(*):Buffer} serialize Serialization function for responses
- * @param {function(Buffer):*} deserialize Deserialization function for requests
+ * @param {grpc.Server~handleCall} handler Function that takes a stream of
+ * request values and returns a stream of response values
+ * @param {grpc~serialize} serialize Serialization function for responses
+ * @param {grpc~deserialize} deserialize Deserialization function for requests
* @param {string} type The streaming type of method that this handles
* @return {boolean} True if the handler was set. False if a handler was already
* set for that name.
@@ -700,6 +835,27 @@ Server.prototype.register = function(name, handler, serialize, deserialize,
return true;
};
+/**
+ * Gracefully shuts down the server. The server will stop receiving new calls,
+ * and any pending calls will complete. The callback will be called when all
+ * pending calls have completed and the server is fully shut down. This method
+ * is idempotent with itself and forceShutdown.
+ * @param {function()} callback The shutdown complete callback
+ */
+Server.prototype.tryShutdown = function(callback) {
+ this._server.tryShutdown(callback);
+};
+
+/**
+ * Forcibly shuts down the server. The server will stop receiving new calls
+ * and cancel all pending calls. When it returns, the server has shut down.
+ * This method is idempotent with itself and tryShutdown, and it will trigger
+ * any outstanding tryShutdown callbacks.
+ */
+Server.prototype.forceShutdown = function() {
+ this._server.forceShutdown();
+};
+
var unimplementedStatusResponse = {
code: constants.status.UNIMPLEMENTED,
details: 'The server does not implement this method'
@@ -721,13 +877,10 @@ var defaultHandler = {
};
/**
- * Add a service to the server, with a corresponding implementation. If you are
- * generating this from a proto file, you should instead use
- * addProtoService.
- * @param {Object<String, *>} service The service descriptor, as
- * {@link module:src/common.getProtobufServiceAttrs} returns
- * @param {Object<String, function>} implementation Map of method names to
- * method implementation for the provided service.
+ * Add a service to the server, with a corresponding implementation.
+ * @param {grpc~ServiceDefinition} service The service descriptor
+ * @param {Object<String, grpc.Server~handleCall>} implementation Map of method
+ * names to method implementation for the provided service.
*/
Server.prototype.addService = function(service, implementation) {
if (!_.isObject(service) || !_.isObject(implementation)) {
@@ -788,10 +941,10 @@ var logAddProtoServiceDeprecationOnce = _.once(function() {
/**
* Add a proto service to the server, with a corresponding implementation
- * @deprecated Use grpc.load and Server#addService instead
+ * @deprecated Use {@link grpc.Server#addService} instead
* @param {Protobuf.Reflect.Service} service The proto service descriptor
- * @param {Object<String, function>} implementation Map of method names to
- * method implementation for the provided service.
+ * @param {Object<String, grpc.Server~handleCall>} implementation Map of method
+ * names to method implementation for the provided service.
*/
Server.prototype.addProtoService = function(service, implementation) {
var options;
@@ -815,10 +968,11 @@ Server.prototype.addProtoService = function(service, implementation) {
};
/**
- * Binds the server to the given port, with SSL enabled if creds is given
+ * Binds the server to the given port, with SSL disabled if creds is an
+ * insecure credentials object
* @param {string} port The port that the server should bind on, in the format
* "address:port"
- * @param {ServerCredentials=} creds Server credential object to be used for
+ * @param {grpc.ServerCredentials} creds Server credential object to be used for
* SSL. Pass an insecure credentials object for an insecure port.
*/
Server.prototype.bind = function(port, creds) {
@@ -828,7 +982,4 @@ Server.prototype.bind = function(port, creds) {
return this._server.addHttp2Port(port, creds);
};
-/**
- * @see module:src/server~Server
- */
exports.Server = Server;
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index d2f0511af2..6f1c269267 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -1322,14 +1322,14 @@ describe('Cancelling surface client', function() {
});
it('Should correctly cancel a unary call', function(done) {
var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) {
- assert.strictEqual(err.code, surface_client.status.CANCELLED);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
done();
});
call.cancel();
});
it('Should correctly cancel a client stream call', function(done) {
var call = client.sum(function(err, resp) {
- assert.strictEqual(err.code, surface_client.status.CANCELLED);
+ assert.strictEqual(err.code, grpc.status.CANCELLED);
done();
});
call.cancel();
@@ -1338,7 +1338,7 @@ describe('Cancelling surface client', function() {
var call = client.fib({'limit': 5});
call.on('data', function() {});
call.on('error', function(error) {
- assert.strictEqual(error.code, surface_client.status.CANCELLED);
+ assert.strictEqual(error.code, grpc.status.CANCELLED);
done();
});
call.cancel();
@@ -1347,7 +1347,7 @@ describe('Cancelling surface client', function() {
var call = client.divMany();
call.on('data', function() {});
call.on('error', function(error) {
- assert.strictEqual(error.code, surface_client.status.CANCELLED);
+ assert.strictEqual(error.code, grpc.status.CANCELLED);
done();
});
call.cancel();
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 9770301d09..5f8075467d 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -313,6 +313,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/census/grpc_filter.c',
'src/core/ext/census/grpc_plugin.c',
'src/core/ext/census/initialize.c',
+ 'src/core/ext/census/intrusive_hash_map.c',
'src/core/ext/census/mlog.c',
'src/core/ext/census/operation.c',
'src/core/ext/census/placeholders.c',
diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
index cd896f32c3..0f399f8f8d 100644
--- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
+++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
@@ -152,4 +152,4 @@ def enable_server_reflection(service_names, server, pool=None):
pool: DescriptorPool object to use (descriptor_pool.Default() if None).
"""
reflection_pb2_grpc.add_ServerReflectionServicer_to_server(
- ReflectionServicer(service_names), server, pool)
+ ReflectionServicer(service_names, pool), server)
diff --git a/templates/README.md b/templates/README.md
index eedc6e9c09..7b7707203f 100644
--- a/templates/README.md
+++ b/templates/README.md
@@ -1,3 +1,12 @@
+# Regenerating project files
+
+Prerequisites: `python`, `pip install mako`
+
+```
+# Regenerate the projects files using templates
+tools/buildgen/generate_projects.sh
+```
+
# Quick justification
We've approached the problem of the build system from a lot of different
diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c
new file mode 100644
index 0000000000..fe8d3a1675
--- /dev/null
+++ b/test/core/census/intrusive_hash_map_test.c
@@ -0,0 +1,299 @@
+/*
+ *
+ * Copyright 2017, 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/intrusive_hash_map.h"
+
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* The initial size of an intrusive hash map will be 2 to this power. */
+static const uint32_t kInitialLog2Size = 4;
+
+/* Simple object used for testing intrusive_hash_map. */
+typedef struct object { uint64_t val; } object;
+
+/* Helper function to allocate and initialize object. */
+static inline object *make_new_object(uint64_t val) {
+ object *obj = (object *)gpr_malloc(sizeof(object));
+ obj->val = val;
+ return obj;
+}
+
+/* Wrapper struct for object. */
+typedef struct ptr_item {
+ INTRUSIVE_HASH_MAP_HEADER;
+ object *obj;
+} ptr_item;
+
+/* Helper function that creates a new hash map item. It is up to the user to
+ * free the item that was allocated. */
+static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) {
+ ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item));
+ new_item->IHM_key = key;
+ new_item->IHM_hash_link = NULL;
+ new_item->obj = make_new_object(value);
+ return new_item;
+}
+
+/* Helper function to deallocate ptr_item. */
+static void free_ptr_item(void *ptr) { gpr_free(((ptr_item *)ptr)->obj); }
+
+/* Simple string object used for testing intrusive_hash_map. */
+typedef struct string_item {
+ INTRUSIVE_HASH_MAP_HEADER;
+ // User data.
+ char buf[32];
+ uint16_t len;
+} string_item;
+
+/* Helper function to allocate and initialize string object. */
+static string_item *make_string_item(uint64_t key, const char *buf,
+ uint16_t len) {
+ string_item *item = (string_item *)gpr_malloc(sizeof(string_item));
+ item->IHM_key = key;
+ item->IHM_hash_link = NULL;
+ item->len = len;
+ memcpy(item->buf, buf, sizeof(char) * len);
+ return item;
+}
+
+/* Helper function for comparing two string objects. */
+static bool compare_string_item(const string_item *A, const string_item *B) {
+ if (A->IHM_key != B->IHM_key || A->len != B->len)
+ return false;
+ else {
+ for (int i = 0; i < A->len; ++i) {
+ if (A->buf[i] != B->buf[i]) return false;
+ }
+ }
+
+ return true;
+}
+
+void test_empty() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+ GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map));
+ GPR_ASSERT(intrusive_hash_map_empty(&hash_map));
+ intrusive_hash_map_free(&hash_map, NULL);
+}
+
+void test_single_item() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+
+ ptr_item *new_item = make_ptr_item(10, 20);
+ bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item);
+ GPR_ASSERT(ok);
+
+ ptr_item *item1 =
+ (ptr_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10);
+ GPR_ASSERT(item1->obj->val == 20);
+ GPR_ASSERT(item1 == new_item);
+
+ ptr_item *item2 =
+ (ptr_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10);
+ GPR_ASSERT(item2 == new_item);
+
+ gpr_free(new_item->obj);
+ gpr_free(new_item);
+ GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map));
+ intrusive_hash_map_free(&hash_map, &free_ptr_item);
+}
+
+void test_two_items() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+
+ string_item *new_item1 = make_string_item(10, "test1", 5);
+ bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1);
+ GPR_ASSERT(ok);
+ string_item *new_item2 = make_string_item(20, "test2", 5);
+ ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item2);
+ GPR_ASSERT(ok);
+
+ string_item *item1 =
+ (string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10);
+ GPR_ASSERT(compare_string_item(new_item1, item1));
+ GPR_ASSERT(item1 == new_item1);
+ string_item *item2 =
+ (string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)20);
+ GPR_ASSERT(compare_string_item(new_item2, item2));
+ GPR_ASSERT(item2 == new_item2);
+
+ item1 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10);
+ GPR_ASSERT(item1 == new_item1);
+ item2 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)20);
+ GPR_ASSERT(item2 == new_item2);
+
+ gpr_free(new_item1);
+ gpr_free(new_item2);
+ GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map));
+ intrusive_hash_map_free(&hash_map, NULL);
+}
+
+// Test resetting and clearing the hash map.
+void test_reset_clear() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+
+ // Add some data to the hash_map.
+ for (uint64_t i = 0; i < 3; ++i) {
+ intrusive_hash_map_insert(&hash_map, (hm_item *)make_ptr_item(i, i));
+ }
+ GPR_ASSERT(3 == intrusive_hash_map_size(&hash_map));
+
+ // Test find.
+ for (uint64_t i = 0; i < 3; ++i) {
+ ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i);
+ GPR_ASSERT(item != NULL);
+ GPR_ASSERT(item->IHM_key == i && item->obj->val == i);
+ }
+
+ intrusive_hash_map_clear(&hash_map, &free_ptr_item);
+ GPR_ASSERT(intrusive_hash_map_empty(&hash_map));
+ intrusive_hash_map_free(&hash_map, &free_ptr_item);
+}
+
+// Check that the hash_map contains every key between [min_value, max_value]
+// (inclusive).
+void check_hash_map_values(intrusive_hash_map *hash_map, uint64_t min_value,
+ uint64_t max_value) {
+ GPR_ASSERT(intrusive_hash_map_size(hash_map) == max_value - min_value + 1);
+
+ for (uint64_t i = min_value; i <= max_value; ++i) {
+ ptr_item *item = (ptr_item *)intrusive_hash_map_find(hash_map, i);
+ GPR_ASSERT(item != NULL);
+ GPR_ASSERT(item->obj->val == i);
+ }
+}
+
+// Add many items and cause the hash_map to extend.
+void test_extend() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+
+ const uint64_t kNumValues = (1 << 16);
+
+ for (uint64_t i = 0; i < kNumValues; ++i) {
+ ptr_item *item = make_ptr_item(i, i);
+ bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item);
+ GPR_ASSERT(ok);
+ if (i % 1000 == 0) {
+ check_hash_map_values(&hash_map, 0, i);
+ }
+ }
+
+ for (uint64_t i = 0; i < kNumValues; ++i) {
+ ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i);
+ GPR_ASSERT(item != NULL);
+ GPR_ASSERT(item->IHM_key == i && item->obj->val == i);
+ ptr_item *item2 = (ptr_item *)intrusive_hash_map_erase(&hash_map, i);
+ GPR_ASSERT(item == item2);
+ gpr_free(item->obj);
+ gpr_free(item);
+ }
+
+ GPR_ASSERT(intrusive_hash_map_empty(&hash_map));
+ intrusive_hash_map_free(&hash_map, &free_ptr_item);
+}
+
+void test_stress() {
+ intrusive_hash_map hash_map;
+ intrusive_hash_map_init(&hash_map, kInitialLog2Size);
+ size_t n = 0;
+
+ // Randomly add and insert entries 1000000 times.
+ for (uint64_t i = 0; i < 1000000; ++i) {
+ int op = rand() & 0x1;
+
+ switch (op) {
+ // Case 0 is insertion of entry.
+ case 0: {
+ uint64_t key = (uint64_t)(rand() % 10000);
+ ptr_item *item = make_ptr_item(key, key);
+ bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item);
+ if (ok) {
+ n++;
+ } else {
+ gpr_free(item->obj);
+ gpr_free(item);
+ }
+ break;
+ }
+ // Case 1 is removal of entry.
+ case 1: {
+ uint64_t key = (uint64_t)(rand() % 10000);
+ ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, key);
+ if (item != NULL) {
+ n--;
+ GPR_ASSERT(key == item->obj->val);
+ ptr_item *item2 =
+ (ptr_item *)intrusive_hash_map_erase(&hash_map, key);
+ GPR_ASSERT(item == item2);
+ gpr_free(item->obj);
+ gpr_free(item);
+ }
+ break;
+ }
+ }
+ }
+ // Check size
+ GPR_ASSERT(n == intrusive_hash_map_size(&hash_map));
+
+ // Clean the hash_map up.
+ intrusive_hash_map_clear(&hash_map, &free_ptr_item);
+ GPR_ASSERT(intrusive_hash_map_empty(&hash_map));
+ intrusive_hash_map_free(&hash_map, &free_ptr_item);
+}
+
+int main(int argc, char **argv) {
+ grpc_test_init(argc, argv);
+ gpr_time_init();
+ srand((unsigned)gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
+
+ test_empty();
+ test_single_item();
+ test_two_items();
+ test_reset_clear();
+ test_extend();
+ test_stress();
+
+ return 0;
+}
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index eb0883b797..15410dec01 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -883,6 +883,9 @@ src/core/ext/census/grpc_filter.c \
src/core/ext/census/grpc_filter.h \
src/core/ext/census/grpc_plugin.c \
src/core/ext/census/initialize.c \
+src/core/ext/census/intrusive_hash_map.c \
+src/core/ext/census/intrusive_hash_map.h \
+src/core/ext/census/intrusive_hash_map_internal.h \
src/core/ext/census/mlog.c \
src/core/ext/census/mlog.h \
src/core/ext/census/operation.c \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index ec2836ec42..97e079d8a8 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -191,6 +191,23 @@
"headers": [],
"is_filegroup": false,
"language": "c",
+ "name": "census_intrusive_hash_map_test",
+ "src": [
+ "test/core/census/intrusive_hash_map_test.c"
+ ],
+ "third_party": false,
+ "type": "target"
+ },
+ {
+ "deps": [
+ "gpr",
+ "gpr_test_util",
+ "grpc",
+ "grpc_test_util"
+ ],
+ "headers": [],
+ "is_filegroup": false,
+ "language": "c",
"name": "census_resource_test",
"src": [
"test/core/census/resource_test.c"
@@ -7541,6 +7558,8 @@
"src/core/ext/census/gen/census.pb.h",
"src/core/ext/census/gen/trace_context.pb.h",
"src/core/ext/census/grpc_filter.h",
+ "src/core/ext/census/intrusive_hash_map.h",
+ "src/core/ext/census/intrusive_hash_map_internal.h",
"src/core/ext/census/mlog.h",
"src/core/ext/census/resource.h",
"src/core/ext/census/rpc_metric_id.h",
@@ -7571,6 +7590,9 @@
"src/core/ext/census/grpc_filter.h",
"src/core/ext/census/grpc_plugin.c",
"src/core/ext/census/initialize.c",
+ "src/core/ext/census/intrusive_hash_map.c",
+ "src/core/ext/census/intrusive_hash_map.h",
+ "src/core/ext/census/intrusive_hash_map_internal.h",
"src/core/ext/census/mlog.c",
"src/core/ext/census/mlog.h",
"src/core/ext/census/operation.c",
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index d1e3a99a08..82db441a1a 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -237,6 +237,28 @@
"flaky": false,
"gtest": false,
"language": "c",
+ "name": "census_intrusive_hash_map_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ]
+ },
+ {
+ "args": [],
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": false,
+ "language": "c",
"name": "census_resource_test",
"platforms": [
"linux",
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 3754035308..3ff773300f 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -41,6 +41,7 @@ import subprocess
import sys
import tempfile
import time
+import errno
# cpu cost measurement
@@ -132,29 +133,44 @@ _TAG_COLOR = {
_FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(level=logging.INFO, format=_FORMAT)
+
+def eintr_be_gone(fn):
+ """Run fn until it doesn't stop because of EINTR"""
+ while True:
+ try:
+ return fn()
+ except IOError, e:
+ if e.errno != errno.EINTR:
+ raise
+
+
+
def message(tag, msg, explanatory_text=None, do_newline=False):
if message.old_tag == tag and message.old_msg == msg and not explanatory_text:
return
message.old_tag = tag
message.old_msg = msg
- try:
- if platform_string() == 'windows' or not sys.stdout.isatty():
- if explanatory_text:
- logging.info(explanatory_text)
- logging.info('%s: %s', tag, msg)
- else:
- sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % (
- _BEGINNING_OF_LINE,
- _CLEAR_LINE,
- '\n%s' % explanatory_text if explanatory_text is not None else '',
- _COLORS[_TAG_COLOR[tag]][1],
- _COLORS[_TAG_COLOR[tag]][0],
- tag,
- msg,
- '\n' if do_newline or explanatory_text is not None else ''))
- sys.stdout.flush()
- except:
- pass
+ while True:
+ try:
+ if platform_string() == 'windows' or not sys.stdout.isatty():
+ if explanatory_text:
+ logging.info(explanatory_text)
+ logging.info('%s: %s', tag, msg)
+ else:
+ sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % (
+ _BEGINNING_OF_LINE,
+ _CLEAR_LINE,
+ '\n%s' % explanatory_text if explanatory_text is not None else '',
+ _COLORS[_TAG_COLOR[tag]][1],
+ _COLORS[_TAG_COLOR[tag]][0],
+ tag,
+ msg,
+ '\n' if do_newline or explanatory_text is not None else ''))
+ sys.stdout.flush()
+ return
+ except IOError, e:
+ if e.errno != errno.EINTR:
+ raise
message.old_tag = ''
message.old_msg = ''
@@ -226,16 +242,6 @@ class JobResult(object):
self.cpu_measured = 0
-def eintr_be_gone(fn):
- """Run fn until it doesn't stop because of EINTR"""
- while True:
- try:
- return fn()
- except IOError, e:
- if e.errno != errno.EINTR:
- raise
-
-
def read_from_start(f):
f.seek(0)
return f.read()
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 97a75e7762..284dd68c16 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -129,6 +129,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_context_test", "vcxp
{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_intrusive_hash_map_test", "vcxproj\test\census_intrusive_hash_map_test\census_intrusive_hash_map_test.vcxproj", "{BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}"
+ ProjectSection(myProperties) = preProject
+ lib = "False"
+ EndProjectSection
+ ProjectSection(ProjectDependencies) = postProject
+ {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+ {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+ {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+ {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+ EndProjectSection
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_resource_test", "vcxproj\test\census_resource_test\census_resource_test.vcxproj", "{18CF99B5-3C61-EC3D-9509-3C95334C3B88}"
ProjectSection(myProperties) = preProject
lib = "False"
@@ -1899,6 +1910,22 @@ Global
{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|Win32.Build.0 = Release|Win32
{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.ActiveCfg = Release|x64
{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.Build.0 = Release|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|x64.ActiveCfg = Debug|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|Win32.ActiveCfg = Release|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|x64.ActiveCfg = Release|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|Win32.Build.0 = Debug|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug|x64.Build.0 = Debug|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|Win32.Build.0 = Release|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release|x64.Build.0 = Release|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|Win32.Build.0 = Debug|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|x64.ActiveCfg = Debug|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Debug-DLL|x64.Build.0 = Debug|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|Win32.ActiveCfg = Release|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|Win32.Build.0 = Release|Win32
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|x64.ActiveCfg = Release|x64
+ {BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}.Release-DLL|x64.Build.0 = Release|x64
{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|Win32.ActiveCfg = Debug|Win32
{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|x64.ActiveCfg = Debug|x64
{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 2ccda23694..1303366574 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -504,6 +504,8 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
@@ -993,6 +995,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 3a1c1f9c5a..9f25a1c179 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -712,6 +712,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
<Filter>src\core\ext\census</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
+ <Filter>src\core\ext\census</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
<Filter>src\core\ext\census</Filter>
</ClCompile>
@@ -1454,6 +1457,12 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
<Filter>src\core\ext\census</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h">
+ <Filter>src\core\ext\census</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h">
+ <Filter>src\core\ext\census</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
<Filter>src\core\ext\census</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index d084d70702..ac403a7c48 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -469,6 +469,8 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h" />
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
@@ -900,6 +902,8 @@
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
</ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\operation.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index ba826852a3..9fee2ec22b 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -625,6 +625,9 @@
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\initialize.c">
<Filter>src\core\ext\census</Filter>
</ClCompile>
+ <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.c">
+ <Filter>src\core\ext\census</Filter>
+ </ClCompile>
<ClCompile Include="$(SolutionDir)\..\src\core\ext\census\mlog.c">
<Filter>src\core\ext\census</Filter>
</ClCompile>
@@ -1289,6 +1292,12 @@
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
<Filter>src\core\ext\census</Filter>
</ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map.h">
+ <Filter>src\core\ext\census</Filter>
+ </ClInclude>
+ <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\intrusive_hash_map_internal.h">
+ <Filter>src\core\ext\census</Filter>
+ </ClInclude>
<ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
<Filter>src\core\ext\census</Filter>
</ClInclude>
diff --git a/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj
new file mode 100644
index 0000000000..46ea06b2a0
--- /dev/null
+++ b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}</ProjectGuid>
+ <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+ <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+ <PlatformToolset>v110</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+ <PlatformToolset>v140</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+ <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+ <TargetName>census_intrusive_hash_map_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'">
+ <TargetName>census_intrusive_hash_map_test</TargetName>
+ <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+ <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+ <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+ <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+ <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+ <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\census\intrusive_hash_map_test.c">
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+ <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+ <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+ <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+ </ProjectReference>
+ <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+ <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+ </ImportGroup>
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+ <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+ </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters
new file mode 100644
index 0000000000..2dfa300e97
--- /dev/null
+++ b/vsprojects/vcxproj/test/census_intrusive_hash_map_test/census_intrusive_hash_map_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="$(SolutionDir)\..\test\core\census\intrusive_hash_map_test.c">
+ <Filter>test\core\census</Filter>
+ </ClCompile>
+ </ItemGroup>
+
+ <ItemGroup>
+ <Filter Include="test">
+ <UniqueIdentifier>{24bfacc6-bd89-4cdf-4183-3ff53180fa48}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core">
+ <UniqueIdentifier>{71b1debf-71c7-c1e9-9e01-21330ede0d7f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="test\core\census">
+ <UniqueIdentifier>{0228063a-a601-967e-27ed-9f6197cb3629}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project>
+