proxygen
SettingsImpl.h
Go to the documentation of this file.
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 
18 #include <memory>
19 #include <mutex>
20 #include <string>
21 #include <typeindex>
22 
23 #include <folly/CachelinePadded.h>
24 #include <folly/Conv.h>
25 #include <folly/Range.h>
26 #include <folly/SharedMutex.h>
27 #include <folly/ThreadLocal.h>
29 
30 namespace folly {
31 namespace settings {
32 namespace detail {
33 
37 template <class T>
38 struct IsSmallPOD
39  : std::integral_constant<
40  bool,
41  std::is_trivial<T>::value && sizeof(T) <= sizeof(uint64_t)> {};
42 
43 template <class T>
44 struct SettingContents {
45  std::string updateReason;
46  T value;
47 
48  template <class... Args>
49  SettingContents(std::string _reason, Args&&... args)
50  : updateReason(std::move(_reason)), value(std::forward<Args>(args)...) {}
51 };
52 
53 class SnapshotBase;
54 
55 class SettingCoreBase {
56  public:
57  using Key = intptr_t;
58  using Version = uint64_t;
59 
60  virtual void setFromString(
61  StringPiece newValue,
62  StringPiece reason,
63  SnapshotBase* snapshot) = 0;
64  virtual std::pair<std::string, std::string> getAsString(
65  const SnapshotBase* snapshot) const = 0;
66  virtual void resetToDefault(SnapshotBase* snapshot) = 0;
67  virtual const SettingMetadata& meta() const = 0;
68  virtual ~SettingCoreBase() {}
69 
73  Key getKey() const {
74  return reinterpret_cast<Key>(this);
75  }
76 };
77 
78 void registerSetting(SettingCoreBase& core);
79 
83 SettingCoreBase::Version nextGlobalVersion();
84 
85 template <class T>
86 class SettingCore;
87 
91 class BoxedValue {
92  public:
93  BoxedValue() = default;
94 
98  template <class T>
99  explicit BoxedValue(const SettingContents<T>& value)
100  : value_(std::make_shared<SettingContents<T>>(value)) {}
101 
106  template <class T>
107  BoxedValue(const T& value, StringPiece reason, SettingCore<T>& core)
108  : value_(std::make_shared<SettingContents<T>>(reason.str(), value)),
109  publish_([value = value_, &core]() {
110  auto& contents = BoxedValue::unboxImpl<T>(value.get());
111  core.set(contents.value, contents.updateReason);
112  }) {}
113 
117  template <class T>
118  const SettingContents<T>& unbox() const {
119  return BoxedValue::unboxImpl<T>(value_.get());
120  }
121 
125  void publish() {
126  if (publish_) {
127  publish_();
128  }
129  }
130 
131  private:
132  std::shared_ptr<void> value_;
133  std::function<void()> publish_;
134 
135  template <class T>
136  static const SettingContents<T>& unboxImpl(void* value) {
137  return *static_cast<const SettingContents<T>*>(value);
138  }
139 };
140 
145 void saveValueForOutstandingSnapshots(
146  SettingCoreBase::Key settingKey,
147  SettingCoreBase::Version version,
148  const BoxedValue& value);
149 
153 const BoxedValue* getSavedValue(
154  SettingCoreBase::Key key,
155  SettingCoreBase::Version at);
156 
157 class SnapshotBase {
158  public:
162  using SettingsInfo = std::pair<std::string, std::string>;
163 
168  virtual void publish() = 0;
169 
178  virtual bool setFromString(
179  StringPiece settingName,
180  StringPiece newValue,
181  StringPiece reason) = 0;
182 
187  virtual Optional<SettingsInfo> getAsString(StringPiece settingName) const = 0;
188 
195  virtual bool resetToDefault(StringPiece settingName) = 0;
196 
201  virtual void forEachSetting(
202  const std::function<
203  void(const SettingMetadata&, StringPiece, StringPiece)>& func)
204  const = 0;
205 
206  virtual ~SnapshotBase();
207 
208  protected:
209  detail::SettingCoreBase::Version at_;
210  std::unordered_map<detail::SettingCoreBase::Key, detail::BoxedValue>
211  snapshotValues_;
212 
213  template <typename T>
214  friend class SettingCore;
215 
216  SnapshotBase();
217 
218  template <class T>
219  const SettingContents<T>& get(const detail::SettingCore<T>& core) const {
220  auto it = snapshotValues_.find(core.getKey());
221  if (it != snapshotValues_.end()) {
222  return it->second.template unbox<T>();
223  }
224  auto savedValue = detail::getSavedValue(core.getKey(), at_);
225  if (savedValue) {
226  return savedValue->template unbox<T>();
227  }
228  return core.getSlow();
229  }
230 
231  template <class T>
232  void set(detail::SettingCore<T>& core, const T& t, StringPiece reason) {
233  snapshotValues_[core.getKey()] = detail::BoxedValue(t, reason, core);
234  }
235 };
236 
237 template <class T>
240  return T(newValue);
241 }
242 template <class T>
245  return to<T>(newValue);
246 }
247 
248 template <class T>
249 class SettingCore : public SettingCoreBase {
250  public:
251  using Contents = SettingContents<T>;
252 
254  StringPiece newValue,
255  StringPiece reason,
256  SnapshotBase* snapshot) override {
257  set(convertOrConstruct<T>(newValue), reason.str(), snapshot);
258  }
259 
260  std::pair<std::string, std::string> getAsString(
261  const SnapshotBase* snapshot) const override {
262  auto& contents = snapshot ? snapshot->get(*this) : getSlow();
263  return std::make_pair(
264  to<std::string>(contents.value), contents.updateReason);
265  }
266 
267  void resetToDefault(SnapshotBase* snapshot) override {
268  set(defaultValue_, "default", snapshot);
269  }
270 
271  const SettingMetadata& meta() const override {
272  return meta_;
273  }
274 
282  std::atomic<uint64_t>& trivialStorage) const {
283  return getImpl(IsSmallPOD<T>(), trivialStorage);
284  }
285  const SettingContents<T>& getSlow() const {
286  return *tlValue();
287  }
288  /***
289  * SmallPOD version: just read the global atomic
290  */
291  T getImpl(std::true_type, std::atomic<uint64_t>& trivialStorage) const {
292  uint64_t v = trivialStorage.load();
293  T t;
294  std::memcpy(&t, &v, sizeof(T));
295  return t;
296  }
297 
301  const T& getImpl(std::false_type, std::atomic<uint64_t>& /* ignored */)
302  const {
303  return const_cast<SettingCore*>(this)->tlValue()->value;
304  }
305 
306  void set(const T& t, StringPiece reason, SnapshotBase* snapshot = nullptr) {
307  /* Check that we can still display it (will throw otherwise) */
308  to<std::string>(t);
309 
310  if (snapshot) {
311  snapshot->set(*this, t, reason);
312  return;
313  }
314 
315  SharedMutex::WriteHolder lg(globalLock_);
316 
317  if (globalValue_) {
319  getKey(), *settingVersion_, BoxedValue(*globalValue_));
320  }
321  globalValue_ = std::make_shared<Contents>(reason.str(), t);
322  if (IsSmallPOD<T>::value) {
323  uint64_t v = 0;
324  std::memcpy(&v, &t, sizeof(T));
325  trivialStorage_.store(v);
326  }
327  *settingVersion_ = nextGlobalVersion();
328  }
329 
330  const T& defaultValue() const {
331  return defaultValue_;
332  }
333 
335  SettingMetadata meta,
336  T defaultValue,
337  std::atomic<uint64_t>& trivialStorage)
338  : meta_(std::move(meta)),
339  defaultValue_(std::move(defaultValue)),
340  trivialStorage_(trivialStorage),
341  localValue_([]() {
342  return new CachelinePadded<
343  std::pair<Version, std::shared_ptr<Contents>>>(0, nullptr);
344  }) {
345  set(defaultValue_, "default");
346  registerSetting(*this);
347  }
348 
349  private:
351  const T defaultValue_;
352 
354  std::shared_ptr<Contents> globalValue_;
355 
356  std::atomic<uint64_t>& trivialStorage_;
357 
358  /* Thread local versions start at 0, this will force a read on first access.
359  */
361 
364 
365  FOLLY_ALWAYS_INLINE const std::shared_ptr<Contents>& tlValue() const {
366  auto& value = **localValue_;
367  if (LIKELY(value.first == *settingVersion_)) {
368  return value.second;
369  }
370  return tlValueSlow();
371  }
372  FOLLY_NOINLINE const std::shared_ptr<Contents>& tlValueSlow() const {
373  auto& value = **localValue_;
374  while (value.first < *settingVersion_) {
375  /* If this destroys the old value, do it without holding the lock */
376  value.second.reset();
377  SharedMutex::ReadHolder lg(globalLock_);
378  value.first = *settingVersion_;
379  value.second = globalValue_;
380  }
381  return value.second;
382  }
383 };
384 
385 } // namespace detail
386 } // namespace settings
387 } // namespace folly
SettingCoreBase::Version nextGlobalVersion()
Definition: Settings.cpp:125
void set(const T &t, StringPiece reason, SnapshotBase *snapshot=nullptr)
Definition: SettingsImpl.h:306
void setFromString(StringPiece newValue, StringPiece reason, SnapshotBase *snapshot) override
Definition: SettingsImpl.h:253
std::string str() const
Definition: Range.h:591
#define FOLLY_ALWAYS_INLINE
Definition: CPortability.h:151
SettingCore(SettingMetadata meta, T defaultValue, std::atomic< uint64_t > &trivialStorage)
Definition: SettingsImpl.h:334
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
#define LIKELY(x)
Definition: Likely.h:47
STL namespace.
folly::std T
static http_parser_settings settings
Definition: test.c:1529
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
const SettingMetadata & meta() const override
Definition: SettingsImpl.h:271
bool_constant< true > true_type
Definition: gtest-port.h:2210
std::atomic< uint64_t > & trivialStorage_
Definition: SettingsImpl.h:356
void saveValueForOutstandingSnapshots(SettingCoreBase::Key settingKey, SettingCoreBase::Version version, const BoxedValue &value)
Definition: Settings.cpp:129
#define FOLLY_NOINLINE
Definition: CPortability.h:142
void resetToDefault(SnapshotBase *snapshot) override
Definition: SettingsImpl.h:267
FOLLY_ALWAYS_INLINE const std::shared_ptr< Contents > & tlValue() const
Definition: SettingsImpl.h:365
const BoxedValue *FOLLY_NULLABLE getSavedValue(SettingCoreBase::Key settingKey, SettingCoreBase::Version at)
Definition: Settings.cpp:142
ThreadLocal< CachelinePadded< std::pair< Version, std::shared_ptr< Contents > > > > localValue_
Definition: SettingsImpl.h:363
void registerSetting(SettingCoreBase &core)
Definition: Settings.cpp:33
static const char *const value
Definition: Conv.cpp:50
std::enable_if_t< std::is_constructible< T, StringPiece >::value, T > convertOrConstruct(StringPiece newValue)
Definition: SettingsImpl.h:239
TrafficKey getKey()
const T & getImpl(std::false_type, std::atomic< uint64_t > &) const
Definition: SettingsImpl.h:301
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
FOLLY_NOINLINE const std::shared_ptr< Contents > & tlValueSlow() const
Definition: SettingsImpl.h:372
std::conditional_t< IsSmallPOD< T >::value, T, const T & > getWithHint(std::atomic< uint64_t > &trivialStorage) const
Definition: SettingsImpl.h:281
std::pair< std::string, std::string > getAsString(const SnapshotBase *snapshot) const override
Definition: SettingsImpl.h:260
std::shared_ptr< Contents > globalValue_
Definition: SettingsImpl.h:354
const SettingContents< T > & getSlow() const
Definition: SettingsImpl.h:285
T getImpl(std::true_type, std::atomic< uint64_t > &trivialStorage) const
Definition: SettingsImpl.h:291