Settings.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /*
  2. * Copyright 2018-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <functional>
  18. #include <string>
  19. #include <folly/Range.h>
  20. #include <folly/experimental/settings/SettingsMetadata.h>
  21. #include <folly/experimental/settings/detail/SettingsImpl.h>
  22. namespace folly {
  23. namespace settings {
  24. class Snapshot;
  25. namespace detail {
  26. /**
  27. * @param TrivialPtr location of the small type storage. Optimization
  28. * for better inlining.
  29. */
  30. template <class T, std::atomic<uint64_t>* TrivialPtr>
  31. class SettingWrapper {
  32. public:
  33. /**
  34. * Returns the setting's current value.
  35. *
  36. * As an optimization, returns by value for small types, and by
  37. * const& for larger types. Note that the returned reference is not
  38. * guaranteed to be long-lived and should not be saved anywhere. In
  39. * particular, a set() call might invalidate a reference obtained
  40. * here after some amount of time (on the order of minutes).
  41. */
  42. std::conditional_t<IsSmallPOD<T>::value, T, const T&> operator*() const {
  43. return core_.getWithHint(*TrivialPtr);
  44. }
  45. const T* operator->() const {
  46. return &core_.getSlow().value;
  47. }
  48. /**
  49. * Atomically updates the setting's current value. Will invalidate
  50. * any previous calls to operator*() after some amount of time (on
  51. * the order of minutes).
  52. *
  53. * @param reason Will be stored with the current value, useful for debugging.
  54. * @throws std::runtime_error If we can't convert t to string.
  55. */
  56. void set(const T& t, StringPiece reason = "api") {
  57. core_.set(t, reason);
  58. }
  59. /**
  60. * Returns the default value this setting was constructed with.
  61. * NOTE: SettingsMetadata is type-agnostic, so it only stores the string
  62. * representation of the default value. This method returns the
  63. * actual value that was passed on construction.
  64. */
  65. const T& defaultValue() const {
  66. return core_.defaultValue();
  67. }
  68. explicit SettingWrapper(SettingCore<T>& core) : core_(core) {}
  69. private:
  70. SettingCore<T>& core_;
  71. friend class folly::settings::Snapshot;
  72. };
  73. /* C++20 has std::type_indentity */
  74. template <class T>
  75. struct TypeIdentity {
  76. using type = T;
  77. };
  78. template <class T>
  79. using TypeIdentityT = typename TypeIdentity<T>::type;
  80. /**
  81. * Optimization: fast-path on top of the Meyers singleton. Each
  82. * translation unit gets this code inlined, while the slow path
  83. * initialization code is not. We check the global pointer which
  84. * should only be initialized after the Meyers singleton. It's ok for
  85. * multiple calls to attempt to update the global pointer, as they
  86. * would be serialized on the Meyer's singleton initialization lock
  87. * anyway.
  88. *
  89. * Both FOLLY_SETTING_DECLARE and FOLLY_SETTING_DEFINE will provide
  90. * a copy of this function and we work around ODR by using different
  91. * overload types.
  92. *
  93. * Requires a trailing semicolon.
  94. */
  95. #define FOLLY_SETTINGS_DEFINE_LOCAL_FUNC__( \
  96. _project, _name, _Type, _overloadType) \
  97. extern std::atomic<folly::settings::detail::SettingCore<_Type>*> \
  98. FOLLY_SETTINGS_CACHE__##_project##_##_name; \
  99. extern std::atomic<uint64_t> FOLLY_SETTINGS_TRIVIAL__##_project##_##_name; \
  100. folly::settings::detail::SettingCore<_Type>& \
  101. FOLLY_SETTINGS_FUNC__##_project##_##_name(); \
  102. FOLLY_ALWAYS_INLINE auto FOLLY_SETTINGS_LOCAL_FUNC__##_project##_##_name( \
  103. _overloadType) { \
  104. if (!FOLLY_SETTINGS_CACHE__##_project##_##_name.load()) { \
  105. FOLLY_SETTINGS_CACHE__##_project##_##_name.store( \
  106. &FOLLY_SETTINGS_FUNC__##_project##_##_name()); \
  107. } \
  108. return folly::settings::detail:: \
  109. SettingWrapper<_Type, &FOLLY_SETTINGS_TRIVIAL__##_project##_##_name>( \
  110. *FOLLY_SETTINGS_CACHE__##_project##_##_name.load()); \
  111. } \
  112. /* This is here just to force a semicolon */ \
  113. folly::settings::detail::SettingCore<_Type>& \
  114. FOLLY_SETTINGS_FUNC__##_project##_##_name()
  115. } // namespace detail
  116. /**
  117. * Defines a setting.
  118. *
  119. * FOLLY_SETTING_DEFINE() can only be placed in a single translation unit
  120. * and will be checked against accidental collisions.
  121. *
  122. * The setting API can be accessed via FOLLY_SETTING(project, name).<api_func>()
  123. * and is documented in the Setting class.
  124. *
  125. * All settings for a common namespace; (project, name) must be unique
  126. * for the whole program. Collisions are verified at runtime on
  127. * program startup.
  128. *
  129. * @param _project Project identifier, can only contain [a-zA-Z0-9]
  130. * @param _name setting name within the project, can only contain [_a-zA-Z0-9].
  131. * The string "<project>_<name>" must be unique for the whole program.
  132. * @param _Type setting value type
  133. * @param _def default value for the setting
  134. * @param _desc setting documentation
  135. */
  136. #define FOLLY_SETTING_DEFINE(_project, _name, _Type, _def, _desc) \
  137. /* Fastpath optimization, see notes in FOLLY_SETTINGS_DEFINE_LOCAL_FUNC__. \
  138. Aggregate all off these together in a single section for better TLB \
  139. and cache locality. */ \
  140. __attribute__((__section__(".folly.settings.cache"))) \
  141. std::atomic<folly::settings::detail::SettingCore<_Type>*> \
  142. FOLLY_SETTINGS_CACHE__##_project##_##_name; \
  143. /* Location for the small value cache (if _Type is small and trivial). \
  144. Intentionally located right after the pointer cache above to take \
  145. advantage of the prefetching */ \
  146. __attribute__((__section__(".folly.settings.cache"))) std::atomic<uint64_t> \
  147. FOLLY_SETTINGS_TRIVIAL__##_project##_##_name; \
  148. /* Meyers singleton to avoid SIOF */ \
  149. FOLLY_NOINLINE folly::settings::detail::SettingCore<_Type>& \
  150. FOLLY_SETTINGS_FUNC__##_project##_##_name() { \
  151. static folly::Indestructible<folly::settings::detail::SettingCore<_Type>> \
  152. setting( \
  153. folly::settings::SettingMetadata{ \
  154. #_project, #_name, #_Type, typeid(_Type), #_def, _desc}, \
  155. folly::settings::detail::TypeIdentityT<_Type>{_def}, \
  156. FOLLY_SETTINGS_TRIVIAL__##_project##_##_name); \
  157. return *setting; \
  158. } \
  159. /* Ensure the setting is registered even if not used in program */ \
  160. auto& FOLLY_SETTINGS_INIT__##_project##_##_name = \
  161. FOLLY_SETTINGS_FUNC__##_project##_##_name(); \
  162. FOLLY_SETTINGS_DEFINE_LOCAL_FUNC__(_project, _name, _Type, char)
  163. /**
  164. * Declares a setting that's defined elsewhere.
  165. */
  166. #define FOLLY_SETTING_DECLARE(_project, _name, _Type) \
  167. FOLLY_SETTINGS_DEFINE_LOCAL_FUNC__(_project, _name, _Type, int)
  168. /**
  169. * Accesses a defined setting.
  170. * Rationale for the macro:
  171. * 1) Searchability, all settings access is done via FOLLY_SETTING(...)
  172. * 2) Prevents omitting trailing () by accident, which could
  173. * lead to bugs like `auto value = *FOLLY_SETTING_project_name;`,
  174. * which compiles but dereferences the function pointer instead of
  175. * the setting itself.
  176. */
  177. #define FOLLY_SETTING(_project, _name) \
  178. FOLLY_SETTINGS_LOCAL_FUNC__##_project##_##_name(0)
  179. /**
  180. * @return If the setting exists, returns the current settings metadata.
  181. * Empty Optional otherwise.
  182. */
  183. Optional<SettingMetadata> getSettingsMeta(StringPiece settingName);
  184. namespace detail {
  185. /**
  186. * Like SettingWrapper, but checks against any values saved/updated in a
  187. * snapshot.
  188. */
  189. template <class T>
  190. class SnapshotSettingWrapper {
  191. public:
  192. /**
  193. * The references are only valid for the duration of the snapshot's
  194. * lifetime or until the setting has been updated in the snapshot,
  195. * whichever happens earlier.
  196. */
  197. const T& operator*() const;
  198. const T* operator->() const {
  199. return &operator*();
  200. }
  201. /**
  202. * Update the setting in the snapshot, the effects are not visible
  203. * in this snapshot.
  204. */
  205. void set(const T& t, StringPiece reason = "api") {
  206. core_.set(t, reason, &snapshot_);
  207. }
  208. private:
  209. Snapshot& snapshot_;
  210. SettingCore<T>& core_;
  211. friend class folly::settings::Snapshot;
  212. SnapshotSettingWrapper(Snapshot& snapshot, SettingCore<T>& core)
  213. : snapshot_(snapshot), core_(core) {}
  214. };
  215. } // namespace detail
  216. /**
  217. * Captures the current state of all setting values and allows
  218. * updating multiple settings at once, with verification and rollback.
  219. *
  220. * A single snapshot cannot be used concurrently from different
  221. * threads. Multiple concurrent snapshots are safe. Passing a single
  222. * snapshot from one thread to another is safe as long as the user
  223. * properly synchronizes the handoff.
  224. *
  225. * Example usage:
  226. *
  227. * folly::settings::Snapshot snapshot;
  228. * // FOLLY_SETTING(project, name) refers to the globally visible value
  229. * // snapshot(FOLLY_SETTING(project, name)) refers to the value saved in the
  230. * // snapshot
  231. * FOLLY_SETTING(project, name).set(new_value);
  232. * assert(*FOLLY_SETTING(project, name) == new_value);
  233. * assert(*snapshot(FOLLY_SETTING(project, name)) == old_value);
  234. *
  235. * snapshot(FOLLY_SETTING(project, name)).set(new_snapshot_value);
  236. * assert(*FOLLY_SETTING(project, name) == new_value);
  237. * assert(*snapshot(FOLLY_SETTING(project, name)) == new_snapshot_value);
  238. *
  239. * // At this point we can discard the snapshot and forget new_snapshot_value,
  240. * // or choose to publish:
  241. * snapshot.publish();
  242. * assert(*FOLLY_SETTING(project, name) == new_snapshot_value);
  243. */
  244. class Snapshot final : public detail::SnapshotBase {
  245. public:
  246. /**
  247. * Wraps a global FOLLY_SETTING(a, b) and returns a snapshot-local wrapper.
  248. */
  249. template <class T, std::atomic<uint64_t>* P>
  250. detail::SnapshotSettingWrapper<T> operator()(
  251. detail::SettingWrapper<T, P>&& setting) {
  252. return detail::SnapshotSettingWrapper<T>(*this, setting.core_);
  253. }
  254. /**
  255. * Returns a snapshot of all current setting values.
  256. * Global settings changes will not be visible in the snapshot, and vice
  257. * versa.
  258. */
  259. Snapshot() = default;
  260. /**
  261. * Apply all settings updates from this snapshot to the global state
  262. * unconditionally.
  263. */
  264. void publish() override;
  265. /**
  266. * Look up a setting by name, and update the value from a string
  267. * representation.
  268. *
  269. * @returns True if the setting was successfully updated, false if no setting
  270. * with that name was found.
  271. * @throws std::runtime_error If there's a conversion error.
  272. */
  273. bool setFromString(
  274. StringPiece settingName,
  275. StringPiece newValue,
  276. StringPiece reason) override;
  277. /**
  278. * @return If the setting exists, the current setting information.
  279. * Empty Optional otherwise.
  280. */
  281. Optional<SettingsInfo> getAsString(StringPiece settingName) const override;
  282. /**
  283. * Reset the value of the setting identified by name to its default value.
  284. * The reason will be set to "default".
  285. *
  286. * @return True if the setting was reset, false if the setting is not found.
  287. */
  288. bool resetToDefault(StringPiece settingName) override;
  289. /**
  290. * Iterates over all known settings and calls
  291. * func(meta, to<string>(value), reason) for each.
  292. */
  293. void forEachSetting(const std::function<
  294. void(const SettingMetadata&, StringPiece, StringPiece)>&
  295. func) const override;
  296. private:
  297. template <typename T>
  298. friend class detail::SnapshotSettingWrapper;
  299. };
  300. namespace detail {
  301. template <class T>
  302. inline const T& SnapshotSettingWrapper<T>::operator*() const {
  303. return snapshot_.get(core_).value;
  304. }
  305. } // namespace detail
  306. } // namespace settings
  307. } // namespace folly