sapling/eden/fs/inodes/Overlay.cpp

746 lines
24 KiB
C++
Raw Normal View History

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#include "eden/fs/inodes/Overlay.h"
#include <boost/filesystem.hpp>
#include <algorithm>
#include <folly/Exception.h>
#include <folly/File.h>
#include <folly/FileUtil.h>
#include <folly/Range.h>
#include <folly/io/Cursor.h>
#include <folly/io/IOBuf.h>
#include <folly/logging/xlog.h>
#include <folly/stop_watch.h>
#include <thrift/lib/cpp2/protocol/Serializer.h>
#include "eden/fs/config/EdenConfig.h"
#include "eden/fs/inodes/DirEntry.h"
#include "eden/fs/inodes/IFileContentStore.h"
#include "eden/fs/inodes/InodeBase.h"
#include "eden/fs/inodes/InodeTable.h"
#include "eden/fs/inodes/OverlayFile.h"
#include "eden/fs/inodes/TreeInode.h"
#include "eden/fs/inodes/sqlitecatalog/BufferedSqliteInodeCatalog.h"
#include "eden/fs/inodes/sqlitecatalog/SqliteInodeCatalog.h"
#include "eden/fs/sqlite/SqliteDatabase.h"
#include "eden/fs/utils/Bug.h"
#include "eden/fs/utils/PathFuncs.h"
namespace facebook::eden {
namespace {
constexpr uint64_t ioCountMask = 0x7FFFFFFFFFFFFFFFull;
constexpr uint64_t ioClosedMask = 1ull << 63;
std::unique_ptr<InodeCatalog> makeInodeCatalog(
AbsolutePathPiece localDir,
Overlay::InodeCatalogType inodeCatalogType,
const EdenConfig& config,
IFileContentStore* fileContentStore) {
if (inodeCatalogType == Overlay::InodeCatalogType::Tree) {
return std::make_unique<SqliteInodeCatalog>(localDir);
} else if (inodeCatalogType == Overlay::InodeCatalogType::TreeInMemory) {
XLOG(WARN) << "In-memory overlay requested. This will cause data loss.";
return std::make_unique<SqliteInodeCatalog>(
std::make_unique<SqliteDatabase>(SqliteDatabase::inMemory));
} else if (
inodeCatalogType == Overlay::InodeCatalogType::TreeSynchronousOff) {
return std::make_unique<SqliteInodeCatalog>(
localDir, SqliteTreeStore::SynchronousMode::Off);
} else if (inodeCatalogType == Overlay::InodeCatalogType::TreeBuffered) {
XLOG(DBG4) << "Buffered tree overlay being used";
return std::make_unique<BufferedSqliteInodeCatalog>(localDir, config);
} else if (
inodeCatalogType == Overlay::InodeCatalogType::TreeInMemoryBuffered) {
XLOG(WARN)
<< "In-memory buffered overlay requested. This will cause data loss.";
return std::make_unique<BufferedSqliteInodeCatalog>(
std::make_unique<SqliteDatabase>(SqliteDatabase::inMemory), config);
} else if (
inodeCatalogType ==
Overlay::InodeCatalogType::TreeSynchronousOffBuffered) {
XLOG(DBG2)
<< "Buffered tree overlay being used with synchronous-mode = off";
return std::make_unique<BufferedSqliteInodeCatalog>(
localDir, config, SqliteTreeStore::SynchronousMode::Off);
}
#ifdef _WIN32
(void)fileContentStore;
if (inodeCatalogType == Overlay::InodeCatalogType::Legacy) {
throw std::runtime_error(
"Legacy overlay type is not supported. Please reclone.");
}
return std::make_unique<SqliteInodeCatalog>(localDir);
#else
return std::make_unique<FsInodeCatalog>(
static_cast<FileContentStore*>(fileContentStore));
#endif
}
std::unique_ptr<IFileContentStore> makeFileContentStore(
AbsolutePathPiece localDir) {
#ifdef _WIN32
(void)localDir;
return nullptr;
#else
return std::make_unique<FileContentStore>(localDir);
#endif
}
} // namespace
using folly::Unit;
using std::optional;
std::shared_ptr<Overlay> Overlay::create(
AbsolutePathPiece localDir,
CaseSensitivity caseSensitive,
InodeCatalogType inodeCatalogType,
std::shared_ptr<StructuredLogger> logger,
const EdenConfig& config) {
// This allows us to access the private constructor.
struct MakeSharedEnabler : public Overlay {
explicit MakeSharedEnabler(
AbsolutePathPiece localDir,
CaseSensitivity caseSensitive,
InodeCatalogType inodeCatalogType,
std::shared_ptr<StructuredLogger> logger,
const EdenConfig& config)
: Overlay(localDir, caseSensitive, inodeCatalogType, logger, config) {}
};
return std::make_shared<MakeSharedEnabler>(
localDir, caseSensitive, inodeCatalogType, logger, config);
}
Overlay::Overlay(
AbsolutePathPiece localDir,
CaseSensitivity caseSensitive,
InodeCatalogType inodeCatalogType,
std::shared_ptr<StructuredLogger> logger,
const EdenConfig& config)
: fileContentStore_{makeFileContentStore(localDir)},
inodeCatalog_{makeInodeCatalog(
localDir,
inodeCatalogType,
config,
fileContentStore_ ? fileContentStore_.get() : nullptr)},
inodeCatalogType_{inodeCatalogType},
supportsSemanticOperations_{inodeCatalog_->supportsSemanticOperations()},
localDir_{localDir},
caseSensitive_{caseSensitive},
structuredLogger_{logger} {}
Overlay::~Overlay() {
close();
}
void Overlay::close() {
XCHECK_NE(std::this_thread::get_id(), gcThread_.get_id());
gcQueue_.lock()->stop = true;
gcCondVar_.notify_one();
if (gcThread_.joinable()) {
gcThread_.join();
}
// Make sure everything is shut down in reverse of construction order.
// Cleanup is not necessary if tree overlay was not initialized and either
// there is no file content store or the it was not initalized
if (!inodeCatalog_->initialized() &&
(!fileContentStore_ ||
(fileContentStore_ && !fileContentStore_->initialized()))) {
return;
}
// Since we are closing the overlay, no other threads can still be using
// it. They must have used some external synchronization mechanism to
// ensure this, so it is okay for us to still use relaxed access to
// nextInodeNumber_.
std::optional<InodeNumber> optNextInodeNumber;
auto nextInodeNumber = nextInodeNumber_.load(std::memory_order_relaxed);
if (nextInodeNumber) {
optNextInodeNumber = InodeNumber{nextInodeNumber};
}
closeAndWaitForOutstandingIO();
#ifndef _WIN32
inodeMetadataTable_.reset();
#endif // !_WIN32
inodeCatalog_->close(optNextInodeNumber);
if (fileContentStore_ && inodeCatalogType_ != InodeCatalogType::Legacy) {
fileContentStore_->close();
}
}
bool Overlay::isClosed() {
return outstandingIORequests_.load(std::memory_order_acquire) & ioClosedMask;
}
#ifndef _WIN32
struct statfs Overlay::statFs() {
IORequest req{this};
XCHECK(fileContentStore_);
return fileContentStore_->statFs();
}
#endif // !_WIN32
folly::SemiFuture<Unit> Overlay::initialize(
std::shared_ptr<const EdenConfig> config,
inodes: implement FSCK for Windows Tree Overlay Summary: This diff implements FSCK for EdenFS Windows. On Windows, users can still modify EdenFS mounts even when EdenFS is not running, which may cause mismatch between EdenFS state and on-disk view. This subsequently may cause issues when EdenFS is running again (such as permission error, not seeing added entries in `hg status`, etc..). This diff adds FSCK to EdenFS Windows. It is not exactly same as what fsck traditionally do on *NIX systems. We are still dubbing it as FSCK since it works at the same place as eden fsck. At startup, FSCK will crawl the EdenFS mount to compare the overlay state with disk state. It then synchronizes the overlay view with what the user has on disk. Note Windows does not always permit user to modify the mount, it only allows changes in certain situation. In particular, when the directory is in Full state, this diff takes advantage of that so we can finish the scanning by only scans such directories. One limitation of Windows FSCK is that, it cannot reliably tell if the user deleted a directory or file from dirty placeholder directories. This is because ProjectedFS will hide untouched entries under dirty placeholder directory when EdenFS is not running, and there is no way we can tell if the entry is gone because of user deletion or hid by ProjectedFS. This is not perfect but acceptable to some extent. One possible failure scenario is: 1. User creates a directory named `foo`. 2. User writes a file to that directory (`foo/bar`). 3. EdenFS then stops running. 4. User then deletes the entire `foo` directory on disk. 5. EdenFS starts again, `foo` will be recrated with an empty `bar` file. This will still correctly show in `hg status`, and the user is able to delete them again. Reviewed By: xavierd Differential Revision: D27872753 fbshipit-source-id: c553db568379062ff4504204c1a1785664f87c00
2021-05-18 09:36:54 +03:00
std::optional<AbsolutePath> mountPath,
OverlayChecker::ProgressCallback&& progressCallback,
OverlayChecker::LookupCallback&& lookupCallback) {
// The initOverlay() call is potentially slow, so we want to avoid
// performing it in the current thread and blocking returning to our caller.
//
// We already spawn a separate thread for garbage collection. It's convenient
// to simply use this existing thread to perform the initialization logic
// before waiting for GC work to do.
auto [initPromise, initFuture] = folly::makePromiseContract<Unit>();
gcThread_ = std::thread([this,
config = std::move(config),
inodes: implement FSCK for Windows Tree Overlay Summary: This diff implements FSCK for EdenFS Windows. On Windows, users can still modify EdenFS mounts even when EdenFS is not running, which may cause mismatch between EdenFS state and on-disk view. This subsequently may cause issues when EdenFS is running again (such as permission error, not seeing added entries in `hg status`, etc..). This diff adds FSCK to EdenFS Windows. It is not exactly same as what fsck traditionally do on *NIX systems. We are still dubbing it as FSCK since it works at the same place as eden fsck. At startup, FSCK will crawl the EdenFS mount to compare the overlay state with disk state. It then synchronizes the overlay view with what the user has on disk. Note Windows does not always permit user to modify the mount, it only allows changes in certain situation. In particular, when the directory is in Full state, this diff takes advantage of that so we can finish the scanning by only scans such directories. One limitation of Windows FSCK is that, it cannot reliably tell if the user deleted a directory or file from dirty placeholder directories. This is because ProjectedFS will hide untouched entries under dirty placeholder directory when EdenFS is not running, and there is no way we can tell if the entry is gone because of user deletion or hid by ProjectedFS. This is not perfect but acceptable to some extent. One possible failure scenario is: 1. User creates a directory named `foo`. 2. User writes a file to that directory (`foo/bar`). 3. EdenFS then stops running. 4. User then deletes the entire `foo` directory on disk. 5. EdenFS starts again, `foo` will be recrated with an empty `bar` file. This will still correctly show in `hg status`, and the user is able to delete them again. Reviewed By: xavierd Differential Revision: D27872753 fbshipit-source-id: c553db568379062ff4504204c1a1785664f87c00
2021-05-18 09:36:54 +03:00
mountPath = std::move(mountPath),
progressCallback = std::move(progressCallback),
lookupCallback = lookupCallback,
promise = std::move(initPromise)]() mutable {
try {
initOverlay(
std::move(config),
std::move(mountPath),
progressCallback,
lookupCallback);
} catch (...) {
auto ew = folly::exception_wrapper{std::current_exception()};
XLOG(ERR) << "overlay initialization failed for " << localDir_ << ": "
<< ew;
promise.setException(std::move(ew));
return;
}
promise.setValue();
gcThread();
});
return std::move(initFuture);
}
void Overlay::initOverlay(
std::shared_ptr<const EdenConfig> config,
inodes: implement FSCK for Windows Tree Overlay Summary: This diff implements FSCK for EdenFS Windows. On Windows, users can still modify EdenFS mounts even when EdenFS is not running, which may cause mismatch between EdenFS state and on-disk view. This subsequently may cause issues when EdenFS is running again (such as permission error, not seeing added entries in `hg status`, etc..). This diff adds FSCK to EdenFS Windows. It is not exactly same as what fsck traditionally do on *NIX systems. We are still dubbing it as FSCK since it works at the same place as eden fsck. At startup, FSCK will crawl the EdenFS mount to compare the overlay state with disk state. It then synchronizes the overlay view with what the user has on disk. Note Windows does not always permit user to modify the mount, it only allows changes in certain situation. In particular, when the directory is in Full state, this diff takes advantage of that so we can finish the scanning by only scans such directories. One limitation of Windows FSCK is that, it cannot reliably tell if the user deleted a directory or file from dirty placeholder directories. This is because ProjectedFS will hide untouched entries under dirty placeholder directory when EdenFS is not running, and there is no way we can tell if the entry is gone because of user deletion or hid by ProjectedFS. This is not perfect but acceptable to some extent. One possible failure scenario is: 1. User creates a directory named `foo`. 2. User writes a file to that directory (`foo/bar`). 3. EdenFS then stops running. 4. User then deletes the entire `foo` directory on disk. 5. EdenFS starts again, `foo` will be recrated with an empty `bar` file. This will still correctly show in `hg status`, and the user is able to delete them again. Reviewed By: xavierd Differential Revision: D27872753 fbshipit-source-id: c553db568379062ff4504204c1a1785664f87c00
2021-05-18 09:36:54 +03:00
std::optional<AbsolutePath> mountPath,
FOLLY_MAYBE_UNUSED const OverlayChecker::ProgressCallback& progressCallback,
FOLLY_MAYBE_UNUSED OverlayChecker::LookupCallback& lookupCallback) {
IORequest req{this};
auto optNextInodeNumber = inodeCatalog_->initOverlay(true);
if (fileContentStore_ && inodeCatalogType_ != InodeCatalogType::Legacy) {
fileContentStore_->initialize(true);
}
if (!optNextInodeNumber.has_value()) {
#ifndef _WIN32
// If the next-inode-number data is missing it means that this overlay was
// not shut down cleanly the last time it was used. If this was caused by a
// hard system reboot this can sometimes cause corruption and/or missing
// data in some of the on-disk state.
//
// Use OverlayChecker to scan the overlay for any issues, and also compute
// correct next inode number as it does so.
XLOG(WARN) << "Overlay " << localDir_
<< " was not shut down cleanly. Performing fsck scan.";
// TODO(zeyi): `OverlayCheck` should be associated with the specific
// Overlay implementation. `static_cast` is a temporary workaround.
//
// Note: lookupCallback is a reference but is stored on OverlayChecker.
// Therefore OverlayChecker must not exist longer than this initOverlay
// call.
OverlayChecker checker(
static_cast<FsInodeCatalog*>(inodeCatalog_.get()),
static_cast<FileContentStore*>(fileContentStore_.get()),
std::nullopt,
lookupCallback);
folly::stop_watch<> fsckRuntime;
checker.scanForErrors(progressCallback);
auto result = checker.repairErrors();
auto fsckRuntimeInSeconds =
std::chrono::duration<double>{fsckRuntime.elapsed()}.count();
if (result) {
// If totalErrors - fixedErrors is nonzero, then we failed to
// fix all of the problems.
auto success = !(result->totalErrors - result->fixedErrors);
structuredLogger_->logEvent(
Fsck{fsckRuntimeInSeconds, success, true /*attempted_repair*/});
} else {
structuredLogger_->logEvent(Fsck{
fsckRuntimeInSeconds, true /*success*/, false /*attempted_repair*/});
}
optNextInodeNumber = checker.getNextInodeNumber();
#else
// SqliteInodeCatalog will always return the value of next Inode number, if
// we end up here - it's a bug.
EDEN_BUG() << "Tree Overlay is null value for NextInodeNumber";
#endif
} else {
hadCleanStartup_ = true;
}
inodes: implement FSCK for Windows Tree Overlay Summary: This diff implements FSCK for EdenFS Windows. On Windows, users can still modify EdenFS mounts even when EdenFS is not running, which may cause mismatch between EdenFS state and on-disk view. This subsequently may cause issues when EdenFS is running again (such as permission error, not seeing added entries in `hg status`, etc..). This diff adds FSCK to EdenFS Windows. It is not exactly same as what fsck traditionally do on *NIX systems. We are still dubbing it as FSCK since it works at the same place as eden fsck. At startup, FSCK will crawl the EdenFS mount to compare the overlay state with disk state. It then synchronizes the overlay view with what the user has on disk. Note Windows does not always permit user to modify the mount, it only allows changes in certain situation. In particular, when the directory is in Full state, this diff takes advantage of that so we can finish the scanning by only scans such directories. One limitation of Windows FSCK is that, it cannot reliably tell if the user deleted a directory or file from dirty placeholder directories. This is because ProjectedFS will hide untouched entries under dirty placeholder directory when EdenFS is not running, and there is no way we can tell if the entry is gone because of user deletion or hid by ProjectedFS. This is not perfect but acceptable to some extent. One possible failure scenario is: 1. User creates a directory named `foo`. 2. User writes a file to that directory (`foo/bar`). 3. EdenFS then stops running. 4. User then deletes the entire `foo` directory on disk. 5. EdenFS starts again, `foo` will be recrated with an empty `bar` file. This will still correctly show in `hg status`, and the user is able to delete them again. Reviewed By: xavierd Differential Revision: D27872753 fbshipit-source-id: c553db568379062ff4504204c1a1785664f87c00
2021-05-18 09:36:54 +03:00
// On Windows, we need to scan the state of the repository every time at
// start up to find any potential changes happened when EdenFS is not
// running.
//
// mountPath will be empty during benchmarking so we must check the value
// here to skip scanning in that case.
if (folly::kIsWindows && mountPath.has_value()) {
folly::stop_watch<> fsckRuntime;
optNextInodeNumber =
dynamic_cast<SqliteInodeCatalog*>(inodeCatalog_.get())
->scanLocalChanges(std::move(config), *mountPath, lookupCallback);
auto fsckRuntimeInSeconds =
std::chrono::duration<double>{fsckRuntime.elapsed()}.count();
structuredLogger_->logEvent(Fsck{
fsckRuntimeInSeconds, true /*success*/, false /*attempted_repair*/});
inodes: implement FSCK for Windows Tree Overlay Summary: This diff implements FSCK for EdenFS Windows. On Windows, users can still modify EdenFS mounts even when EdenFS is not running, which may cause mismatch between EdenFS state and on-disk view. This subsequently may cause issues when EdenFS is running again (such as permission error, not seeing added entries in `hg status`, etc..). This diff adds FSCK to EdenFS Windows. It is not exactly same as what fsck traditionally do on *NIX systems. We are still dubbing it as FSCK since it works at the same place as eden fsck. At startup, FSCK will crawl the EdenFS mount to compare the overlay state with disk state. It then synchronizes the overlay view with what the user has on disk. Note Windows does not always permit user to modify the mount, it only allows changes in certain situation. In particular, when the directory is in Full state, this diff takes advantage of that so we can finish the scanning by only scans such directories. One limitation of Windows FSCK is that, it cannot reliably tell if the user deleted a directory or file from dirty placeholder directories. This is because ProjectedFS will hide untouched entries under dirty placeholder directory when EdenFS is not running, and there is no way we can tell if the entry is gone because of user deletion or hid by ProjectedFS. This is not perfect but acceptable to some extent. One possible failure scenario is: 1. User creates a directory named `foo`. 2. User writes a file to that directory (`foo/bar`). 3. EdenFS then stops running. 4. User then deletes the entire `foo` directory on disk. 5. EdenFS starts again, `foo` will be recrated with an empty `bar` file. This will still correctly show in `hg status`, and the user is able to delete them again. Reviewed By: xavierd Differential Revision: D27872753 fbshipit-source-id: c553db568379062ff4504204c1a1785664f87c00
2021-05-18 09:36:54 +03:00
}
nextInodeNumber_.store(optNextInodeNumber->get(), std::memory_order_relaxed);
#ifndef _WIN32
// Open after infoFile_'s lock is acquired because the InodeTable acquires
// its own lock, which should be released prior to infoFile_.
inodeMetadataTable_ = InodeMetadataTable::open(
(localDir_ + PathComponentPiece{FileContentStore::kMetadataFile})
.c_str());
#endif // !_WIN32
}
InodeNumber Overlay::allocateInodeNumber() {
// InodeNumber should generally be 64-bits wide, in which case it isn't even
// worth bothering to handle the case where nextInodeNumber_ wraps. We don't
// need to bother checking for conflicts with existing inode numbers since
// this can only happen if we wrap around. We don't currently support
// platforms with 32-bit inode numbers.
static_assert(
sizeof(nextInodeNumber_) == sizeof(InodeNumber),
"expected nextInodeNumber_ and InodeNumber to have the same size");
static_assert(
sizeof(InodeNumber) >= 8, "expected InodeNumber to be at least 64 bits");
// This could be a relaxed atomic operation. It doesn't matter on x86 but
// might on ARM.
auto previous = nextInodeNumber_++;
XDCHECK_NE(0u, previous) << "allocateInodeNumber called before initialize";
return InodeNumber{previous};
}
DirContents Overlay::loadOverlayDir(InodeNumber inodeNumber) {
DirContents result(caseSensitive_);
IORequest req{this};
auto dirData = inodeCatalog_->loadOverlayDir(inodeNumber);
if (!dirData.has_value()) {
return result;
}
const auto& dir = dirData.value();
bool shouldMigrateToNewFormat = false;
for (auto& iter : *dir.entries_ref()) {
const auto& name = iter.first;
const auto& value = iter.second;
InodeNumber ino;
if (*value.inodeNumber_ref()) {
ino = InodeNumber::fromThrift(*value.inodeNumber_ref());
} else {
ino = allocateInodeNumber();
shouldMigrateToNewFormat = true;
}
if (value.hash_ref() && !value.hash_ref()->empty()) {
separate out ObjectId [proxy hash removal 1/n] Summary: The goal of this stack is to remove Proxy Hash type, but to achieve that we need first to address some tech debt in Eden codebase. For the long time EdenFs had single Hash type that was used for many different use cases. One of major uses for Hash type is identifies internal EdenFs objects such as blobs, trees, and others. We seem to reach agreement that we need a different type for those identifiers, so we introduce separate ObjectId type in this diff to denote new identifier type and replace _some_ usage of Hash with ObjectId. We still retain original Hash type for other use cases. Roughly speaking, this is how this diff separates between Hash and ObjectId: **ObjectId**: * Everything that is stored in local store(blobs, trees, commits) **Hash20**: * Explicit hashes(Sha1 of the blob) * Hg identifiers: manifest id and blob hg ig For now, in this diff ObjectId has exactly same content as Hash, but this will change in the future diffs. Doing this way allows to keep diff size manageable, while migrating to new ObjectId right away would produce insanely large diff that would be both hard to make and review. There are few more things that needs to be done before we can get to the meat of removing proxy hashes: 1) Replace include Hash.h with ObjectId.h where needed 2) Remove Hash type, explicitly rename rest of Hash usages to Hash20 3) Modify content of ObjectId to support new use cases 4) Modify serialized metadata and possibly other places that assume ObjectId size is fixed and equal to Hash20 size Reviewed By: chadaustin Differential Revision: D31316477 fbshipit-source-id: 0d5e4460a461bcaac6b9fd884517e129aeaf4baf
2021-10-01 20:24:21 +03:00
auto hash =
ObjectId{folly::ByteRange{folly::StringPiece{*value.hash_ref()}}};
result.emplace(PathComponentPiece{name}, *value.mode_ref(), ino, hash);
} else {
// The inode is materialized
result.emplace(PathComponentPiece{name}, *value.mode_ref(), ino);
}
}
if (shouldMigrateToNewFormat) {
saveOverlayDir(inodeNumber, result);
}
return result;
}
overlay::OverlayEntry Overlay::serializeOverlayEntry(const DirEntry& ent) {
overlay::OverlayEntry entry;
// TODO: Eventually, we should only serialize the child entry's dtype into
// the Overlay. But, as of now, it's possible to create an inode under a
// tree, serialize that tree into the overlay, then restart Eden. Since
// writing mode bits into the InodeMetadataTable only occurs when the inode
// is loaded, the initial mode bits must persist until the first load.
entry.mode_ref() = ent.getInitialMode();
entry.inodeNumber_ref() = ent.getInodeNumber().get();
if (!ent.isMaterialized()) {
Make ObjectId a variable length hash [proxy hash removal 4/n] Summary: This diff modifies ObjectId structure to support storing more information directly in ObjectId, avoiding proxy objects like HgProxyHash and ReCasDigestProxyHash. Storing this information directly in ObjectId allows to avoid additional db access for loading/storing those proxy hash objects, reducing file access latency in hot case. **New ObjectId format** ObjectId can now content variable length hash. The variable length can be used in following cases: (1) To replace ReCasDigestProxyHash, extra 8 bytes can be used to store size portion of `remote_execution::TDigest` (2) To replace HgProxyHash, extra 1 byte can be used to identify whether ObjectId represents ProxyHashId or an HgId. In the future, ObjectId can contain path or other information needed to implement ACL **Compatibility notes** For compatibility reasons, we only currently initialize ObjectId with 20-bytes content. This is essential to allow smooth migration to a new format (a) Until new hash format is actually used(e.g. we switch HgBackingStore to store HgId inside ObjectId), this code is backwards compatible with other EdenFs versions. This revision can be safely rolled back and previous version of EdenFs can still read inode data written by this version (b) When we introduce support for new ObjectId into HgBackingStore, we can gate it's usage behind config, allowing controlled slow roll out of new ObjectId format. **ToDo** Just to track progress of removing proxy hashes, few things are still left: * We need different format for SerializedTreeMetadata * We need to support new format for thriftHash * We need to actually switch HgBackingStore to embed HgId information into ObjectId, instead of using ProxyHash Not planned: * Migration of ReCasDigestProxyHash - I don't know how to test it, so someone else should probably do that Reviewed By: chadaustin Differential Revision: D31668130 fbshipit-source-id: 720127354c648651bb35e850beb8dd252a5566b2
2021-10-23 03:50:34 +03:00
entry.hash_ref() = ent.getHash().asString();
}
return entry;
}
overlay::OverlayDir Overlay::serializeOverlayDir(
InodeNumber inodeNumber,
const DirContents& dir) {
IORequest req{this};
auto nextInodeNumber = nextInodeNumber_.load(std::memory_order_relaxed);
XCHECK_LT(inodeNumber.get(), nextInodeNumber)
<< "serializeOverlayDir called with unallocated inode number";
// TODO: T20282158 clean up access of child inode information.
//
// Translate the data to the thrift equivalents
overlay::OverlayDir odir;
for (auto& entIter : dir) {
const auto& entName = entIter.first;
const auto& ent = entIter.second;
XCHECK_NE(entName, "")
<< "serializeOverlayDir called with entry with an empty path for directory with inodeNumber="
<< inodeNumber;
XCHECK_LT(ent.getInodeNumber().get(), nextInodeNumber)
<< "serializeOverlayDir called with entry using unallocated inode number";
odir.entries_ref()->emplace(
std::make_pair(entName.asString(), serializeOverlayEntry(ent)));
}
return odir;
}
void Overlay::saveOverlayDir(InodeNumber inodeNumber, const DirContents& dir) {
inodeCatalog_->saveOverlayDir(
inodeNumber, serializeOverlayDir(inodeNumber, dir));
}
void Overlay::freeInodeFromMetadataTable(InodeNumber ino) {
#ifndef _WIN32
// TODO: batch request during GC
getInodeMetadataTable()->freeInode(ino);
#else
(void)ino;
#endif
}
void Overlay::removeOverlayFile(InodeNumber inodeNumber) {
#ifndef _WIN32
IORequest req{this};
freeInodeFromMetadataTable(inodeNumber);
fileContentStore_->removeOverlayFile(inodeNumber);
#else
(void)inodeNumber;
#endif
}
void Overlay::removeOverlayDir(InodeNumber inodeNumber) {
IORequest req{this};
freeInodeFromMetadataTable(inodeNumber);
inodeCatalog_->removeOverlayDir(inodeNumber);
}
void Overlay::recursivelyRemoveOverlayDir(InodeNumber inodeNumber) {
IORequest req{this};
freeInodeFromMetadataTable(inodeNumber);
// This inode's data must be removed from the overlay before
// recursivelyRemoveOverlayDir returns to avoid a race condition if
// recursivelyRemoveOverlayDir(I) is called immediately prior to
// saveOverlayDir(I). There's also no risk of violating our durability
// guarantees if the process dies after this call but before the thread could
// remove this data.
auto dirData = inodeCatalog_->loadAndRemoveOverlayDir(inodeNumber);
if (dirData) {
gcQueue_.lock()->queue.emplace_back(std::move(*dirData));
gcCondVar_.notify_one();
}
}
#ifndef _WIN32
folly::Future<folly::Unit> Overlay::flushPendingAsync() {
folly::Promise<folly::Unit> promise;
auto future = promise.getFuture();
gcQueue_.lock()->queue.emplace_back(std::move(promise));
gcCondVar_.notify_one();
return future;
}
#endif // !_WIN32
bool Overlay::hasOverlayDir(InodeNumber inodeNumber) {
IORequest req{this};
return inodeCatalog_->hasOverlayDir(inodeNumber);
}
#ifndef _WIN32
bool Overlay::hasOverlayFile(InodeNumber inodeNumber) {
IORequest req{this};
XCHECK(fileContentStore_);
return fileContentStore_->hasOverlayFile(inodeNumber);
}
// Helper function to open,validate,
// get file pointer of an overlay file
OverlayFile Overlay::openFile(
InodeNumber inodeNumber,
folly::StringPiece headerId) {
IORequest req{this};
XCHECK(fileContentStore_);
return OverlayFile(
fileContentStore_->openFile(inodeNumber, headerId), weak_from_this());
}
OverlayFile Overlay::openFileNoVerify(InodeNumber inodeNumber) {
IORequest req{this};
XCHECK(fileContentStore_);
return OverlayFile(
fileContentStore_->openFileNoVerify(inodeNumber), weak_from_this());
}
OverlayFile Overlay::createOverlayFile(
InodeNumber inodeNumber,
folly::ByteRange contents) {
IORequest req{this};
XCHECK_LT(inodeNumber.get(), nextInodeNumber_.load(std::memory_order_relaxed))
<< "createOverlayFile called with unallocated inode number";
XCHECK(fileContentStore_);
return OverlayFile(
fileContentStore_->createOverlayFile(inodeNumber, contents),
weak_from_this());
}
OverlayFile Overlay::createOverlayFile(
InodeNumber inodeNumber,
const folly::IOBuf& contents) {
IORequest req{this};
XCHECK_LT(inodeNumber.get(), nextInodeNumber_.load(std::memory_order_relaxed))
<< "createOverlayFile called with unallocated inode number";
XCHECK(fileContentStore_);
return OverlayFile(
fileContentStore_->createOverlayFile(inodeNumber, contents),
weak_from_this());
}
#endif // !_WIN32
InodeNumber Overlay::getMaxInodeNumber() {
auto ino = nextInodeNumber_.load(std::memory_order_relaxed);
XCHECK_GT(ino, 1u);
return InodeNumber{ino - 1};
}
bool Overlay::tryIncOutstandingIORequests() {
uint64_t currentOutstandingIO =
outstandingIORequests_.load(std::memory_order_seq_cst);
// Retry incrementing the IO count while we have not either successfully
// updated outstandingIORequests_ or closed the overlay
while (!(currentOutstandingIO & ioClosedMask)) {
// If not closed, currentOutstandingIO now holds what
// outstandingIORequests_ actually contained
if (outstandingIORequests_.compare_exchange_weak(
currentOutstandingIO,
currentOutstandingIO + 1,
std::memory_order_seq_cst)) {
return true;
}
}
// If we have broken out of the above loop, the overlay is closed and we
// been unable to increment outstandingIORequests_.
return false;
}
void Overlay::decOutstandingIORequests() {
uint64_t outstanding =
outstandingIORequests_.fetch_sub(1, std::memory_order_seq_cst);
XCHECK_NE(0ull, outstanding) << "Decremented too far!";
// If the overlay is closed and we just finished our last IO request (meaning
// the previous value of outstandingIORequests_ was 1), then wake the waiting
// thread.
if ((outstanding & ioClosedMask) && (outstanding & ioCountMask) == 1) {
lastOutstandingRequestIsComplete_.post();
}
}
void Overlay::closeAndWaitForOutstandingIO() {
uint64_t outstanding =
outstandingIORequests_.fetch_or(ioClosedMask, std::memory_order_seq_cst);
// If we have outstanding IO requests, wait for them. This should not block if
// this baton has already been posted between the load in the fetch_or and
// this if statement.
if (outstanding & ioCountMask) {
lastOutstandingRequestIsComplete_.wait();
}
}
void Overlay::gcThread() noexcept {
for (;;) {
std::vector<GCRequest> requests;
{
auto lock = gcQueue_.lock();
while (lock->queue.empty()) {
if (lock->stop) {
return;
}
gcCondVar_.wait(lock.as_lock());
continue;
}
requests = std::move(lock->queue);
}
for (auto& request : requests) {
try {
handleGCRequest(request);
} catch (const std::exception& e) {
XLOG(ERR) << "handleGCRequest should never throw, but it did: "
<< e.what();
}
}
}
}
void Overlay::handleGCRequest(GCRequest& request) {
IORequest req{this};
inodes: perform maintenance in the overlay thread Summary: During shutdown, the overlay background thread is terminated, and the overlay closed, but EdenServer timers are still running. One of which being the manageOverlay one which performs a maintenance on the Overlay. In some cases, shutdown and this timer are racing each other, causing the timer to run after the overlay has been closed, causing a use after free and crashing EdenFS. To solve this, we can either add locks around closing the overlay and the maintenance to guarantee that they do not race, or we can move the maintenance operation to a thread that is known to be running only when the overlay is opened. This diff takes the second approach. The bug manifest itself like so: I0712 01:16:48.253296 21620 EdenServiceHandler.cpp:3394] [000002517432E1E0] initiateShutdown() took 368 µs I0712 01:16:48.253838 24700 PrjfsChannel.cpp:1185] Stopping PrjfsChannel for: C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main I0712 01:16:48.258533 19188 EdenServer.cpp:1624] mount point "C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main" stopped V0712 01:16:48.258814 19188 EdenMount.cpp:851] beginning shutdown for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.259895 19188 EdenMount.cpp:855] shutdown complete for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.287378 19188 EdenMount.cpp:861] successfully closed overlay at C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main Unhandled win32 exception code=0xC0000005. Fatal error detected at: #0 00007FF707BA3D81 (https://github.com/facebookexperimental/eden/commit/7a686d9c8f746a025cb429e41cb977713937ec20) facebook::eden::SqliteDatabase::checkpoint Z:\shipit\eden\eden\fs\sqlite\SqliteDatabase.cpp:99 #1 00007FF7072D4090 facebook::eden::EdenServer::manageOverlay Z:\shipit\eden\eden\fs\service\EdenServer.cpp:2142 #2 00007FF7074765D0 facebook::eden::PeriodicTask::timeoutExpired Z:\shipit\eden\eden\fs\service\PeriodicTask.cpp:32 #3 00007FF707500F93 folly::HHWheelTimerBase<std::chrono::duration<__int64,std::ratio<1,1000> > >::timeoutExpired Z:\shipit\folly\folly\io\async\HHWheelTimer.cpp:286 #4 00007FF70757BB44 folly::AsyncTimeout::libeventCallback Z:\shipit\folly\folly\io\async\AsyncTimeout.cpp:174 #5 00007FF708E7AD45 (https://github.com/facebookexperimental/eden/commit/645b6fca0a180a05f9c18b01fce566d80c507830) event_priority_set #6 00007FF708E7AA3A event_priority_set #7 00007FF708E77343 event_base_loop #8 00007FF707515FC5 folly::EventBase::loopMain Z:\shipit\folly\folly\io\async\EventBase.cpp:405 #9 00007FF707515C62 folly::EventBase::loopBody Z:\shipit\folly\folly\io\async\EventBase.cpp:326 #10 00007FF7072DC5EE facebook::eden::EdenServer::performCleanup Z:\shipit\eden\eden\fs\service\EdenServer.cpp:1212 #11 00007FF707219BED facebook::eden::runEdenMain Z:\shipit\eden\eden\fs\service\EdenMain.cpp:395 #12 00007FF7071C624A main Z:\shipit\eden\eden\fs\service\oss\main.cpp:23 #13 00007FF708E87A94 __scrt_common_main_seh d:\A01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #14 00007FFC96DC7034 BaseThreadInitThunk #15 00007FFC98C5CEC1 RtlUserThreadStart Reviewed By: fanzeyi Differential Revision: D37793444 fbshipit-source-id: cd33302789c2c7a29d566d5bac6e119eccf0a5f2
2022-07-12 22:25:51 +03:00
if (std::holds_alternative<GCRequest::MaintenanceRequest>(
request.requestType)) {
inodeCatalog_->maintenance();
inodes: perform maintenance in the overlay thread Summary: During shutdown, the overlay background thread is terminated, and the overlay closed, but EdenServer timers are still running. One of which being the manageOverlay one which performs a maintenance on the Overlay. In some cases, shutdown and this timer are racing each other, causing the timer to run after the overlay has been closed, causing a use after free and crashing EdenFS. To solve this, we can either add locks around closing the overlay and the maintenance to guarantee that they do not race, or we can move the maintenance operation to a thread that is known to be running only when the overlay is opened. This diff takes the second approach. The bug manifest itself like so: I0712 01:16:48.253296 21620 EdenServiceHandler.cpp:3394] [000002517432E1E0] initiateShutdown() took 368 µs I0712 01:16:48.253838 24700 PrjfsChannel.cpp:1185] Stopping PrjfsChannel for: C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main I0712 01:16:48.258533 19188 EdenServer.cpp:1624] mount point "C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main" stopped V0712 01:16:48.258814 19188 EdenMount.cpp:851] beginning shutdown for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.259895 19188 EdenMount.cpp:855] shutdown complete for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.287378 19188 EdenMount.cpp:861] successfully closed overlay at C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main Unhandled win32 exception code=0xC0000005. Fatal error detected at: #0 00007FF707BA3D81 (https://github.com/facebookexperimental/eden/commit/7a686d9c8f746a025cb429e41cb977713937ec20) facebook::eden::SqliteDatabase::checkpoint Z:\shipit\eden\eden\fs\sqlite\SqliteDatabase.cpp:99 #1 00007FF7072D4090 facebook::eden::EdenServer::manageOverlay Z:\shipit\eden\eden\fs\service\EdenServer.cpp:2142 #2 00007FF7074765D0 facebook::eden::PeriodicTask::timeoutExpired Z:\shipit\eden\eden\fs\service\PeriodicTask.cpp:32 #3 00007FF707500F93 folly::HHWheelTimerBase<std::chrono::duration<__int64,std::ratio<1,1000> > >::timeoutExpired Z:\shipit\folly\folly\io\async\HHWheelTimer.cpp:286 #4 00007FF70757BB44 folly::AsyncTimeout::libeventCallback Z:\shipit\folly\folly\io\async\AsyncTimeout.cpp:174 #5 00007FF708E7AD45 (https://github.com/facebookexperimental/eden/commit/645b6fca0a180a05f9c18b01fce566d80c507830) event_priority_set #6 00007FF708E7AA3A event_priority_set #7 00007FF708E77343 event_base_loop #8 00007FF707515FC5 folly::EventBase::loopMain Z:\shipit\folly\folly\io\async\EventBase.cpp:405 #9 00007FF707515C62 folly::EventBase::loopBody Z:\shipit\folly\folly\io\async\EventBase.cpp:326 #10 00007FF7072DC5EE facebook::eden::EdenServer::performCleanup Z:\shipit\eden\eden\fs\service\EdenServer.cpp:1212 #11 00007FF707219BED facebook::eden::runEdenMain Z:\shipit\eden\eden\fs\service\EdenMain.cpp:395 #12 00007FF7071C624A main Z:\shipit\eden\eden\fs\service\oss\main.cpp:23 #13 00007FF708E87A94 __scrt_common_main_seh d:\A01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #14 00007FFC96DC7034 BaseThreadInitThunk #15 00007FFC98C5CEC1 RtlUserThreadStart Reviewed By: fanzeyi Differential Revision: D37793444 fbshipit-source-id: cd33302789c2c7a29d566d5bac6e119eccf0a5f2
2022-07-12 22:25:51 +03:00
return;
}
if (auto* flush =
std::get_if<GCRequest::FlushRequest>(&request.requestType)) {
flush->setValue();
return;
}
// Should only include inode numbers for trees.
std::queue<InodeNumber> queue;
// TODO: For better throughput on large tree collections, it might make
// sense to split this into two threads: one for traversing the tree and
// another that makes the actual unlink calls.
auto safeRemoveOverlayFile = [&](InodeNumber inodeNumber) {
try {
removeOverlayFile(inodeNumber);
} catch (const std::exception& e) {
XLOG(ERR) << "Failed to remove overlay data for file inode "
<< inodeNumber << ": " << e.what();
}
};
auto processDir = [&](const overlay::OverlayDir& dir) {
for (const auto& entry : *dir.entries_ref()) {
const auto& value = entry.second;
if (!(*value.inodeNumber_ref())) {
// Legacy-only. All new Overlay trees have inode numbers for all
// children.
continue;
}
auto ino = InodeNumber::fromThrift(*value.inodeNumber_ref());
if (S_ISDIR(*value.mode_ref())) {
queue.push(ino);
} else {
// No need to recurse, but delete any file at this inode. Note that,
// under normal operation, there should be nothing at this path
// because files are only written into the overlay if they're
// materialized.
safeRemoveOverlayFile(ino);
}
}
};
inodes: perform maintenance in the overlay thread Summary: During shutdown, the overlay background thread is terminated, and the overlay closed, but EdenServer timers are still running. One of which being the manageOverlay one which performs a maintenance on the Overlay. In some cases, shutdown and this timer are racing each other, causing the timer to run after the overlay has been closed, causing a use after free and crashing EdenFS. To solve this, we can either add locks around closing the overlay and the maintenance to guarantee that they do not race, or we can move the maintenance operation to a thread that is known to be running only when the overlay is opened. This diff takes the second approach. The bug manifest itself like so: I0712 01:16:48.253296 21620 EdenServiceHandler.cpp:3394] [000002517432E1E0] initiateShutdown() took 368 µs I0712 01:16:48.253838 24700 PrjfsChannel.cpp:1185] Stopping PrjfsChannel for: C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main I0712 01:16:48.258533 19188 EdenServer.cpp:1624] mount point "C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main" stopped V0712 01:16:48.258814 19188 EdenMount.cpp:851] beginning shutdown for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.259895 19188 EdenMount.cpp:855] shutdown complete for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.287378 19188 EdenMount.cpp:861] successfully closed overlay at C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main Unhandled win32 exception code=0xC0000005. Fatal error detected at: #0 00007FF707BA3D81 (https://github.com/facebookexperimental/eden/commit/7a686d9c8f746a025cb429e41cb977713937ec20) facebook::eden::SqliteDatabase::checkpoint Z:\shipit\eden\eden\fs\sqlite\SqliteDatabase.cpp:99 #1 00007FF7072D4090 facebook::eden::EdenServer::manageOverlay Z:\shipit\eden\eden\fs\service\EdenServer.cpp:2142 #2 00007FF7074765D0 facebook::eden::PeriodicTask::timeoutExpired Z:\shipit\eden\eden\fs\service\PeriodicTask.cpp:32 #3 00007FF707500F93 folly::HHWheelTimerBase<std::chrono::duration<__int64,std::ratio<1,1000> > >::timeoutExpired Z:\shipit\folly\folly\io\async\HHWheelTimer.cpp:286 #4 00007FF70757BB44 folly::AsyncTimeout::libeventCallback Z:\shipit\folly\folly\io\async\AsyncTimeout.cpp:174 #5 00007FF708E7AD45 (https://github.com/facebookexperimental/eden/commit/645b6fca0a180a05f9c18b01fce566d80c507830) event_priority_set #6 00007FF708E7AA3A event_priority_set #7 00007FF708E77343 event_base_loop #8 00007FF707515FC5 folly::EventBase::loopMain Z:\shipit\folly\folly\io\async\EventBase.cpp:405 #9 00007FF707515C62 folly::EventBase::loopBody Z:\shipit\folly\folly\io\async\EventBase.cpp:326 #10 00007FF7072DC5EE facebook::eden::EdenServer::performCleanup Z:\shipit\eden\eden\fs\service\EdenServer.cpp:1212 #11 00007FF707219BED facebook::eden::runEdenMain Z:\shipit\eden\eden\fs\service\EdenMain.cpp:395 #12 00007FF7071C624A main Z:\shipit\eden\eden\fs\service\oss\main.cpp:23 #13 00007FF708E87A94 __scrt_common_main_seh d:\A01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #14 00007FFC96DC7034 BaseThreadInitThunk #15 00007FFC98C5CEC1 RtlUserThreadStart Reviewed By: fanzeyi Differential Revision: D37793444 fbshipit-source-id: cd33302789c2c7a29d566d5bac6e119eccf0a5f2
2022-07-12 22:25:51 +03:00
processDir(std::get<overlay::OverlayDir>(request.requestType));
while (!queue.empty()) {
auto ino = queue.front();
queue.pop();
overlay::OverlayDir dir;
try {
freeInodeFromMetadataTable(ino);
auto dirData = inodeCatalog_->loadAndRemoveOverlayDir(ino);
if (!dirData.has_value()) {
XLOG(DBG7) << "no dir data for inode " << ino;
continue;
} else {
dir = std::move(*dirData);
}
} catch (const std::exception& e) {
XLOG(ERR) << "While collecting, failed to load tree data for inode "
<< ino << ": " << e.what();
continue;
}
processDir(dir);
}
}
void Overlay::addChild(
InodeNumber parent,
const std::pair<PathComponent, DirEntry>& childEntry,
const DirContents& content) {
if (supportsSemanticOperations_) {
inodeCatalog_->addChild(
parent, childEntry.first, serializeOverlayEntry(childEntry.second));
} else {
saveOverlayDir(parent, content);
}
}
void Overlay::removeChild(
InodeNumber parent,
PathComponentPiece childName,
const DirContents& content) {
if (supportsSemanticOperations_) {
inodeCatalog_->removeChild(parent, childName);
} else {
saveOverlayDir(parent, content);
}
}
void Overlay::removeChildren(InodeNumber parent, const DirContents& content) {
saveOverlayDir(parent, content);
}
void Overlay::renameChild(
InodeNumber src,
InodeNumber dst,
PathComponentPiece srcName,
PathComponentPiece dstName,
const DirContents& srcContent,
const DirContents& dstContent) {
if (supportsSemanticOperations_) {
inodeCatalog_->renameChild(src, dst, srcName, dstName);
} else {
saveOverlayDir(src, srcContent);
if (dst.get() != src.get()) {
saveOverlayDir(dst, dstContent);
}
}
}
void Overlay::maintenance() {
inodes: perform maintenance in the overlay thread Summary: During shutdown, the overlay background thread is terminated, and the overlay closed, but EdenServer timers are still running. One of which being the manageOverlay one which performs a maintenance on the Overlay. In some cases, shutdown and this timer are racing each other, causing the timer to run after the overlay has been closed, causing a use after free and crashing EdenFS. To solve this, we can either add locks around closing the overlay and the maintenance to guarantee that they do not race, or we can move the maintenance operation to a thread that is known to be running only when the overlay is opened. This diff takes the second approach. The bug manifest itself like so: I0712 01:16:48.253296 21620 EdenServiceHandler.cpp:3394] [000002517432E1E0] initiateShutdown() took 368 µs I0712 01:16:48.253838 24700 PrjfsChannel.cpp:1185] Stopping PrjfsChannel for: C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main I0712 01:16:48.258533 19188 EdenServer.cpp:1624] mount point "C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main" stopped V0712 01:16:48.258814 19188 EdenMount.cpp:851] beginning shutdown for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.259895 19188 EdenMount.cpp:855] shutdown complete for EdenMount C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main V0712 01:16:48.287378 19188 EdenMount.cpp:861] successfully closed overlay at C:\\cygwin\\tmp\\eden_test.stop_at_ea.m3931hyz\\mounts\\main Unhandled win32 exception code=0xC0000005. Fatal error detected at: #0 00007FF707BA3D81 (https://github.com/facebookexperimental/eden/commit/7a686d9c8f746a025cb429e41cb977713937ec20) facebook::eden::SqliteDatabase::checkpoint Z:\shipit\eden\eden\fs\sqlite\SqliteDatabase.cpp:99 #1 00007FF7072D4090 facebook::eden::EdenServer::manageOverlay Z:\shipit\eden\eden\fs\service\EdenServer.cpp:2142 #2 00007FF7074765D0 facebook::eden::PeriodicTask::timeoutExpired Z:\shipit\eden\eden\fs\service\PeriodicTask.cpp:32 #3 00007FF707500F93 folly::HHWheelTimerBase<std::chrono::duration<__int64,std::ratio<1,1000> > >::timeoutExpired Z:\shipit\folly\folly\io\async\HHWheelTimer.cpp:286 #4 00007FF70757BB44 folly::AsyncTimeout::libeventCallback Z:\shipit\folly\folly\io\async\AsyncTimeout.cpp:174 #5 00007FF708E7AD45 (https://github.com/facebookexperimental/eden/commit/645b6fca0a180a05f9c18b01fce566d80c507830) event_priority_set #6 00007FF708E7AA3A event_priority_set #7 00007FF708E77343 event_base_loop #8 00007FF707515FC5 folly::EventBase::loopMain Z:\shipit\folly\folly\io\async\EventBase.cpp:405 #9 00007FF707515C62 folly::EventBase::loopBody Z:\shipit\folly\folly\io\async\EventBase.cpp:326 #10 00007FF7072DC5EE facebook::eden::EdenServer::performCleanup Z:\shipit\eden\eden\fs\service\EdenServer.cpp:1212 #11 00007FF707219BED facebook::eden::runEdenMain Z:\shipit\eden\eden\fs\service\EdenMain.cpp:395 #12 00007FF7071C624A main Z:\shipit\eden\eden\fs\service\oss\main.cpp:23 #13 00007FF708E87A94 __scrt_common_main_seh d:\A01\_work\12\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 #14 00007FFC96DC7034 BaseThreadInitThunk #15 00007FFC98C5CEC1 RtlUserThreadStart Reviewed By: fanzeyi Differential Revision: D37793444 fbshipit-source-id: cd33302789c2c7a29d566d5bac6e119eccf0a5f2
2022-07-12 22:25:51 +03:00
gcQueue_.lock()->queue.emplace_back(Overlay::GCRequest::MaintenanceRequest{});
}
} // namespace facebook::eden