glob: use SerialExecutor to avoid fan-out

Summary:
To address the Thrift QueueTimeout issue we have been seeing in EdenFS Thrift server.

The underlying issue is that, `globFiles` Thrift method in EdenFS is causing too much fanouts, overloading the Thrift CPU worker. As a result, all the new incoming requests are waiting in the Thrift queue too long to get picked, resulting as QueueTimeout exceptions on the client side.

This diff adds `folly::SerialExecutor` for the `globFiles` method to limit concurrency when processing glob requests.

Reviewed By: chadaustin

Differential Revision: D41390586

fbshipit-source-id: 54d834bb370d4ae693089051f200b7103de2f85b
This commit is contained in:
Zeyi (Rice) Fan 2023-01-18 16:41:25 -08:00 committed by Facebook GitHub Bot
parent 0b7baa9025
commit 8618070891

View File

@ -20,6 +20,7 @@
#include <folly/String.h>
#include <folly/chrono/Conv.h>
#include <folly/container/Access.h>
#include <folly/executors/SerialExecutor.h>
#include <folly/futures/Future.h>
#include <folly/logging/Logger.h>
#include <folly/logging/LoggerDB.h>
@ -27,6 +28,7 @@
#include <folly/stop_watch.h>
#include <folly/system/Shell.h>
#include <thrift/lib/cpp/util/EnumUtils.h>
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include "eden/common/utils/ProcessNameCache.h"
#include "eden/fs/config/CheckoutConfig.h"
@ -2673,7 +2675,7 @@ EdenServiceHandler::semifuture_globFiles(std::unique_ptr<GlobParams> params) {
context,
server_->getServerState());
auto globFut =
ImmediateFuture<std::unique_ptr<Glob>> globFut =
std::move(backgroundFuture)
.thenValue([mount = server_->getMount(
absolutePathFromThrift(*params->mountPoint())),
@ -2683,11 +2685,24 @@ EdenServiceHandler::semifuture_globFiles(std::unique_ptr<GlobParams> params) {
&context](auto&&) mutable {
return globber.glob(mount, serverState, std::move(globs), context);
});
globFut = std::move(globFut).ensure(
[helper = std::move(helper), params = std::move(params)] {});
return detachIfBackgrounded(
std::move(globFut), server_->getServerState(), isBackground)
.semi();
globFut = detachIfBackgrounded(
std::move(globFut), server_->getServerState(), isBackground);
if (globFut.isReady()) {
return std::move(globFut).semi();
}
// The glob code has a very large fan-out that can easily overload the Thrift
// CPU worker pool. To combat with that, we limit the execution to a single
// thread by using `folly::SerialExecutor` so the glob queries will not
// overload the executor.
auto serial = folly::SerialExecutor::create(
server_->getServer()->getThreadManager().get());
return std::move(globFut).semi().via(serial);
}
folly::SemiFuture<folly::Unit> EdenServiceHandler::semifuture_prefetchFiles(