Reland channel args C++ type (#29113)
* Revert "Revert "Introduce ChannelArgs C++ type (#28860)" (#29106)"
This reverts commit f0283aac40.
* x
* fix
* Automated change: Fix sanity tests
Co-authored-by: ctiller <ctiller@users.noreply.github.com>
This commit is contained in:
parent
842ed8d461
commit
ccf70cf273
9
BUILD
9
BUILD
|
|
@ -1769,6 +1769,9 @@ grpc_cc_library(
|
|||
hdrs = [
|
||||
"src/core/lib/avl/avl.h",
|
||||
],
|
||||
external_deps = [
|
||||
"absl/container:inlined_vector",
|
||||
],
|
||||
deps = [
|
||||
"gpr_platform",
|
||||
],
|
||||
|
|
@ -2413,12 +2416,18 @@ grpc_cc_library(
|
|||
external_deps = [
|
||||
"absl/strings",
|
||||
"absl/strings:str_format",
|
||||
"absl/types:variant",
|
||||
"absl/types:optional",
|
||||
],
|
||||
language = "c++",
|
||||
deps = [
|
||||
"avl",
|
||||
"channel_stack_type",
|
||||
"gpr_base",
|
||||
"grpc_codegen",
|
||||
"match",
|
||||
"ref_counted",
|
||||
"ref_counted_ptr",
|
||||
"useful",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -631,7 +631,6 @@ if(gRPC_BUILD_TESTS)
|
|||
add_dependencies(buildtests_c bin_decoder_test)
|
||||
add_dependencies(buildtests_c bin_encoder_test)
|
||||
add_dependencies(buildtests_c buffer_list_test)
|
||||
add_dependencies(buildtests_c channel_args_test)
|
||||
add_dependencies(buildtests_c channel_stack_test)
|
||||
add_dependencies(buildtests_c check_gcp_environment_linux_test)
|
||||
add_dependencies(buildtests_c check_gcp_environment_windows_test)
|
||||
|
|
@ -806,6 +805,7 @@ if(gRPC_BUILD_TESTS)
|
|||
add_dependencies(buildtests_cxx certificate_provider_registry_test)
|
||||
add_dependencies(buildtests_cxx certificate_provider_store_test)
|
||||
add_dependencies(buildtests_cxx cfstream_test)
|
||||
add_dependencies(buildtests_cxx channel_args_test)
|
||||
add_dependencies(buildtests_cxx channel_arguments_test)
|
||||
add_dependencies(buildtests_cxx channel_creds_registry_test)
|
||||
add_dependencies(buildtests_cxx channel_filter_test)
|
||||
|
|
@ -4680,33 +4680,6 @@ target_link_libraries(buffer_list_test
|
|||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(channel_args_test
|
||||
test/core/channel/channel_args_test.cc
|
||||
)
|
||||
|
||||
target_include_directories(channel_args_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
|
||||
${_gRPC_RE2_INCLUDE_DIR}
|
||||
${_gRPC_SSL_INCLUDE_DIR}
|
||||
${_gRPC_UPB_GENERATED_DIR}
|
||||
${_gRPC_UPB_GRPC_GENERATED_DIR}
|
||||
${_gRPC_UPB_INCLUDE_DIR}
|
||||
${_gRPC_XXHASH_INCLUDE_DIR}
|
||||
${_gRPC_ZLIB_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(channel_args_test
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
grpc_test_util
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
|
|
@ -7726,6 +7699,7 @@ target_include_directories(avl_test
|
|||
target_link_libraries(avl_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
absl::inlined_vector
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -8489,6 +8463,41 @@ target_link_libraries(cfstream_test
|
|||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(channel_args_test
|
||||
test/core/channel/channel_args_test.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
||||
target_include_directories(channel_args_test
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
|
||||
${_gRPC_RE2_INCLUDE_DIR}
|
||||
${_gRPC_SSL_INCLUDE_DIR}
|
||||
${_gRPC_UPB_GENERATED_DIR}
|
||||
${_gRPC_UPB_GRPC_GENERATED_DIR}
|
||||
${_gRPC_UPB_INCLUDE_DIR}
|
||||
${_gRPC_XXHASH_INCLUDE_DIR}
|
||||
${_gRPC_ZLIB_INCLUDE_DIR}
|
||||
third_party/googletest/googletest/include
|
||||
third_party/googletest/googletest
|
||||
third_party/googletest/googlemock/include
|
||||
third_party/googletest/googlemock
|
||||
${_gRPC_PROTO_GENS_DIR}
|
||||
)
|
||||
|
||||
target_link_libraries(channel_args_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
grpc_test_util
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
|
|
|
|||
|
|
@ -728,7 +728,9 @@ libs:
|
|||
- src/core/lib/gprpp/chunked_vector.h
|
||||
- src/core/lib/gprpp/cpp_impl_of.h
|
||||
- src/core/lib/gprpp/dual_ref_counted.h
|
||||
- src/core/lib/gprpp/match.h
|
||||
- src/core/lib/gprpp/orphanable.h
|
||||
- src/core/lib/gprpp/overload.h
|
||||
- src/core/lib/gprpp/ref_counted.h
|
||||
- src/core/lib/gprpp/ref_counted_ptr.h
|
||||
- src/core/lib/gprpp/table.h
|
||||
|
|
@ -1907,7 +1909,9 @@ libs:
|
|||
- src/core/lib/gprpp/chunked_vector.h
|
||||
- src/core/lib/gprpp/cpp_impl_of.h
|
||||
- src/core/lib/gprpp/dual_ref_counted.h
|
||||
- src/core/lib/gprpp/match.h
|
||||
- src/core/lib/gprpp/orphanable.h
|
||||
- src/core/lib/gprpp/overload.h
|
||||
- src/core/lib/gprpp/ref_counted.h
|
||||
- src/core/lib/gprpp/ref_counted_ptr.h
|
||||
- src/core/lib/gprpp/table.h
|
||||
|
|
@ -3330,15 +3334,6 @@ targets:
|
|||
- test/core/iomgr/buffer_list_test.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
- name: channel_args_test
|
||||
build: test
|
||||
language: c
|
||||
headers: []
|
||||
src:
|
||||
- test/core/channel/channel_args_test.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: channel_stack_test
|
||||
build: test
|
||||
language: c
|
||||
|
|
@ -4546,7 +4541,8 @@ targets:
|
|||
- src/core/lib/avl/avl.h
|
||||
src:
|
||||
- test/core/avl/avl_test.cc
|
||||
deps: []
|
||||
deps:
|
||||
- absl/container:inlined_vector
|
||||
uses_polling: false
|
||||
- name: aws_request_signer_test
|
||||
gtest: true
|
||||
|
|
@ -4862,6 +4858,16 @@ targets:
|
|||
- test/cpp/end2end/test_service_impl.cc
|
||||
deps:
|
||||
- grpc++_test_util
|
||||
- name: channel_args_test
|
||||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers: []
|
||||
src:
|
||||
- test/core/channel/channel_args_test.cc
|
||||
deps:
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: channel_arguments_test
|
||||
gtest: true
|
||||
build: test
|
||||
|
|
|
|||
|
|
@ -688,9 +688,11 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/global_config_generic.h',
|
||||
'src/core/lib/gprpp/host_port.h',
|
||||
'src/core/lib/gprpp/manual_constructor.h',
|
||||
'src/core/lib/gprpp/match.h',
|
||||
'src/core/lib/gprpp/memory.h',
|
||||
'src/core/lib/gprpp/mpscq.h',
|
||||
'src/core/lib/gprpp/orphanable.h',
|
||||
'src/core/lib/gprpp/overload.h',
|
||||
'src/core/lib/gprpp/ref_counted.h',
|
||||
'src/core/lib/gprpp/ref_counted_ptr.h',
|
||||
'src/core/lib/gprpp/stat.h',
|
||||
|
|
@ -1493,9 +1495,11 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/global_config_generic.h',
|
||||
'src/core/lib/gprpp/host_port.h',
|
||||
'src/core/lib/gprpp/manual_constructor.h',
|
||||
'src/core/lib/gprpp/match.h',
|
||||
'src/core/lib/gprpp/memory.h',
|
||||
'src/core/lib/gprpp/mpscq.h',
|
||||
'src/core/lib/gprpp/orphanable.h',
|
||||
'src/core/lib/gprpp/overload.h',
|
||||
'src/core/lib/gprpp/ref_counted.h',
|
||||
'src/core/lib/gprpp/ref_counted_ptr.h',
|
||||
'src/core/lib/gprpp/stat.h',
|
||||
|
|
|
|||
|
|
@ -1087,10 +1087,12 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/host_port.cc',
|
||||
'src/core/lib/gprpp/host_port.h',
|
||||
'src/core/lib/gprpp/manual_constructor.h',
|
||||
'src/core/lib/gprpp/match.h',
|
||||
'src/core/lib/gprpp/memory.h',
|
||||
'src/core/lib/gprpp/mpscq.cc',
|
||||
'src/core/lib/gprpp/mpscq.h',
|
||||
'src/core/lib/gprpp/orphanable.h',
|
||||
'src/core/lib/gprpp/overload.h',
|
||||
'src/core/lib/gprpp/ref_counted.h',
|
||||
'src/core/lib/gprpp/ref_counted_ptr.h',
|
||||
'src/core/lib/gprpp/stat.h',
|
||||
|
|
@ -2093,9 +2095,11 @@ Pod::Spec.new do |s|
|
|||
'src/core/lib/gprpp/global_config_generic.h',
|
||||
'src/core/lib/gprpp/host_port.h',
|
||||
'src/core/lib/gprpp/manual_constructor.h',
|
||||
'src/core/lib/gprpp/match.h',
|
||||
'src/core/lib/gprpp/memory.h',
|
||||
'src/core/lib/gprpp/mpscq.h',
|
||||
'src/core/lib/gprpp/orphanable.h',
|
||||
'src/core/lib/gprpp/overload.h',
|
||||
'src/core/lib/gprpp/ref_counted.h',
|
||||
'src/core/lib/gprpp/ref_counted_ptr.h',
|
||||
'src/core/lib/gprpp/stat.h',
|
||||
|
|
|
|||
|
|
@ -1006,10 +1006,12 @@ Gem::Specification.new do |s|
|
|||
s.files += %w( src/core/lib/gprpp/host_port.cc )
|
||||
s.files += %w( src/core/lib/gprpp/host_port.h )
|
||||
s.files += %w( src/core/lib/gprpp/manual_constructor.h )
|
||||
s.files += %w( src/core/lib/gprpp/match.h )
|
||||
s.files += %w( src/core/lib/gprpp/memory.h )
|
||||
s.files += %w( src/core/lib/gprpp/mpscq.cc )
|
||||
s.files += %w( src/core/lib/gprpp/mpscq.h )
|
||||
s.files += %w( src/core/lib/gprpp/orphanable.h )
|
||||
s.files += %w( src/core/lib/gprpp/overload.h )
|
||||
s.files += %w( src/core/lib/gprpp/ref_counted.h )
|
||||
s.files += %w( src/core/lib/gprpp/ref_counted_ptr.h )
|
||||
s.files += %w( src/core/lib/gprpp/stat.h )
|
||||
|
|
|
|||
|
|
@ -986,10 +986,12 @@
|
|||
<file baseinstalldir="/" name="src/core/lib/gprpp/host_port.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/host_port.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/manual_constructor.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/match.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/memory.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/mpscq.cc" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/mpscq.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/orphanable.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/overload.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/ref_counted.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/ref_counted_ptr.h" role="src" />
|
||||
<file baseinstalldir="/" name="src/core/lib/gprpp/stat.h" role="src" />
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/container/inlined_vector.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
template <class K, class V = void>
|
||||
|
|
@ -32,8 +34,12 @@ class AVL {
|
|||
AVL Add(K key, V value) const {
|
||||
return AVL(AddKey(root_, std::move(key), std::move(value)));
|
||||
}
|
||||
AVL Remove(const K& key) const { return AVL(RemoveKey(root_, key)); }
|
||||
const V* Lookup(const K& key) const {
|
||||
template <typename SomethingLikeK>
|
||||
AVL Remove(const SomethingLikeK& key) const {
|
||||
return AVL(RemoveKey(root_, key));
|
||||
}
|
||||
template <typename SomethingLikeK>
|
||||
const V* Lookup(const SomethingLikeK& key) const {
|
||||
NodePtr n = Get(root_, key);
|
||||
return n ? &n->kv.second : nullptr;
|
||||
}
|
||||
|
|
@ -50,7 +56,36 @@ class AVL {
|
|||
ForEachImpl(root_.get(), std::forward<F>(f));
|
||||
}
|
||||
|
||||
bool SameIdentity(AVL avl) const { return root_ == avl.root_; }
|
||||
bool SameIdentity(const AVL& avl) const { return root_ == avl.root_; }
|
||||
|
||||
bool operator==(const AVL& other) const {
|
||||
Iterator a(root_);
|
||||
Iterator b(other.root_);
|
||||
for (;;) {
|
||||
Node* p = a.current();
|
||||
Node* q = b.current();
|
||||
if (p == nullptr) return q == nullptr;
|
||||
if (q == nullptr) return false;
|
||||
if (p->kv != q->kv) return false;
|
||||
a.MoveNext();
|
||||
b.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator<(const AVL& other) const {
|
||||
Iterator a(root_);
|
||||
Iterator b(other.root_);
|
||||
for (;;) {
|
||||
Node* p = a.current();
|
||||
Node* q = b.current();
|
||||
if (p == nullptr) return q != nullptr;
|
||||
if (q == nullptr) return false;
|
||||
if (p->kv < q->kv) return true;
|
||||
if (p->kv != q->kv) return false;
|
||||
a.MoveNext();
|
||||
b.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct Node;
|
||||
|
|
@ -68,6 +103,32 @@ class AVL {
|
|||
};
|
||||
NodePtr root_;
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
explicit Iterator(const NodePtr& root) {
|
||||
auto* n = root.get();
|
||||
while (n != nullptr) {
|
||||
stack_.push_back(n);
|
||||
n = n->left.get();
|
||||
}
|
||||
}
|
||||
Node* current() const { return stack_.empty() ? nullptr : stack_.back(); }
|
||||
void MoveNext() {
|
||||
auto* n = stack_.back();
|
||||
stack_.pop_back();
|
||||
if (n->right != nullptr) {
|
||||
n = n->right.get();
|
||||
while (n != nullptr) {
|
||||
stack_.push_back(n);
|
||||
n = n->left.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
absl::InlinedVector<Node*, 8> stack_;
|
||||
};
|
||||
|
||||
explicit AVL(NodePtr root) : root_(std::move(root)) {}
|
||||
|
||||
template <class F>
|
||||
|
|
@ -86,7 +147,8 @@ class AVL {
|
|||
1 + std::max(Height(left), Height(right)));
|
||||
}
|
||||
|
||||
static NodePtr Get(const NodePtr& node, const K& key) {
|
||||
template <typename SomethingLikeK>
|
||||
static NodePtr Get(const NodePtr& node, const SomethingLikeK& key) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -198,7 +260,8 @@ class AVL {
|
|||
return node;
|
||||
}
|
||||
|
||||
static NodePtr RemoveKey(const NodePtr& node, const K& key) {
|
||||
template <typename SomethingLikeK>
|
||||
static NodePtr RemoveKey(const NodePtr& node, const SomethingLikeK& key) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,108 @@
|
|||
|
||||
#include "src/core/lib/gpr/string.h"
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/core/lib/gprpp/match.h"
|
||||
|
||||
namespace {
|
||||
|
||||
int PointerCompare(void* a_ptr, const grpc_arg_pointer_vtable* a_vtable,
|
||||
void* b_ptr, const grpc_arg_pointer_vtable* b_vtable) {
|
||||
int c = grpc_core::QsortCompare(a_ptr, b_ptr);
|
||||
if (c == 0) return 0;
|
||||
c = grpc_core::QsortCompare(a_vtable, b_vtable);
|
||||
if (c != 0) return c;
|
||||
return a_vtable->cmp(a_ptr, b_ptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
bool ChannelArgs::Pointer::operator==(const Pointer& rhs) const {
|
||||
return PointerCompare(p_, vtable_, rhs.p_, rhs.vtable_) == 0;
|
||||
}
|
||||
|
||||
bool ChannelArgs::Pointer::operator<(const Pointer& rhs) const {
|
||||
return PointerCompare(p_, vtable_, rhs.p_, rhs.vtable_) < 0;
|
||||
}
|
||||
|
||||
ChannelArgs::ChannelArgs() = default;
|
||||
|
||||
ChannelArgs ChannelArgs::Set(grpc_arg arg) const {
|
||||
switch (arg.type) {
|
||||
case GRPC_ARG_INTEGER:
|
||||
return Set(arg.key, arg.value.integer);
|
||||
case GRPC_ARG_STRING:
|
||||
if (arg.value.string != nullptr) return Set(arg.key, arg.value.string);
|
||||
return Set(arg.key, "");
|
||||
case GRPC_ARG_POINTER:
|
||||
return Set(arg.key,
|
||||
Pointer(arg.value.pointer.vtable->copy(arg.value.pointer.p),
|
||||
arg.value.pointer.vtable));
|
||||
}
|
||||
GPR_UNREACHABLE_CODE(return ChannelArgs());
|
||||
}
|
||||
|
||||
ChannelArgs ChannelArgs::FromC(const grpc_channel_args* args) {
|
||||
ChannelArgs result;
|
||||
if (args != nullptr) {
|
||||
for (size_t i = 0; i < args->num_args; i++) {
|
||||
result = result.Set(args->args[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const grpc_channel_args* ChannelArgs::ToC() const {
|
||||
std::vector<grpc_arg> c_args;
|
||||
args_.ForEach([&c_args](const std::string& key, const Value& value) {
|
||||
char* name = const_cast<char*>(key.c_str());
|
||||
c_args.push_back(Match(
|
||||
value,
|
||||
[name](int i) { return grpc_channel_arg_integer_create(name, i); },
|
||||
[name](const std::string& s) {
|
||||
return grpc_channel_arg_string_create(name,
|
||||
const_cast<char*>(s.c_str()));
|
||||
},
|
||||
[name](const Pointer& p) {
|
||||
return grpc_channel_arg_pointer_create(name, p.c_pointer(),
|
||||
p.c_vtable());
|
||||
}));
|
||||
});
|
||||
return grpc_channel_args_copy_and_add(nullptr, c_args.data(), c_args.size());
|
||||
}
|
||||
|
||||
ChannelArgs ChannelArgs::Set(absl::string_view key, Value value) const {
|
||||
return ChannelArgs(args_.Add(std::string(key), std::move(value)));
|
||||
}
|
||||
|
||||
ChannelArgs ChannelArgs::Remove(absl::string_view key) const {
|
||||
return ChannelArgs(args_.Remove(key));
|
||||
}
|
||||
|
||||
absl::optional<int> ChannelArgs::GetInt(absl::string_view name) const {
|
||||
auto* v = Get(name);
|
||||
if (v == nullptr) return absl::nullopt;
|
||||
if (!absl::holds_alternative<int>(*v)) return absl::nullopt;
|
||||
return absl::get<int>(*v);
|
||||
}
|
||||
|
||||
absl::optional<absl::string_view> ChannelArgs::GetString(
|
||||
absl::string_view name) const {
|
||||
auto* v = Get(name);
|
||||
if (v == nullptr) return absl::nullopt;
|
||||
if (!absl::holds_alternative<std::string>(*v)) return absl::nullopt;
|
||||
return absl::get<std::string>(*v);
|
||||
}
|
||||
|
||||
void* ChannelArgs::GetVoidPointer(absl::string_view name) const {
|
||||
auto* v = Get(name);
|
||||
if (v == nullptr) return nullptr;
|
||||
if (!absl::holds_alternative<Pointer>(*v)) return nullptr;
|
||||
return absl::get<Pointer>(*v).c_pointer();
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
static grpc_arg copy_arg(const grpc_arg* src) {
|
||||
grpc_arg dst;
|
||||
|
|
@ -156,16 +258,8 @@ static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
|
|||
case GRPC_ARG_INTEGER:
|
||||
return grpc_core::QsortCompare(a->value.integer, b->value.integer);
|
||||
case GRPC_ARG_POINTER:
|
||||
c = grpc_core::QsortCompare(a->value.pointer.p, b->value.pointer.p);
|
||||
if (c != 0) {
|
||||
c = grpc_core::QsortCompare(a->value.pointer.vtable,
|
||||
b->value.pointer.vtable);
|
||||
if (c == 0) {
|
||||
c = a->value.pointer.vtable->cmp(a->value.pointer.p,
|
||||
b->value.pointer.p);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
return PointerCompare(a->value.pointer.p, a->value.pointer.vtable,
|
||||
b->value.pointer.p, b->value.pointer.vtable);
|
||||
}
|
||||
GPR_UNREACHABLE_CODE(return 0);
|
||||
}
|
||||
|
|
@ -369,25 +463,11 @@ std::string grpc_channel_args_string(const grpc_channel_args* args) {
|
|||
}
|
||||
|
||||
namespace grpc_core {
|
||||
const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src) {
|
||||
if (src == nullptr) return nullptr;
|
||||
// Create result.
|
||||
grpc_channel_args* dst =
|
||||
static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
|
||||
dst->args =
|
||||
static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * src->num_args));
|
||||
dst->num_args = 0;
|
||||
for (size_t i = 0; i < src->num_args; ++i) {
|
||||
if (absl::StartsWith(src->args[i].key, "grpc.internal.")) continue;
|
||||
dst->args[dst->num_args++] = copy_arg(&src->args[i]);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) {
|
||||
if (src == nullptr) return nullptr;
|
||||
std::map<absl::string_view, const grpc_arg*> values;
|
||||
std::map<absl::string_view, std::vector<std::string>> concatenated_values;
|
||||
ChannelArgs ChannelArgsBuiltinPrecondition(const grpc_channel_args* src) {
|
||||
if (src == nullptr) return ChannelArgs();
|
||||
ChannelArgs output;
|
||||
std::map<absl::string_view, std::vector<absl::string_view>>
|
||||
concatenated_values;
|
||||
for (size_t i = 0; i < src->num_args; i++) {
|
||||
absl::string_view key = src->args[i].key;
|
||||
// User-agent strings were traditionally multi-valued and concatenated.
|
||||
|
|
@ -401,46 +481,23 @@ const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) {
|
|||
concatenated_values[key].push_back(src->args[i].value.string);
|
||||
}
|
||||
continue;
|
||||
} else if (absl::StartsWith(key, "grpc.internal.")) {
|
||||
continue;
|
||||
}
|
||||
auto it = values.find(key);
|
||||
if (it == values.end()) {
|
||||
values[key] = &src->args[i];
|
||||
if (!output.Contains(key)) {
|
||||
output = output.Set(src->args[i]);
|
||||
} else {
|
||||
// Traditional grpc_channel_args_find behavior was to pick the first
|
||||
// value.
|
||||
// For compatibility with existing users, we will do the same here.
|
||||
}
|
||||
}
|
||||
if (values.size() + concatenated_values.size() == src->num_args) {
|
||||
return grpc_channel_args_copy(src);
|
||||
}
|
||||
// Concatenate the concatenated values.
|
||||
std::map<absl::string_view, std::string> concatenated_values_str;
|
||||
for (const auto& concatenated_value : concatenated_values) {
|
||||
concatenated_values_str[concatenated_value.first] =
|
||||
absl::StrJoin(concatenated_value.second, " ");
|
||||
output = output.Set(concatenated_value.first,
|
||||
absl::StrJoin(concatenated_value.second, " "));
|
||||
}
|
||||
// Create the result
|
||||
std::vector<grpc_arg> argv;
|
||||
argv.reserve(values.size());
|
||||
for (const auto& a : values) {
|
||||
argv.push_back(*a.second);
|
||||
}
|
||||
for (const auto& a : concatenated_values_str) {
|
||||
argv.push_back(
|
||||
grpc_channel_arg_string_create(const_cast<char*>(a.first.data()),
|
||||
const_cast<char*>(a.second.c_str())));
|
||||
}
|
||||
grpc_channel_args args = {argv.size(), argv.data()};
|
||||
// Log that we're mutating things
|
||||
gpr_log(GPR_INFO,
|
||||
"Uniquification pass on channel args is mutating them: {%s} is being "
|
||||
"changed to {%s}",
|
||||
grpc_channel_args_string(src).c_str(),
|
||||
grpc_channel_args_string(&args).c_str());
|
||||
// Return the result (note we need to copy because we're borrowing the args
|
||||
// from src still!)
|
||||
return grpc_channel_args_copy(&args);
|
||||
return output;
|
||||
}
|
||||
} // namespace grpc_core
|
||||
|
||||
|
|
|
|||
|
|
@ -23,12 +23,175 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "absl/types/variant.h"
|
||||
|
||||
#include <grpc/impl/codegen/grpc_types.h>
|
||||
|
||||
#include "src/core/lib/avl/avl.h"
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/surface/channel_stack_type.h"
|
||||
|
||||
// Channel args are intentionally immutable, to avoid the need for locking.
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// Define a traits object for vtable lookup - allows us to integrate with
|
||||
// existing code easily (just define the trait!) and allows some magic in
|
||||
// ChannelArgs to automatically derive a vtable from a T*.
|
||||
// To participate as a pointer, instances should expose the function:
|
||||
// // Gets the vtable for this type
|
||||
// static const grpc_channel_arg_vtable* VTable();
|
||||
// // Performs any mutations required for channel args to own a pointer
|
||||
// // Only needed if ChannelArgs::Set is to be called with a raw pointer.
|
||||
// static void* TakeUnownedPointer(T* p);
|
||||
template <typename T, typename Ignored = void /* for SFINAE */>
|
||||
struct ChannelArgTypeTraits;
|
||||
|
||||
template <typename T>
|
||||
struct ChannelArgTypeTraits<
|
||||
T, absl::enable_if_t<std::is_base_of<RefCounted<T>, T>::value, void>> {
|
||||
static const grpc_arg_pointer_vtable* VTable() {
|
||||
static const grpc_arg_pointer_vtable tbl = {
|
||||
// copy
|
||||
[](void* p) -> void* { return static_cast<T*>(p)->Ref().release(); },
|
||||
// destroy
|
||||
[](void* p) { static_cast<T*>(p)->Unref(); },
|
||||
// compare
|
||||
[](void* p1, void* p2) {
|
||||
return QsortCompare(*static_cast<const T*>(p1),
|
||||
*static_cast<const T*>(p2));
|
||||
},
|
||||
};
|
||||
return &tbl;
|
||||
};
|
||||
};
|
||||
|
||||
class ChannelArgs {
|
||||
public:
|
||||
class Pointer {
|
||||
public:
|
||||
Pointer(void* p, const grpc_arg_pointer_vtable* vtable)
|
||||
: p_(p), vtable_(vtable == nullptr ? EmptyVTable() : vtable) {}
|
||||
~Pointer() { vtable_->destroy(p_); }
|
||||
|
||||
Pointer(const Pointer& other)
|
||||
: p_(other.vtable_->copy(other.p_)), vtable_(other.vtable_) {}
|
||||
Pointer& operator=(Pointer other) {
|
||||
std::swap(p_, other.p_);
|
||||
std::swap(vtable_, other.vtable_);
|
||||
return *this;
|
||||
}
|
||||
Pointer(Pointer&& other) noexcept : p_(other.p_), vtable_(other.vtable_) {
|
||||
other.p_ = nullptr;
|
||||
other.vtable_ = EmptyVTable();
|
||||
}
|
||||
Pointer& operator=(Pointer&& other) noexcept {
|
||||
std::swap(p_, other.p_);
|
||||
std::swap(vtable_, other.vtable_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Pointer& rhs) const;
|
||||
bool operator<(const Pointer& rhs) const;
|
||||
bool operator!=(const Pointer& rhs) const { return !(*this == rhs); }
|
||||
|
||||
void* c_pointer() const { return p_; }
|
||||
|
||||
const grpc_arg_pointer_vtable* c_vtable() const { return vtable_; }
|
||||
|
||||
private:
|
||||
static const grpc_arg_pointer_vtable* EmptyVTable() {
|
||||
static const grpc_arg_pointer_vtable vtable = {
|
||||
// copy
|
||||
[](void* p) { return p; },
|
||||
// destroy
|
||||
[](void*) {},
|
||||
// cmp
|
||||
[](void* p1, void* p2) -> int { return QsortCompare(p1, p2); },
|
||||
};
|
||||
return &vtable;
|
||||
}
|
||||
|
||||
void* p_;
|
||||
const grpc_arg_pointer_vtable* vtable_;
|
||||
};
|
||||
using Value = absl::variant<int, std::string, Pointer>;
|
||||
|
||||
ChannelArgs();
|
||||
|
||||
static ChannelArgs FromC(const grpc_channel_args* args);
|
||||
// Construct a new grpc_channel_args struct which the caller will own.
|
||||
// It should be destroyed with grpc_channel_args_destroy.
|
||||
const grpc_channel_args* ToC() const;
|
||||
|
||||
const Value* Get(absl::string_view name) const { return args_.Lookup(name); }
|
||||
GRPC_MUST_USE_RESULT ChannelArgs Set(absl::string_view name,
|
||||
Value value) const;
|
||||
GRPC_MUST_USE_RESULT ChannelArgs Set(grpc_arg arg) const;
|
||||
template <typename T>
|
||||
GRPC_MUST_USE_RESULT absl::enable_if_t<
|
||||
std::is_same<const grpc_arg_pointer_vtable*,
|
||||
decltype(ChannelArgTypeTraits<T>::vtable())>::value,
|
||||
ChannelArgs>
|
||||
Set(absl::string_view name, T* value) const {
|
||||
return Set(name, Pointer(ChannelArgTypeTraits<T>::TakeUnownedPointer(value),
|
||||
ChannelArgTypeTraits<T>::VTable()));
|
||||
}
|
||||
template <typename T>
|
||||
GRPC_MUST_USE_RESULT absl::enable_if_t<
|
||||
std::is_same<const grpc_arg_pointer_vtable*,
|
||||
decltype(ChannelArgTypeTraits<T>::VTable())>::value,
|
||||
ChannelArgs>
|
||||
Set(absl::string_view name, RefCountedPtr<T> value) const {
|
||||
return Set(name,
|
||||
Pointer(value.release(), ChannelArgTypeTraits<T>::VTable()));
|
||||
}
|
||||
GRPC_MUST_USE_RESULT ChannelArgs Remove(absl::string_view name) const;
|
||||
bool Contains(absl::string_view name) const { return Get(name) != nullptr; }
|
||||
|
||||
absl::optional<int> GetInt(absl::string_view name) const;
|
||||
absl::optional<absl::string_view> GetString(absl::string_view name) const;
|
||||
void* GetVoidPointer(absl::string_view name) const;
|
||||
template <typename T>
|
||||
T* GetPointer(absl::string_view name) const {
|
||||
return static_cast<T*>(GetVoidPointer(name));
|
||||
}
|
||||
|
||||
// Object based get/set.
|
||||
// Deal with the common case that we set a pointer to an object under
|
||||
// the same name in every usage.
|
||||
// Expects ChannelArgTypeTraits to exist for T, and T to expose:
|
||||
// static string_view ChannelArgName();
|
||||
template <typename T>
|
||||
GRPC_MUST_USE_RESULT ChannelArgs SetObject(T* p) const {
|
||||
return Set(T::ChannelArgName(), p);
|
||||
}
|
||||
template <typename T>
|
||||
GRPC_MUST_USE_RESULT ChannelArgs SetObject(RefCountedPtr<T> p) const {
|
||||
return Set(T::ChannelArgName(), std::move(p));
|
||||
}
|
||||
template <typename T>
|
||||
T* GetObject() {
|
||||
return GetPointer<T>(T::ChannelArgName());
|
||||
}
|
||||
|
||||
bool operator<(const ChannelArgs& other) const { return args_ < other.args_; }
|
||||
bool operator==(const ChannelArgs& other) const {
|
||||
return args_ == other.args_;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ChannelArgs(AVL<std::string, Value> args) : args_(std::move(args)) {}
|
||||
|
||||
AVL<std::string, Value> args_;
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
/** Copy the arguments in \a src into a new instance */
|
||||
grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src);
|
||||
|
||||
|
|
@ -120,15 +283,10 @@ grpc_arg grpc_channel_arg_pointer_create(char* name, void* value,
|
|||
std::string grpc_channel_args_string(const grpc_channel_args* args);
|
||||
|
||||
namespace grpc_core {
|
||||
/** Remove any channel args prefixed with 'grpc.internal.'
|
||||
* These are used for internal implementation details and are not intended to
|
||||
* be exposed to users.
|
||||
* Returns a new channel args instance.
|
||||
* Does not take ownership of \a src.
|
||||
* Should be called by any public API that receives channel args. */
|
||||
const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src);
|
||||
/** Ensure no duplicate channel args, in preparation for moving to a map<> */
|
||||
const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src);
|
||||
// Ensure no duplicate channel args (with some backwards compatibility hacks).
|
||||
// Eliminate any grpc.internal.* args.
|
||||
// Return a C++ object.
|
||||
ChannelArgs ChannelArgsBuiltinPrecondition(const grpc_channel_args* src);
|
||||
} // namespace grpc_core
|
||||
|
||||
// Takes ownership of the old_args
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ void ChannelArgsPreconditioning::Builder::RegisterStage(Stage stage) {
|
|||
}
|
||||
|
||||
ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() {
|
||||
// TODO(ctiller): should probably make this registered too.
|
||||
stages_.emplace_back(RemoveGrpcInternalArgs);
|
||||
stages_.emplace_back(UniquifyChannelArgKeys);
|
||||
|
||||
ChannelArgsPreconditioning preconditioning;
|
||||
preconditioning.stages_ = std::move(stages_);
|
||||
return preconditioning;
|
||||
|
|
@ -36,13 +32,11 @@ ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() {
|
|||
|
||||
const grpc_channel_args* ChannelArgsPreconditioning::PreconditionChannelArgs(
|
||||
const grpc_channel_args* args) const {
|
||||
const grpc_channel_args* owned_args = nullptr;
|
||||
ChannelArgs channel_args = ChannelArgsBuiltinPrecondition(args);
|
||||
for (auto& stage : stages_) {
|
||||
args = stage(args);
|
||||
grpc_channel_args_destroy(owned_args);
|
||||
owned_args = args;
|
||||
channel_args = stage(std::move(channel_args));
|
||||
}
|
||||
return args;
|
||||
return channel_args.ToC();
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@ class ChannelArgsPreconditioning {
|
|||
// Take channel args and mutate them.
|
||||
// Does not take ownership of the channel args passed in.
|
||||
// Returns a new channel args object that is owned by the caller.
|
||||
using Stage =
|
||||
std::function<const grpc_channel_args*(const grpc_channel_args*)>;
|
||||
using Stage = std::function<ChannelArgs(ChannelArgs)>;
|
||||
|
||||
class Builder {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/resource_quota/resource_quota.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
|
|
@ -30,30 +31,13 @@ ResourceQuotaRefPtr ResourceQuotaFromChannelArgs(
|
|||
->Ref();
|
||||
}
|
||||
|
||||
namespace {
|
||||
grpc_arg MakeArg(ResourceQuota* quota) {
|
||||
return grpc_channel_arg_pointer_create(
|
||||
const_cast<char*>(GRPC_ARG_RESOURCE_QUOTA), quota,
|
||||
grpc_resource_quota_arg_vtable());
|
||||
}
|
||||
|
||||
const grpc_channel_args* EnsureResourceQuotaInChannelArgs(
|
||||
const grpc_channel_args* args) {
|
||||
const grpc_arg* existing =
|
||||
grpc_channel_args_find(args, GRPC_ARG_RESOURCE_QUOTA);
|
||||
if (existing != nullptr && existing->type == GRPC_ARG_POINTER &&
|
||||
existing->value.pointer.p != nullptr) {
|
||||
return grpc_channel_args_copy(args);
|
||||
}
|
||||
ChannelArgs EnsureResourceQuotaInChannelArgs(ChannelArgs args) {
|
||||
if (args.GetObject<ResourceQuota>() != nullptr) return args;
|
||||
// If there's no existing quota, add it to the default one - shared between
|
||||
// all channel args declared thusly. This prevents us from accidentally not
|
||||
// sharing subchannels due to their channel args not specifying a quota.
|
||||
const char* remove[] = {GRPC_ARG_RESOURCE_QUOTA};
|
||||
auto new_arg = MakeArg(ResourceQuota::Default().get());
|
||||
return grpc_channel_args_copy_and_add_and_remove(args, remove, 1, &new_arg,
|
||||
1);
|
||||
return args.SetObject(ResourceQuota::Default());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void RegisterResourceQuota(CoreConfiguration::Builder* builder) {
|
||||
builder->channel_args_preconditioning()->RegisterStage(
|
||||
|
|
@ -63,16 +47,7 @@ void RegisterResourceQuota(CoreConfiguration::Builder* builder) {
|
|||
} // namespace grpc_core
|
||||
|
||||
extern "C" const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable() {
|
||||
static const grpc_arg_pointer_vtable vtable = {
|
||||
// copy
|
||||
[](void* p) -> void* {
|
||||
return static_cast<grpc_core::ResourceQuota*>(p)->Ref().release();
|
||||
},
|
||||
// destroy
|
||||
[](void* p) { static_cast<grpc_core::ResourceQuota*>(p)->Unref(); },
|
||||
// compare
|
||||
[](void* p, void* q) { return grpc_core::QsortCompare(p, q); }};
|
||||
return &vtable;
|
||||
return grpc_core::ChannelArgTypeTraits<grpc_core::ResourceQuota>::VTable();
|
||||
}
|
||||
|
||||
extern "C" grpc_resource_quota* grpc_resource_quota_create(const char* name) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ class ResourceQuota : public RefCounted<ResourceQuota>,
|
|||
ResourceQuota(const ResourceQuota&) = delete;
|
||||
ResourceQuota& operator=(const ResourceQuota&) = delete;
|
||||
|
||||
static absl::string_view ChannelArgName() { return GRPC_ARG_RESOURCE_QUOTA; }
|
||||
|
||||
MemoryQuotaRefPtr memory_quota() { return memory_quota_; }
|
||||
|
||||
const RefCountedPtr<ThreadQuota>& thread_quota() { return thread_quota_; }
|
||||
|
|
@ -44,6 +46,8 @@ class ResourceQuota : public RefCounted<ResourceQuota>,
|
|||
// The default global resource quota
|
||||
static ResourceQuotaRefPtr Default();
|
||||
|
||||
bool operator<(const ResourceQuota& other) const { return this < &other; }
|
||||
|
||||
private:
|
||||
MemoryQuotaRefPtr memory_quota_;
|
||||
RefCountedPtr<ThreadQuota> thread_quota_;
|
||||
|
|
|
|||
|
|
@ -23,29 +23,27 @@ namespace grpc_core {
|
|||
|
||||
class Fuzzer {
|
||||
public:
|
||||
void Run(const avl_fuzzer::Msg& msg) {
|
||||
CheckEqual();
|
||||
for (const auto& action : msg.actions()) {
|
||||
switch (action.action_case()) {
|
||||
case avl_fuzzer::Action::kSet:
|
||||
avl_ = avl_.Add(action.key(), action.set());
|
||||
map_[action.key()] = action.set();
|
||||
break;
|
||||
case avl_fuzzer::Action::kDel:
|
||||
avl_ = avl_.Remove(action.key());
|
||||
map_.erase(action.key());
|
||||
break;
|
||||
case avl_fuzzer::Action::kGet: {
|
||||
auto* p = avl_.Lookup(action.key());
|
||||
auto it = map_.find(action.key());
|
||||
if (it == map_.end() && p != nullptr) abort();
|
||||
if (it != map_.end() && p == nullptr) abort();
|
||||
if (it != map_.end() && it->second != *p) abort();
|
||||
} break;
|
||||
case avl_fuzzer::Action::ACTION_NOT_SET:
|
||||
break;
|
||||
}
|
||||
CheckEqual();
|
||||
Fuzzer() { CheckEqual(); }
|
||||
~Fuzzer() { CheckEqual(); }
|
||||
void Run(const avl_fuzzer::Action& action) {
|
||||
switch (action.action_case()) {
|
||||
case avl_fuzzer::Action::kSet:
|
||||
avl_ = avl_.Add(action.key(), action.set());
|
||||
map_[action.key()] = action.set();
|
||||
break;
|
||||
case avl_fuzzer::Action::kDel:
|
||||
avl_ = avl_.Remove(action.key());
|
||||
map_.erase(action.key());
|
||||
break;
|
||||
case avl_fuzzer::Action::kGet: {
|
||||
auto* p = avl_.Lookup(action.key());
|
||||
auto it = map_.find(action.key());
|
||||
if (it == map_.end() && p != nullptr) abort();
|
||||
if (it != map_.end() && p == nullptr) abort();
|
||||
if (it != map_.end() && it->second != *p) abort();
|
||||
} break;
|
||||
case avl_fuzzer::Action::ACTION_NOT_SET:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,8 +63,38 @@ class Fuzzer {
|
|||
std::map<int, int> map_;
|
||||
};
|
||||
|
||||
template <typename RepeatedField>
|
||||
AVL<int, int> AvlFromProto(const RepeatedField& p) {
|
||||
AVL<int, int> a;
|
||||
for (const auto& kv : p) {
|
||||
a = a.Add(kv.key(), kv.value());
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
template <typename RepeatedField>
|
||||
std::map<int, int> MapFromProto(const RepeatedField& p) {
|
||||
std::map<int, int> a;
|
||||
for (const auto& kv : p) {
|
||||
a[kv.key()] = kv.value();
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
DEFINE_PROTO_FUZZER(const avl_fuzzer::Msg& msg) {
|
||||
grpc_core::Fuzzer().Run(msg);
|
||||
grpc_core::Fuzzer fuzzer;
|
||||
for (const auto& action : msg.actions()) {
|
||||
grpc_core::Fuzzer().Run(action);
|
||||
}
|
||||
|
||||
for (const auto& cmp : msg.compares()) {
|
||||
auto left_avl = grpc_core::AvlFromProto(cmp.left());
|
||||
auto left_map = grpc_core::MapFromProto(cmp.left());
|
||||
auto right_avl = grpc_core::AvlFromProto(cmp.right());
|
||||
auto right_map = grpc_core::MapFromProto(cmp.right());
|
||||
if ((left_avl == right_avl) != (left_map == right_map)) abort();
|
||||
if ((left_avl < right_avl) != (left_map < right_map)) abort();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,17 @@ message Action {
|
|||
}
|
||||
}
|
||||
|
||||
message KeyValue {
|
||||
int32 key = 1;
|
||||
int32 value = 2;
|
||||
}
|
||||
|
||||
message Compares {
|
||||
repeated KeyValue left = 1;
|
||||
repeated KeyValue right = 2;
|
||||
}
|
||||
|
||||
message Msg {
|
||||
repeated Action actions = 2;
|
||||
repeated Compares compares = 3;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
actions {
|
||||
del {
|
||||
}
|
||||
}
|
||||
compares {
|
||||
left {
|
||||
key: 50397184
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
compares {
|
||||
right {
|
||||
key: 805306368
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ licenses(["notice"])
|
|||
grpc_cc_test(
|
||||
name = "channel_args_test",
|
||||
srcs = ["channel_args_test.cc"],
|
||||
external_deps = ["gtest"],
|
||||
language = "C++",
|
||||
uses_polling = False,
|
||||
deps = [
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <grpc/grpc_security.h>
|
||||
#include <grpc/impl/codegen/grpc_types.h>
|
||||
#include <grpc/impl/codegen/log.h>
|
||||
|
|
@ -27,11 +29,101 @@
|
|||
|
||||
#include "src/core/lib/channel/channel_stack.h"
|
||||
#include "src/core/lib/gpr/useful.h"
|
||||
#include "src/core/lib/gprpp/ref_counted.h"
|
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h"
|
||||
#include "src/core/lib/iomgr/exec_ctx.h"
|
||||
#include "src/core/lib/surface/channel.h"
|
||||
#include "test/core/util/test_config.h"
|
||||
|
||||
static void test_create(void) {
|
||||
namespace grpc_core {
|
||||
|
||||
TEST(ChannelArgsTest, Noop) { ChannelArgs(); }
|
||||
|
||||
TEST(ChannelArgsTest, SetGetRemove) {
|
||||
const grpc_arg_pointer_vtable malloc_vtable = {
|
||||
// copy
|
||||
[](void* p) { return p; },
|
||||
// destroy
|
||||
[](void*) {},
|
||||
// equal
|
||||
[](void* p1, void* p2) { return QsortCompare(p1, p2); },
|
||||
};
|
||||
void* ptr = gpr_malloc(42);
|
||||
|
||||
ChannelArgs a;
|
||||
ChannelArgs b = a.Set("answer", 42);
|
||||
ChannelArgs c = b.Set("foo", "bar");
|
||||
ChannelArgs d = c.Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable));
|
||||
ChannelArgs e = d.Set("alpha", "beta");
|
||||
ChannelArgs f = e.Remove("answer");
|
||||
EXPECT_EQ(a.Get("answer"), nullptr);
|
||||
EXPECT_EQ(*b.Get("answer"), ChannelArgs::Value(42));
|
||||
EXPECT_EQ(*c.Get("answer"), ChannelArgs::Value(42));
|
||||
EXPECT_EQ(c.GetInt("answer"), 42);
|
||||
EXPECT_EQ(c.GetString("answer"), absl::nullopt);
|
||||
EXPECT_EQ(f.Get("answer"), nullptr);
|
||||
EXPECT_EQ(*c.Get("foo"), ChannelArgs::Value("bar"));
|
||||
EXPECT_EQ(c.GetString("foo"), "bar");
|
||||
EXPECT_EQ(c.GetString("answer"), absl::nullopt);
|
||||
EXPECT_EQ(*d.Get("ptr"),
|
||||
ChannelArgs::Value(ChannelArgs::Pointer(ptr, &malloc_vtable)));
|
||||
EXPECT_EQ(*e.Get("alpha"), ChannelArgs::Value("beta"));
|
||||
gpr_free(ptr);
|
||||
}
|
||||
|
||||
TEST(ChannelArgsTest, StoreRefCountedPtr) {
|
||||
struct Test : public RefCounted<Test> {
|
||||
explicit Test(int n) : n(n) {}
|
||||
int n;
|
||||
bool operator<(const Test& rhs) const { return n < rhs.n; }
|
||||
};
|
||||
auto p = MakeRefCounted<Test>(123);
|
||||
|
||||
ChannelArgs a;
|
||||
a = a.Set("test", std::move(p));
|
||||
EXPECT_EQ(a.GetPointer<Test>("test")->n, 123);
|
||||
}
|
||||
|
||||
TEST(ChannelArgsTest, ObjectApi) {
|
||||
struct MyFancyObject : public RefCounted<MyFancyObject> {
|
||||
explicit MyFancyObject(int n) : n(n) {}
|
||||
static absl::string_view ChannelArgName() {
|
||||
return "grpc.internal.my-fancy-object";
|
||||
}
|
||||
int n;
|
||||
bool operator<(const MyFancyObject& rhs) const { return n < rhs.n; }
|
||||
};
|
||||
auto p = MakeRefCounted<MyFancyObject>(42);
|
||||
ChannelArgs a;
|
||||
a = a.SetObject(std::move(p));
|
||||
EXPECT_EQ(a.GetObject<MyFancyObject>()->n, 42);
|
||||
}
|
||||
|
||||
TEST(ChannelArgsTest, ToAndFromC) {
|
||||
const grpc_arg_pointer_vtable malloc_vtable = {
|
||||
// copy
|
||||
[](void* p) { return p; },
|
||||
// destroy
|
||||
[](void*) {},
|
||||
// equal
|
||||
[](void* p1, void* p2) { return QsortCompare(p1, p2); },
|
||||
};
|
||||
void* ptr = gpr_malloc(42);
|
||||
ChannelArgs a = ChannelArgs()
|
||||
.Set("answer", 42)
|
||||
.Set("foo", "bar")
|
||||
.Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable))
|
||||
.Set("alpha", "beta");
|
||||
const grpc_channel_args* c = a.ToC();
|
||||
ChannelArgs b = ChannelArgs::FromC(c);
|
||||
grpc_channel_args_destroy(c);
|
||||
EXPECT_EQ(a, b);
|
||||
gpr_free(ptr);
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
TEST(GrpcChannelArgsTest, Create) {
|
||||
grpc_core::ExecCtx exec_ctx;
|
||||
grpc_arg to_add[2];
|
||||
grpc_channel_args* ch_args;
|
||||
|
|
@ -80,7 +172,7 @@ static int fake_pointer_cmp(void* a, void* b) {
|
|||
static const grpc_arg_pointer_vtable fake_pointer_arg_vtable = {
|
||||
fake_pointer_arg_copy, fake_pointer_arg_destroy, fake_pointer_cmp};
|
||||
|
||||
static void test_channel_create_with_args(void) {
|
||||
TEST(GrpcChannelArgsTest, ChannelCreateWithArgs) {
|
||||
grpc_arg client_a[3];
|
||||
|
||||
client_a[0] =
|
||||
|
|
@ -131,53 +223,7 @@ grpc_channel_args* mutate_channel_args(const char* target,
|
|||
return new_args;
|
||||
}
|
||||
|
||||
// Minimal stack should not have client_idle filter
|
||||
static bool channel_has_client_idle_filter(grpc_channel* c) {
|
||||
grpc_channel_stack* stack = grpc_channel_get_channel_stack(c);
|
||||
for (size_t i = 0; i < stack->count; i++) {
|
||||
if (strcmp(grpc_channel_stack_element(stack, i)->filter->name,
|
||||
"client_idle") == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void test_channel_create_with_global_mutator(void) {
|
||||
grpc_channel_args_set_client_channel_creation_mutator(mutate_channel_args);
|
||||
// We also add some custom args to make sure the ownership is correct.
|
||||
grpc_arg client_a[3];
|
||||
|
||||
client_a[0] =
|
||||
grpc_channel_arg_integer_create(const_cast<char*>("arg_int"), 0);
|
||||
client_a[1] = grpc_channel_arg_string_create(
|
||||
const_cast<char*>("arg_str"), const_cast<char*>("arg_str_val"));
|
||||
// allocated and adds custom pointer arg
|
||||
fake_class* fc = static_cast<fake_class*>(gpr_malloc(sizeof(fake_class)));
|
||||
fc->foo = 42;
|
||||
client_a[2] = grpc_channel_arg_pointer_create(
|
||||
const_cast<char*>("arg_pointer"), fc, &fake_pointer_arg_vtable);
|
||||
|
||||
// creates channels
|
||||
grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
|
||||
grpc_channel_credentials* creds = grpc_insecure_credentials_create();
|
||||
grpc_channel* c = grpc_channel_create("no_op_mutator", creds, &client_args);
|
||||
grpc_channel_credentials_release(creds);
|
||||
GPR_ASSERT(channel_has_client_idle_filter(c));
|
||||
grpc_channel_destroy(c);
|
||||
|
||||
grpc_channel_credentials* another_creds = grpc_insecure_credentials_create();
|
||||
c = grpc_channel_create("minimal_stack_mutator", another_creds, &client_args);
|
||||
grpc_channel_credentials_release(another_creds);
|
||||
GPR_ASSERT(channel_has_client_idle_filter(c) == false);
|
||||
grpc_channel_destroy(c);
|
||||
|
||||
gpr_free(fc);
|
||||
auto mutator = grpc_channel_args_get_client_channel_creation_mutator();
|
||||
GPR_ASSERT(mutator == &mutate_channel_args);
|
||||
}
|
||||
|
||||
static void test_server_create_with_args(void) {
|
||||
TEST(GrpcChannelArgsTest, TestServerCreateWithArgs) {
|
||||
grpc_arg server_a[3];
|
||||
|
||||
// adds integer arg
|
||||
|
|
@ -207,14 +253,10 @@ static void test_server_create_with_args(void) {
|
|||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
grpc::testing::TestEnvironment env(argc, argv);
|
||||
grpc_init();
|
||||
test_create();
|
||||
test_channel_create_with_args();
|
||||
test_server_create_with_args();
|
||||
// This has to be the last test.
|
||||
// TODO(markdroth): re-enable this test once client_idle is re-enabled
|
||||
// test_channel_create_with_global_mutator();
|
||||
auto r = RUN_ALL_TESTS();
|
||||
grpc_shutdown();
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1985,10 +1985,12 @@ src/core/lib/gprpp/global_config_generic.h \
|
|||
src/core/lib/gprpp/host_port.cc \
|
||||
src/core/lib/gprpp/host_port.h \
|
||||
src/core/lib/gprpp/manual_constructor.h \
|
||||
src/core/lib/gprpp/match.h \
|
||||
src/core/lib/gprpp/memory.h \
|
||||
src/core/lib/gprpp/mpscq.cc \
|
||||
src/core/lib/gprpp/mpscq.h \
|
||||
src/core/lib/gprpp/orphanable.h \
|
||||
src/core/lib/gprpp/overload.h \
|
||||
src/core/lib/gprpp/ref_counted.h \
|
||||
src/core/lib/gprpp/ref_counted_ptr.h \
|
||||
src/core/lib/gprpp/stat.h \
|
||||
|
|
|
|||
|
|
@ -1779,10 +1779,12 @@ src/core/lib/gprpp/global_config_generic.h \
|
|||
src/core/lib/gprpp/host_port.cc \
|
||||
src/core/lib/gprpp/host_port.h \
|
||||
src/core/lib/gprpp/manual_constructor.h \
|
||||
src/core/lib/gprpp/match.h \
|
||||
src/core/lib/gprpp/memory.h \
|
||||
src/core/lib/gprpp/mpscq.cc \
|
||||
src/core/lib/gprpp/mpscq.h \
|
||||
src/core/lib/gprpp/orphanable.h \
|
||||
src/core/lib/gprpp/overload.h \
|
||||
src/core/lib/gprpp/ref_counted.h \
|
||||
src/core/lib/gprpp/ref_counted_ptr.h \
|
||||
src/core/lib/gprpp/stat.h \
|
||||
|
|
|
|||
|
|
@ -525,30 +525,6 @@
|
|||
],
|
||||
"uses_polling": true
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
"ci_platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"cpu_cost": 1.0,
|
||||
"exclude_configs": [],
|
||||
"exclude_iomgrs": [],
|
||||
"flaky": false,
|
||||
"gtest": false,
|
||||
"language": "c",
|
||||
"name": "channel_args_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
@ -3303,6 +3279,30 @@
|
|||
],
|
||||
"uses_polling": true
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
"ci_platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"cpu_cost": 1.0,
|
||||
"exclude_configs": [],
|
||||
"exclude_iomgrs": [],
|
||||
"flaky": false,
|
||||
"gtest": true,
|
||||
"language": "c++",
|
||||
"name": "channel_args_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
|
|||
Loading…
Reference in New Issue