win: move some code between the dispatcher and the channel

Summary:
By making the EdenDispatcher less Windows dependant, we can more easily move it
into a non-Windows specific location later.

Reviewed By: chadaustin

Differential Revision: D23298028

fbshipit-source-id: 21726677808a9b8ce3d3e211dd65d9e47caad569
This commit is contained in:
Xavier Deguillard 2020-08-24 16:47:16 -07:00 committed by Facebook GitHub Bot
parent 1b00df7887
commit 111d960ccb
3 changed files with 151 additions and 130 deletions

View File

@ -71,30 +71,23 @@ constexpr uint32_t kMaxChunkSize = 5 * 1024 * 1024; // 5 MiB
EdenDispatcher::EdenDispatcher(EdenMount* mount) EdenDispatcher::EdenDispatcher(EdenMount* mount)
: mount_{mount}, dotEdenConfig_{makeDotEdenConfig(*mount)} {} : mount_{mount}, dotEdenConfig_{makeDotEdenConfig(*mount)} {}
HRESULT EdenDispatcher::startEnumeration( folly::Future<folly::Unit> EdenDispatcher::opendir(
const PRJ_CALLBACK_DATA& callbackData, RelativePath path,
const GUID& enumerationId) noexcept { const Guid guid) {
try { FB_LOGF(mount_->getStraceLogger(), DBG7, "opendir({}, guid={})", path, guid);
auto relPath = RelativePath(callbackData.FilePathName);
auto guid = Guid(enumerationId);
FB_LOGF( return mount_->getInode(path)
mount_->getStraceLogger(), DBG7, "opendir({}, guid={})", relPath, guid); .thenValue([](const InodePtr inode) {
auto treePtr = inode.asTreePtr();
return treePtr->readdir();
})
.thenValue([this, guid = std::move(guid)](auto&& dirents) {
auto [iterator, inserted] =
enumSessions_.wlock()->emplace(guid, std::move(dirents));
DCHECK(inserted);
auto list = mount_->getInode(relPath) return folly::unit;
.thenValue([](const InodePtr inode) { });
auto treePtr = inode.asTreePtr();
return treePtr->readdir();
})
.get();
auto [iterator, inserted] =
enumSessions_.wlock()->emplace(guid, std::move(list));
DCHECK(inserted);
return S_OK;
} catch (const std::exception& ex) {
return exceptionToHResult(ex);
}
} }
HRESULT EdenDispatcher::endEnumeration(const GUID& enumerationId) noexcept { HRESULT EdenDispatcher::endEnumeration(const GUID& enumerationId) noexcept {
@ -185,111 +178,56 @@ HRESULT EdenDispatcher::getEnumerationData(
} }
} }
HRESULT folly::Future<std::optional<InodeMetadata>> EdenDispatcher::lookup(
EdenDispatcher::getFileInfo(const PRJ_CALLBACK_DATA& callbackData) noexcept { RelativePath path) {
try { FB_LOGF(mount_->getStraceLogger(), DBG7, "lookup({})", path);
auto relPath = RelativePath(callbackData.FilePathName);
FB_LOGF(mount_->getStraceLogger(), DBG7, "lookup({})", relPath);
struct InodeMetadata { return mount_->getInode(path)
// To ensure that the OS has a record of the canonical file name, and not .thenValue(
// just whatever case was used to lookup the file, we capture the [](const InodePtr inode)
// relative path here. -> folly::Future<std::optional<InodeMetadata>> {
RelativePath path; return inode->stat(ObjectFetchContext::getNullContext())
size_t size; .thenValue([inode = std::move(inode)](struct stat&& stat) {
bool isDir; // Ensure that the OS has a record of the canonical
}; // file name, and not just whatever case was used to
// lookup the file
return mount_->getInode(relPath) size_t size = stat.st_size;
.thenValue( return InodeMetadata{*inode->getPath(), size, inode->isDir()};
[](const InodePtr inode) });
-> folly::Future<std::optional<InodeMetadata>> { })
return inode->stat(ObjectFetchContext::getNullContext()) .thenError(
.thenValue([inode = std::move(inode)](struct stat&& stat) { folly::tag_t<std::system_error>{},
// Ensure that the OS has a record of the canonical [path = std::move(path), this](const std::system_error& ex)
// file name, and not just whatever case was used to -> folly::Future<std::optional<InodeMetadata>> {
// lookup the file if (isEnoent(ex)) {
size_t size = stat.st_size; if (path == kDotEdenConfigPath) {
return InodeMetadata{ return folly::makeFuture(InodeMetadata{
*inode->getPath(), size, inode->isDir()}; std::move(path), dotEdenConfig_.length(), false});
}); } else {
}) XLOG(DBG6) << path << ": File not found";
.thenError( return folly::makeFuture(std::nullopt);
folly::tag_t<std::system_error>{},
[relPath = std::move(relPath), this](const std::system_error& ex)
-> folly::Future<std::optional<InodeMetadata>> {
if (isEnoent(ex)) {
if (relPath == kDotEdenConfigPath) {
return folly::makeFuture(
InodeMetadata{relPath, dotEdenConfig_.length(), false});
} else {
XLOG(DBG6) << relPath << ": File not found";
return folly::makeFuture(std::nullopt);
}
} }
return folly::makeFuture<std::optional<InodeMetadata>>(ex); }
}) return folly::makeFuture<std::optional<InodeMetadata>>(ex);
.thenValue([context = callbackData.NamespaceVirtualizationContext]( });
const std::optional<InodeMetadata>&& metadata) {
if (!metadata) {
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
PRJ_PLACEHOLDER_INFO placeholderInfo{};
placeholderInfo.FileBasicInfo.IsDirectory = metadata->isDir;
placeholderInfo.FileBasicInfo.FileSize = metadata->size;
auto inodeName = metadata->path.wide();
HRESULT result = PrjWritePlaceholderInfo(
context,
inodeName.c_str(),
&placeholderInfo,
sizeof(placeholderInfo));
if (FAILED(result)) {
XLOGF(
DBG6,
"{}: {:x} ({})",
metadata->path,
result,
win32ErrorToString(result));
}
return result;
})
.thenError(
folly::tag_t<std::exception>{},
[](const std::exception& ex) { return exceptionToHResult(ex); })
.get();
} catch (const std::exception& ex) {
return exceptionToHResult(ex);
}
} }
HRESULT folly::Future<bool> EdenDispatcher::access(RelativePath path) {
EdenDispatcher::queryFileName(const PRJ_CALLBACK_DATA& callbackData) noexcept { FB_LOGF(mount_->getStraceLogger(), DBG7, "access({})", path);
try {
auto relPath = RelativePath(callbackData.FilePathName);
FB_LOGF(mount_->getStraceLogger(), DBG7, "access({})", relPath);
return mount_->getInode(relPath) return mount_->getInode(path)
.thenValue([](const InodePtr) { return S_OK; }) .thenValue([](const InodePtr) { return true; })
.thenError( .thenError(
folly::tag_t<std::system_error>{}, folly::tag_t<std::system_error>{},
[relPath = std::move(relPath)](const std::system_error& ex) { [path = std::move(path)](const std::system_error& ex) {
if (isEnoent(ex)) { if (isEnoent(ex)) {
if (relPath == kDotEdenConfigPath) { if (path == kDotEdenConfigPath) {
return folly::makeFuture(S_OK); return folly::makeFuture(true);
}
return folly::makeFuture(
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
} }
return folly::makeFuture<HRESULT>(ex); return folly::makeFuture(false);
}) }
.get(); return folly::makeFuture<bool>(ex);
} catch (const std::exception& ex) { });
return exceptionToHResult(ex);
}
} }
namespace { namespace {

View File

@ -24,13 +24,20 @@ namespace facebook {
namespace eden { namespace eden {
class EdenMount; class EdenMount;
struct InodeMetadata {
// To ensure that the OS has a record of the canonical file name, and not
// just whatever case was used to lookup the file, we capture the
// relative path here.
RelativePath path;
size_t size;
bool isDir;
};
class EdenDispatcher { class EdenDispatcher {
public: public:
explicit EdenDispatcher(EdenMount* mount); explicit EdenDispatcher(EdenMount* mount);
HRESULT startEnumeration( folly::Future<folly::Unit> opendir(RelativePath path, const Guid guid);
const PRJ_CALLBACK_DATA& callbackData,
const GUID& enumerationId) noexcept;
HRESULT getEnumerationData( HRESULT getEnumerationData(
const PRJ_CALLBACK_DATA& callbackData, const PRJ_CALLBACK_DATA& callbackData,
@ -40,9 +47,9 @@ class EdenDispatcher {
HRESULT endEnumeration(const GUID& enumerationId) noexcept; HRESULT endEnumeration(const GUID& enumerationId) noexcept;
HRESULT folly::Future<std::optional<InodeMetadata>> lookup(RelativePath path);
getFileInfo(const PRJ_CALLBACK_DATA& callbackData) noexcept;
folly::Future<bool> access(RelativePath path);
HRESULT HRESULT
queryFileName(const PRJ_CALLBACK_DATA& callbackData) noexcept; queryFileName(const PRJ_CALLBACK_DATA& callbackData) noexcept;

View File

@ -18,7 +18,11 @@ using folly::sformat;
namespace { namespace {
using facebook::eden::EdenDispatcher; using facebook::eden::EdenDispatcher;
using facebook::eden::exceptionToHResult;
using facebook::eden::Guid;
using facebook::eden::InodeMetadata;
using facebook::eden::RelativePath; using facebook::eden::RelativePath;
using facebook::eden::win32ErrorToString;
#define BAIL_ON_RECURSIVE_CALL(callbackData) \ #define BAIL_ON_RECURSIVE_CALL(callbackData) \
do { \ do { \
@ -42,8 +46,22 @@ static HRESULT startEnumeration(
const PRJ_CALLBACK_DATA* callbackData, const PRJ_CALLBACK_DATA* callbackData,
const GUID* enumerationId) noexcept { const GUID* enumerationId) noexcept {
BAIL_ON_RECURSIVE_CALL(callbackData); BAIL_ON_RECURSIVE_CALL(callbackData);
return getDispatcher(callbackData)
->startEnumeration(*callbackData, *enumerationId); try {
auto path = RelativePath(callbackData->FilePathName);
auto guid = Guid(*enumerationId);
return getDispatcher(callbackData)
->opendir(std::move(path), std::move(guid))
.thenValue([](auto&&) { return S_OK; })
.thenError(
folly::tag_t<std::exception>{},
[](const std::exception& ex) { return exceptionToHResult(ex); })
.get();
return S_OK;
} catch (const std::exception& ex) {
return exceptionToHResult(ex);
}
} }
static HRESULT endEnumeration( static HRESULT endEnumeration(
@ -70,12 +88,70 @@ static HRESULT getEnumerationData(
static HRESULT getPlaceholderInfo( static HRESULT getPlaceholderInfo(
const PRJ_CALLBACK_DATA* callbackData) noexcept { const PRJ_CALLBACK_DATA* callbackData) noexcept {
BAIL_ON_RECURSIVE_CALL(callbackData); BAIL_ON_RECURSIVE_CALL(callbackData);
return getDispatcher(callbackData)->getFileInfo(*callbackData);
try {
auto path = RelativePath(callbackData->FilePathName);
return getDispatcher(callbackData)
->lookup(std::move(path))
.thenValue([context = callbackData->NamespaceVirtualizationContext](
const std::optional<InodeMetadata>&& optMetadata) {
if (!optMetadata) {
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
auto metadata = std::move(optMetadata).value();
PRJ_PLACEHOLDER_INFO placeholderInfo{};
placeholderInfo.FileBasicInfo.IsDirectory = metadata.isDir;
placeholderInfo.FileBasicInfo.FileSize = metadata.size;
auto inodeName = metadata.path.wide();
HRESULT result = PrjWritePlaceholderInfo(
context,
inodeName.c_str(),
&placeholderInfo,
sizeof(placeholderInfo));
if (FAILED(result)) {
XLOGF(
DBG6,
"{}: {:x} ({})",
metadata.path,
result,
win32ErrorToString(result));
}
return result;
})
.thenError(
folly::tag_t<std::exception>{},
[](const std::exception& ex) { return exceptionToHResult(ex); })
.get();
} catch (const std::exception& ex) {
return exceptionToHResult(ex);
}
} }
static HRESULT queryFileName(const PRJ_CALLBACK_DATA* callbackData) noexcept { static HRESULT queryFileName(const PRJ_CALLBACK_DATA* callbackData) noexcept {
BAIL_ON_RECURSIVE_CALL(callbackData); BAIL_ON_RECURSIVE_CALL(callbackData);
return getDispatcher(callbackData)->queryFileName(*callbackData);
try {
auto path = RelativePath(callbackData->FilePathName);
return getDispatcher(callbackData)
->access(std::move(path))
.thenValue([](bool present) {
if (present) {
return S_OK;
} else {
return HRESULT(ERROR_FILE_NOT_FOUND);
}
})
.thenError(
folly::tag_t<std::exception>{},
[](const std::exception& ex) { return exceptionToHResult(ex); })
.get();
} catch (const std::exception& ex) {
return exceptionToHResult(ex);
}
} }
static HRESULT getFileData( static HRESULT getFileData(