mirror of
https://github.com/facebook/sapling.git
synced 2024-10-04 22:07:44 +03:00
migrate functionScheduler to eventBase timer
Summary: This is reasonably straightforward, although a little more fiddly than I'd hoped because the timer wheel stuff doesn't offer a convenient way to set up a recurring timer. I've also made the inode unloading code get run globally for all mounts; it was previously scheduling one timer per mount point. This nets out the same; the function scheduler was just a single thread anyway, so there is no change in the level of concurrency. I believe that this tidies up the unload counter too; it looked like we'd set the counter to be the result of the last mount point that we processed rather than the aggregate of all mounts. Having the unload timer be associated with the server rather than the mount points means that we don't have to do anything special to coordinate with the timer management when the mount point is being torn down. Reviewed By: bolinfest Differential Revision: D5792938 fbshipit-source-id: 1a14bb7b7f4952139e684fe6b52f64bd1ba70dd0
This commit is contained in:
parent
e837848da5
commit
fe1a376e0f
@ -157,6 +157,44 @@ folly::Future<Unit> EdenServer::unmountAll() {
|
||||
});
|
||||
}
|
||||
|
||||
void EdenServer::scheduleFlushStats() {
|
||||
mainEventBase_->timer().scheduleTimeoutFn(
|
||||
[this] {
|
||||
flushStatsNow();
|
||||
scheduleFlushStats();
|
||||
},
|
||||
std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
void EdenServer::unloadInodes() {
|
||||
std::vector<TreeInodePtr> roots;
|
||||
{
|
||||
auto mountPoints = mountPoints_.wlock();
|
||||
for (auto& entry : *mountPoints) {
|
||||
roots.emplace_back(entry.second.edenMount->getRootInode());
|
||||
}
|
||||
}
|
||||
|
||||
if (!roots.empty()) {
|
||||
XLOG(INFO) << "UnloadInodeScheduler Unloading Free Inodes";
|
||||
auto serviceData = stats::ServiceData::get();
|
||||
|
||||
uint64_t totalUnloaded = serviceData->getCounter(kPeriodicUnloadCounterKey);
|
||||
for (auto& rootInode : roots) {
|
||||
totalUnloaded += rootInode->unloadChildrenNow(
|
||||
std::chrono::minutes(FLAGS_unload_age_minutes));
|
||||
}
|
||||
serviceData->setCounter(kPeriodicUnloadCounterKey, totalUnloaded);
|
||||
}
|
||||
|
||||
scheduleInodeUnload(std::chrono::hours(FLAGS_unload_interval_hours));
|
||||
}
|
||||
|
||||
void EdenServer::scheduleInodeUnload(std::chrono::milliseconds timeout) {
|
||||
mainEventBase_->timer().scheduleTimeoutFn(
|
||||
[this] { unloadInodes(); }, timeout);
|
||||
}
|
||||
|
||||
void EdenServer::prepare() {
|
||||
acquireEdenLock();
|
||||
// Store a pointer to the EventBase that will be used to drive
|
||||
@ -165,18 +203,23 @@ void EdenServer::prepare() {
|
||||
createThriftServer();
|
||||
|
||||
localStore_ = make_shared<LocalStore>(rocksPath_);
|
||||
functionScheduler_ = make_shared<folly::FunctionScheduler>();
|
||||
functionScheduler_->setThreadName("EdenFuncSched");
|
||||
functionScheduler_->start();
|
||||
|
||||
// Start stats aggregation
|
||||
functionScheduler_->addFunction(
|
||||
[this] { flushStatsNow(); }, std::chrono::seconds(1));
|
||||
scheduleFlushStats();
|
||||
|
||||
// Set the ServiceData counter for tracking number of inodes unloaded by
|
||||
// periodic job for unloading inodes to zero on EdenServer start.
|
||||
stats::ServiceData::get()->setCounter(kPeriodicUnloadCounterKey, 0);
|
||||
|
||||
// Schedule a periodic job to unload unused inodes based on the last access
|
||||
// time. currently Eden does not have accurate timestamp tracking for inodes,
|
||||
// so using unloadChildrenNow just to validate the behaviour. We will have to
|
||||
// modify current unloadChildrenNow function to unload inodes based on the
|
||||
// last access time.
|
||||
if (FLAGS_unload_interval_hours > 0) {
|
||||
scheduleInodeUnload(std::chrono::minutes(FLAGS_start_delay_minutes));
|
||||
}
|
||||
|
||||
auto pool =
|
||||
make_shared<wangle::CPUThreadPoolExecutor>(FLAGS_num_eden_threads);
|
||||
wangle::setCPUExecutor(pool);
|
||||
@ -279,29 +322,6 @@ void EdenServer::mount(shared_ptr<EdenMount> edenMount) {
|
||||
// wait for it to finish.
|
||||
(void)finishFuture;
|
||||
|
||||
// Adding function for the newly added mountpoint to Schedule
|
||||
// a periodic job to unload unused inodes based on the last access time.
|
||||
// currently Eden doesnot have accurate timestamp tracking for inodes, so
|
||||
// using unloadChildrenNow just to validate the behaviour. We will have to
|
||||
// modify current unloadChildrenNow function to unload inodes based on the
|
||||
// last access time.
|
||||
if (FLAGS_unload_interval_hours > 0) {
|
||||
functionScheduler_->addFunction(
|
||||
[edenMount] {
|
||||
auto rootInode = (edenMount.get())->getRootInode();
|
||||
XLOG(INFO) << "UnloadInodeScheduler Unloading Free Inodes";
|
||||
auto unloadCount = rootInode->unloadChildrenNow(
|
||||
std::chrono::minutes(FLAGS_unload_age_minutes));
|
||||
unloadCount +=
|
||||
stats::ServiceData::get()->getCounter(kPeriodicUnloadCounterKey);
|
||||
stats::ServiceData::get()->setCounter(
|
||||
kPeriodicUnloadCounterKey, unloadCount);
|
||||
},
|
||||
std::chrono::hours(FLAGS_unload_interval_hours),
|
||||
getPeriodicUnloadFunctionName(edenMount.get()),
|
||||
std::chrono::minutes(FLAGS_start_delay_minutes));
|
||||
}
|
||||
|
||||
// Register callback for getting Loaded inodes in the memory for a mountPoint.
|
||||
stats::ServiceData::get()->getDynamicCounters()->registerCallback(
|
||||
edenMount->getCounterName(CounterName::LOADED), [edenMount] {
|
||||
@ -361,8 +381,6 @@ Future<Unit> EdenServer::unmount(StringPiece mountPath) {
|
||||
void EdenServer::mountFinished(EdenMount* edenMount) {
|
||||
auto mountPath = edenMount->getPath().stringPiece();
|
||||
XLOG(INFO) << "mount point \"" << mountPath << "\" stopped";
|
||||
functionScheduler_->cancelFunctionAndWait(
|
||||
getPeriodicUnloadFunctionName(edenMount));
|
||||
stats::ServiceData::get()->getDynamicCounters()->unregisterCallback(
|
||||
edenMount->getCounterName(CounterName::LOADED));
|
||||
stats::ServiceData::get()->getDynamicCounters()->unregisterCallback(
|
||||
@ -386,10 +404,6 @@ void EdenServer::mountFinished(EdenMount* edenMount) {
|
||||
});
|
||||
}
|
||||
|
||||
string EdenServer::getPeriodicUnloadFunctionName(const EdenMount* mount) {
|
||||
return folly::to<string>("unload:", mount->getPath().stringPiece());
|
||||
}
|
||||
|
||||
EdenServer::MountList EdenServer::getMountPoints() const {
|
||||
MountList results;
|
||||
{
|
||||
@ -527,7 +541,6 @@ void EdenServer::stop() const {
|
||||
|
||||
void EdenServer::shutdown() {
|
||||
unmountAll().get();
|
||||
functionScheduler_->shutdown();
|
||||
}
|
||||
|
||||
void EdenServer::flushStatsNow() const {
|
||||
|
@ -180,15 +180,6 @@ class EdenServer {
|
||||
*/
|
||||
void flushStatsNow() const;
|
||||
|
||||
/**
|
||||
* Returns shared_ptr of FunctionScheduler which can be used to schedule
|
||||
* periodic jobs in EdenServer, Currently this function scheduler is used for
|
||||
* unloading free inodes periodically and stats aggregation
|
||||
*/
|
||||
std::shared_ptr<folly::FunctionScheduler> getFunctionScheduler() {
|
||||
return functionScheduler_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the main thread's EventBase.
|
||||
*
|
||||
@ -221,6 +212,22 @@ class EdenServer {
|
||||
EdenServer(EdenServer const&) = delete;
|
||||
EdenServer& operator=(EdenServer const&) = delete;
|
||||
|
||||
// Schedules a timer to flush stats (and reschedule itself).
|
||||
// We should have at most one of these pending at a time.
|
||||
// Must be called only from the eventBase thread.
|
||||
void scheduleFlushStats();
|
||||
|
||||
// Schedule a call to unloadInodes() to happen after timeout
|
||||
// has expired.
|
||||
// Must be called only from the eventBase thread.
|
||||
void scheduleInodeUnload(std::chrono::milliseconds timeout);
|
||||
|
||||
// Perform unloading of inodes based on their last access time
|
||||
// and then schedule another call to unloadInodes() to happen
|
||||
// at the next appropriate interval. The unload attempt applies to
|
||||
// all mounts.
|
||||
void unloadInodes();
|
||||
|
||||
std::shared_ptr<BackingStore> createBackingStore(
|
||||
folly::StringPiece type,
|
||||
folly::StringPiece name);
|
||||
@ -230,7 +237,6 @@ class EdenServer {
|
||||
|
||||
// Called when a mount has been unmounted and has stopped.
|
||||
void mountFinished(EdenMount* mountPoint);
|
||||
std::string getPeriodicUnloadFunctionName(const EdenMount* mount);
|
||||
|
||||
// Called before destructing EdenServer
|
||||
void shutdown();
|
||||
@ -260,11 +266,6 @@ class EdenServer {
|
||||
folly::Synchronized<MountMap> mountPoints_;
|
||||
mutable fusell::ThreadLocalEdenStats edenStats_;
|
||||
|
||||
/**
|
||||
* Function scheduler to unload free inodes periodically
|
||||
*/
|
||||
std::shared_ptr<folly::FunctionScheduler> functionScheduler_;
|
||||
|
||||
/**
|
||||
* The EventBase driving the main thread loop.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user