First stab at config framework (#27014)
* First stab at config framework * Automated change: Fix sanity tests * add test for threaded initialization * better test * clang format * better filenames * Automated change: Fix sanity tests Co-authored-by: ctiller <ctiller@users.noreply.github.com>
This commit is contained in:
parent
f5d3ed2db1
commit
cad2255d8c
14
BUILD
14
BUILD
|
|
@ -783,6 +783,20 @@ grpc_cc_library(
|
|||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "config",
|
||||
srcs = [
|
||||
"src/core/lib/config/core_configuration.cc",
|
||||
],
|
||||
language = "c++",
|
||||
public_hdrs = [
|
||||
"src/core/lib/config/core_configuration.h",
|
||||
],
|
||||
deps = [
|
||||
"gpr_platform",
|
||||
],
|
||||
)
|
||||
|
||||
grpc_cc_library(
|
||||
name = "debug_location",
|
||||
language = "c++",
|
||||
|
|
|
|||
|
|
@ -843,6 +843,7 @@ if(gRPC_BUILD_TESTS)
|
|||
add_dependencies(buildtests_cxx connectivity_state_test)
|
||||
add_dependencies(buildtests_cxx context_allocator_end2end_test)
|
||||
add_dependencies(buildtests_cxx context_list_test)
|
||||
add_dependencies(buildtests_cxx core_configuration_test)
|
||||
add_dependencies(buildtests_cxx delegating_channel_test)
|
||||
add_dependencies(buildtests_cxx destroy_grpclb_channel_with_active_connect_stress_test)
|
||||
add_dependencies(buildtests_cxx dual_ref_counted_test)
|
||||
|
|
@ -10233,6 +10234,41 @@ target_link_libraries(context_list_test
|
|||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
add_executable(core_configuration_test
|
||||
src/core/lib/config/core_configuration.cc
|
||||
test/core/config/core_configuration_test.cc
|
||||
third_party/googletest/googletest/src/gtest-all.cc
|
||||
third_party/googletest/googlemock/src/gmock-all.cc
|
||||
)
|
||||
|
||||
target_include_directories(core_configuration_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(core_configuration_test
|
||||
${_gRPC_PROTOBUF_LIBRARIES}
|
||||
${_gRPC_ALLTARGETS_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
endif()
|
||||
if(gRPC_BUILD_TESTS)
|
||||
|
||||
|
|
|
|||
|
|
@ -5119,6 +5119,17 @@ targets:
|
|||
deps:
|
||||
- grpc_test_util
|
||||
uses_polling: false
|
||||
- name: core_configuration_test
|
||||
gtest: true
|
||||
build: test
|
||||
language: c++
|
||||
headers:
|
||||
- src/core/lib/config/core_configuration.h
|
||||
src:
|
||||
- src/core/lib/config/core_configuration.cc
|
||||
- test/core/config/core_configuration_test.cc
|
||||
deps: []
|
||||
uses_polling: false
|
||||
- name: delegating_channel_test
|
||||
gtest: true
|
||||
build: test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2021 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/impl/codegen/port_platform.h>
|
||||
|
||||
#include "src/core/lib/config/core_configuration.h"
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
std::atomic<CoreConfiguration*> CoreConfiguration::config_;
|
||||
|
||||
CoreConfiguration::Builder::Builder() = default;
|
||||
|
||||
CoreConfiguration* CoreConfiguration::Builder::Build() {
|
||||
return new CoreConfiguration;
|
||||
}
|
||||
|
||||
CoreConfiguration::CoreConfiguration() = default;
|
||||
|
||||
const CoreConfiguration& CoreConfiguration::BuildNewAndMaybeSet() {
|
||||
// Construct builder, pass it up to code that knows about build configuration
|
||||
Builder builder;
|
||||
BuildCoreConfiguration(&builder);
|
||||
// Use builder to construct a confguration
|
||||
CoreConfiguration* p = builder.Build();
|
||||
// Try to set configuration global - it's possible another thread raced us
|
||||
// here, in which case we drop the work we did and use the one that got set
|
||||
// first
|
||||
CoreConfiguration* expected = nullptr;
|
||||
if (!config_.compare_exchange_strong(expected, p,
|
||||
std::memory_order_release)) {
|
||||
delete p;
|
||||
return *expected;
|
||||
}
|
||||
return *p;
|
||||
}
|
||||
|
||||
void CoreConfiguration::Reset() {
|
||||
delete config_.exchange(nullptr, std::memory_order_acquire);
|
||||
}
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2021 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_LIB_CONFIG_CORE_CONFIGURATION_H
|
||||
#define GRPC_CORE_LIB_CONFIG_CORE_CONFIGURATION_H
|
||||
|
||||
#include <grpc/impl/codegen/port_platform.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// Global singleton that stores library configuration - factories, etc...
|
||||
// that plugins might choose to extend.
|
||||
class CoreConfiguration {
|
||||
public:
|
||||
CoreConfiguration(const CoreConfiguration&) = delete;
|
||||
CoreConfiguration& operator=(const CoreConfiguration&) = delete;
|
||||
|
||||
// Builder is passed to plugins, etc... at initialization time to collect
|
||||
// their configuration and assemble the published CoreConfiguration.
|
||||
class Builder {
|
||||
public:
|
||||
private:
|
||||
friend class CoreConfiguration;
|
||||
|
||||
Builder();
|
||||
CoreConfiguration* Build();
|
||||
};
|
||||
|
||||
// Lifetime methods
|
||||
|
||||
// Get the core configuration; if it does not exist, create it.
|
||||
static const CoreConfiguration& Get() {
|
||||
CoreConfiguration* p = config_.load(std::memory_order_acquire);
|
||||
if (p != nullptr) {
|
||||
return *p;
|
||||
}
|
||||
return BuildNewAndMaybeSet();
|
||||
}
|
||||
|
||||
// Drop the core configuration. Users must ensure no other threads are
|
||||
// accessing the configuration.
|
||||
static void Reset();
|
||||
|
||||
// Accessors
|
||||
|
||||
private:
|
||||
CoreConfiguration();
|
||||
|
||||
// Create a new CoreConfiguration, and either set it or throw it away.
|
||||
// We allow multiple CoreConfiguration's to be created in parallel.
|
||||
static const CoreConfiguration& BuildNewAndMaybeSet();
|
||||
|
||||
// The configuration
|
||||
static std::atomic<CoreConfiguration*> config_;
|
||||
};
|
||||
|
||||
extern void BuildCoreConfiguration(CoreConfiguration::Builder* builder);
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_LIB_CONFIG_CORE_CONFIGURATION_H */
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2021 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.
|
||||
|
||||
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
grpc_package(name = "test/core/config")
|
||||
|
||||
grpc_cc_test(
|
||||
name = "core_configuration_test",
|
||||
srcs = ["core_configuration_test.cc"],
|
||||
external_deps = ["gtest"],
|
||||
language = "c++",
|
||||
uses_polling = False,
|
||||
deps = [
|
||||
"//:config",
|
||||
"//test/core/util:grpc_suppressions",
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2021 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 "src/core/lib/config/core_configuration.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
namespace grpc_core {
|
||||
|
||||
// Allow substitution of config builder - in real code this would iterate
|
||||
// through all plugins
|
||||
namespace testing {
|
||||
using ConfigBuilderFunction = std::function<void(CoreConfiguration::Builder*)>;
|
||||
static ConfigBuilderFunction g_mock_builder;
|
||||
} // namespace testing
|
||||
|
||||
void BuildCoreConfiguration(CoreConfiguration::Builder* builder) {
|
||||
::grpc_core::testing::g_mock_builder(builder);
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
// Helper for testing - clear out any state, rebuild configuration with fn being
|
||||
// the initializer
|
||||
void InitConfigWithBuilder(ConfigBuilderFunction fn) {
|
||||
CoreConfiguration::Reset();
|
||||
g_mock_builder = fn;
|
||||
CoreConfiguration::Get();
|
||||
g_mock_builder = nullptr;
|
||||
}
|
||||
|
||||
TEST(ConfigTest, NoopConfig) {
|
||||
InitConfigWithBuilder([](CoreConfiguration::Builder*) {});
|
||||
CoreConfiguration::Get();
|
||||
}
|
||||
|
||||
TEST(ConfigTest, ThreadedInit) {
|
||||
CoreConfiguration::Reset();
|
||||
g_mock_builder = [](CoreConfiguration::Builder*) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
};
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(64);
|
||||
for (int i = 0; i < 64; i++) {
|
||||
threads.push_back(std::thread([]() { CoreConfiguration::Get(); }));
|
||||
}
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
}
|
||||
g_mock_builder = nullptr;
|
||||
CoreConfiguration::Get();
|
||||
}
|
||||
} // namespace testing
|
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
@ -4369,6 +4369,30 @@
|
|||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
"ci_platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"cpu_cost": 1.0,
|
||||
"exclude_configs": [],
|
||||
"exclude_iomgrs": [],
|
||||
"flaky": false,
|
||||
"gtest": true,
|
||||
"language": "c++",
|
||||
"name": "core_configuration_test",
|
||||
"platforms": [
|
||||
"linux",
|
||||
"mac",
|
||||
"posix",
|
||||
"windows"
|
||||
],
|
||||
"uses_polling": false
|
||||
},
|
||||
{
|
||||
"args": [],
|
||||
"benchmark": false,
|
||||
|
|
|
|||
Loading…
Reference in New Issue