allow 1000 background FUSE requests

Summary:
DurhamG discovered that setting max_background in fuse_init_out allows
a larger number of concurrent FUSE requests. The documentation
indicates it's intended to affect background requests like readahead,
but empirically you can observe increased live FUSE requests with `rg
-j200` and `eden top`. Default to 1000 because EdenFS can handle a
large amount of concurrency and we want to avoid blob and tree fetches
to block FUSE IO when not necessary.

Reviewed By: xavierd

Differential Revision: D27526032

fbshipit-source-id: 0d3fa383772f719524a9be84b73fa2eb599580d7
This commit is contained in:
Chad Austin 2021-05-17 12:46:49 -07:00 committed by Facebook GitHub Bot
parent 48b35a0a5e
commit c5b895d7f2
6 changed files with 49 additions and 8 deletions

View File

@ -354,6 +354,18 @@ class EdenConfig : private ConfigSettingManager {
// [fuse]
/**
* The maximum number of concurrent FUSE requests we allow the kernel to send
* us.
*
* Linux FUSE defaults to 12, but EdenFS can handle a great deal of
* concurrency.
*/
ConfigSetting<int32_t> fuseMaximumRequests{
"fuse:max-concurrent-requests",
1000,
this};
/**
* The maximum time duration allowed for a fuse request. If a request exceeds
* this amount of time, an ETIMEDOUT error will be returned to the kernel to
@ -412,6 +424,15 @@ class EdenConfig : private ConfigSettingManager {
1000,
this};
/**
* The maximum number of concurrent requests allowed into userspace from the
* kernel. This corresponds to fuse_init_out::max_background. The
* documentation this applies to only readaheads and async direct IO, but
* empirically we have observed the number of concurrent requests is limited
* to 12 (FUSE_DEFAULT_MAX_BACKGROUND) unless this is set high.
*/
ConfigSetting<uint32_t> maximumFuseRequests{"fuse:max-requests", 1000, this};
/**
* Buffer size for read and writes requests. Default to 1 MiB.
*/

View File

@ -782,7 +782,8 @@ FuseChannel::FuseChannel(
folly::Duration requestTimeout,
Notifications* notifications,
CaseSensitivity caseSensitive,
bool requireUtf8Path)
bool requireUtf8Path,
int32_t maximumBackgroundRequests)
: bufferSize_(std::max(size_t(getpagesize()) + 0x1000, MIN_BUFSIZE)),
numThreads_(numThreads),
dispatcher_(std::move(dispatcher)),
@ -790,8 +791,9 @@ FuseChannel::FuseChannel(
mountPath_(mountPath),
requestTimeout_(requestTimeout),
notifications_(notifications),
caseSensitive_(caseSensitive),
requireUtf8Path_(requireUtf8Path),
caseSensitive_{caseSensitive},
requireUtf8Path_{requireUtf8Path},
maximumBackgroundRequests_{maximumBackgroundRequests},
fuseDevice_(std::move(fuseDevice)),
processAccessLog_(std::move(processNameCache)),
traceDetailedArguments_(std::make_shared<std::atomic<size_t>>(0)),
@ -1368,9 +1370,22 @@ void FuseChannel::readInitPacket() {
connInfo.major = init.init.major;
connInfo.minor = init.init.minor;
connInfo.max_write = bufferSize_ - 4096;
connInfo.max_readahead = init.init.max_readahead;
int32_t max_background = maximumBackgroundRequests_;
if (max_background > 65535) {
max_background = 65535;
} else if (max_background < 0) {
max_background = 0;
}
// The libfuse documentation says this only applies to background
// requests like readahead prefetches and direct I/O, but we have
// empirically observed that, on Linux, without setting this value,
// `rg -j 200` limits the number of active FUSE requests to 16.
connInfo.max_background = static_cast<uint32_t>(max_background);
// Allow the kernel to default connInfo.congestion_threshold. Linux
// picks 3/4 of max_background.
const auto capable = init.init.flags;
auto& want = connInfo.flags;

View File

@ -228,7 +228,8 @@ class FuseChannel {
folly::Duration requestTimeout,
Notifications* FOLLY_NULLABLE notifications,
CaseSensitivity caseSensitive,
bool requireUtf8Path);
bool requireUtf8Path,
int32_t maximumBackgroundRequests);
/**
* Destroy the FuseChannel.
@ -742,6 +743,7 @@ class FuseChannel {
Notifications* const notifications_;
CaseSensitivity caseSensitive_;
bool requireUtf8Path_;
int32_t maximumBackgroundRequests_;
/*
* connInfo_ is modified during the initialization process,

View File

@ -135,7 +135,8 @@ int main(int argc, char** argv) {
std::chrono::seconds(60),
nullptr,
CaseSensitivity::Sensitive,
true));
true,
12 /* the default on Linux */));
XLOG(INFO) << "Starting FUSE...";
auto completionFuture = channel->initialize().get();

View File

@ -79,7 +79,8 @@ class FuseChannelTest : public ::testing::Test {
std::chrono::seconds(60),
nullptr,
CaseSensitivity::Sensitive,
true));
true,
12));
}
FuseChannel::StopFuture performInit(

View File

@ -1280,7 +1280,8 @@ std::unique_ptr<FuseChannel, FuseChannelDeleter> makeFuseChannel(
edenConfig->fuseRequestTimeout.getValue()),
mount->getServerState()->getNotifications(),
mount->getCheckoutConfig()->getCaseSensitive(),
mount->getCheckoutConfig()->getRequireUtf8Path())};
mount->getCheckoutConfig()->getRequireUtf8Path(),
edenConfig->fuseMaximumRequests.getValue())};
}
} // namespace
#endif