2019-12-11 01:04:02 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
|
*
|
|
|
|
* This software may be used and distributed according to the terms of the
|
|
|
|
* GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
2020-06-08 22:42:36 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
#include <folly/portability/Windows.h>
|
|
|
|
|
|
|
|
#include <folly/futures/Future.h>
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2020-09-23 19:40:09 +03:00
|
|
|
#include <ProjectedFSLib.h> // @manual
|
2020-11-14 01:26:17 +03:00
|
|
|
#include "eden/fs/prjfs/Enumerator.h"
|
2020-09-22 19:08:07 +03:00
|
|
|
#include "eden/fs/utils/Guid.h"
|
2019-12-11 01:04:02 +03:00
|
|
|
#include "eden/fs/utils/PathFuncs.h"
|
2020-09-11 18:35:51 +03:00
|
|
|
#include "eden/fs/utils/ProcessAccessLog.h"
|
2021-01-05 23:15:31 +03:00
|
|
|
#include "eden/fs/utils/Rcu.h"
|
2019-12-11 01:04:02 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
class EdenMount;
|
2020-09-23 19:40:09 +03:00
|
|
|
class Dispatcher;
|
2020-12-03 21:43:41 +03:00
|
|
|
class Notifications;
|
2021-01-05 23:15:31 +03:00
|
|
|
class PrjfsChannelInner;
|
|
|
|
class PrjfsRequestContext;
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
struct RcuTag;
|
|
|
|
using RcuLockedPtr = RcuPtr<PrjfsChannelInner, RcuTag>::RcuLockedPtr;
|
|
|
|
} // namespace detail
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
class PrjfsChannelInner {
|
2019-12-11 01:04:02 +03:00
|
|
|
public:
|
2020-12-03 21:43:41 +03:00
|
|
|
PrjfsChannelInner(
|
2020-09-23 19:40:09 +03:00
|
|
|
Dispatcher* const dispatcher,
|
2020-10-20 19:32:22 +03:00
|
|
|
const folly::Logger* straceLogger,
|
2020-12-03 21:43:41 +03:00
|
|
|
ProcessAccessLog& processAccessLog,
|
2020-12-03 21:43:41 +03:00
|
|
|
folly::Duration requestTimeout,
|
2021-01-05 23:15:31 +03:00
|
|
|
Notifications* notifications);
|
2020-09-11 18:35:51 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
~PrjfsChannelInner() = default;
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
explicit PrjfsChannelInner() = delete;
|
|
|
|
PrjfsChannelInner(const PrjfsChannelInner&) = delete;
|
|
|
|
PrjfsChannelInner& operator=(const PrjfsChannelInner&) = delete;
|
2020-06-20 04:02:42 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Start a directory listing.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
2020-12-03 21:43:41 +03:00
|
|
|
HRESULT startEnumeration(
|
2021-01-05 23:15:31 +03:00
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
2020-12-03 21:43:41 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
|
|
|
const GUID* enumerationId);
|
2020-04-24 22:42:38 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Terminate a directory listing.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
2020-12-03 21:43:41 +03:00
|
|
|
HRESULT endEnumeration(
|
2021-01-05 23:15:31 +03:00
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
2020-12-03 21:43:41 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
|
|
|
const GUID* enumerationId);
|
inodes: invalidate more on Windows
Summary:
Cache invalidation is hard, and on Windows we avoided doing a lot of them. It
turns out, this was the wrong decision as it's fairly easy to find cases where
the filesystem view is different from the manifest state.
Since the Linux code is most likely correct in where the invalidation is done,
let's also do the same on Windows, removing a whole lot of #ifdef. It is very
likely that as a result of this diff we end up invalidating more than needed,
thus slowing down EdenFS, but at this point I'd prefer to err on the side of
correctness, performance will come later.
While invalidating files should use PrjDeleteFile, for directories, we simply
need to mark them as placeholder, as directories created by a user won't have a
placeholder, thus ProjectedFS would bypass EdenFS when listing in.
Reviewed By: chadaustin
Differential Revision: D22833202
fbshipit-source-id: d807557f5e44279c49ab701b7a797253ef1f0717
2020-08-03 21:24:55 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Populate as many directory entries that dirEntryBufferHandle can take.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
2020-12-03 21:43:41 +03:00
|
|
|
HRESULT getEnumerationData(
|
2021-01-05 23:15:31 +03:00
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
2020-12-03 21:43:41 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
|
|
|
const GUID* enumerationId,
|
|
|
|
PCWSTR searchExpression,
|
|
|
|
PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle);
|
2020-08-15 03:33:49 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Obtain the metadata for a given file.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
|
|
|
HRESULT getPlaceholderInfo(
|
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
|
|
|
const PRJ_CALLBACK_DATA* callbackData);
|
2020-09-11 18:35:51 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Test whether a given file exist in the repository.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
|
|
|
HRESULT queryFileName(
|
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
|
|
|
const PRJ_CALLBACK_DATA* callbackData);
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Read the content of the given file.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
2020-12-03 21:43:41 +03:00
|
|
|
HRESULT getFileData(
|
2021-01-05 23:15:31 +03:00
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
2020-12-03 21:43:41 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
|
|
|
UINT64 byteOffset,
|
|
|
|
UINT32 length);
|
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
/**
|
|
|
|
* Notifies of state change for the given file.
|
|
|
|
*
|
|
|
|
* May spawn futures which will extend the lifetime of self.
|
|
|
|
*/
|
2020-12-03 21:43:41 +03:00
|
|
|
HRESULT notification(
|
2021-01-05 23:15:31 +03:00
|
|
|
std::shared_ptr<PrjfsRequestContext> context,
|
2020-12-03 21:43:41 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
|
|
|
BOOLEAN isDirectory,
|
|
|
|
PRJ_NOTIFICATION notificationType,
|
|
|
|
PCWSTR destinationFileName,
|
|
|
|
PRJ_NOTIFICATION_PARAMETERS* notificationParameters);
|
2020-10-20 19:32:22 +03:00
|
|
|
|
2020-09-11 18:35:51 +03:00
|
|
|
ProcessAccessLog& getProcessAccessLog() {
|
|
|
|
return processAccessLog_;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
void setMountChannel(PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT channel) {
|
|
|
|
mountChannel_ = channel;
|
2020-09-17 04:55:52 +03:00
|
|
|
}
|
|
|
|
|
2020-09-17 04:55:52 +03:00
|
|
|
void sendSuccess(
|
|
|
|
int32_t commandId,
|
|
|
|
PRJ_COMPLETE_COMMAND_EXTENDED_PARAMETERS* FOLLY_NULLABLE extra);
|
|
|
|
|
|
|
|
void sendError(int32_t commandId, HRESULT error);
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
private:
|
|
|
|
const folly::Logger& getStraceLogger() const {
|
|
|
|
return *straceLogger_;
|
|
|
|
}
|
|
|
|
|
2020-11-14 01:26:17 +03:00
|
|
|
void addDirectoryEnumeration(Guid guid, std::vector<FileMetadata> dirents) {
|
|
|
|
auto [iterator, inserted] = enumSessions_.wlock()->emplace(
|
|
|
|
std::move(guid), std::make_shared<Enumerator>(std::move(dirents)));
|
|
|
|
XDCHECK(inserted);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<std::shared_ptr<Enumerator>> findDirectoryEnumeration(
|
|
|
|
Guid& guid) {
|
|
|
|
auto enumerators = enumSessions_.rlock();
|
|
|
|
auto it = enumerators->find(guid);
|
|
|
|
|
|
|
|
if (it == enumerators->end()) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
return it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void removeDirectoryEnumeration(Guid& guid) {
|
|
|
|
auto erasedCount = enumSessions_.wlock()->erase(guid);
|
|
|
|
XDCHECK(erasedCount == 1);
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
// Internal ProjectedFS channel used to communicate with ProjectedFS.
|
2019-12-11 01:04:02 +03:00
|
|
|
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT mountChannel_{nullptr};
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2020-09-23 19:40:09 +03:00
|
|
|
Dispatcher* const dispatcher_{nullptr};
|
2020-10-20 19:32:22 +03:00
|
|
|
const folly::Logger* const straceLogger_{nullptr};
|
2020-12-03 21:43:41 +03:00
|
|
|
|
|
|
|
// The processAccessLog_ is owned by PrjfsChannel which is guaranteed to have
|
|
|
|
// its lifetime be longer than that of PrjfsChannelInner.
|
|
|
|
ProcessAccessLog& processAccessLog_;
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
const folly::Duration requestTimeout_;
|
2020-12-03 21:43:41 +03:00
|
|
|
Notifications* const notifications_;
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
// Set of currently active directory enumerations.
|
|
|
|
folly::Synchronized<folly::F14FastMap<Guid, std::shared_ptr<Enumerator>>>
|
|
|
|
enumSessions_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PrjfsChannel {
|
|
|
|
public:
|
|
|
|
PrjfsChannel(const PrjfsChannel&) = delete;
|
|
|
|
PrjfsChannel& operator=(const PrjfsChannel&) = delete;
|
|
|
|
|
|
|
|
explicit PrjfsChannel() = delete;
|
|
|
|
|
|
|
|
PrjfsChannel(
|
|
|
|
AbsolutePathPiece mountPath,
|
|
|
|
Dispatcher* const dispatcher,
|
|
|
|
const folly::Logger* straceLogger,
|
2020-12-03 21:43:41 +03:00
|
|
|
std::shared_ptr<ProcessNameCache> processNameCache,
|
2020-12-03 21:43:41 +03:00
|
|
|
folly::Duration requestTimeout,
|
2020-12-15 19:03:23 +03:00
|
|
|
Notifications* notifications,
|
|
|
|
Guid guid);
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
~PrjfsChannel();
|
|
|
|
|
|
|
|
void start(bool readOnly, bool useNegativePathCaching);
|
2020-12-03 21:43:41 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop the PrjfsChannel.
|
|
|
|
*
|
|
|
|
* The returned future will complete once all the pending callbacks and
|
|
|
|
* notifications are completed.
|
|
|
|
*
|
|
|
|
* PrjfsChannel must not be destructed until the returned future is
|
|
|
|
* fulfilled.
|
|
|
|
*/
|
|
|
|
folly::SemiFuture<folly::Unit> stop();
|
2020-12-03 21:43:41 +03:00
|
|
|
|
|
|
|
struct StopData {};
|
|
|
|
folly::SemiFuture<StopData> getStopFuture();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a file that has been cached on disk by ProjectedFS. This should be
|
|
|
|
* called when the content of a materialized file has changed, typically
|
|
|
|
* called during on an `update` operation.
|
|
|
|
*
|
|
|
|
* This can fail when the underlying file cannot be evicted from ProjectedFS,
|
|
|
|
* one example is when the user has locked the file.
|
|
|
|
*/
|
|
|
|
FOLLY_NODISCARD folly::Try<void> removeCachedFile(RelativePathPiece path);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ensure that the directory is a placeholder so that ProjectedFS will always
|
|
|
|
* invoke the opendir/readdir callbacks when the user is listing files in it.
|
|
|
|
* This particularly matters for directories that were created by the user to
|
|
|
|
* later be committed.
|
|
|
|
*/
|
|
|
|
FOLLY_NODISCARD folly::Try<void> addDirectoryPlaceholder(
|
|
|
|
RelativePathPiece path);
|
|
|
|
|
|
|
|
void flushNegativePathCache();
|
|
|
|
|
|
|
|
ProcessAccessLog& getProcessAccessLog() {
|
|
|
|
return processAccessLog_;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
/**
|
|
|
|
* Copy the inner channel.
|
|
|
|
*
|
|
|
|
* As long as the returned value is alive, the mount cannot be unmounted.
|
|
|
|
* When an unmount is pending, the shared_ptr will be NULL.
|
|
|
|
*/
|
2021-01-05 23:15:31 +03:00
|
|
|
detail::RcuLockedPtr getInner() {
|
|
|
|
return inner_.rlock();
|
2020-12-03 21:43:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const AbsolutePath mountPath_;
|
2019-12-11 01:04:02 +03:00
|
|
|
Guid mountId_;
|
2020-08-15 03:33:49 +03:00
|
|
|
bool useNegativePathCaching_{true};
|
2020-09-29 04:13:05 +03:00
|
|
|
folly::Promise<StopData> stopPromise_;
|
2020-09-11 18:35:51 +03:00
|
|
|
|
|
|
|
ProcessAccessLog processAccessLog_;
|
2020-11-14 01:26:17 +03:00
|
|
|
|
2021-01-05 23:15:31 +03:00
|
|
|
RcuPtr<PrjfsChannelInner, detail::RcuTag> inner_;
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
// Internal ProjectedFS channel used to communicate with ProjectedFS.
|
|
|
|
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT mountChannel_{nullptr};
|
2019-12-11 01:04:02 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|