stop using RequestContext

Summary:
Setting up, tearing down, and querying RequestContext has some
overhead that I would like to avoid in the inner FUSE loop, so replace
RequestData with a single class that's heap-allocated at the start of
a request and is guaranteed to survive until the request ends, and is
otherwise explicitly passed where it's needed.

Reviewed By: kmancini

Differential Revision: D22712310

fbshipit-source-id: fc30d0b0f7e22b39306b857194ea07a913110b0f
This commit is contained in:
Chad Austin 2020-08-27 00:17:20 -07:00 committed by Facebook GitHub Bot
parent bd63a78f96
commit 8e848c7a77
11 changed files with 186 additions and 153 deletions

View File

@ -65,6 +65,7 @@ void Dispatcher::initConnection(const fuse_init_out& out) {
void Dispatcher::destroy() {}
folly::Future<fuse_entry_out> Dispatcher::lookup(
uint64_t /*requestID*/,
InodeNumber /*parent*/,
PathComponentPiece /*name*/,
ObjectFetchContext& /*context*/) {

View File

@ -63,9 +63,12 @@ class Dispatcher {
virtual void destroy();
/**
* Lookup a directory entry by name and get its attributes
* Lookup a directory entry by name and get its attributes.
*
* requestID is given here to assert invariants in tests.
*/
virtual folly::Future<fuse_entry_out> lookup(
uint64_t requestID,
InodeNumber parent,
PathComponentPiece name,
ObjectFetchContext& context);

View File

@ -9,7 +9,6 @@
#include <boost/cast.hpp>
#include <folly/futures/Future.h>
#include <folly/io/async/Request.h>
#include <folly/logging/xlog.h>
#include <folly/system/ThreadName.h>
#include <signal.h>
@ -33,8 +32,10 @@ namespace {
// This is the minimum size used by libfuse so we use it too!
constexpr size_t MIN_BUFSIZE = 0x21000;
using Handler = folly::Future<folly::Unit> (
FuseChannel::*)(const fuse_in_header* header, const uint8_t* arg);
using Handler = folly::Future<folly::Unit> (FuseChannel::*)(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
using AccessType = ProcessAccessLog::AccessType;
@ -1272,13 +1273,11 @@ void FuseChannel::processSession() {
default: {
if (handlerEntry && handlerEntry->handler) {
// Start a new request and associate it with the current thread.
// It will be disassociated when we leave this scope, but will
// propagate across any futures that are spawned as part of this
// request.
RequestContextScopeGuard requestContextGuard;
auto& request = RequestData::create(this, *header, dispatcher_);
// This is a shared_ptr because, due to timeouts, the internal request
// lifetime may not match the FUSE request lifetime, so we capture it
// in both. I'm sure this could be improved with some cleverness.
auto request =
std::make_shared<RequestData>(this, *header, dispatcher_);
uint64_t requestId;
{
// Save a weak reference to this new request context.
@ -1293,18 +1292,19 @@ void FuseChannel::processSession() {
}
request
.catchErrors(
->catchErrors(
folly::makeFutureWith([&] {
request.startRequest(
request->startRequest(
dispatcher_->getStats(),
handlerEntry->histogram,
*(liveRequestWatches_.get()));
return (this->*handlerEntry->handler)(
&request.getReq(), arg);
*request, &request->getReq(), arg);
})
.ensure([request] {})
.within(requestTimeout_),
notifications_)
.ensure([this, requestId] {
.ensure([this, requestId, request] {
auto state = state_.wlock();
// Remove the request from the map
@ -1380,6 +1380,7 @@ void FuseChannel::sessionComplete(folly::Synchronized<State>::LockedPtr state) {
}
folly::Future<folly::Unit> FuseChannel::fuseRead(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto read = reinterpret_cast<const fuse_read_in*>(arg);
@ -1387,11 +1388,12 @@ folly::Future<folly::Unit> FuseChannel::fuseRead(
XLOG(DBG7) << "FUSE_READ";
auto ino = InodeNumber{header->nodeid};
return dispatcher_->read(ino, read->size, read->offset, RequestData::get())
.thenValue([](BufVec&& buf) { RequestData::get().sendReply(*buf); });
return dispatcher_->read(ino, read->size, read->offset, request)
.thenValue([&request](BufVec&& buf) { request.sendReply(*buf); });
}
folly::Future<folly::Unit> FuseChannel::fuseWrite(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto write = reinterpret_cast<const fuse_write_in*>(arg);
@ -1404,14 +1406,15 @@ folly::Future<folly::Unit> FuseChannel::fuseWrite(
auto ino = InodeNumber{header->nodeid};
return dispatcher_
->write(ino, folly::StringPiece{bufPtr, write->size}, write->offset)
.thenValue([](size_t written) {
.thenValue([&request](size_t written) {
fuse_write_out out = {};
out.size = written;
RequestData::get().sendReply(out);
request.sendReply(out);
});
}
folly::Future<folly::Unit> FuseChannel::fuseLookup(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
PathComponentPiece name{reinterpret_cast<const char*>(arg)};
@ -1419,44 +1422,48 @@ folly::Future<folly::Unit> FuseChannel::fuseLookup(
XLOG(DBG7) << "FUSE_LOOKUP parent=" << parent << " name=" << name;
return dispatcher_->lookup(parent, name, RequestData::get())
return dispatcher_->lookup(header->unique, parent, name, request)
.thenValue(
[](fuse_entry_out param) { RequestData::get().sendReply(param); });
[&request](fuse_entry_out param) { request.sendReply(param); });
}
folly::Future<folly::Unit> FuseChannel::fuseForget(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
auto forget = reinterpret_cast<const fuse_forget_in*>(arg);
XLOG(DBG7) << "FUSE_FORGET inode=" << header->nodeid
<< " nlookup=" << forget->nlookup;
dispatcher_->forget(InodeNumber{header->nodeid}, forget->nlookup);
RequestData::get().replyNone();
request.replyNone();
return folly::unit;
}
folly::Future<folly::Unit> FuseChannel::fuseGetAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* /*arg*/) {
XLOG(DBG7) << "FUSE_GETATTR inode=" << header->nodeid;
return dispatcher_->getattr(InodeNumber{header->nodeid}, RequestData::get())
.thenValue([](Dispatcher::Attr attr) {
RequestData::get().sendReply(attr.asFuseAttr());
return dispatcher_->getattr(InodeNumber{header->nodeid}, request)
.thenValue([&request](Dispatcher::Attr attr) {
request.sendReply(attr.asFuseAttr());
});
}
folly::Future<folly::Unit> FuseChannel::fuseSetAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto setattr = reinterpret_cast<const fuse_setattr_in*>(arg);
XLOG(DBG7) << "FUSE_SETATTR inode=" << header->nodeid;
return dispatcher_->setattr(InodeNumber{header->nodeid}, *setattr)
.thenValue([](Dispatcher::Attr attr) {
RequestData::get().sendReply(attr.asFuseAttr());
.thenValue([&request](Dispatcher::Attr attr) {
request.sendReply(attr.asFuseAttr());
});
}
folly::Future<folly::Unit> FuseChannel::fuseReadLink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* /*arg*/) {
XLOG(DBG7) << "FUSE_READLINK inode=" << header->nodeid;
@ -1466,12 +1473,13 @@ folly::Future<folly::Unit> FuseChannel::fuseReadLink(
#endif
return dispatcher_
->readlink(InodeNumber{header->nodeid}, kernelCachesReadlink)
.thenValue([](std::string&& str) {
RequestData::get().sendReply(folly::StringPiece(str));
.thenValue([&request](std::string&& str) {
request.sendReply(folly::StringPiece(str));
});
}
folly::Future<folly::Unit> FuseChannel::fuseSymlink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto nameStr = reinterpret_cast<const char*>(arg);
@ -1481,10 +1489,11 @@ folly::Future<folly::Unit> FuseChannel::fuseSymlink(
return dispatcher_->symlink(InodeNumber{header->nodeid}, name, link)
.thenValue(
[](fuse_entry_out param) { RequestData::get().sendReply(param); });
[&request](fuse_entry_out param) { request.sendReply(param); });
}
folly::Future<folly::Unit> FuseChannel::fuseMknod(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto nod = reinterpret_cast<const fuse_mknod_in*>(arg);
@ -1505,10 +1514,11 @@ folly::Future<folly::Unit> FuseChannel::fuseMknod(
return dispatcher_
->mknod(InodeNumber{header->nodeid}, name, nod->mode, nod->rdev)
.thenValue(
[](fuse_entry_out entry) { RequestData::get().sendReply(entry); });
[&request](fuse_entry_out entry) { request.sendReply(entry); });
}
folly::Future<folly::Unit> FuseChannel::fuseMkdir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto dir = reinterpret_cast<const fuse_mkdir_in*>(arg);
@ -1526,10 +1536,11 @@ folly::Future<folly::Unit> FuseChannel::fuseMkdir(
return dispatcher_
->mkdir(InodeNumber{header->nodeid}, name, dir->mode & ~dir->umask)
.thenValue(
[](fuse_entry_out entry) { RequestData::get().sendReply(entry); });
[&request](fuse_entry_out entry) { request.sendReply(entry); });
}
folly::Future<folly::Unit> FuseChannel::fuseUnlink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto nameStr = reinterpret_cast<const char*>(arg);
@ -1538,10 +1549,11 @@ folly::Future<folly::Unit> FuseChannel::fuseUnlink(
XLOG(DBG7) << "FUSE_UNLINK " << name;
return dispatcher_->unlink(InodeNumber{header->nodeid}, name)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseRmdir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto nameStr = reinterpret_cast<const char*>(arg);
@ -1550,10 +1562,11 @@ folly::Future<folly::Unit> FuseChannel::fuseRmdir(
XLOG(DBG7) << "FUSE_RMDIR " << name;
return dispatcher_->rmdir(InodeNumber{header->nodeid}, name)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseRename(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto rename = reinterpret_cast<const fuse_rename_in*>(arg);
@ -1569,10 +1582,11 @@ folly::Future<folly::Unit> FuseChannel::fuseRename(
oldName,
InodeNumber{rename->newdir},
newName)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseLink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto link = reinterpret_cast<const fuse_link_in*>(arg);
@ -1584,47 +1598,50 @@ folly::Future<folly::Unit> FuseChannel::fuseLink(
return dispatcher_
->link(InodeNumber{link->oldnodeid}, InodeNumber{header->nodeid}, newName)
.thenValue(
[](fuse_entry_out param) { RequestData::get().sendReply(param); });
[&request](fuse_entry_out param) { request.sendReply(param); });
}
folly::Future<folly::Unit> FuseChannel::fuseOpen(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto open = reinterpret_cast<const fuse_open_in*>(arg);
XLOG(DBG7) << "FUSE_OPEN";
auto ino = InodeNumber{header->nodeid};
return dispatcher_->open(ino, open->flags).thenValue([](uint64_t fh) {
return dispatcher_->open(ino, open->flags).thenValue([&request](uint64_t fh) {
fuse_open_out out = {};
out.open_flags |= FOPEN_KEEP_CACHE;
out.fh = fh;
RequestData::get().sendReply(out);
request.sendReply(out);
});
}
folly::Future<folly::Unit> FuseChannel::fuseStatFs(
RequestData& request,
const fuse_in_header* header,
const uint8_t* /*arg*/) {
XLOG(DBG7) << "FUSE_STATFS";
return dispatcher_->statfs(InodeNumber{header->nodeid})
.thenValue([](struct fuse_kstatfs&& info) {
.thenValue([&request](struct fuse_kstatfs&& info) {
fuse_statfs_out out = {};
out.st = info;
RequestData::get().sendReply(out);
request.sendReply(out);
});
}
folly::Future<folly::Unit> FuseChannel::fuseRelease(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
XLOG(DBG7) << "FUSE_RELEASE";
auto ino = InodeNumber{header->nodeid};
auto release = reinterpret_cast<const fuse_release_in*>(arg);
return dispatcher_->release(ino, release->fh).thenValue([](folly::Unit) {
RequestData::get().replyError(0);
});
return dispatcher_->release(ino, release->fh)
.thenValue([&request](folly::Unit) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseFsync(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto fsync = reinterpret_cast<const fuse_fsync_in*>(arg);
@ -1634,12 +1651,13 @@ folly::Future<folly::Unit> FuseChannel::fuseFsync(
XLOG(DBG7) << "FUSE_FSYNC";
auto ino = InodeNumber{header->nodeid};
return dispatcher_->fsync(ino, datasync).thenValue([](auto&&) {
RequestData::get().replyError(0);
return dispatcher_->fsync(ino, datasync).thenValue([&request](auto&&) {
request.replyError(0);
});
}
folly::Future<folly::Unit> FuseChannel::fuseSetXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto setxattr = reinterpret_cast<const fuse_setxattr_in*>(arg);
@ -1652,10 +1670,11 @@ folly::Future<folly::Unit> FuseChannel::fuseSetXAttr(
return dispatcher_
->setxattr(InodeNumber{header->nodeid}, attrName, value, setxattr->flags)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseGetXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto getxattr = reinterpret_cast<const fuse_getxattr_in*>(arg);
@ -1663,8 +1682,7 @@ folly::Future<folly::Unit> FuseChannel::fuseGetXAttr(
const StringPiece attrName{nameStr};
XLOG(DBG7) << "FUSE_GETXATTR";
return dispatcher_->getxattr(InodeNumber{header->nodeid}, attrName)
.thenValue([size = getxattr->size](std::string attr) {
auto& request = RequestData::get();
.thenValue([&request, size = getxattr->size](const std::string& attr) {
if (size == 0) {
fuse_getxattr_out out = {};
out.size = attr.size();
@ -1678,66 +1696,68 @@ folly::Future<folly::Unit> FuseChannel::fuseGetXAttr(
}
folly::Future<folly::Unit> FuseChannel::fuseListXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto listattr = reinterpret_cast<const fuse_getxattr_in*>(arg);
XLOG(DBG7) << "FUSE_LISTXATTR";
return dispatcher_->listxattr(InodeNumber{header->nodeid})
.thenValue([size = listattr->size](std::vector<std::string> attrs) {
auto& request = RequestData::get();
.thenValue(
[&request, size = listattr->size](std::vector<std::string> attrs) {
// Initialize count to include the \0 for each
// entry.
size_t count = attrs.size();
for (const auto& attr : attrs) {
count += attr.size();
}
// Initialize count to include the \0 for each
// entry.
size_t count = attrs.size();
for (const auto& attr : attrs) {
count += attr.size();
}
if (size == 0) {
// caller is asking for the overall size
fuse_getxattr_out out = {};
out.size = count;
request.sendReply(out);
} else if (size < count) {
XLOG(DBG7) << "LISTXATTR input size is " << size << " and count is "
<< count;
request.replyError(ERANGE);
} else {
std::string buf;
buf.reserve(count);
for (const auto& attr : attrs) {
buf.append(attr);
buf.push_back(0);
}
XLOG(DBG7) << "LISTXATTR: " << buf;
request.sendReply(folly::StringPiece(buf));
}
});
if (size == 0) {
// caller is asking for the overall size
fuse_getxattr_out out = {};
out.size = count;
request.sendReply(out);
} else if (size < count) {
XLOG(DBG7) << "LISTXATTR input size is " << size
<< " and count is " << count;
request.replyError(ERANGE);
} else {
std::string buf;
buf.reserve(count);
for (const auto& attr : attrs) {
buf.append(attr);
buf.push_back(0);
}
XLOG(DBG7) << "LISTXATTR: " << buf;
request.sendReply(folly::StringPiece(buf));
}
});
}
folly::Future<folly::Unit> FuseChannel::fuseRemoveXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto nameStr = reinterpret_cast<const char*>(arg);
const StringPiece attrName{nameStr};
XLOG(DBG7) << "FUSE_REMOVEXATTR";
return dispatcher_->removexattr(InodeNumber{header->nodeid}, attrName)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseFlush(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto flush = reinterpret_cast<const fuse_flush_in*>(arg);
XLOG(DBG7) << "FUSE_FLUSH";
auto ino = InodeNumber{header->nodeid};
return dispatcher_->flush(ino, flush->lock_owner).thenValue([](auto&&) {
RequestData::get().replyError(0);
});
return dispatcher_->flush(ino, flush->lock_owner)
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseOpenDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto open = reinterpret_cast<const fuse_open_in*>(arg);
@ -1745,7 +1765,7 @@ folly::Future<folly::Unit> FuseChannel::fuseOpenDir(
auto ino = InodeNumber{header->nodeid};
auto minorVersion = connInfo_->minor;
return dispatcher_->opendir(ino, open->flags)
.thenValue([minorVersion](uint64_t fh) {
.thenValue([&request, minorVersion](uint64_t fh) {
fuse_open_out out = {};
#ifdef FOPEN_CACHE_DIR
if (minorVersion >= 28) {
@ -1756,37 +1776,38 @@ folly::Future<folly::Unit> FuseChannel::fuseOpenDir(
(void)minorVersion;
#endif
out.fh = fh;
RequestData::get().sendReply(out);
request.sendReply(out);
});
}
folly::Future<folly::Unit> FuseChannel::fuseReadDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
auto read = reinterpret_cast<const fuse_read_in*>(arg);
XLOG(DBG7) << "FUSE_READDIR";
auto ino = InodeNumber{header->nodeid};
return dispatcher_
->readdir(
ino, DirList{read->size}, read->offset, read->fh, RequestData::get())
.thenValue([](DirList&& list) {
->readdir(ino, DirList{read->size}, read->offset, read->fh, request)
.thenValue([&request](DirList&& list) {
const auto buf = list.getBuf();
RequestData::get().sendReply(StringPiece{buf});
request.sendReply(StringPiece{buf});
});
}
folly::Future<folly::Unit> FuseChannel::fuseReleaseDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
XLOG(DBG7) << "FUSE_RELEASEDIR";
auto ino = InodeNumber{header->nodeid};
auto release = reinterpret_cast<const fuse_release_in*>(arg);
return dispatcher_->releasedir(ino, release->fh).thenValue([](folly::Unit) {
RequestData::get().replyError(0);
});
return dispatcher_->releasedir(ino, release->fh)
.thenValue([&request](folly::Unit) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseFsyncDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto fsync = reinterpret_cast<const fuse_fsync_in*>(arg);
@ -1796,21 +1817,23 @@ folly::Future<folly::Unit> FuseChannel::fuseFsyncDir(
XLOG(DBG7) << "FUSE_FSYNCDIR";
auto ino = InodeNumber{header->nodeid};
return dispatcher_->fsyncdir(ino, datasync).thenValue([](auto&&) {
RequestData::get().replyError(0);
return dispatcher_->fsyncdir(ino, datasync).thenValue([&request](auto&&) {
request.replyError(0);
});
}
folly::Future<folly::Unit> FuseChannel::fuseAccess(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto access = reinterpret_cast<const fuse_access_in*>(arg);
XLOG(DBG7) << "FUSE_ACCESS";
return dispatcher_->access(InodeNumber{header->nodeid}, access->mask)
.thenValue([](auto&&) { RequestData::get().replyError(0); });
.thenValue([&request](auto&&) { request.replyError(0); });
}
folly::Future<folly::Unit> FuseChannel::fuseCreate(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto create = reinterpret_cast<const fuse_create_in*>(arg);
@ -1818,7 +1841,7 @@ folly::Future<folly::Unit> FuseChannel::fuseCreate(
XLOG(DBG7) << "FUSE_CREATE " << name;
auto ino = InodeNumber{header->nodeid};
return dispatcher_->create(ino, name, create->mode, create->flags)
.thenValue([](fuse_entry_out entry) {
.thenValue([&request](fuse_entry_out entry) {
fuse_open_out out = {};
out.open_flags |= FOPEN_KEEP_CACHE;
@ -1831,25 +1854,27 @@ folly::Future<folly::Unit> FuseChannel::fuseCreate(
vec.push_back(make_iovec(entry));
vec.push_back(make_iovec(out));
RequestData::get().sendReply(std::move(vec));
request.sendReply(std::move(vec));
});
}
folly::Future<folly::Unit> FuseChannel::fuseBmap(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg) {
const auto bmap = reinterpret_cast<const fuse_bmap_in*>(arg);
XLOG(DBG7) << "FUSE_BMAP";
return dispatcher_
->bmap(InodeNumber{header->nodeid}, bmap->blocksize, bmap->block)
.thenValue([](uint64_t resultIdx) {
.thenValue([&request](uint64_t resultIdx) {
fuse_bmap_out out;
out.block = resultIdx;
RequestData::get().sendReply(out);
request.sendReply(out);
});
}
folly::Future<folly::Unit> FuseChannel::fuseBatchForget(
RequestData& /*request*/,
const fuse_in_header* /*header*/,
const uint8_t* arg) {
const auto forgets = reinterpret_cast<const fuse_batch_forget_in*>(arg);

View File

@ -31,7 +31,6 @@
#include "eden/fs/utils/ProcessAccessLog.h"
namespace folly {
class RequestContext;
struct Unit;
} // namespace folly
@ -40,6 +39,7 @@ namespace eden {
class Dispatcher;
class Notifications;
class RequestData;
class FuseChannel {
public:
@ -402,96 +402,127 @@ class FuseChannel {
public:
folly::Future<folly::Unit> fuseRead(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseWrite(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseLookup(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseForget(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseGetAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseSetAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseReadLink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseSymlink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseMknod(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseMkdir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseUnlink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseRmdir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseRename(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseLink(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseOpen(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseStatFs(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseRelease(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseFsync(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseSetXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseGetXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseListXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseRemoveXAttr(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseFlush(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseOpenDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseReadDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseReleaseDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseFsyncDir(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseAccess(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseCreate(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseBmap(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);
folly::Future<folly::Unit> fuseBatchForget(
RequestData& request,
const fuse_in_header* header,
const uint8_t* arg);

View File

@ -21,33 +21,12 @@ using namespace std::chrono;
namespace facebook {
namespace eden {
const std::string RequestData::kKey("fuse");
RequestData::RequestData(
FuseChannel* channel,
const fuse_in_header& fuseHeader,
Dispatcher* dispatcher)
: channel_(channel), fuseHeader_(fuseHeader), dispatcher_(dispatcher) {}
RequestData& RequestData::get() {
const auto data = folly::RequestContext::get()->getContextData(kKey);
if (UNLIKELY(!data)) {
XLOG(FATAL) << "boom for missing RequestData";
throw std::runtime_error("no fuse request data set in this context!");
}
return *dynamic_cast<RequestData*>(data);
}
RequestData& RequestData::create(
FuseChannel* channel,
const fuse_in_header& fuseHeader,
Dispatcher* dispatcher) {
folly::RequestContext::get()->setContextData(
RequestData::kKey,
std::make_unique<RequestData>(channel, fuseHeader, dispatcher));
return get();
}
void RequestData::startRequest(
EdenStats* stats,
FuseThreadStats::HistogramPtr histogram,
@ -130,7 +109,7 @@ void RequestData::systemErrorHandler(
errnum = err.code().value();
}
XLOG(DBG5) << folly::exceptionStr(err);
RequestData::get().replyError(errnum);
replyError(errnum);
if (notifications) {
notifications->showGenericErrorNotification(err);
}
@ -140,7 +119,7 @@ void RequestData::genericErrorHandler(
const std::exception& err,
Notifications* FOLLY_NULLABLE notifications) {
XLOG(DBG5) << folly::exceptionStr(err);
RequestData::get().replyError(EIO);
replyError(EIO);
if (notifications) {
notifications->showGenericErrorNotification(err);
}
@ -151,7 +130,7 @@ void RequestData::timeoutErrorHandler(
Notifications* FOLLY_NULLABLE notifications) {
XLOG_EVERY_MS(WARN, 1000)
<< "FUSE request timed out: " << folly::exceptionStr(err);
RequestData::get().replyError(ETIMEDOUT);
replyError(ETIMEDOUT);
if (notifications) {
notifications->showGenericErrorNotification(err);
}

View File

@ -8,7 +8,6 @@
#pragma once
#include <folly/futures/Future.h>
#include <folly/io/async/Request.h>
#include <atomic>
#include <utility>
@ -25,19 +24,13 @@ namespace eden {
class Dispatcher;
/**
* Follows a request across executors and futures. startRequest should be
* called before initiating a request and will be run where this is
* initated. catchErrors will wrap a request future so that finishRequest is
* called when it is completed. finishRequest will be executed where the request
* is executed which may be in a different thread than startRequest was run.
* Thus this will be run single threaded (only running from one thread at a
* time, but may run on different threads.
* Each FUSE request has a corresponding RequestData object that is allocated at
* request start and deallocated when it finishes.
*
* see folly/io/async/Request.h for more info on RequestData
* see eden/fs/fuse/FuseChannel.cpp FuseChannel::processSession for how this
* should be used
* Unless a member function indicates otherwise, RequestData may be used from
* multiple threads, but only by one thread at a time.
*/
class RequestData : public folly::RequestData, public ObjectFetchContext {
class RequestData : public ObjectFetchContext {
FuseChannel* channel_;
fuse_in_header fuseHeader_;
// Needed to track stats
@ -76,7 +69,6 @@ class RequestData : public folly::RequestData, public ObjectFetchContext {
ImportPriority(ImportPriorityKind::High)};
public:
static const std::string kKey;
RequestData(const RequestData&) = delete;
RequestData& operator=(const RequestData&) = delete;
RequestData(RequestData&&) = delete;
@ -85,17 +77,13 @@ class RequestData : public folly::RequestData, public ObjectFetchContext {
FuseChannel* channel,
const fuse_in_header& fuseHeader,
Dispatcher* dispatcher);
static RequestData& get();
static RequestData& create(
FuseChannel* channel,
const fuse_in_header& fuseHeader,
Dispatcher* dispatcher);
bool hasCallback() override {
return false;
}
// Override of `ObjectFetchContext`
/**
* Override of `ObjectFetchContext`
*
* Unlike other RequestData function, this may be called concurrently by
* arbitrary threads.
*/
void didFetch(ObjectType /*type*/, const Hash& /*hash*/, Origin origin)
override {
if (origin == Origin::FromBackingStore) {
@ -158,10 +146,10 @@ class RequestData : public folly::RequestData, public ObjectFetchContext {
folly::Future<folly::Unit> catchErrors(
folly::Future<folly::Unit>&& fut,
Notifications* FOLLY_NULLABLE notifications) {
return std::move(fut).thenTryInline([notifications](
return std::move(fut).thenTryInline([this, notifications](
folly::Try<folly::Unit>&& try_) {
SCOPE_EXIT {
RequestData::get().finishRequest();
finishRequest();
};
if (try_.hasException()) {
if (auto* err = try_.tryGetExceptionObject<folly::FutureTimeout>()) {
@ -179,13 +167,13 @@ class RequestData : public folly::RequestData, public ObjectFetchContext {
});
}
static void systemErrorHandler(
void systemErrorHandler(
const std::system_error& err,
Notifications* FOLLY_NULLABLE notifications);
static void genericErrorHandler(
void genericErrorHandler(
const std::exception& err,
Notifications* FOLLY_NULLABLE notifications);
static void timeoutErrorHandler(
void timeoutErrorHandler(
const folly::FutureTimeout& err,
Notifications* FOLLY_NULLABLE notifications);

View File

@ -100,6 +100,7 @@ folly::Future<folly::Unit> EdenDispatcher::releasedir(
}
folly::Future<fuse_entry_out> EdenDispatcher::lookup(
uint64_t /*requestID*/,
InodeNumber parent,
PathComponentPiece namepiece,
ObjectFetchContext& context) {

View File

@ -38,6 +38,7 @@ class EdenDispatcher : public Dispatcher {
folly::Future<uint64_t> opendir(InodeNumber ino, int flags) override;
folly::Future<folly::Unit> releasedir(InodeNumber ino, uint64_t fh) override;
folly::Future<fuse_entry_out> lookup(
uint64_t requestID,
InodeNumber parent,
PathComponentPiece name,
ObjectFetchContext& context) override;

View File

@ -107,7 +107,8 @@ TEST(RawEdenDispatcherTest, lookup_returns_valid_inode_for_good_file) {
auto entry =
mount.getDispatcher()
->lookup(kRootNodeId, "good"_pc, ObjectFetchContext::getNullContext())
->lookup(
0, kRootNodeId, "good"_pc, ObjectFetchContext::getNullContext())
.get(0ms);
EXPECT_NE(0, entry.nodeid);
EXPECT_NE(0, entry.attr.ino);
@ -119,7 +120,7 @@ TEST(RawEdenDispatcherTest, lookup_returns_valid_inode_for_bad_file) {
builder.setFile("bad", "contents");
TestMount mount{builder, /*startReady=*/false};
auto entryFuture = mount.getDispatcher()->lookup(
kRootNodeId, "bad"_pc, ObjectFetchContext::getNullContext());
0, kRootNodeId, "bad"_pc, ObjectFetchContext::getNullContext());
builder.getStoredBlob("bad"_relpath)
->triggerError(std::runtime_error("failed to load"));
auto entry = std::move(entryFuture).get(0ms);

View File

@ -19,10 +19,10 @@ namespace facebook {
namespace eden {
Future<fuse_entry_out> TestDispatcher::lookup(
uint64_t requestID,
InodeNumber parent,
PathComponentPiece name,
ObjectFetchContext& /*context*/) {
auto requestID = RequestData::get().getReq().unique;
XLOG(DBG5) << "received lookup " << requestID << ": parent=" << parent
<< ", name=" << name;
auto result = Future<fuse_entry_out>::makeEmpty();

View File

@ -21,6 +21,8 @@
namespace facebook {
namespace eden {
class RequestData;
/**
* A FUSE Dispatcher implementation for use in unit tests.
*
@ -44,6 +46,7 @@ class TestDispatcher : public Dispatcher {
using Dispatcher::Dispatcher;
folly::Future<fuse_entry_out> lookup(
uint64_t requestID,
InodeNumber parent,
PathComponentPiece name,
ObjectFetchContext& context) override;