Commit cf7517b8 authored by Anton Likhtarov's avatar Anton Likhtarov Committed by Facebook Github Bot

Move in global setting APIs into Snapshot

Summary: This forces users to take a Snapshot and makes global settings updates both atomic and more explicit.

Differential Revision: D10055254

fbshipit-source-id: 73ce34acdadad19d5b75e74ad26f13dc7763228d
parent 845a46cc
...@@ -50,56 +50,57 @@ void registerSetting(SettingCoreBase& core) { ...@@ -50,56 +50,57 @@ void registerSetting(SettingCoreBase& core) {
} // namespace detail } // namespace detail
bool setFromString( Optional<SettingMetadata> getSettingsMeta(StringPiece settingName) {
StringPiece settingName,
StringPiece newValue,
StringPiece reason) {
auto mapPtr = detail::settingsMap().rlock(); auto mapPtr = detail::settingsMap().rlock();
auto it = mapPtr->find(settingName.str()); auto it = mapPtr->find(settingName.str());
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return false; return none;
} }
it->second->setFromString(newValue, reason); return it->second->meta();
return true;
} }
Optional<SettingsInfo> getAsString(StringPiece settingName) { bool Snapshot::setFromString(
StringPiece settingName,
StringPiece newValue,
StringPiece reason) {
auto mapPtr = detail::settingsMap().rlock(); auto mapPtr = detail::settingsMap().rlock();
auto it = mapPtr->find(settingName.str()); auto it = mapPtr->find(settingName.str());
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return folly::none; return false;
} }
return it->second->getAsString(); it->second->setFromString(newValue, reason, this);
return true;
} }
Optional<SettingMetadata> getSettingsMeta(StringPiece settingName) { Optional<Snapshot::SettingsInfo> Snapshot::getAsString(
StringPiece settingName) const {
auto mapPtr = detail::settingsMap().rlock(); auto mapPtr = detail::settingsMap().rlock();
auto it = mapPtr->find(settingName.str()); auto it = mapPtr->find(settingName.str());
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return folly::none; return none;
} }
return it->second->meta(); return it->second->getAsString(this);
} }
bool resetToDefault(StringPiece settingName) { bool Snapshot::resetToDefault(StringPiece settingName) {
auto mapPtr = detail::settingsMap().rlock(); auto mapPtr = detail::settingsMap().rlock();
auto it = mapPtr->find(settingName.str()); auto it = mapPtr->find(settingName.str());
if (it == mapPtr->end()) { if (it == mapPtr->end()) {
return false; return false;
} }
it->second->resetToDefault(); it->second->resetToDefault(this);
return true; return true;
} }
void forEachSetting( void Snapshot::forEachSetting(
const std::function<void(const SettingMetadata&, StringPiece, StringPiece)>& const std::function<void(const SettingMetadata&, StringPiece, StringPiece)>&
func) { func) const {
detail::SettingsMap map; detail::SettingsMap map;
/* Note that this won't hold the lock over the callback, which is /* Note that this won't hold the lock over the callback, which is
what we want since the user might call other settings:: APIs */ what we want since the user might call other settings:: APIs */
map = *detail::settingsMap().rlock(); map = *detail::settingsMap().rlock();
for (const auto& kv : map) { for (const auto& kv : map) {
auto value = kv.second->getAsString(); auto value = kv.second->getAsString(this);
func(kv.second->meta(), value.first, value.second); func(kv.second->meta(), value.first, value.second);
} }
} }
......
...@@ -48,7 +48,7 @@ class SettingWrapper { ...@@ -48,7 +48,7 @@ class SettingWrapper {
return core_.getWithHint(*TrivialPtr); return core_.getWithHint(*TrivialPtr);
} }
const T* operator->() const { const T* operator->() const {
return &core_.getSlow(); return &core_.getSlow().value;
} }
/** /**
...@@ -182,51 +182,11 @@ using TypeIdentityT = typename TypeIdentity<T>::type; ...@@ -182,51 +182,11 @@ using TypeIdentityT = typename TypeIdentity<T>::type;
#define FOLLY_SETTING(_project, _name) \ #define FOLLY_SETTING(_project, _name) \
FOLLY_SETTINGS_LOCAL_FUNC__##_project##_##_name(0) FOLLY_SETTINGS_LOCAL_FUNC__##_project##_##_name(0)
/**
* Look up a setting by name, and update the value from a string representation.
*
* @returns True if the setting was successfully updated, false if no setting
* with that name was found.
* @throws std::runtime_error If there's a conversion error.
*/
bool setFromString(
folly::StringPiece settingName,
folly::StringPiece newValue,
folly::StringPiece reason);
/**
* Type that encapsulates the current pair of (to<string>(value), reason)
*/
using SettingsInfo = std::pair<std::string, std::string>;
/**
* @return If the setting exists, the current setting information.
* Empty Optional otherwise.
*/
folly::Optional<SettingsInfo> getAsString(folly::StringPiece settingName);
/** /**
* @return If the setting exists, returns the current settings metadata. * @return If the setting exists, returns the current settings metadata.
* Empty Optional otherwise. * Empty Optional otherwise.
*/ */
folly::Optional<SettingMetadata> getSettingsMeta( Optional<SettingMetadata> getSettingsMeta(StringPiece settingName);
folly::StringPiece settingName);
/**
* Reset the value of the setting identified by name to its default value.
* The reason will be set to "default".
*
* @return True if the setting was reset, false if the setting is not found.
*/
bool resetToDefault(folly::StringPiece settingName);
/**
* Iterates over all known settings and calls
* func(meta, to<string>(value), reason) for each.
*/
void forEachSetting(
const std::function<
void(const SettingMetadata&, folly::StringPiece, folly::StringPiece)>&
func);
namespace detail { namespace detail {
...@@ -316,7 +276,42 @@ class Snapshot final : public detail::SnapshotBase { ...@@ -316,7 +276,42 @@ class Snapshot final : public detail::SnapshotBase {
* Apply all settings updates from this snapshot to the global state * Apply all settings updates from this snapshot to the global state
* unconditionally. * unconditionally.
*/ */
void publish(); void publish() override;
/**
* Look up a setting by name, and update the value from a string
* representation.
*
* @returns True if the setting was successfully updated, false if no setting
* with that name was found.
* @throws std::runtime_error If there's a conversion error.
*/
bool setFromString(
StringPiece settingName,
StringPiece newValue,
StringPiece reason) override;
/**
* @return If the setting exists, the current setting information.
* Empty Optional otherwise.
*/
Optional<SettingsInfo> getAsString(StringPiece settingName) const override;
/**
* Reset the value of the setting identified by name to its default value.
* The reason will be set to "default".
*
* @return True if the setting was reset, false if the setting is not found.
*/
bool resetToDefault(StringPiece settingName) override;
/**
* Iterates over all known settings and calls
* func(meta, to<string>(value), reason) for each.
*/
void forEachSetting(const std::function<
void(const SettingMetadata&, StringPiece, StringPiece)>&
func) const override;
private: private:
template <typename T> template <typename T>
...@@ -326,7 +321,7 @@ class Snapshot final : public detail::SnapshotBase { ...@@ -326,7 +321,7 @@ class Snapshot final : public detail::SnapshotBase {
namespace detail { namespace detail {
template <class T> template <class T>
inline const T& SnapshotSettingWrapper<T>::operator*() const { inline const T& SnapshotSettingWrapper<T>::operator*() const {
return snapshot_.get(core_); return snapshot_.get(core_).value;
} }
} // namespace detail } // namespace detail
......
...@@ -50,14 +50,20 @@ struct SettingContents { ...@@ -50,14 +50,20 @@ struct SettingContents {
: updateReason(std::move(_reason)), value(std::forward<Args>(args)...) {} : updateReason(std::move(_reason)), value(std::forward<Args>(args)...) {}
}; };
class SnapshotBase;
class SettingCoreBase { class SettingCoreBase {
public: public:
using Key = intptr_t; using Key = intptr_t;
using Version = uint64_t; using Version = uint64_t;
virtual void setFromString(StringPiece newValue, StringPiece reason) = 0; virtual void setFromString(
virtual std::pair<std::string, std::string> getAsString() const = 0; StringPiece newValue,
virtual void resetToDefault() = 0; StringPiece reason,
SnapshotBase* snapshot) = 0;
virtual std::pair<std::string, std::string> getAsString(
const SnapshotBase* snapshot) const = 0;
virtual void resetToDefault(SnapshotBase* snapshot) = 0;
virtual const SettingMetadata& meta() const = 0; virtual const SettingMetadata& meta() const = 0;
virtual ~SettingCoreBase() {} virtual ~SettingCoreBase() {}
...@@ -90,25 +96,27 @@ class BoxedValue { ...@@ -90,25 +96,27 @@ class BoxedValue {
* Stores a value that can be retrieved later * Stores a value that can be retrieved later
*/ */
template <class T> template <class T>
explicit BoxedValue(const T& value) : value_(std::make_shared<T>(value)) {} explicit BoxedValue(const SettingContents<T>& value)
: value_(std::make_shared<SettingContents<T>>(value)) {}
/** /**
* Stores a value that can be both retrieved later and optionally * Stores a value that can be both retrieved later and optionally
* applied globally * applied globally
*/ */
template <class T> template <class T>
BoxedValue(const T& value, folly::StringPiece reason, SettingCore<T>& core) BoxedValue(const T& value, StringPiece reason, SettingCore<T>& core)
: value_(std::make_shared<T>(value)), : value_(std::make_shared<SettingContents<T>>(reason.str(), value)),
publish_([value = value_, &core, r = reason.str()]() { publish_([value = value_, &core]() {
core.set(unboxImpl<T>(value.get()), r); auto& contents = BoxedValue::unboxImpl<T>(value.get());
core.set(contents.value, contents.updateReason);
}) {} }) {}
/** /**
* Returns the reference to the stored value * Returns the reference to the stored value
*/ */
template <class T> template <class T>
const T& unbox() const { const SettingContents<T>& unbox() const {
return unboxImpl<T>(value_.get()); return BoxedValue::unboxImpl<T>(value_.get());
} }
/** /**
...@@ -125,8 +133,8 @@ class BoxedValue { ...@@ -125,8 +133,8 @@ class BoxedValue {
std::function<void()> publish_; std::function<void()> publish_;
template <class T> template <class T>
static const T& unboxImpl(void* value) { static const SettingContents<T>& unboxImpl(void* value) {
return *static_cast<const T*>(value); return *static_cast<const SettingContents<T>*>(value);
} }
}; };
...@@ -147,6 +155,56 @@ const BoxedValue* getSavedValue( ...@@ -147,6 +155,56 @@ const BoxedValue* getSavedValue(
SettingCoreBase::Version at); SettingCoreBase::Version at);
class SnapshotBase { class SnapshotBase {
public:
/**
* Type that encapsulates the current pair of (to<string>(value), reason)
*/
using SettingsInfo = std::pair<std::string, std::string>;
/**
* Apply all settings updates from this snapshot to the global state
* unconditionally.
*/
virtual void publish() = 0;
/**
* Look up a setting by name, and update the value from a string
* representation.
*
* @returns True if the setting was successfully updated, false if no setting
* with that name was found.
* @throws std::runtime_error If there's a conversion error.
*/
virtual bool setFromString(
StringPiece settingName,
StringPiece newValue,
StringPiece reason) = 0;
/**
* @return If the setting exists, the current setting information.
* Empty Optional otherwise.
*/
virtual Optional<SettingsInfo> getAsString(StringPiece settingName) const = 0;
/**
* Reset the value of the setting identified by name to its default value.
* The reason will be set to "default".
*
* @return True if the setting was reset, false if the setting is not found.
*/
virtual bool resetToDefault(StringPiece settingName) = 0;
/**
* Iterates over all known settings and calls
* func(meta, to<string>(value), reason) for each.
*/
virtual void forEachSetting(
const std::function<
void(const SettingMetadata&, StringPiece, StringPiece)>& func)
const = 0;
virtual ~SnapshotBase();
protected: protected:
detail::SettingCoreBase::Version at_; detail::SettingCoreBase::Version at_;
std::unordered_map<detail::SettingCoreBase::Key, detail::BoxedValue> std::unordered_map<detail::SettingCoreBase::Key, detail::BoxedValue>
...@@ -156,10 +214,9 @@ class SnapshotBase { ...@@ -156,10 +214,9 @@ class SnapshotBase {
friend class SettingCore; friend class SettingCore;
SnapshotBase(); SnapshotBase();
virtual ~SnapshotBase();
template <class T> template <class T>
const T& get(detail::SettingCore<T>& core) const { const SettingContents<T>& get(const detail::SettingCore<T>& core) const {
auto it = snapshotValues_.find(core.getKey()); auto it = snapshotValues_.find(core.getKey());
if (it != snapshotValues_.end()) { if (it != snapshotValues_.end()) {
return it->second.template unbox<T>(); return it->second.template unbox<T>();
...@@ -193,17 +250,24 @@ class SettingCore : public SettingCoreBase { ...@@ -193,17 +250,24 @@ class SettingCore : public SettingCoreBase {
public: public:
using Contents = SettingContents<T>; using Contents = SettingContents<T>;
void setFromString(StringPiece newValue, StringPiece reason) override { void setFromString(
set(convertOrConstruct<T>(newValue), reason.str()); StringPiece newValue,
StringPiece reason,
SnapshotBase* snapshot) override {
set(convertOrConstruct<T>(newValue), reason.str(), snapshot);
} }
std::pair<std::string, std::string> getAsString() const override {
auto contents = *const_cast<SettingCore*>(this)->tlValue(); std::pair<std::string, std::string> getAsString(
const SnapshotBase* snapshot) const override {
auto& contents = snapshot ? snapshot->get(*this) : getSlow();
return std::make_pair( return std::make_pair(
to<std::string>(contents.value), contents.updateReason); to<std::string>(contents.value), contents.updateReason);
} }
void resetToDefault() override {
set(defaultValue_, "default"); void resetToDefault(SnapshotBase* snapshot) override {
set(defaultValue_, "default", snapshot);
} }
const SettingMetadata& meta() const override { const SettingMetadata& meta() const override {
return meta_; return meta_;
} }
...@@ -218,8 +282,8 @@ class SettingCore : public SettingCoreBase { ...@@ -218,8 +282,8 @@ class SettingCore : public SettingCoreBase {
std::atomic<uint64_t>& trivialStorage) const { std::atomic<uint64_t>& trivialStorage) const {
return getImpl(IsSmallPOD<T>(), trivialStorage); return getImpl(IsSmallPOD<T>(), trivialStorage);
} }
const T& getSlow() const { const SettingContents<T>& getSlow() const {
return getImpl(std::false_type{}, trivialStorage_); return *tlValue();
} }
/*** /***
* SmallPOD version: just read the global atomic * SmallPOD version: just read the global atomic
...@@ -252,7 +316,7 @@ class SettingCore : public SettingCoreBase { ...@@ -252,7 +316,7 @@ class SettingCore : public SettingCoreBase {
if (globalValue_) { if (globalValue_) {
saveValueForOutstandingSnapshots( saveValueForOutstandingSnapshots(
getKey(), *settingVersion_, BoxedValue(globalValue_->value)); getKey(), *settingVersion_, BoxedValue(*globalValue_));
} }
globalValue_ = std::make_shared<Contents>(reason.str(), t); globalValue_ = std::make_shared<Contents>(reason.str(), t);
if (IsSmallPOD<T>::value) { if (IsSmallPOD<T>::value) {
...@@ -296,14 +360,14 @@ class SettingCore : public SettingCoreBase { ...@@ -296,14 +360,14 @@ class SettingCore : public SettingCoreBase {
Indestructible<std::pair<Version, std::shared_ptr<Contents>>>>> Indestructible<std::pair<Version, std::shared_ptr<Contents>>>>>
localValue_; localValue_;
FOLLY_ALWAYS_INLINE std::shared_ptr<Contents>& tlValue() { FOLLY_ALWAYS_INLINE std::shared_ptr<Contents>& tlValue() const {
auto& value = ***localValue_; auto& value = ***localValue_;
if (LIKELY(value.first == *settingVersion_)) { if (LIKELY(value.first == *settingVersion_)) {
return value.second; return value.second;
} }
return tlValueSlow(); return tlValueSlow();
} }
FOLLY_NOINLINE std::shared_ptr<Contents>& tlValueSlow() { FOLLY_NOINLINE std::shared_ptr<Contents>& tlValueSlow() const {
auto& value = ***localValue_; auto& value = ***localValue_;
while (value.first < *settingVersion_) { while (value.first < *settingVersion_) {
/* If this destroys the old value, do it without holding the lock */ /* If this destroys the old value, do it without holding the lock */
......
...@@ -84,29 +84,43 @@ FOLLY_SETTING_DEFINE( ...@@ -84,29 +84,43 @@ FOLLY_SETTING_DEFINE(
TEST(Settings, user_defined) { TEST(Settings, user_defined) {
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100); EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
EXPECT_TRUE(
folly::settings::setFromString("follytest_user_defined", "a", "test"));
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
{ {
auto info = folly::settings::getAsString("follytest_user_defined"); folly::settings::Snapshot sn;
EXPECT_TRUE(sn.setFromString("follytest_user_defined", "a", "test"));
sn.publish();
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
}
{
folly::settings::Snapshot sn;
auto info = sn.getAsString("follytest_user_defined");
EXPECT_TRUE(info.hasValue()); EXPECT_TRUE(info.hasValue());
EXPECT_EQ(info->first, "a_out"); EXPECT_EQ(info->first, "a_out");
EXPECT_EQ(info->second, "test"); EXPECT_EQ(info->second, "test");
} }
EXPECT_THROW(
folly::settings::setFromString("follytest_user_defined", "c", "test2"),
std::runtime_error);
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
{ {
auto info = folly::settings::getAsString("follytest_user_defined"); folly::settings::Snapshot sn;
EXPECT_THROW(
sn.setFromString("follytest_user_defined", "c", "test2"),
std::runtime_error);
sn.publish();
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 0);
}
{
folly::settings::Snapshot sn;
auto info = sn.getAsString("follytest_user_defined");
EXPECT_TRUE(info.hasValue()); EXPECT_TRUE(info.hasValue());
EXPECT_EQ(info->first, "a_out"); EXPECT_EQ(info->first, "a_out");
EXPECT_EQ(info->second, "test"); EXPECT_EQ(info->second, "test");
} }
EXPECT_TRUE(folly::settings::resetToDefault("follytest_user_defined"));
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
{ {
auto info = folly::settings::getAsString("follytest_user_defined"); folly::settings::Snapshot sn;
EXPECT_TRUE(sn.resetToDefault("follytest_user_defined"));
sn.publish();
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
}
{
folly::settings::Snapshot sn;
auto info = sn.getAsString("follytest_user_defined");
EXPECT_TRUE(info.hasValue()); EXPECT_TRUE(info.hasValue());
EXPECT_EQ(info->first, "b_out"); EXPECT_EQ(info->first, "b_out");
EXPECT_EQ(info->second, "default"); EXPECT_EQ(info->second, "default");
...@@ -119,7 +133,8 @@ TEST(Settings, user_defined) { ...@@ -119,7 +133,8 @@ TEST(Settings, user_defined) {
std::runtime_error); std::runtime_error);
EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100); EXPECT_EQ(some_ns::FOLLY_SETTING(follytest, user_defined)->value_, 100);
{ {
auto info = folly::settings::getAsString("follytest_user_defined"); folly::settings::Snapshot sn;
auto info = sn.getAsString("follytest_user_defined");
EXPECT_TRUE(info.hasValue()); EXPECT_TRUE(info.hasValue());
EXPECT_EQ(info->first, "b_out"); EXPECT_EQ(info->first, "b_out");
EXPECT_EQ(info->second, "default"); EXPECT_EQ(info->second, "default");
...@@ -138,12 +153,13 @@ TEST(Settings, basic) { ...@@ -138,12 +153,13 @@ TEST(Settings, basic) {
a_ns::setRemote(200); a_ns::setRemote(200);
EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 200); EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 200);
EXPECT_EQ(a_ns::getRemote(), 200); EXPECT_EQ(a_ns::getRemote(), 200);
{
auto res = folly::settings::getAsString("follytest_public_flag_to_a"); folly::settings::Snapshot sn;
EXPECT_TRUE(res.hasValue()); auto res = sn.getAsString("follytest_public_flag_to_a");
EXPECT_EQ(res->first, "200"); EXPECT_TRUE(res.hasValue());
EXPECT_EQ(res->second, "remote_set"); EXPECT_EQ(res->first, "200");
EXPECT_EQ(res->second, "remote_set");
}
{ {
auto meta = folly::settings::getSettingsMeta("follytest_public_flag_to_a"); auto meta = folly::settings::getSettingsMeta("follytest_public_flag_to_a");
EXPECT_TRUE(meta.hasValue()); EXPECT_TRUE(meta.hasValue());
...@@ -153,7 +169,6 @@ TEST(Settings, basic) { ...@@ -153,7 +169,6 @@ TEST(Settings, basic) {
EXPECT_EQ(md.typeStr, "int"); EXPECT_EQ(md.typeStr, "int");
EXPECT_EQ(md.typeId, typeid(int)); EXPECT_EQ(md.typeId, typeid(int));
} }
{ {
auto meta = folly::settings::getSettingsMeta("follytest_some_flag"); auto meta = folly::settings::getSettingsMeta("follytest_some_flag");
EXPECT_TRUE(meta.hasValue()); EXPECT_TRUE(meta.hasValue());
...@@ -163,65 +178,81 @@ TEST(Settings, basic) { ...@@ -163,65 +178,81 @@ TEST(Settings, basic) {
EXPECT_EQ(md.typeStr, "std::string"); EXPECT_EQ(md.typeStr, "std::string");
EXPECT_EQ(md.typeId, typeid(std::string)); EXPECT_EQ(md.typeId, typeid(std::string));
} }
{
res = folly::settings::getAsString("follytest_nonexisting"); folly::settings::Snapshot sn;
EXPECT_FALSE(res.hasValue()); auto res = sn.getAsString("follytest_nonexisting");
EXPECT_FALSE(res.hasValue());
EXPECT_TRUE(folly::settings::setFromString( }
"follytest_public_flag_to_a", "300", "from_string")); {
EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 300); folly::settings::Snapshot sn;
EXPECT_TRUE(
sn.setFromString("follytest_public_flag_to_a", "300", "from_string"));
sn.publish();
EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 300);
}
EXPECT_EQ(a_ns::getRemote(), 300); EXPECT_EQ(a_ns::getRemote(), 300);
res = folly::settings::getAsString("follytest_public_flag_to_a"); {
EXPECT_TRUE(res.hasValue()); folly::settings::Snapshot sn;
EXPECT_EQ(res->first, "300"); auto res = sn.getAsString("follytest_public_flag_to_a");
EXPECT_EQ(res->second, "from_string"); EXPECT_TRUE(res.hasValue());
EXPECT_EQ(res->first, "300");
EXPECT_FALSE(folly::settings::setFromString( EXPECT_EQ(res->second, "from_string");
"follytest_nonexisting", "300", "from_string")); }
{
std::string allFlags; folly::settings::Snapshot sn;
folly::settings::forEachSetting( EXPECT_FALSE(
[&allFlags]( sn.setFromString("follytest_nonexisting", "300", "from_string"));
const folly::settings::SettingMetadata& meta, }
folly::StringPiece value, {
folly::StringPiece reason) { std::string allFlags;
if (meta.typeId == typeid(int)) { folly::settings::Snapshot sn;
EXPECT_EQ(meta.typeStr, "int"); sn.forEachSetting([&allFlags](
} else if (meta.typeId == typeid(std::string)) { const folly::settings::SettingMetadata& meta,
EXPECT_EQ(meta.typeStr, "std::string"); folly::StringPiece value,
} else if (meta.typeId == typeid(unsigned int)) { folly::StringPiece reason) {
EXPECT_EQ(meta.typeStr, "unsigned int"); if (meta.typeId == typeid(int)) {
} else if (meta.typeId == typeid(some_ns::UserDefinedType)) { EXPECT_EQ(meta.typeStr, "int");
EXPECT_EQ(meta.typeStr, "UserDefinedType"); } else if (meta.typeId == typeid(std::string)) {
} else { EXPECT_EQ(meta.typeStr, "std::string");
ASSERT_FALSE(true); } else if (meta.typeId == typeid(unsigned int)) {
} EXPECT_EQ(meta.typeStr, "unsigned int");
allFlags += folly::sformat( } else if (meta.typeId == typeid(some_ns::UserDefinedType)) {
"{}/{}/{}/{}/{}/{}/{}\n", EXPECT_EQ(meta.typeStr, "UserDefinedType");
meta.project, } else {
meta.name, ASSERT_FALSE(true);
meta.typeStr, }
meta.defaultStr, allFlags += folly::sformat(
meta.description, "{}/{}/{}/{}/{}/{}/{}\n",
value, meta.project,
reason); meta.name,
}); meta.typeStr,
EXPECT_EQ( meta.defaultStr,
allFlags, meta.description,
"follytest/internal_flag_to_a/int/789/Desc of int/789/default\n" value,
"follytest/internal_flag_to_b/std::string/\"test\"/Desc of str/test/default\n" reason);
"follytest/multi_token_type/unsigned int/123/Test that multi-token type names can be used/123/default\n" });
"follytest/public_flag_to_a/int/456/Public flag to a/300/from_string\n" EXPECT_EQ(
"follytest/public_flag_to_b/std::string/\"basdf\"/Public flag to b/basdf/default\n" allFlags,
"follytest/some_flag/std::string/\"default\"/Description/default/default\n" "follytest/internal_flag_to_a/int/789/Desc of int/789/default\n"
"follytest/unused/std::string/\"unused_default\"/Not used, but should still be in the list/unused_default/default\n" "follytest/internal_flag_to_b/std::string/\"test\"/Desc of str/test/default\n"
"follytest/user_defined/UserDefinedType/\"b\"/User defined type constructed from string/b_out/default\n"); "follytest/multi_token_type/unsigned int/123/Test that multi-token type names can be used/123/default\n"
"follytest/public_flag_to_a/int/456/Public flag to a/300/from_string\n"
EXPECT_TRUE(folly::settings::resetToDefault("follytest_public_flag_to_a")); "follytest/public_flag_to_b/std::string/\"basdf\"/Public flag to b/basdf/default\n"
EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 456); "follytest/some_flag/std::string/\"default\"/Description/default/default\n"
EXPECT_EQ(a_ns::getRemote(), 456); "follytest/unused/std::string/\"unused_default\"/Not used, but should still be in the list/unused_default/default\n"
"follytest/user_defined/UserDefinedType/\"b\"/User defined type constructed from string/b_out/default\n");
EXPECT_FALSE(folly::settings::resetToDefault("follytest_nonexisting")); }
{
folly::settings::Snapshot sn;
EXPECT_TRUE(sn.resetToDefault("follytest_public_flag_to_a"));
sn.publish();
EXPECT_EQ(*a_ns::FOLLY_SETTING(follytest, public_flag_to_a), 456);
EXPECT_EQ(a_ns::getRemote(), 456);
}
{
folly::settings::Snapshot sn;
EXPECT_FALSE(sn.resetToDefault("follytest_nonexisting"));
}
} }
TEST(Settings, snapshot) { TEST(Settings, snapshot) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment