/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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. */ #pragma once #include <functional> #include <string> #include <vector> #include <folly/Likely.h> #include <folly/Range.h> #include <folly/settings/Types.h> #include <folly/settings/detail/SettingsImpl.h> namespace folly { namespace settings { class Snapshot; namespace detail { /** * @param TrivialPtr location of the small type storage. Optimization * for better inlining. */ template <class T, std::atomic<uint64_t>* TrivialPtr> class SettingWrapper { … }; /** * Optimization: fast-path on top of the Meyers singleton. Each * translation unit gets this code inlined, while the slow path * initialization code is not. We check the global pointer which * should only be initialized after the Meyers singleton. It's ok for * multiple calls to attempt to update the global pointer, as they * would be serialized on the Meyer's singleton initialization lock * anyway. * * Both FOLLY_SETTING_DECLARE and FOLLY_SETTING_DEFINE will provide * a copy of this function and we work around ODR by using different * overload types. * * Requires a trailing semicolon. */ #define FOLLY_DETAIL_SETTINGS_DEFINE_LOCAL_FUNC__( \ _project, _name, _Type, _overloadType) … } // namespace detail /** * Defines a setting. * * Settings are either mutable or immutable where mutable setting values can * change at runtime whereas immutable setting values can not be changed after * the setting project is frozen (see Immutables.h). * * FOLLY_SETTING_DEFINE() can only be placed in a single translation unit * and will be checked against accidental collisions. * * The setting API can be accessed via FOLLY_SETTING(project, name).<api_func>() * and is documented in the Setting class. * * All settings for a common namespace; (project, name) must be unique * for the whole program. Collisions are verified at runtime on * program startup. * * @param _project Project identifier, can only contain [a-zA-Z0-9] * @param _name setting name within the project, can only contain [_a-zA-Z0-9]. * The string "<project>_<name>" must be unique for the whole program. * @param _Type setting value type * @param _def default value for the setting * @param _mut mutability of the setting * @param _desc setting documentation */ #define FOLLY_SETTING_DEFINE(_project, _name, _Type, _def, _mut, _desc) … /** * Declares a setting that's defined elsewhere. */ #define FOLLY_SETTING_DECLARE(_project, _name, _Type) … /** * Accesses a defined setting. * Rationale for the macro: * 1) Searchability, all settings access is done via FOLLY_SETTING(...) * 2) Prevents omitting trailing () by accident, which could * lead to bugs like `auto value = *FOLLY_SETTING_project_name;`, * which compiles but dereferences the function pointer instead of * the setting itself. */ #define FOLLY_SETTING(_project, _name) … /** * @return If the setting exists, returns the current settings metadata. * Empty Optional otherwise. */ Optional<SettingMetadata> getSettingsMeta(StringPiece settingName); /** * @return SettingMetadata for all registered settings in the process. */ std::vector<SettingMetadata> getAllSettingsMeta(); namespace detail { /** * Like SettingWrapper, but checks against any values saved/updated in a * snapshot. */ template <class T> class SnapshotSettingWrapper { … }; } // namespace detail /** * Captures the current state of all setting values and allows * updating multiple settings at once, with verification and rollback. * * A single snapshot cannot be used concurrently from different * threads. Multiple concurrent snapshots are safe. Passing a single * snapshot from one thread to another is safe as long as the user * properly synchronizes the handoff. * * Example usage: * * folly::settings::Snapshot snapshot; * // FOLLY_SETTING(project, name) refers to the globally visible value * // snapshot(FOLLY_SETTING(project, name)) refers to the value saved in the * // snapshot * FOLLY_SETTING(project, name).set(new_value); * assert(*FOLLY_SETTING(project, name) == new_value); * assert(*snapshot(FOLLY_SETTING(project, name)) == old_value); * * snapshot(FOLLY_SETTING(project, name)).set(new_snapshot_value); * assert(*FOLLY_SETTING(project, name) == new_value); * assert(*snapshot(FOLLY_SETTING(project, name)) == new_snapshot_value); * * // At this point we can discard the snapshot and forget new_snapshot_value, * // or choose to publish: * snapshot.publish(); * assert(*FOLLY_SETTING(project, name) == new_snapshot_value); */ class Snapshot final : public detail::SnapshotBase { … }; namespace detail { template <class T> inline const T& SnapshotSettingWrapper<T>::operator*() const { … } template <class T, std::atomic<uint64_t>* TrivialPtr> inline std::conditional_t<IsSmallPOD<T>::value, T, const T&> SettingWrapper<T, TrivialPtr>::value(const Snapshot& snapshot) const { … } template <class T, std::atomic<uint64_t>* TrivialPtr> StringPiece SettingWrapper<T, TrivialPtr>::updateReason( const Snapshot& snapshot) const { … } } // namespace detail } // namespace settings } // namespace folly