LB policy API: add OOB backend metric API (#29012)

* WIP: add OOB backend metric API for LB policies

* fix some includes

* minor fixes

* picking this up again...

* more WIP

* health checking: cancel stream if response message fails to parse

* basic structure in place, but still have synchronization issues to address

* ORCA: implement ORCA RPC service for OOB backend metric reporting

* fix unused parameter error

* gen_upb_api

* add missing build deps

* increase test timing fudge factor

* add missing copyright header

* fix build and locking problems

* clang-format

* document API

* buildifier

* add test, but doesn't build yet

* new test working, but broke existing test, and need to fix server API

* don't register as a generic service

* update test for new orca service registration API

* fix build

* sanitize

* report interval defaults to min interval

* add channel trace event on UNIMPLEMENTED

* don't regenerate the response proto unless something changed

* add missing build dep

* fix comment
pull/29460/head
Mark D. Roth 3 years ago committed by GitHub
parent 2b42b24a94
commit be53d2ce3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      BUILD
  2. 18
      CMakeLists.txt
  3. 4
      Makefile
  4. 39
      build_autogenerated.yaml
  5. 3
      config.m4
  6. 5
      config.w32
  7. 6
      gRPC-C++.podspec
  8. 8
      gRPC-Core.podspec
  9. 5
      grpc.gemspec
  10. 4
      grpc.gyp
  11. 5
      package.xml
  12. 20
      src/core/ext/filters/client_channel/backend_metric.cc
  13. 23
      src/core/ext/filters/client_channel/backend_metric.h
  14. 34
      src/core/ext/filters/client_channel/client_channel.cc
  15. 382
      src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc
  16. 57
      src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h
  17. 23
      src/core/ext/filters/client_channel/subchannel.cc
  18. 31
      src/core/ext/filters/client_channel/subchannel.h
  19. 48
      src/core/ext/filters/client_channel/subchannel_interface.h
  20. 40
      src/core/ext/filters/client_channel/subchannel_interface_internal.h
  21. 2
      src/python/grpcio/grpc_core_dependencies.py
  22. 126
      test/core/util/test_lb_policies.cc
  23. 9
      test/core/util/test_lb_policies.h
  24. 1
      test/cpp/end2end/BUILD
  25. 151
      test/cpp/end2end/client_lb_end2end_test.cc
  26. 5
      tools/doxygen/Doxyfile.c++.internal
  27. 5
      tools/doxygen/Doxyfile.core.internal

@ -2473,6 +2473,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/http_proxy.cc",
"src/core/ext/filters/client_channel/lb_policy.cc",
"src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc",
"src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc",
"src/core/ext/filters/client_channel/lb_policy_registry.cc",
"src/core/ext/filters/client_channel/local_subchannel_pool.cc",
"src/core/ext/filters/client_channel/proxy_mapper_registry.cc",
@ -2500,6 +2501,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/http_proxy.h",
"src/core/ext/filters/client_channel/lb_policy.h",
"src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h",
"src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h",
"src/core/ext/filters/client_channel/lb_policy_factory.h",
"src/core/ext/filters/client_channel/lb_policy_registry.h",
"src/core/ext/filters/client_channel/local_subchannel_pool.h",
@ -2511,6 +2513,7 @@ grpc_cc_library(
"src/core/ext/filters/client_channel/retry_throttle.h",
"src/core/ext/filters/client_channel/subchannel.h",
"src/core/ext/filters/client_channel/subchannel_interface.h",
"src/core/ext/filters/client_channel/subchannel_interface_internal.h",
"src/core/ext/filters/client_channel/subchannel_pool_interface.h",
"src/core/ext/filters/client_channel/subchannel_stream_client.h",
],
@ -2542,6 +2545,7 @@ grpc_cc_library(
"json",
"json_util",
"orphanable",
"protobuf_duration_upb",
"ref_counted",
"ref_counted_ptr",
"server_address",
@ -2550,6 +2554,7 @@ grpc_cc_library(
"time",
"uri_parser",
"useful",
"xds_orca_service_upb",
"xds_orca_upb",
],
)

18
CMakeLists.txt generated

@ -1623,6 +1623,7 @@ add_library(grpc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
@ -1838,6 +1839,7 @@ add_library(grpc
src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c
src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c
src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c
@ -2560,6 +2562,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
@ -2643,6 +2646,7 @@ add_library(grpc_unsecure
src/core/ext/upb-generated/src/proto/grpc/lookup/v1/rls.upb.c
src/core/ext/upb-generated/validate/validate.upb.c
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
src/core/lib/address_utils/parse_address.cc
src/core/lib/address_utils/sockaddr_utils.cc
src/core/lib/backoff/backoff.cc
@ -9280,6 +9284,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
src/cpp/server/orca/orca_service.cc
test/core/util/test_lb_policies.cc
test/cpp/end2end/client_lb_end2end_test.cc
test/cpp/end2end/connection_delay_injector.cc
@ -13171,19 +13176,6 @@ add_executable(orca_service_end2end_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_service.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_service.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_service.grpc.pb.h
src/core/ext/upb-generated/google/api/annotations.upb.c
src/core/ext/upb-generated/google/api/http.upb.c
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/protobuf/descriptor.upb.c
src/core/ext/upb-generated/google/protobuf/duration.upb.c
src/core/ext/upb-generated/google/protobuf/empty.upb.c
src/core/ext/upb-generated/google/protobuf/struct.upb.c
src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/ext/upb-generated/validate/validate.upb.c
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
src/cpp/server/orca/orca_service.cc
test/cpp/end2end/orca_service_end2end_test.cc
third_party/googletest/googletest/src/gtest-all.cc

4
Makefile generated

@ -1046,6 +1046,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
@ -1261,6 +1262,7 @@ LIBGRPC_SRC = \
src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c \
src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c \
@ -1830,6 +1832,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
@ -1913,6 +1916,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/upb-generated/src/proto/grpc/lookup/v1/rls.upb.c \
src/core/ext/upb-generated/validate/validate.upb.c \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c \
src/core/lib/address_utils/parse_address.cc \
src/core/lib/address_utils/sockaddr_utils.cc \
src/core/lib/backoff/backoff.cc \

@ -335,6 +335,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
- src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
- src/core/ext/filters/client_channel/lb_policy/xds/xds.h
@ -356,6 +357,7 @@ libs:
- src/core/ext/filters/client_channel/retry_throttle.h
- src/core/ext/filters/client_channel/subchannel.h
- src/core/ext/filters/client_channel/subchannel_interface.h
- src/core/ext/filters/client_channel/subchannel_interface_internal.h
- src/core/ext/filters/client_channel/subchannel_pool_interface.h
- src/core/ext/filters/client_channel/subchannel_stream_client.h
- src/core/ext/filters/deadline/deadline_filter.h
@ -534,6 +536,7 @@ libs:
- src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h
- src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h
- src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h
- src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.h
- src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.h
@ -995,6 +998,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc
- src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
- src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
@ -1210,6 +1214,7 @@ libs:
- src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c
- src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
- src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c
- src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c
- src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c
@ -1811,6 +1816,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
- src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h
- src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
- src/core/ext/filters/client_channel/lb_policy_factory.h
@ -1829,6 +1835,7 @@ libs:
- src/core/ext/filters/client_channel/retry_throttle.h
- src/core/ext/filters/client_channel/subchannel.h
- src/core/ext/filters/client_channel/subchannel_interface.h
- src/core/ext/filters/client_channel/subchannel_interface_internal.h
- src/core/ext/filters/client_channel/subchannel_pool_interface.h
- src/core/ext/filters/client_channel/subchannel_stream_client.h
- src/core/ext/filters/deadline/deadline_filter.h
@ -1881,6 +1888,7 @@ libs:
- src/core/ext/upb-generated/src/proto/grpc/lookup/v1/rls.upb.h
- src/core/ext/upb-generated/validate/validate.upb.h
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h
- src/core/lib/address_utils/parse_address.h
- src/core/lib/address_utils/sockaddr_utils.h
- src/core/lib/avl/avl.h
@ -2124,6 +2132,7 @@ libs:
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc
- src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc
- src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc
- src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
- src/core/ext/filters/client_channel/lb_policy/priority/priority.cc
- src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc
@ -2207,6 +2216,7 @@ libs:
- src/core/ext/upb-generated/src/proto/grpc/lookup/v1/rls.upb.c
- src/core/ext/upb-generated/validate/validate.upb.c
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
- src/core/lib/address_utils/parse_address.cc
- src/core/lib/address_utils/sockaddr_utils.cc
- src/core/lib/backoff/backoff.cc
@ -5137,6 +5147,7 @@ targets:
- src/proto/grpc/testing/echo_messages.proto
- src/proto/grpc/testing/simple_messages.proto
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- src/cpp/server/orca/orca_service.cc
- test/core/util/test_lb_policies.cc
- test/cpp/end2end/client_lb_end2end_test.cc
- test/cpp/end2end/connection_delay_injector.cc
@ -6651,36 +6662,10 @@ targets:
gtest: true
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/api/annotations.upb.h
- src/core/ext/upb-generated/google/api/http.upb.h
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/protobuf/descriptor.upb.h
- src/core/ext/upb-generated/google/protobuf/duration.upb.h
- src/core/ext/upb-generated/google/protobuf/empty.upb.h
- src/core/ext/upb-generated/google/protobuf/struct.upb.h
- src/core/ext/upb-generated/google/protobuf/timestamp.upb.h
- src/core/ext/upb-generated/google/protobuf/wrappers.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/ext/upb-generated/validate/validate.upb.h
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h
headers: []
src:
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- src/proto/grpc/testing/xds/v3/orca_service.proto
- src/core/ext/upb-generated/google/api/annotations.upb.c
- src/core/ext/upb-generated/google/api/http.upb.c
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/protobuf/descriptor.upb.c
- src/core/ext/upb-generated/google/protobuf/duration.upb.c
- src/core/ext/upb-generated/google/protobuf/empty.upb.c
- src/core/ext/upb-generated/google/protobuf/struct.upb.c
- src/core/ext/upb-generated/google/protobuf/timestamp.upb.c
- src/core/ext/upb-generated/google/protobuf/wrappers.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/ext/upb-generated/validate/validate.upb.c
- src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c
- src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c
- src/cpp/server/orca/orca_service.cc
- test/cpp/end2end/orca_service_end2end_test.cc
deps:

3
config.m4 generated

@ -64,6 +64,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
@ -279,6 +280,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c \
src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c \
@ -1245,6 +1247,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/annotations/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/core/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/data/orca/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/service/orca/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/type/matcher/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upb-generated/xds/type/v3)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/upbdefs-generated/envoy/admin/v3)

5
config.w32 generated

@ -30,6 +30,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_balancer_addresses.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_client_stats.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\load_balancer_api.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\oob_backend_metric.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\priority\\priority.cc " +
"src\\core\\ext\\filters\\client_channel\\lb_policy\\ring_hash\\ring_hash.cc " +
@ -245,6 +246,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\upb-generated\\xds\\core\\v3\\resource_locator.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\core\\v3\\resource_name.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\data\\orca\\v3\\orca_load_report.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\service\\orca\\v3\\orca.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\type\\matcher\\v3\\matcher.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\type\\matcher\\v3\\regex.upb.c " +
"src\\core\\ext\\upb-generated\\xds\\type\\matcher\\v3\\string.upb.c " +
@ -1303,6 +1305,9 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\data");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\data\\orca");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\data\\orca\\v3");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\service");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\service\\orca");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\service\\orca\\v3");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\type");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\type\\matcher");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\upb-generated\\xds\\type\\matcher\\v3");

6
gRPC-C++.podspec generated

@ -236,6 +236,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
@ -257,6 +258,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_interface_internal.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h',
@ -473,6 +475,7 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.h',
@ -1065,6 +1068,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
@ -1086,6 +1090,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_interface_internal.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h',
@ -1284,6 +1289,7 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.h',

8
gRPC-Core.podspec generated

@ -237,6 +237,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
@ -293,6 +295,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel.cc',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_interface_internal.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.cc',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/client_channel/subchannel_stream_client.cc',
@ -651,6 +654,8 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c',
@ -1686,6 +1691,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.h',
'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h',
'src/core/ext/filters/client_channel/lb_policy/xds/xds.h',
@ -1707,6 +1713,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/retry_throttle.h',
'src/core/ext/filters/client_channel/subchannel.h',
'src/core/ext/filters/client_channel/subchannel_interface.h',
'src/core/ext/filters/client_channel/subchannel_interface_internal.h',
'src/core/ext/filters/client_channel/subchannel_pool_interface.h',
'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h',
@ -1885,6 +1892,7 @@ Pod::Spec.new do |s|
'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.h',
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.h',
'src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.h',

5
grpc.gemspec generated

@ -156,6 +156,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/priority/priority.cc )
s.files += %w( src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc )
@ -212,6 +214,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/subchannel.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_interface.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_interface_internal.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_pool_interface.cc )
s.files += %w( src/core/ext/filters/client_channel/subchannel_pool_interface.h )
s.files += %w( src/core/ext/filters/client_channel/subchannel_stream_client.cc )
@ -570,6 +573,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h )
s.files += %w( src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c )
s.files += %w( src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h )
s.files += %w( src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c )
s.files += %w( src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h )
s.files += %w( src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c )
s.files += %w( src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h )
s.files += %w( src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c )

4
grpc.gyp generated

@ -395,6 +395,7 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
@ -610,6 +611,7 @@
'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c',
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c',
@ -1152,6 +1154,7 @@
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
@ -1235,6 +1238,7 @@
'src/core/ext/upb-generated/src/proto/grpc/lookup/v1/rls.upb.c',
'src/core/ext/upb-generated/validate/validate.upb.c',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c',
'src/core/lib/address_utils/parse_address.cc',
'src/core/lib/address_utils/sockaddr_utils.cc',
'src/core/lib/backoff/backoff.cc',

5
package.xml generated

@ -136,6 +136,8 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/priority/priority.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc" role="src" />
@ -192,6 +194,7 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_interface_internal.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_pool_interface.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_pool_interface.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/subchannel_stream_client.cc" role="src" />
@ -550,6 +553,8 @@
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c" role="src" />

@ -32,14 +32,15 @@ std::map<absl::string_view, double> ParseMap(
const EntryType* (*entry_func)(const xds_data_orca_v3_OrcaLoadReport*,
size_t*),
upb_StringView (*key_func)(const EntryType*),
double (*value_func)(const EntryType*), Arena* arena) {
double (*value_func)(const EntryType*),
BackendMetricAllocatorInterface* allocator) {
std::map<absl::string_view, double> result;
size_t i = kUpb_Map_Begin;
while (true) {
const auto* entry = entry_func(msg, &i);
if (entry == nullptr) break;
upb_StringView key_view = key_func(entry);
char* key = static_cast<char*>(arena->Alloc(key_view.size));
char* key = allocator->AllocateString(key_view.size);
memcpy(key, key_view.data, key_view.size);
result[absl::string_view(key, key_view.size)] = value_func(entry);
}
@ -49,14 +50,15 @@ std::map<absl::string_view, double> ParseMap(
} // namespace
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
ParseBackendMetricData(const Slice& serialized_load_report, Arena* arena) {
ParseBackendMetricData(absl::string_view serialized_load_report,
BackendMetricAllocatorInterface* allocator) {
upb::Arena upb_arena;
xds_data_orca_v3_OrcaLoadReport* msg = xds_data_orca_v3_OrcaLoadReport_parse(
reinterpret_cast<const char*>(serialized_load_report.begin()),
serialized_load_report.size(), upb_arena.ptr());
serialized_load_report.data(), serialized_load_report.size(),
upb_arena.ptr());
if (msg == nullptr) return nullptr;
auto* backend_metric_data = arena->New<
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData>();
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
backend_metric_data = allocator->AllocateBackendMetricData();
backend_metric_data->cpu_utilization =
xds_data_orca_v3_OrcaLoadReport_cpu_utilization(msg);
backend_metric_data->mem_utilization =
@ -67,12 +69,12 @@ ParseBackendMetricData(const Slice& serialized_load_report, Arena* arena) {
ParseMap<xds_data_orca_v3_OrcaLoadReport_RequestCostEntry>(
msg, xds_data_orca_v3_OrcaLoadReport_request_cost_next,
xds_data_orca_v3_OrcaLoadReport_RequestCostEntry_key,
xds_data_orca_v3_OrcaLoadReport_RequestCostEntry_value, arena);
xds_data_orca_v3_OrcaLoadReport_RequestCostEntry_value, allocator);
backend_metric_data->utilization =
ParseMap<xds_data_orca_v3_OrcaLoadReport_UtilizationEntry>(
msg, xds_data_orca_v3_OrcaLoadReport_utilization_next,
xds_data_orca_v3_OrcaLoadReport_UtilizationEntry_key,
xds_data_orca_v3_OrcaLoadReport_UtilizationEntry_value, arena);
xds_data_orca_v3_OrcaLoadReport_UtilizationEntry_value, allocator);
return backend_metric_data;
}

@ -19,19 +19,28 @@
#include <grpc/support/port_platform.h>
#include <grpc/slice.h>
#include "absl/strings/string_view.h"
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
namespace grpc_core {
// Parses the serialized load report and allocates a BackendMetricData
// object on the arena.
class BackendMetricAllocatorInterface {
public:
virtual ~BackendMetricAllocatorInterface() = default;
virtual LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
AllocateBackendMetricData() = 0;
virtual char* AllocateString(size_t size) = 0;
};
// Parses the serialized load report and populates out.
// Returns false on error.
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
ParseBackendMetricData(const Slice& serialized_load_report, Arena* arena);
ParseBackendMetricData(absl::string_view serialized_load_report,
BackendMetricAllocatorInterface* allocator);
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKEND_METRIC_H */
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKEND_METRIC_H

@ -51,6 +51,8 @@
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
#include "src/core/ext/filters/client_channel/retry_filter.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
#include "src/core/ext/filters/client_channel/subchannel_interface_internal.h"
#include "src/core/ext/filters/deadline/deadline_filter.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_args.h"
@ -527,6 +529,15 @@ class ClientChannel::SubchannelWrapper : public SubchannelInterface {
void ResetBackoff() override { subchannel_->ResetBackoff(); }
void AddDataWatcher(std::unique_ptr<DataWatcherInterface> watcher) override
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*chand_->work_serializer_) {
std::unique_ptr<InternalSubchannelDataWatcherInterface> internal_watcher(
static_cast<InternalSubchannelDataWatcherInterface*>(
watcher.release()));
internal_watcher->SetSubchannel(subchannel_.get());
data_watchers_.push_back(std::move(internal_watcher));
}
const grpc_channel_args* channel_args() override {
return subchannel_->channel_args();
}
@ -667,6 +678,8 @@ class ClientChannel::SubchannelWrapper : public SubchannelInterface {
// corresponding WrapperWatcher to cancel on the underlying subchannel.
std::map<ConnectivityStateWatcherInterface*, WatcherWrapper*> watcher_map_
ABSL_GUARDED_BY(*chand_->work_serializer_);
std::vector<std::unique_ptr<InternalSubchannelDataWatcherInterface>>
data_watchers_ ABSL_GUARDED_BY(*chand_->work_serializer_);
};
//
@ -2548,14 +2561,33 @@ class ClientChannel::LoadBalancedCall::BackendMetricAccessor
lb_call_->recv_trailing_metadata_ != nullptr) {
if (const auto* md = lb_call_->recv_trailing_metadata_->get_pointer(
XEndpointLoadMetricsBinMetadata())) {
BackendMetricAllocator allocator(lb_call_->arena_);
lb_call_->backend_metric_data_ =
ParseBackendMetricData(*md, lb_call_->arena_);
ParseBackendMetricData(md->as_string_view(), &allocator);
}
}
return lb_call_->backend_metric_data_;
}
private:
class BackendMetricAllocator : public BackendMetricAllocatorInterface {
public:
explicit BackendMetricAllocator(Arena* arena) : arena_(arena) {}
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
AllocateBackendMetricData() override {
return arena_->New<
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData>();
}
char* AllocateString(size_t size) override {
return static_cast<char*>(arena_->Alloc(size));
}
private:
Arena* arena_;
};
LoadBalancedCall* lb_call_;
};

@ -0,0 +1,382 @@
//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h"
#include "google/protobuf/duration.upb.h"
#include "upb/upb.hpp"
#include "xds/data/orca/v3/orca_load_report.upb.h"
#include "xds/service/orca/v3/orca.upb.h"
#include <grpc/status.h>
#include "src/core/ext/filters/client_channel/backend_metric.h"
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface_internal.h"
#include "src/core/ext/filters/client_channel/subchannel_stream_client.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/error_utils.h"
namespace grpc_core {
namespace {
TraceFlag grpc_orca_client_trace(false, "orca_client");
constexpr char kProducerType[] = "orca";
class OrcaWatcher;
// This producer is registered with a subchannel. It creates a
// streaming ORCA call and reports the resulting backend metrics to all
// registered watchers.
class OrcaProducer : public Subchannel::DataProducerInterface {
public:
explicit OrcaProducer(RefCountedPtr<Subchannel> subchannel);
void Orphan() override;
const char* type() override { return kProducerType; }
// Adds and removes watchers.
void AddWatcher(OrcaWatcher* watcher);
void RemoveWatcher(OrcaWatcher* watcher);
private:
class ConnectivityWatcher;
class OrcaStreamEventHandler;
// Returns the minimum requested reporting interval across all watchers.
Duration GetMinIntervalLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
// Starts a new stream if we have a connected subchannel.
// Called whenever the reporting interval changes or the subchannel
// transitions to state READY.
void MaybeStartStreamLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(&mu_);
// Handles a connectivity state change on the subchannel.
void OnConnectivityStateChange(grpc_connectivity_state state);
// Called to notify watchers of a new backend metric report.
void NotifyWatchers(
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData&
backend_metric_data);
RefCountedPtr<Subchannel> subchannel_;
RefCountedPtr<ConnectedSubchannel> connected_subchannel_;
ConnectivityWatcher* connectivity_watcher_;
Mutex mu_;
std::set<OrcaWatcher*> watchers_ ABSL_GUARDED_BY(mu_);
Duration report_interval_ ABSL_GUARDED_BY(mu_) = Duration::Infinity();
OrphanablePtr<SubchannelStreamClient> stream_client_ ABSL_GUARDED_BY(mu_);
};
// This watcher is returned to the LB policy and added to the
// client channel SubchannelWrapper.
class OrcaWatcher : public InternalSubchannelDataWatcherInterface {
public:
OrcaWatcher(Duration report_interval,
std::unique_ptr<OobBackendMetricWatcher> watcher)
: report_interval_(report_interval), watcher_(std::move(watcher)) {}
~OrcaWatcher() override;
Duration report_interval() const { return report_interval_; }
OobBackendMetricWatcher* watcher() const { return watcher_.get(); }
// When the client channel sees this wrapper, it will pass it the real
// subchannel to use.
void SetSubchannel(Subchannel* subchannel) override;
private:
const Duration report_interval_;
std::unique_ptr<OobBackendMetricWatcher> watcher_;
RefCountedPtr<OrcaProducer> producer_;
};
//
// OrcaProducer::ConnectivityWatcher
//
class OrcaProducer::ConnectivityWatcher
: public Subchannel::ConnectivityStateWatcherInterface {
public:
explicit ConnectivityWatcher(WeakRefCountedPtr<OrcaProducer> producer)
: producer_(std::move(producer)),
interested_parties_(grpc_pollset_set_create()) {}
~ConnectivityWatcher() override {
grpc_pollset_set_destroy(interested_parties_);
}
void OnConnectivityStateChange() override {
auto change = PopConnectivityStateChange();
producer_->OnConnectivityStateChange(change.state);
}
grpc_pollset_set* interested_parties() override {
return interested_parties_;
}
private:
WeakRefCountedPtr<OrcaProducer> producer_;
grpc_pollset_set* interested_parties_;
};
//
// OrcaProducer::OrcaStreamEventHandler
//
class OrcaProducer::OrcaStreamEventHandler
: public SubchannelStreamClient::CallEventHandler {
public:
OrcaStreamEventHandler(WeakRefCountedPtr<OrcaProducer> producer,
Duration report_interval)
: producer_(std::move(producer)), report_interval_(report_interval) {}
Slice GetPathLocked() override {
return Slice::FromStaticString(
"/xds.service.orca.v3.OpenRcaService/StreamCoreMetrics");
}
void OnCallStartLocked(SubchannelStreamClient* /*client*/) override {}
void OnRetryTimerStartLocked(SubchannelStreamClient* /*client*/) override {}
grpc_slice EncodeSendMessageLocked() override {
upb::Arena arena;
xds_service_orca_v3_OrcaLoadReportRequest* request =
xds_service_orca_v3_OrcaLoadReportRequest_new(arena.ptr());
gpr_timespec timespec = report_interval_.as_timespec();
auto* report_interval =
xds_service_orca_v3_OrcaLoadReportRequest_mutable_report_interval(
request, arena.ptr());
google_protobuf_Duration_set_seconds(report_interval, timespec.tv_sec);
google_protobuf_Duration_set_nanos(report_interval, timespec.tv_nsec);
size_t buf_length;
char* buf = xds_service_orca_v3_OrcaLoadReportRequest_serialize(
request, arena.ptr(), &buf_length);
grpc_slice request_slice = GRPC_SLICE_MALLOC(buf_length);
memcpy(GRPC_SLICE_START_PTR(request_slice), buf, buf_length);
return request_slice;
}
absl::Status RecvMessageReadyLocked(
SubchannelStreamClient* /*client*/,
absl::string_view serialized_message) override {
auto* allocator = new BackendMetricAllocator(producer_);
auto* backend_metric_data =
ParseBackendMetricData(serialized_message, allocator);
if (backend_metric_data == nullptr) {
delete allocator;
return absl::InvalidArgumentError("unable to parse Orca response");
}
allocator->AsyncNotifyWatchersAndDelete();
return absl::OkStatus();
}
void RecvTrailingMetadataReadyLocked(SubchannelStreamClient* /*client*/,
grpc_status_code status) override {
if (status == GRPC_STATUS_UNIMPLEMENTED) {
static const char kErrorMessage[] =
"Orca stream returned UNIMPLEMENTED; disabling";
gpr_log(GPR_ERROR, kErrorMessage);
auto* channelz_node = producer_->subchannel_->channelz_node();
if (channelz_node != nullptr) {
channelz_node->AddTraceEvent(
channelz::ChannelTrace::Error,
grpc_slice_from_static_string(kErrorMessage));
}
}
}
private:
// This class acts as storage for the parsed backend metric data. It
// is injected into ParseBackendMetricData() as an allocator that
// returns internal storage. It then also acts as a place to hold
// onto the data during an async hop into the ExecCtx before sending
// notifications, which avoids lock inversion problems due to
// acquiring producer_->mu_ while holding the lock from inside of
// SubchannelStreamClient.
class BackendMetricAllocator : public BackendMetricAllocatorInterface {
public:
explicit BackendMetricAllocator(WeakRefCountedPtr<OrcaProducer> producer)
: producer_(std::move(producer)) {}
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData*
AllocateBackendMetricData() override {
return &backend_metric_data_;
}
char* AllocateString(size_t size) override {
char* string = static_cast<char*>(gpr_malloc(size));
string_storage_.emplace_back(string);
return string;
}
// Notifies watchers asynchronously and then deletes the
// BackendMetricAllocator object.
void AsyncNotifyWatchersAndDelete() {
GRPC_CLOSURE_INIT(&closure_, NotifyWatchersInExecCtx, this, nullptr);
ExecCtx::Run(DEBUG_LOCATION, &closure_, GRPC_ERROR_NONE);
}
private:
static void NotifyWatchersInExecCtx(void* arg,
grpc_error_handle /*error*/) {
auto* self = static_cast<BackendMetricAllocator*>(arg);
self->producer_->NotifyWatchers(self->backend_metric_data_);
delete self;
}
WeakRefCountedPtr<OrcaProducer> producer_;
LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData
backend_metric_data_;
std::vector<UniquePtr<char>> string_storage_;
grpc_closure closure_;
};
WeakRefCountedPtr<OrcaProducer> producer_;
const Duration report_interval_;
};
//
// OrcaProducer
//
OrcaProducer::OrcaProducer(RefCountedPtr<Subchannel> subchannel)
: subchannel_(std::move(subchannel)) {
subchannel_->AddDataProducer(this);
connected_subchannel_ = subchannel_->connected_subchannel();
auto connectivity_watcher = MakeRefCounted<ConnectivityWatcher>(WeakRef());
connectivity_watcher_ = connectivity_watcher.get();
subchannel_->WatchConnectivityState(
connected_subchannel_ == nullptr ? GRPC_CHANNEL_IDLE : GRPC_CHANNEL_READY,
/*health_check_service_name=*/absl::nullopt,
std::move(connectivity_watcher));
}
void OrcaProducer::Orphan() {
{
MutexLock lock(&mu_);
stream_client_.reset();
}
subchannel_->CancelConnectivityStateWatch(
/*health_check_service_name=*/absl::nullopt, connectivity_watcher_);
subchannel_->RemoveDataProducer(this);
}
void OrcaProducer::AddWatcher(OrcaWatcher* watcher) {
MutexLock lock(&mu_);
watchers_.insert(watcher);
Duration watcher_interval = watcher->report_interval();
if (watcher_interval < report_interval_) {
report_interval_ = watcher_interval;
stream_client_.reset();
MaybeStartStreamLocked();
}
}
void OrcaProducer::RemoveWatcher(OrcaWatcher* watcher) {
MutexLock lock(&mu_);
watchers_.erase(watcher);
if (watchers_.empty()) {
stream_client_.reset();
return;
}
Duration new_interval = GetMinIntervalLocked();
if (new_interval < report_interval_) {
report_interval_ = new_interval;
stream_client_.reset();
MaybeStartStreamLocked();
}
}
Duration OrcaProducer::GetMinIntervalLocked() const {
Duration duration = Duration::Infinity();
for (OrcaWatcher* watcher : watchers_) {
Duration watcher_interval = watcher->report_interval();
if (watcher_interval < duration) duration = watcher_interval;
}
return duration;
}
void OrcaProducer::MaybeStartStreamLocked() {
if (connected_subchannel_ == nullptr) return;
stream_client_ = MakeOrphanable<SubchannelStreamClient>(
connected_subchannel_, subchannel_->pollset_set(),
absl::make_unique<OrcaStreamEventHandler>(WeakRef(), report_interval_),
GRPC_TRACE_FLAG_ENABLED(grpc_orca_client_trace) ? "OrcaClient" : nullptr);
}
void OrcaProducer::NotifyWatchers(
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData&
backend_metric_data) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_orca_client_trace)) {
gpr_log(GPR_INFO, "OrcaProducer %p: reporting backend metrics to watchers",
this);
}
MutexLock lock(&mu_);
for (OrcaWatcher* watcher : watchers_) {
watcher->watcher()->OnBackendMetricReport(backend_metric_data);
}
}
void OrcaProducer::OnConnectivityStateChange(grpc_connectivity_state state) {
MutexLock lock(&mu_);
if (state == GRPC_CHANNEL_READY) {
connected_subchannel_ = subchannel_->connected_subchannel();
if (!watchers_.empty()) MaybeStartStreamLocked();
} else {
connected_subchannel_.reset();
stream_client_.reset();
}
}
//
// OrcaWatcher
//
OrcaWatcher::~OrcaWatcher() {
if (producer_ != nullptr) producer_->RemoveWatcher(this);
}
void OrcaWatcher::SetSubchannel(Subchannel* subchannel) {
// Check if our producer is already registered with the subchannel.
// If not, create a new one, which will register itself with the subchannel.
auto* p =
static_cast<OrcaProducer*>(subchannel->GetDataProducer(kProducerType));
if (p != nullptr) producer_ = p->RefIfNonZero();
if (producer_ == nullptr) {
producer_ = MakeRefCounted<OrcaProducer>(subchannel->Ref());
}
// Register ourself with the producer.
producer_->AddWatcher(this);
}
} // namespace
std::unique_ptr<SubchannelInterface::DataWatcherInterface>
MakeOobBackendMetricWatcher(Duration report_interval,
std::unique_ptr<OobBackendMetricWatcher> watcher) {
return absl::make_unique<OrcaWatcher>(report_interval, std::move(watcher));
}
} // namespace grpc_core

@ -0,0 +1,57 @@
//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_OOB_BACKEND_METRIC_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_OOB_BACKEND_METRIC_H
#include <grpc/support/port_platform.h>
#include <memory>
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
namespace grpc_core {
// Interface for LB policies to access out-of-band backend metric data
// from a subchannel. The data is reported from via an ORCA stream
// established on the subchannel whenever an LB policy registers a
// watcher.
//
// To use this, an LB policy will implement its own subclass of
// OobBackendMetricWatcher, which will receive backend metric data as it
// is sent by the server. It will then register that watcher with the
// subchannel like this:
// subchannel->AddDataWatcher(
// MakeOobBackendMetricWatcher(
// absl::make_unique<MyOobBackendMetricWatcherSubclass>(...)));
class OobBackendMetricWatcher {
public:
virtual ~OobBackendMetricWatcher() = default;
virtual void OnBackendMetricReport(
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData&
backend_metric_data) = 0;
};
std::unique_ptr<SubchannelInterface::DataWatcherInterface>
MakeOobBackendMetricWatcher(Duration report_interval,
std::unique_ptr<OobBackendMetricWatcher> watcher);
} // namespace grpc_core
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_OOB_BACKEND_METRIC_H

@ -820,6 +820,29 @@ void Subchannel::Orphan() {
health_watcher_map_.ShutdownLocked();
}
void Subchannel::AddDataProducer(DataProducerInterface* data_producer) {
MutexLock lock(&mu_);
auto& entry = data_producer_map_[data_producer->type()];
GPR_ASSERT(entry == nullptr);
entry = data_producer;
}
void Subchannel::RemoveDataProducer(DataProducerInterface* data_producer) {
MutexLock lock(&mu_);
auto it = data_producer_map_.find(data_producer->type());
GPR_ASSERT(it != data_producer_map_.end());
GPR_ASSERT(it->second == data_producer);
data_producer_map_.erase(it);
}
Subchannel::DataProducerInterface* Subchannel::GetDataProducer(
const char* type) {
MutexLock lock(&mu_);
auto it = data_producer_map_.find(type);
if (it == data_producer_map_.end()) return nullptr;
return it->second;
}
namespace {
// Returns a string indicating the subchannel's connectivity state change to

@ -183,6 +183,20 @@ class Subchannel : public DualRefCounted<Subchannel> {
ABSL_GUARDED_BY(&mu_);
};
// A base class for producers of subchannel-specific data.
// Implementations will typically add their own methods as needed.
class DataProducerInterface : public DualRefCounted<DataProducerInterface> {
public:
// A unique identifier for this implementation.
// Only one producer may be registered under a given type name on a
// given subchannel at any given time.
// Note that we use the pointer address instead of the string
// contents for uniqueness; all instances for a given implementation
// are expected to return the same string *instance*, not just the
// same string contents.
virtual const char* type() = 0;
};
// Creates a subchannel.
static RefCountedPtr<Subchannel> Create(
OrphanablePtr<SubchannelConnector> connector,
@ -198,6 +212,8 @@ class Subchannel : public DualRefCounted<Subchannel> {
// will have an affect when the subchannel creates a new ConnectedSubchannel.
void ThrottleKeepaliveTime(int new_keepalive_time) ABSL_LOCKS_EXCLUDED(mu_);
grpc_pollset_set* pollset_set() const { return pollset_set_; }
const grpc_channel_args* channel_args() const { return args_; }
channelz::SubchannelNode* channelz_node();
@ -245,6 +261,17 @@ class Subchannel : public DualRefCounted<Subchannel> {
// Tears down any existing connection, and arranges for destruction
void Orphan() override ABSL_LOCKS_EXCLUDED(mu_);
// Access to data producer map.
// We do not hold refs to the data producer; the implementation is
// expected to register itself upon construction and remove itself
// upon destruction.
void AddDataProducer(DataProducerInterface* data_producer)
ABSL_LOCKS_EXCLUDED(mu_);
void RemoveDataProducer(DataProducerInterface* data_producer)
ABSL_LOCKS_EXCLUDED(mu_);
DataProducerInterface* GetDataProducer(const char* type)
ABSL_LOCKS_EXCLUDED(mu_);
private:
// A linked list of ConnectivityStateWatcherInterfaces that are monitoring
// the subchannel's state.
@ -360,6 +387,10 @@ class Subchannel : public DualRefCounted<Subchannel> {
// The map of watchers with health check service names.
HealthWatcherMap health_watcher_map_ ABSL_GUARDED_BY(mu_);
// Data provider map.
std::map<const char* /*type*/, DataProducerInterface*> data_producer_map_
ABSL_GUARDED_BY(mu_);
// Minimum connect timeout - must be located before backoff_.
Duration min_connect_timeout_ ABSL_GUARDED_BY(mu_);
// Backoff state.

@ -1,20 +1,18 @@
/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
//
// Copyright 2019 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H
@ -47,6 +45,13 @@ class SubchannelInterface : public RefCounted<SubchannelInterface> {
virtual grpc_pollset_set* interested_parties() = 0;
};
// Opaque interface for watching data of a particular type for this
// subchannel.
class DataWatcherInterface {
public:
virtual ~DataWatcherInterface() = default;
};
explicit SubchannelInterface(const char* trace = nullptr)
: RefCounted<SubchannelInterface>(trace) {}
@ -87,6 +92,10 @@ class SubchannelInterface : public RefCounted<SubchannelInterface> {
// attempt will be started as soon as AttemptToConnect() is called.
virtual void ResetBackoff() = 0;
// Registers a new data watcher.
virtual void AddDataWatcher(
std::unique_ptr<DataWatcherInterface> watcher) = 0;
// TODO(roth): Need a better non-grpc-specific abstraction here.
virtual const grpc_channel_args* channel_args() = 0;
};
@ -120,6 +129,9 @@ class DelegatingSubchannel : public SubchannelInterface {
const grpc_channel_args* channel_args() override {
return wrapped_subchannel_->channel_args();
}
void AddDataWatcher(std::unique_ptr<DataWatcherInterface> watcher) override {
wrapped_subchannel_->AddDataWatcher(std::move(watcher));
}
private:
RefCountedPtr<SubchannelInterface> wrapped_subchannel_;
@ -127,4 +139,4 @@ class DelegatingSubchannel : public SubchannelInterface {
} // namespace grpc_core
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H */
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_H

@ -0,0 +1,40 @@
//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_INTERNAL_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_INTERNAL_H
#include <grpc/support/port_platform.h>
#include <memory>
#include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface.h"
namespace grpc_core {
// Internal interface for watching data of a particular type for this
// subchannel.
class InternalSubchannelDataWatcherInterface
: public SubchannelInterface::DataWatcherInterface {
public:
// Tells the watcher which subchannel to register itself with.
virtual void SetSubchannel(Subchannel* subchannel) = 0;
};
} // namespace grpc_core
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INTERFACE_INTERNAL_H

@ -39,6 +39,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_balancer_addresses.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc',
'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc',
'src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc',
'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc',
'src/core/ext/filters/client_channel/lb_policy/priority/priority.cc',
'src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc',
@ -254,6 +255,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/upb-generated/xds/core/v3/resource_locator.upb.c',
'src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c',
'src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c',
'src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c',
'src/core/ext/upb-generated/xds/type/matcher/v3/string.upb.c',

@ -21,6 +21,7 @@
#include <grpc/support/log.h>
#include "src/core/ext/filters/client_channel/lb_policy.h"
#include "src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/channel/channel_args.h"
@ -522,6 +523,125 @@ class FixedAddressFactory : public LoadBalancingPolicyFactory {
}
};
//
// OobBackendMetricTestLoadBalancingPolicy
//
constexpr char kOobBackendMetricTestLbPolicyName[] =
"oob_backend_metric_test_lb";
class OobBackendMetricTestConfig : public LoadBalancingPolicy::Config {
public:
const char* name() const override {
return kOobBackendMetricTestLbPolicyName;
}
};
class OobBackendMetricTestLoadBalancingPolicy
: public ForwardingLoadBalancingPolicy {
public:
OobBackendMetricTestLoadBalancingPolicy(Args args,
OobBackendMetricCallback cb)
: ForwardingLoadBalancingPolicy(
absl::make_unique<Helper>(
RefCountedPtr<OobBackendMetricTestLoadBalancingPolicy>(this)),
std::move(args),
/*delegate_policy_name=*/"pick_first",
/*initial_refcount=*/2),
cb_(std::move(cb)) {}
~OobBackendMetricTestLoadBalancingPolicy() override = default;
const char* name() const override {
return kOobBackendMetricTestLbPolicyName;
}
private:
class BackendMetricWatcher : public OobBackendMetricWatcher {
public:
BackendMetricWatcher(
ServerAddress address,
RefCountedPtr<OobBackendMetricTestLoadBalancingPolicy> parent)
: address_(std::move(address)), parent_(std::move(parent)) {}
void OnBackendMetricReport(
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData&
backend_metric_data) override {
parent_->cb_(address_, backend_metric_data);
}
private:
ServerAddress address_;
RefCountedPtr<OobBackendMetricTestLoadBalancingPolicy> parent_;
};
class Helper : public ChannelControlHelper {
public:
explicit Helper(
RefCountedPtr<OobBackendMetricTestLoadBalancingPolicy> parent)
: parent_(std::move(parent)) {}
RefCountedPtr<SubchannelInterface> CreateSubchannel(
ServerAddress address, const grpc_channel_args& args) override {
auto subchannel =
parent_->channel_control_helper()->CreateSubchannel(address, args);
subchannel->AddDataWatcher(MakeOobBackendMetricWatcher(
Duration::Seconds(1), absl::make_unique<BackendMetricWatcher>(
std::move(address), parent_)));
return subchannel;
}
void UpdateState(grpc_connectivity_state state, const absl::Status& status,
std::unique_ptr<SubchannelPicker> picker) override {
parent_->channel_control_helper()->UpdateState(state, status,
std::move(picker));
}
void RequestReresolution() override {
parent_->channel_control_helper()->RequestReresolution();
}
absl::string_view GetAuthority() override {
return parent_->channel_control_helper()->GetAuthority();
}
void AddTraceEvent(TraceSeverity severity,
absl::string_view message) override {
parent_->channel_control_helper()->AddTraceEvent(severity, message);
}
private:
RefCountedPtr<OobBackendMetricTestLoadBalancingPolicy> parent_;
};
private:
OobBackendMetricCallback cb_;
};
class OobBackendMetricTestFactory : public LoadBalancingPolicyFactory {
public:
explicit OobBackendMetricTestFactory(OobBackendMetricCallback cb)
: cb_(std::move(cb)) {}
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
LoadBalancingPolicy::Args args) const override {
return MakeOrphanable<OobBackendMetricTestLoadBalancingPolicy>(
std::move(args), cb_);
}
const char* name() const override {
return kOobBackendMetricTestLbPolicyName;
}
RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
const Json& /*json*/, grpc_error_handle* /*error*/) const override {
return MakeRefCounted<OobBackendMetricTestConfig>();
}
private:
OobBackendMetricCallback cb_;
};
} // namespace
void RegisterTestPickArgsLoadBalancingPolicy(TestPickArgsCallback cb,
@ -547,4 +667,10 @@ void RegisterFixedAddressLoadBalancingPolicy() {
absl::make_unique<FixedAddressFactory>());
}
void RegisterOobBackendMetricTestLoadBalancingPolicy(
OobBackendMetricCallback cb) {
LoadBalancingPolicyRegistry::Builder::RegisterLoadBalancingPolicyFactory(
absl::make_unique<OobBackendMetricTestFactory>(std::move(cb)));
}
} // namespace grpc_core

@ -60,6 +60,15 @@ void RegisterAddressTestLoadBalancingPolicy(AddressTestCallback cb);
// single subchannel whose address is in its configuration.
void RegisterFixedAddressLoadBalancingPolicy();
using OobBackendMetricCallback = std::function<void(
ServerAddress,
const LoadBalancingPolicy::BackendMetricAccessor::BackendMetricData&)>;
// Registers an LB policy called "oob_backend_metric_test_lb" that invokes
// cb for each OOB backend metric report on each subchannel.
void RegisterOobBackendMetricTestLoadBalancingPolicy(
OobBackendMetricCallback cb);
} // namespace grpc_core
#endif // GRPC_TEST_CORE_UTIL_TEST_LB_POLICIES_H

@ -493,6 +493,7 @@ grpc_cc_test(
"//:gpr",
"//:grpc",
"//:grpc++",
"//:grpcpp_orca",
"//src/proto/grpc/testing:echo_messages_proto",
"//src/proto/grpc/testing:echo_proto",
"//src/proto/grpc/testing/duplicate:echo_duplicate_proto",

@ -36,6 +36,7 @@
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/ext/orca_service.h>
#include <grpcpp/health_check_service_interface.h>
#include <grpcpp/impl/codegen/sync.h>
#include <grpcpp/server.h>
@ -45,6 +46,7 @@
#include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/address_utils/sockaddr_utils.h"
#include "src/core/lib/backoff/backoff.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/env.h"
@ -340,6 +342,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
const int port_;
std::unique_ptr<Server> server_;
MyTestServiceImpl service_;
experimental::OrcaService orca_service_;
std::unique_ptr<std::thread> thread_;
grpc::internal::Mutex mu_;
@ -348,7 +351,8 @@ class ClientLbEnd2endTest : public ::testing::Test {
bool started_ ABSL_GUARDED_BY(mu_) = false;
explicit ServerData(int port = 0)
: port_(port > 0 ? port : grpc_pick_unused_port_or_die()) {}
: port_(port > 0 ? port : grpc_pick_unused_port_or_die()),
orca_service_(experimental::OrcaService::Options()) {}
void Start(const std::string& server_host) {
gpr_log(GPR_INFO, "starting server on port %d", port_);
@ -371,6 +375,7 @@ class ClientLbEnd2endTest : public ::testing::Test {
grpc_fake_transport_security_server_credentials_create()));
builder.AddListeningPort(server_address.str(), std::move(creds));
builder.RegisterService(&service_);
builder.RegisterService(&orca_service_);
server_ = builder.BuildAndStart();
grpc::internal::MutexLock lock(&mu_);
server_ready_ = true;
@ -1790,6 +1795,24 @@ TEST_F(ClientLbPickArgsTest, Basic) {
<< ArgsSeenListString(pick_args_seen_list);
}
xds::data::orca::v3::OrcaLoadReport BackendMetricDataToOrcaLoadReport(
const grpc_core::LoadBalancingPolicy::BackendMetricAccessor::
BackendMetricData& backend_metric_data) {
xds::data::orca::v3::OrcaLoadReport load_report;
load_report.set_cpu_utilization(backend_metric_data.cpu_utilization);
load_report.set_mem_utilization(backend_metric_data.mem_utilization);
load_report.set_rps(backend_metric_data.requests_per_second);
for (const auto& p : backend_metric_data.request_cost) {
std::string name(p.first);
(*load_report.mutable_request_cost())[name] = p.second;
}
for (const auto& p : backend_metric_data.utilization) {
std::string name(p.first);
(*load_report.mutable_utilization())[name] = p.second;
}
return load_report;
}
class ClientLbInterceptTrailingMetadataTest : public ClientLbEnd2endTest {
protected:
void SetUp() override {
@ -1820,7 +1843,7 @@ class ClientLbInterceptTrailingMetadataTest : public ClientLbEnd2endTest {
return std::move(trailing_metadata_);
}
std::unique_ptr<xds::data::orca::v3::OrcaLoadReport> backend_load_report() {
absl::optional<xds::data::orca::v3::OrcaLoadReport> backend_load_report() {
grpc::internal::MutexLock lock(&mu_);
return std::move(load_report_);
}
@ -1836,20 +1859,7 @@ class ClientLbInterceptTrailingMetadataTest : public ClientLbEnd2endTest {
self->trailing_metadata_ = args_seen.metadata;
if (backend_metric_data != nullptr) {
self->load_report_ =
absl::make_unique<xds::data::orca::v3::OrcaLoadReport>();
self->load_report_->set_cpu_utilization(
backend_metric_data->cpu_utilization);
self->load_report_->set_mem_utilization(
backend_metric_data->mem_utilization);
self->load_report_->set_rps(backend_metric_data->requests_per_second);
for (const auto& p : backend_metric_data->request_cost) {
std::string name = std::string(p.first);
(*self->load_report_->mutable_request_cost())[name] = p.second;
}
for (const auto& p : backend_metric_data->utilization) {
std::string name = std::string(p.first);
(*self->load_report_->mutable_utilization())[name] = p.second;
}
BackendMetricDataToOrcaLoadReport(*backend_metric_data);
}
}
@ -1858,7 +1868,7 @@ class ClientLbInterceptTrailingMetadataTest : public ClientLbEnd2endTest {
int trailers_intercepted_ = 0;
absl::Status last_status_;
grpc_core::MetadataVector trailing_metadata_;
std::unique_ptr<xds::data::orca::v3::OrcaLoadReport> load_report_;
absl::optional<xds::data::orca::v3::OrcaLoadReport> load_report_;
};
ClientLbInterceptTrailingMetadataTest*
@ -1948,7 +1958,7 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesDisabled) {
::testing::Pair("user-agent", ::testing::_),
::testing::Pair("foo", "1"), ::testing::Pair("bar", "2"),
::testing::Pair("baz", "3")));
EXPECT_EQ(nullptr, backend_load_report());
EXPECT_FALSE(backend_load_report().has_value());
}
TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesEnabled) {
@ -1990,7 +2000,7 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, InterceptsRetriesEnabled) {
::testing::Pair("user-agent", ::testing::_),
::testing::Pair("foo", "1"), ::testing::Pair("bar", "2"),
::testing::Pair("baz", "3")));
EXPECT_EQ(nullptr, backend_load_report());
EXPECT_FALSE(backend_load_report().has_value());
}
TEST_F(ClientLbInterceptTrailingMetadataTest, BackendMetricData) {
@ -2018,7 +2028,7 @@ TEST_F(ClientLbInterceptTrailingMetadataTest, BackendMetricData) {
for (size_t i = 0; i < kNumRpcs; ++i) {
CheckRpcSendOk(stub, DEBUG_LOCATION);
auto actual = backend_load_report();
ASSERT_NE(actual, nullptr);
ASSERT_TRUE(actual.has_value());
// TODO(roth): Change this to use EqualsProto() once that becomes
// available in OSS.
EXPECT_EQ(actual->cpu_utilization(), load_report.cpu_utilization());
@ -2121,6 +2131,107 @@ TEST_F(ClientLbAddressTest, Basic) {
EXPECT_EQ(addresses_seen(), expected);
}
class OobBackendMetricTest : public ClientLbEnd2endTest {
protected:
using BackendMetricReport =
std::pair<int /*port*/, xds::data::orca::v3::OrcaLoadReport>;
void SetUp() override {
ClientLbEnd2endTest::SetUp();
current_test_instance_ = this;
}
static void SetUpTestCase() {
grpc_init();
grpc_core::RegisterOobBackendMetricTestLoadBalancingPolicy(
BackendMetricCallback);
}
static void TearDownTestCase() { grpc_shutdown(); }
absl::optional<BackendMetricReport> GetBackendMetricReport() {
grpc::internal::MutexLock lock(&mu_);
if (backend_metric_reports_.empty()) return absl::nullopt;
auto result = std::move(backend_metric_reports_.front());
backend_metric_reports_.pop_front();
return result;
}
private:
static void BackendMetricCallback(
grpc_core::ServerAddress address,
const grpc_core::LoadBalancingPolicy::BackendMetricAccessor::
BackendMetricData& backend_metric_data) {
auto load_report = BackendMetricDataToOrcaLoadReport(backend_metric_data);
int port = grpc_sockaddr_get_port(&address.address());
grpc::internal::MutexLock lock(&current_test_instance_->mu_);
current_test_instance_->backend_metric_reports_.push_back(
{port, std::move(load_report)});
}
static OobBackendMetricTest* current_test_instance_;
grpc::internal::Mutex mu_;
std::deque<BackendMetricReport> backend_metric_reports_ ABSL_GUARDED_BY(&mu_);
};
OobBackendMetricTest* OobBackendMetricTest::current_test_instance_ = nullptr;
TEST_F(OobBackendMetricTest, Basic) {
StartServers(1);
// Set initial backend metric data on server.
constexpr char kMetricName[] = "foo";
servers_[0]->orca_service_.SetCpuUtilization(0.1);
servers_[0]->orca_service_.SetMemoryUtilization(0.2);
servers_[0]->orca_service_.SetNamedUtilization(kMetricName, 0.3);
// Start client.
auto response_generator = BuildResolverResponseGenerator();
auto channel = BuildChannel("oob_backend_metric_test_lb", response_generator);
auto stub = BuildStub(channel);
response_generator.SetNextResolution(GetServersPorts());
// Send an OK RPC.
CheckRpcSendOk(stub, DEBUG_LOCATION);
// Check LB policy name for the channel.
EXPECT_EQ("oob_backend_metric_test_lb",
channel->GetLoadBalancingPolicyName());
// Check report seen by client.
for (size_t i = 0; i < 5; ++i) {
auto report = GetBackendMetricReport();
if (report.has_value()) {
EXPECT_EQ(report->first, servers_[0]->port_);
EXPECT_EQ(report->second.cpu_utilization(), 0.1);
EXPECT_EQ(report->second.mem_utilization(), 0.2);
EXPECT_THAT(
report->second.utilization(),
::testing::UnorderedElementsAre(::testing::Pair(kMetricName, 0.3)));
break;
}
gpr_sleep_until(grpc_timeout_seconds_to_deadline(1));
}
// Now update the utilization data on the server.
// Note that the server may send a new report while we're updating these,
// so we set them in reverse order, so that we know we'll get all new
// data once we see a report with the new CPU utilization value.
servers_[0]->orca_service_.SetNamedUtilization(kMetricName, 0.6);
servers_[0]->orca_service_.SetMemoryUtilization(0.5);
servers_[0]->orca_service_.SetCpuUtilization(0.4);
// Wait for client to see new report.
for (size_t i = 0; i < 5; ++i) {
auto report = GetBackendMetricReport();
if (report.has_value()) {
EXPECT_EQ(report->first, servers_[0]->port_);
if (report->second.cpu_utilization() != 0.1) {
EXPECT_EQ(report->second.cpu_utilization(), 0.4);
EXPECT_EQ(report->second.mem_utilization(), 0.5);
EXPECT_THAT(
report->second.utilization(),
::testing::UnorderedElementsAre(::testing::Pair(kMetricName, 0.6)));
break;
}
}
gpr_sleep_until(grpc_timeout_seconds_to_deadline(1));
}
}
} // namespace
} // namespace testing
} // namespace grpc

@ -1098,6 +1098,8 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
@ -1154,6 +1156,7 @@ src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel.h \
src/core/ext/filters/client_channel/subchannel_interface.h \
src/core/ext/filters/client_channel/subchannel_interface_internal.h \
src/core/ext/filters/client_channel/subchannel_pool_interface.cc \
src/core/ext/filters/client_channel/subchannel_pool_interface.h \
src/core/ext/filters/client_channel/subchannel_stream_client.cc \
@ -1550,6 +1553,8 @@ src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h \
src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c \

@ -918,6 +918,8 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc \
src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.cc \
src/core/ext/filters/client_channel/lb_policy/oob_backend_metric.h \
src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \
src/core/ext/filters/client_channel/lb_policy/priority/priority.cc \
src/core/ext/filters/client_channel/lb_policy/ring_hash/ring_hash.cc \
@ -978,6 +980,7 @@ src/core/ext/filters/client_channel/service_config_channel_arg_filter.cc \
src/core/ext/filters/client_channel/subchannel.cc \
src/core/ext/filters/client_channel/subchannel.h \
src/core/ext/filters/client_channel/subchannel_interface.h \
src/core/ext/filters/client_channel/subchannel_interface_internal.h \
src/core/ext/filters/client_channel/subchannel_pool_interface.cc \
src/core/ext/filters/client_channel/subchannel_pool_interface.h \
src/core/ext/filters/client_channel/subchannel_stream_client.cc \
@ -1340,6 +1343,8 @@ src/core/ext/upb-generated/xds/core/v3/resource_name.upb.c \
src/core/ext/upb-generated/xds/core/v3/resource_name.upb.h \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.c \
src/core/ext/upb-generated/xds/data/orca/v3/orca_load_report.upb.h \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.c \
src/core/ext/upb-generated/xds/service/orca/v3/orca.upb.h \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.c \
src/core/ext/upb-generated/xds/type/matcher/v3/matcher.upb.h \
src/core/ext/upb-generated/xds/type/matcher/v3/regex.upb.c \

Loading…
Cancel
Save