sapling/eden/fs/config/ReloadableConfig.cpp
Chad Austin fc48ab8614 add a ConfigSource layer of indirection between EdenConfig and the toml files
Summary:
EdenConfig had a bunch of hard-coded logic around stat()ing files and
parsing TOML.

Besides code clarity, this had several problems:
* Using an EdenConfig in a unit test would touch the actual filesystem.
* We didn't support reading configs from other sources. For example,
  we've talked about reading EdenConfig from .hgrc.
* ReloadableConfig knew too much about EdenConfig's internal working.
* Changing configs in tests involves calling setValue(), which is an
  unsafe API in the limit.

This diff introduces a new abstraction called ConfigSource, with one
implementation, TomlFileConfigSource.

ConfigSource can indicate that it's time for a reload, and can apply
its values to a non-const EdenConfig instance.

Reviewed By: kmancini

Differential Revision: D41830417

fbshipit-source-id: a0ff90c4a1adb870e4b34da5d16238a6e7b75be2
2023-01-04 12:53:34 -08:00

76 lines
2.0 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#include "eden/fs/config/ReloadableConfig.h"
#include "eden/fs/config/EdenConfig.h"
#include "eden/fs/utils/Bug.h"
#include "eden/fs/utils/EnumValue.h"
#include <folly/logging/xlog.h>
namespace {
/// Throttle change checks to a maximum of one per
/// kEdenConfigMinimumPollDuration.
constexpr std::chrono::seconds kEdenConfigMinimumPollDuration{5};
} // namespace
namespace facebook::eden {
ReloadableConfig::ReloadableConfig(std::shared_ptr<const EdenConfig> config)
: state_{ConfigState{std::move(config)}} {}
ReloadableConfig::ReloadableConfig(
std::shared_ptr<const EdenConfig> config,
ConfigReloadBehavior reloadBehavior)
: state_{ConfigState{std::move(config)}}, reloadBehavior_{reloadBehavior} {}
ReloadableConfig::~ReloadableConfig() = default;
std::shared_ptr<const EdenConfig> ReloadableConfig::getEdenConfig(
ConfigReloadBehavior reload) {
auto now = std::chrono::steady_clock::now();
if (reloadBehavior_.has_value()) {
reload = reloadBehavior_.value();
}
bool shouldReload;
switch (reload) {
case ConfigReloadBehavior::NoReload:
shouldReload = false;
break;
case ConfigReloadBehavior::ForceReload:
shouldReload = true;
break;
case ConfigReloadBehavior::AutoReload: {
auto lastCheck = lastCheck_.load(std::memory_order_acquire);
shouldReload = now - lastCheck >= kEdenConfigMinimumPollDuration;
break;
}
default:
EDEN_BUG() << "Unexpected reload flag: " << enumValue(reload);
}
if (!shouldReload) {
return state_.rlock()->config;
}
auto state = state_.wlock();
// Throttle the updates when using ConfigReloadBehavior::AutoReload
lastCheck_.store(now, std::memory_order_release);
auto& config = state->config;
if (auto newConfig = config->maybeReload()) {
state->config = std::move(newConfig);
}
return state->config;
}
} // namespace facebook::eden