2019-12-11 01:04:02 +03:00
|
|
|
/*
|
2022-01-05 01:58:22 +03:00
|
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
2019-12-11 01:04:02 +03:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
2022-03-22 20:08:32 +03:00
|
|
|
#include <folly/experimental/AtomicReadMostlyMainPtr.h>
|
2022-07-19 22:37:57 +03:00
|
|
|
#include <folly/portability/Windows.h>
|
2022-02-10 23:02:18 +03:00
|
|
|
#include <thrift/lib/cpp/util/EnumUtils.h>
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2023-04-14 10:44:11 +03:00
|
|
|
#include "eden/fs/inodes/FsChannel.h"
|
2020-11-14 01:26:17 +03:00
|
|
|
#include "eden/fs/prjfs/Enumerator.h"
|
2021-02-10 22:46:19 +03:00
|
|
|
#include "eden/fs/prjfs/PrjfsDispatcher.h"
|
2022-02-10 23:02:18 +03:00
|
|
|
#include "eden/fs/service/gen-cpp2/eden_types.h"
|
2022-02-09 01:42:55 +03:00
|
|
|
#include "eden/fs/telemetry/TraceBus.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"
|
2023-03-24 23:50:40 +03:00
|
|
|
#include "eden/fs/utils/RefPtr.h"
|
2019-12-11 01:04:02 +03:00
|
|
|
|
2022-07-19 22:37:57 +03:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <ProjectedFSLib.h> // @manual
|
2023-07-14 18:42:03 +03:00
|
|
|
#include <libloaderapi.h> // @manual
|
2022-07-19 22:37:57 +03:00
|
|
|
#endif
|
|
|
|
|
2022-05-17 20:12:56 +03:00
|
|
|
namespace facebook::eden {
|
2022-07-19 22:37:57 +03:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
2019-12-11 01:04:02 +03:00
|
|
|
class EdenMount;
|
2023-03-24 23:50:40 +03:00
|
|
|
class EdenStats;
|
2022-03-30 19:55:44 +03:00
|
|
|
class Notifier;
|
|
|
|
class ReloadableConfig;
|
2021-01-05 23:15:31 +03:00
|
|
|
class PrjfsChannelInner;
|
|
|
|
class PrjfsRequestContext;
|
|
|
|
|
2023-03-24 23:50:40 +03:00
|
|
|
using EdenStatsPtr = RefPtr<EdenStats>;
|
|
|
|
|
2022-11-10 22:11:48 +03:00
|
|
|
namespace detail {
|
|
|
|
struct PrjfsLiveRequest;
|
|
|
|
}
|
|
|
|
|
2022-02-09 01:42:55 +03:00
|
|
|
using TraceDetailedArgumentsHandle = std::shared_ptr<void>;
|
|
|
|
|
2023-07-14 18:42:03 +03:00
|
|
|
typedef enum __PRJ_EXT_INFO_TYPE {
|
|
|
|
PRJ_EXT_INFO_TYPE_SYMLINK = 1
|
|
|
|
} _PRJ_EXT_INFO_TYPE;
|
|
|
|
|
|
|
|
typedef struct _PRJ_EXTENDED_INFO {
|
|
|
|
_PRJ_EXT_INFO_TYPE InfoType;
|
|
|
|
ULONG NextInfoOffset;
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
PCWSTR TargetName;
|
|
|
|
} Symlink;
|
|
|
|
} DUMMYUNIONNAME;
|
|
|
|
} PRJ_EXTENDED_INFO;
|
|
|
|
|
|
|
|
typedef HRESULT(WINAPI* PPWPI2)(
|
|
|
|
[in] PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT,
|
|
|
|
[in] PCWSTR,
|
|
|
|
[in] const PRJ_PLACEHOLDER_INFO*,
|
|
|
|
[in] UINT32,
|
|
|
|
const _PRJ_EXTENDED_INFO*);
|
2022-02-09 01:42:55 +03:00
|
|
|
struct PrjfsTraceEvent : TraceEventBase {
|
|
|
|
enum Type : unsigned char {
|
|
|
|
START,
|
|
|
|
FINISH,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Contains the useful fields of PRJ_CALLBACK_DATA to save TraceBus memory.
|
|
|
|
*/
|
|
|
|
struct PrjfsOperationData {
|
|
|
|
PrjfsOperationData(const PRJ_CALLBACK_DATA& data)
|
|
|
|
: commandId{data.CommandId}, pid{data.TriggeringProcessId} {}
|
|
|
|
|
|
|
|
PrjfsOperationData(const PrjfsOperationData& data) = default;
|
|
|
|
int32_t commandId;
|
|
|
|
uint32_t pid;
|
|
|
|
};
|
|
|
|
|
|
|
|
PrjfsTraceEvent() = delete;
|
|
|
|
|
|
|
|
static PrjfsTraceEvent start(
|
|
|
|
PrjfsTraceCallType callType,
|
|
|
|
const PrjfsOperationData& data) {
|
|
|
|
return PrjfsTraceEvent{
|
|
|
|
callType, data, StartDetails{std::unique_ptr<std::string>{}}};
|
|
|
|
}
|
|
|
|
|
|
|
|
static PrjfsTraceEvent start(
|
|
|
|
PrjfsTraceCallType callType,
|
|
|
|
const PrjfsOperationData& data,
|
|
|
|
std::string arguments) {
|
|
|
|
return PrjfsTraceEvent{
|
|
|
|
callType,
|
|
|
|
data,
|
|
|
|
StartDetails{std::make_unique<std::string>(std::move(arguments))}};
|
|
|
|
}
|
|
|
|
|
|
|
|
static PrjfsTraceEvent finish(
|
|
|
|
PrjfsTraceCallType callType,
|
|
|
|
const PrjfsOperationData& data) {
|
|
|
|
return PrjfsTraceEvent{callType, PrjfsOperationData{data}, FinishDetails{}};
|
|
|
|
}
|
|
|
|
|
|
|
|
Type getType() const {
|
|
|
|
return std::holds_alternative<StartDetails>(details_) ? Type::START
|
|
|
|
: Type::FINISH;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrjfsTraceCallType getCallType() const {
|
|
|
|
return type_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PrjfsOperationData& getData() const {
|
|
|
|
return data_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::unique_ptr<std::string>& getArguments() const {
|
|
|
|
return std::get<StartDetails>(details_).arguments;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct StartDetails {
|
|
|
|
/**
|
|
|
|
* If detailed trace arguments have been requested, this field contains a
|
|
|
|
* human-readable representation of the Prjfs request arguments.
|
|
|
|
*
|
|
|
|
* It is heap-allocated to reduce memory usage in the common case that
|
|
|
|
* detailed argument tracing is disabled.
|
|
|
|
*/
|
|
|
|
std::unique_ptr<std::string> arguments;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FinishDetails {};
|
|
|
|
|
|
|
|
using Details = std::variant<StartDetails, FinishDetails>;
|
|
|
|
|
|
|
|
PrjfsTraceEvent(
|
|
|
|
PrjfsTraceCallType callType,
|
|
|
|
const PrjfsOperationData& data,
|
|
|
|
Details&& details)
|
|
|
|
: type_{callType}, data_{data}, details_{std::move(details)} {}
|
|
|
|
|
|
|
|
PrjfsTraceCallType type_;
|
|
|
|
PrjfsTraceEvent::PrjfsOperationData data_;
|
|
|
|
Details details_;
|
|
|
|
};
|
|
|
|
|
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(
|
2021-02-10 22:46:19 +03:00
|
|
|
std::unique_ptr<PrjfsDispatcher> dispatcher,
|
2020-10-20 19:32:22 +03:00
|
|
|
const folly::Logger* straceLogger,
|
2022-03-22 20:08:32 +03:00
|
|
|
ProcessAccessLog& processAccessLog,
|
2022-03-30 19:55:44 +03:00
|
|
|
folly::Promise<folly::Unit> deletedPromise,
|
2023-05-08 21:04:48 +03:00
|
|
|
std::shared_ptr<Notifier> notifier,
|
|
|
|
size_t prjfsTraceBusCapacity);
|
2020-09-11 18:35:51 +03:00
|
|
|
|
2022-03-22 20:08:32 +03:00
|
|
|
~PrjfsChannelInner();
|
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
|
|
|
|
2022-01-19 04:20:01 +03:00
|
|
|
ImmediateFuture<folly::Unit> waitForPendingNotifications();
|
|
|
|
|
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,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest,
|
2020-12-03 21:43:41 +03:00
|
|
|
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,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest,
|
2020-12-03 21:43:41 +03:00
|
|
|
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,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest,
|
2020-12-03 21:43:41 +03:00
|
|
|
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,
|
2022-02-09 01:42:55 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest);
|
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,
|
2022-02-09 01:42:55 +03:00
|
|
|
const PRJ_CALLBACK_DATA* callbackData,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest);
|
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,
|
2022-11-10 22:11:48 +03:00
|
|
|
std::unique_ptr<detail::PrjfsLiveRequest> liveRequest,
|
2020-12-03 21:43:41 +03:00
|
|
|
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
|
|
|
|
2021-08-10 21:21:29 +03:00
|
|
|
/**
|
|
|
|
* Notification sent when a file or directory has been created.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> newFileCreated(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath relPath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification sent when a file or directory has been replaced.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> fileOverwritten(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath relPath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification sent when a file has been modified.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> fileHandleClosedFileModified(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath relPath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification sent when a file or directory has been renamed.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> fileRenamed(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath oldPath,
|
|
|
|
RelativePath newPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification sent prior to a file or directory being renamed.
|
|
|
|
*
|
|
|
|
* Called prior to ProjectedFS doing any on-disk checks, and thus if newPath
|
|
|
|
* exist on disk, the file rename may later fail. The rename is known to have
|
|
|
|
* happened only when fileRenamed is called.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> preRename(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath oldPath,
|
|
|
|
RelativePath newPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
2022-03-08 02:36:00 +03:00
|
|
|
/**
|
|
|
|
* Notification sent prior to a file or directory being deleted.
|
|
|
|
*
|
|
|
|
* Called prior to ProjectedFS doing any on-disk checks, and thus if relPath
|
|
|
|
* may or may not exist on disk and the deletion may later fail. The deletion
|
|
|
|
* is known to have happened only when fileHandleClosedFileDeleted is called.
|
|
|
|
*/
|
|
|
|
ImmediateFuture<folly::Unit> preDelete(
|
|
|
|
RelativePath relPath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2022-03-08 02:36:00 +03:00
|
|
|
|
2021-08-10 21:21:29 +03:00
|
|
|
/**
|
|
|
|
* Notification sent when a file or directory has been removed.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> fileHandleClosedFileDeleted(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath relPath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification sent prior to a hardlink being created.
|
|
|
|
*/
|
2021-10-27 05:21:49 +03:00
|
|
|
ImmediateFuture<folly::Unit> preSetHardlink(
|
2021-08-10 21:21:29 +03:00
|
|
|
RelativePath oldPath,
|
|
|
|
RelativePath newPath,
|
|
|
|
bool isDirectory,
|
2022-11-16 00:35:45 +03:00
|
|
|
const ObjectFetchContextPtr& context);
|
2021-08-10 21:21:29 +03:00
|
|
|
|
2023-02-15 03:31:47 +03:00
|
|
|
/**
|
|
|
|
* Notification sent prior to a file being converted to a full file.
|
|
|
|
*/
|
|
|
|
ImmediateFuture<folly::Unit> preConvertToFull(
|
|
|
|
RelativePath relpath,
|
|
|
|
RelativePath destPath,
|
|
|
|
bool isDirectory,
|
|
|
|
const ObjectFetchContextPtr& context);
|
|
|
|
|
2023-06-09 21:52:50 +03:00
|
|
|
/**
|
|
|
|
* This is not a handler for PrjFS notifications, this method can be called by
|
|
|
|
* internal callers who notice that Eden's view of the filesystem is out of
|
|
|
|
* sync.
|
|
|
|
*
|
|
|
|
* Unlike the prjfs notification handlers, the returned future does wait
|
|
|
|
* for the notification to be processed. That means that Eden should be
|
|
|
|
* in sync with the filesystem after the returned future completes.
|
|
|
|
*/
|
|
|
|
ImmediateFuture<folly::Unit> matchEdenViewOfFileToFS(
|
|
|
|
RelativePath relPath,
|
|
|
|
const ObjectFetchContextPtr& context);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-04-12 03:28:23 +03:00
|
|
|
PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT getMountChannel() const {
|
|
|
|
return mountChannel_;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2022-02-09 01:42:55 +03:00
|
|
|
struct OutstandingRequest {
|
|
|
|
PrjfsTraceCallType type;
|
|
|
|
PrjfsTraceEvent::PrjfsOperationData data;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the approximate set of outstanding PrjFS requests. Since
|
|
|
|
* telemetry is tracked on a background thread, the result may very slightly
|
|
|
|
* lag reality.
|
|
|
|
*/
|
|
|
|
std::vector<PrjfsChannelInner::OutstandingRequest> getOutstandingRequests();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* While the returned handle is alive, PrjfsTraceEvents published on the
|
|
|
|
* TraceBus will have detailed argument strings.
|
|
|
|
*/
|
|
|
|
TraceDetailedArgumentsHandle traceDetailedArguments();
|
|
|
|
|
|
|
|
std::shared_ptr<TraceBus<PrjfsTraceEvent>> getTraceBusPtr() {
|
|
|
|
return traceBus_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::atomic<size_t>& getTraceDetailedArguments() const {
|
|
|
|
return traceDetailedArguments_;
|
|
|
|
}
|
|
|
|
|
2023-03-24 23:50:40 +03:00
|
|
|
const EdenStatsPtr& getStats() const {
|
2023-03-23 06:04:41 +03:00
|
|
|
return dispatcher_->getStats();
|
|
|
|
}
|
|
|
|
|
2023-07-14 18:42:03 +03:00
|
|
|
void initializeSymlinkSupport();
|
|
|
|
|
|
|
|
bool symlinksSupported() {
|
|
|
|
return symlinksSupported_;
|
|
|
|
}
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
private:
|
|
|
|
const folly::Logger& getStraceLogger() const {
|
|
|
|
return *straceLogger_;
|
|
|
|
}
|
|
|
|
|
2021-11-05 22:54:45 +03:00
|
|
|
void addDirectoryEnumeration(Guid guid, std::vector<PrjfsDirEntry> dirents) {
|
2020-11-14 01:26:17 +03:00
|
|
|
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) {
|
2022-03-24 03:08:48 +03:00
|
|
|
enumSessions_.wlock()->erase(guid);
|
|
|
|
// In theory, we should check that we removed an entry, but ProjectedFS
|
|
|
|
// sometimes likes to close directories that were never opened, making
|
|
|
|
// checking for the return value of erase unreliable. Since it doesn't
|
|
|
|
// really matter if we remove an entry in this case, we are free to ignore
|
|
|
|
// the return value.
|
2020-11-14 01:26:17 +03:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2021-02-10 22:46:19 +03:00
|
|
|
std::unique_ptr<PrjfsDispatcher> dispatcher_;
|
2020-10-20 19:32:22 +03:00
|
|
|
const folly::Logger* const straceLogger_{nullptr};
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2022-03-30 19:55:44 +03:00
|
|
|
std::shared_ptr<Notifier> notifier_;
|
|
|
|
|
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_;
|
|
|
|
|
|
|
|
// Set of currently active directory enumerations.
|
|
|
|
folly::Synchronized<folly::F14FastMap<Guid, std::shared_ptr<Enumerator>>>
|
|
|
|
enumSessions_;
|
2022-02-09 01:42:55 +03:00
|
|
|
|
2022-03-22 20:08:32 +03:00
|
|
|
// Set when the destructor is called.
|
|
|
|
folly::Promise<folly::Unit> deletedPromise_;
|
|
|
|
|
2022-02-09 01:42:55 +03:00
|
|
|
struct TelemetryState {
|
|
|
|
std::unordered_map<uint64_t, OutstandingRequest> requests;
|
|
|
|
};
|
|
|
|
folly::Synchronized<TelemetryState> telemetryState_;
|
|
|
|
std::vector<TraceSubscriptionHandle<PrjfsTraceEvent>>
|
|
|
|
traceSubscriptionHandles_;
|
|
|
|
std::atomic<size_t> traceDetailedArguments_;
|
|
|
|
// The TraceBus must be the last member because its subscribed functions may
|
|
|
|
// close over `this` and can run until the TraceBus itself is deallocated.
|
|
|
|
std::shared_ptr<TraceBus<PrjfsTraceEvent>> traceBus_;
|
2023-07-14 18:42:03 +03:00
|
|
|
|
|
|
|
bool symlinksSupported_ = false;
|
2020-12-03 21:43:41 +03:00
|
|
|
};
|
|
|
|
|
2023-04-14 10:44:11 +03:00
|
|
|
class PrjfsChannel : public FsChannel {
|
2020-12-03 21:43:41 +03:00
|
|
|
public:
|
|
|
|
PrjfsChannel(const PrjfsChannel&) = delete;
|
|
|
|
PrjfsChannel& operator=(const PrjfsChannel&) = delete;
|
|
|
|
|
|
|
|
explicit PrjfsChannel() = delete;
|
|
|
|
|
|
|
|
PrjfsChannel(
|
|
|
|
AbsolutePathPiece mountPath,
|
2021-02-10 22:46:19 +03:00
|
|
|
std::unique_ptr<PrjfsDispatcher> dispatcher,
|
2023-06-06 22:36:24 +03:00
|
|
|
std::shared_ptr<ReloadableConfig> config,
|
2020-12-03 21:43:41 +03:00
|
|
|
const folly::Logger* straceLogger,
|
2020-12-03 21:43:41 +03:00
|
|
|
std::shared_ptr<ProcessNameCache> processNameCache,
|
2022-03-30 19:55:44 +03:00
|
|
|
Guid guid,
|
2023-06-27 23:11:01 +03:00
|
|
|
bool enableWindowsSymlinks,
|
2023-06-06 22:36:24 +03:00
|
|
|
std::shared_ptr<Notifier> notifier);
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2022-10-18 22:32:52 +03:00
|
|
|
virtual ~PrjfsChannel();
|
2020-12-03 21:43:41 +03:00
|
|
|
|
2023-05-03 02:12:46 +03:00
|
|
|
void destroy() override;
|
|
|
|
|
2023-05-04 02:22:11 +03:00
|
|
|
folly::Future<StopFuture> initialize() override;
|
|
|
|
|
2022-01-19 04:20:01 +03:00
|
|
|
/**
|
|
|
|
* Wait for all the received notifications to be fully handled.
|
|
|
|
*
|
|
|
|
* The PrjfsChannel will receive notifications and immediately dispatch the
|
|
|
|
* work to a background executor and return S_OK to ProjectedFS to unblock
|
|
|
|
* applications writing to the EdenFS repository.
|
|
|
|
*
|
|
|
|
* Thus an application writing to the repository may have their file creation
|
|
|
|
* be successful prior to EdenFS having updated its inode hierarchy. This
|
|
|
|
* discrepancy can cause issues in EdenFS for operations that exclusively
|
|
|
|
* look at the inode hierarchy such as status/checkout/glob.
|
|
|
|
*
|
|
|
|
* The returned ImmediateFuture will complete when all the previously
|
|
|
|
* received notifications have completed.
|
|
|
|
*/
|
2023-05-11 21:55:24 +03:00
|
|
|
ImmediateFuture<folly::Unit> waitForPendingWrites() override;
|
2022-01-19 04:20:01 +03:00
|
|
|
|
2023-06-09 21:52:50 +03:00
|
|
|
/**
|
|
|
|
* Background correctness checkers might notice that EdenFS has an incorrect
|
|
|
|
* view of a file. This can be used to make Eden pickup any changes it missed
|
|
|
|
* to a file.
|
|
|
|
*
|
|
|
|
* Unlike the prjfs notification handlers, the returned future does wait
|
|
|
|
* for the notification to be processed. That means that Eden should be
|
|
|
|
* in sync with the filesystem after the returned future completes.
|
|
|
|
*/
|
|
|
|
ImmediateFuture<folly::Unit> matchEdenViewOfFileToFS(
|
|
|
|
RelativePath relPath,
|
|
|
|
const ObjectFetchContextPtr& context);
|
|
|
|
|
2023-04-25 20:50:52 +03:00
|
|
|
const char* getName() const override {
|
|
|
|
return "prjfs";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool takeoverStop() override {
|
|
|
|
// ProjFS does not support takeover.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2023-04-21 04:49:40 +03:00
|
|
|
struct StopData : FsStopData {
|
|
|
|
bool isUnmounted() override;
|
|
|
|
FsChannelInfo extractTakeoverInfo() override;
|
|
|
|
};
|
2023-05-03 02:12:46 +03:00
|
|
|
|
|
|
|
StopFuture getStopFuture();
|
2020-12-03 21:43:41 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-10-18 22:32:52 +03:00
|
|
|
FOLLY_NODISCARD virtual folly::Try<folly::Unit> removeCachedFile(
|
inodes: move prjfs directory invalidation to a different thread
Summary:
Directory[0] invalidations can trigger recursive ProjectedFS callbacks onto
EdenFS, when this happens we need to make sure that the calling context doesn't
hold any locks/threads that the callback will need to run. We otherwise can run
into a deadlock situation where the callback may try to acquire a lock held by
the calling context.
In this situation, checkout is this calling context, and it has been shown that
directory invalidation may in some cases trigger a recursive lookup. While the
lookup callback doesn't use any shared locks, it pushes work to the server
state thread pool in `ObjectStore::getTree`. Unfortunately, this thread pool is
also where checkout runs, and thus if too many directory invalidation are
occuring at the same time, all the threads in the thread pool might be blocked
and thus `ObjectStore::getTree` may never complete, causing the lookup callback
to not complete, causing the invalidation to not complete, causing checkout to
not complete.
The solution is to move the invalidation away from the thread pool, that way
checkout doesn't block in the thread pool while the invalidation is ongoing,
allowing `ObjectStore::getTree` to push work onto it and run it.
[0]: File invalidation won't trigger these recursive callbacks.
Reviewed By: chadaustin
Differential Revision: D33773892
fbshipit-source-id: a6516afdc5c68ac8d1d7ba75f91c45fb12cc6ee4
2022-01-28 04:41:13 +03:00
|
|
|
RelativePathPiece path);
|
2020-12-03 21:43:41 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2022-10-18 22:32:52 +03:00
|
|
|
FOLLY_NODISCARD virtual folly::Try<folly::Unit> addDirectoryPlaceholder(
|
2020-12-03 21:43:41 +03:00
|
|
|
RelativePathPiece path);
|
|
|
|
|
2023-04-14 10:44:11 +03:00
|
|
|
ImmediateFuture<folly::Unit> completeInvalidations() override;
|
|
|
|
|
2020-12-03 21:43:41 +03:00
|
|
|
void flushNegativePathCache();
|
|
|
|
|
2023-05-03 02:12:46 +03:00
|
|
|
ProcessAccessLog& getProcessAccessLog() override {
|
2020-12-03 21:43:41 +03:00
|
|
|
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.
|
|
|
|
*/
|
2022-03-22 20:08:32 +03:00
|
|
|
folly::ReadMostlySharedPtr<PrjfsChannelInner> getInner() {
|
|
|
|
return inner_.load(std::memory_order_consume);
|
2020-12-03 21:43:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const AbsolutePath mountPath_;
|
2019-12-11 01:04:02 +03:00
|
|
|
Guid mountId_;
|
2023-06-27 23:11:01 +03:00
|
|
|
bool enableSymlinks_;
|
2020-08-15 03:33:49 +03:00
|
|
|
bool useNegativePathCaching_{true};
|
2023-06-06 22:36:24 +03:00
|
|
|
folly::Promise<FsStopDataPtr> stopPromise_{
|
|
|
|
folly::Promise<FsStopDataPtr>::makeEmpty()};
|
2020-09-11 18:35:51 +03:00
|
|
|
|
|
|
|
ProcessAccessLog processAccessLog_;
|
2020-11-14 01:26:17 +03:00
|
|
|
|
2023-02-15 03:31:47 +03:00
|
|
|
std::shared_ptr<ReloadableConfig> config_;
|
|
|
|
|
2022-03-22 20:08:32 +03:00
|
|
|
folly::AtomicReadMostlyMainPtr<PrjfsChannelInner> inner_;
|
|
|
|
folly::SemiFuture<folly::Unit> innerDeleted_;
|
2019-12-11 01:04:02 +03:00
|
|
|
};
|
|
|
|
|
2022-07-19 22:37:57 +03:00
|
|
|
#endif
|
|
|
|
|
2022-05-17 20:12:56 +03:00
|
|
|
} // namespace facebook::eden
|