mirror of
https://github.com/facebook/sapling.git
synced 2024-10-07 07:17:55 +03:00
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:
parent
bd63a78f96
commit
8e848c7a77
@ -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*/) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user