print fsck to stdout

Summary: This diff passes a callback function `progressCallback` from `EdenServer` to make `OverlayChekcer` print fsck messages to stdout.

Reviewed By: fanzeyi

Differential Revision: D21966060

fbshipit-source-id: 317b2c8954c718b51b5295c9f8d7698eb203906e
This commit is contained in:
Ailin Zhang 2020-06-12 12:33:14 -07:00 committed by Facebook GitHub Bot
parent 48544b0233
commit ec906443ea
10 changed files with 72 additions and 27 deletions

View File

@ -219,13 +219,15 @@ EdenMount::EdenMount(
}
FOLLY_NODISCARD folly::Future<folly::Unit> EdenMount::initialize(
std::function<void(std::string)>&& progressCallback,
const std::optional<SerializedInodeMap>& takeover) {
transitionState(State::UNINITIALIZED, State::INITIALIZING);
return serverState_->getFaultInjector()
.checkAsync("mount", getPath().stringPiece())
.via(serverState_->getThreadPool().get())
.thenValue([this](auto&&) {
.thenValue([this, progressCallback = std::move(progressCallback)](
auto&&) mutable {
auto parents = config_->getParentCommits();
parentInfo_.wlock()->parents.setParents(parents);
@ -235,10 +237,10 @@ FOLLY_NODISCARD folly::Future<folly::Unit> EdenMount::initialize(
journal_->recordHashUpdate(parents.parent1());
// Initialize the overlay.
// This must be performed before we do any operations that may allocate
// inode numbers, including creating the root TreeInode.
return overlay_->initialize().deferValue(
[parents](auto&&) { return parents; });
// This must be performed before we do any operations that may
// allocate inode numbers, including creating the root TreeInode.
return overlay_->initialize(std::move(progressCallback))
.deferValue([parents](auto&&) { return parents; });
})
.thenValue(
[this](ParentCommits&& parents) { return createRootInode(parents); })
@ -837,7 +839,6 @@ folly::Future<CheckoutResult> EdenMount::checkout(
*lastCheckoutTime_.wlock() = clock_->getRealtime();
auto journalDiffCallback = std::make_shared<JournalDiffCallback>();
return serverState_->getFaultInjector()
.checkAsync("checkout", getPath().stringPiece())
.via(serverState_->getThreadPool().get())

View File

@ -176,6 +176,7 @@ class EdenMount {
* If takeover data is specified, it is used to initialize the inode map.
*/
FOLLY_NODISCARD folly::Future<folly::Unit> initialize(
std::function<void(std::string)>&& progressCallback = nullptr,
const std::optional<SerializedInodeMap>& takeover = std::nullopt);
/**

View File

@ -103,7 +103,8 @@ struct statfs Overlay::statFs() {
}
#endif // !_WIN32
folly::SemiFuture<Unit> Overlay::initialize() {
folly::SemiFuture<Unit> Overlay::initialize(
std::function<void(std::string)>&& progressCallback) {
// The initOverlay() call is potentially slow, so we want to avoid
// performing it in the current thread and blocking returning to our caller.
//
@ -111,9 +112,12 @@ folly::SemiFuture<Unit> Overlay::initialize() {
// 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, promise = std::move(initPromise)]() mutable {
gcThread_ = std::thread([this,
progressCallback = std::move(progressCallback),
promise = std::move(initPromise)]() mutable {
try {
initOverlay();
initOverlay(progressCallback);
} catch (std::exception& ex) {
XLOG(ERR) << "overlay initialization failed for "
<< backingOverlay_.getLocalDir() << ": " << ex.what();
@ -123,8 +127,8 @@ folly::SemiFuture<Unit> Overlay::initialize() {
}
promise.setValue();
#ifndef _WIN32
// TODO: On Windows files are cached by the ProjectedFS. We need to clean
// the cached files while doing GC.
// TODO: On Windows files are cached by the ProjectedFS. We need to
// clean the cached files while doing GC.
gcThread();
#endif
@ -132,7 +136,8 @@ folly::SemiFuture<Unit> Overlay::initialize() {
return std::move(initFuture);
}
void Overlay::initOverlay() {
void Overlay::initOverlay(
const std::function<void(std::string)>& progressCallback) {
IORequest req{this};
auto optNextInodeNumber = backingOverlay_.initOverlay(true);
if (!optNextInodeNumber.has_value()) {
@ -146,8 +151,9 @@ void Overlay::initOverlay() {
// correct next inode number as it does so.
XLOG(WARN) << "Overlay " << backingOverlay_.getLocalDir()
<< " was not shut down cleanly. Performing fsck scan.";
OverlayChecker checker(&backingOverlay_, std::nullopt);
checker.scanForErrors();
checker.scanForErrors(progressCallback);
checker.repairErrors();
optNextInodeNumber = checker.getNextInodeNumber();
@ -208,7 +214,8 @@ optional<DirContents> Overlay::loadOverlayDir(InodeNumber inodeNumber) {
const auto& name = iter.first;
const auto& value = iter.second;
bool isMaterialized = !value.hash_ref() || value.hash_ref().value().empty();
bool isMaterialized =
!value.hash_ref() || value.hash_ref().value_unchecked().empty();
InodeNumber ino;
if (value.inodeNumber) {
ino = InodeNumber::fromThrift(value.inodeNumber);

View File

@ -100,7 +100,8 @@ class Overlay : public std::enable_shared_from_this<Overlay> {
* - Upgrading the on-disk data from older formats if the Overlay was created
* by an older version of the software.
*/
FOLLY_NODISCARD folly::SemiFuture<folly::Unit> initialize();
FOLLY_NODISCARD folly::SemiFuture<folly::Unit> initialize(
std::function<void(std::string)>&& progressCallback = nullptr);
/**
* Closes the overlay. It is undefined behavior to access the
@ -243,7 +244,8 @@ class Overlay : public std::enable_shared_from_this<Overlay> {
std::vector<GCRequest> queue;
};
void initOverlay();
void initOverlay(
const std::function<void(std::string)>& progressCallback = nullptr);
void gcThread() noexcept;
void handleGCRequest(GCRequest& request);

View File

@ -655,9 +655,16 @@ OverlayChecker::OverlayChecker(
OverlayChecker::~OverlayChecker() {}
void OverlayChecker::scanForErrors() {
XLOG(INFO) << "Starting fsck scan on overlay " << fs_->getLocalDir();
readInodes();
void OverlayChecker::scanForErrors(
const std::function<void(std::string)>& progressCallback) {
auto fsck_start_msg = folly::to<std::string>(
"Starting fsck scan on overlay ", fs_->getLocalDir());
XLOG(INFO) << fsck_start_msg;
if (auto callback = progressCallback) {
callback(fsck_start_msg);
}
readInodes(progressCallback);
linkInodeChildren();
scanForParentErrors();
checkNextInodeNumber();
@ -845,7 +852,8 @@ PathComponent OverlayChecker::findChildName(
return PathComponent(folly::to<string>("[missing_child(", child, ")]"));
}
void OverlayChecker::readInodes() {
void OverlayChecker::readInodes(
const std::function<void(std::string)>& progressCallback) {
// Walk through all of the sharded subdirectories
uint32_t progress10pct = 0;
std::array<char, 2> subdirBuffer;
@ -854,8 +862,18 @@ void OverlayChecker::readInodes() {
// Log a DBG2 message every 10% done
uint32_t progress = (10 * shardID) / FsOverlay::kNumShards;
if (progress > progress10pct) {
XLOG(DBG2) << "fsck:" << fs_->getLocalDir() << ": scan " << progress
<< "0% complete: " << inodes_.size() << " inodes scanned";
auto fsck_path_msg =
folly::to<std::string>("fsck:", fs_->getLocalDir(), ": ");
auto fsck_scanned_msg = folly::to<std::string>(
"scan ",
progress,
"0% complete: ",
inodes_.size(),
" inodes scanned");
XLOG(INFO) << fsck_path_msg << fsck_scanned_msg;
if (auto callback = progressCallback) {
callback(fsck_scanned_msg);
}
progress10pct = progress;
}

View File

@ -64,7 +64,8 @@ class OverlayChecker {
/**
* Scan the overlay for problems.
*/
void scanForErrors();
void scanForErrors(
const std::function<void(std::string)>& progressCallback = nullptr);
/**
* Attempt to repair the errors that were found by scanForErrors().
@ -185,7 +186,8 @@ class OverlayChecker {
PathInfo cachedPathComputation(InodeNumber number, Fn&& fn);
using ShardID = uint32_t;
void readInodes();
void readInodes(
const std::function<void(std::string)>& progressCallback = nullptr);
void readInodeSubdir(const AbsolutePath& path, ShardID shardID);
void loadInode(InodeNumber number, ShardID shardID);
InodeInfo loadInodeInfo(InodeNumber number);

View File

@ -852,7 +852,12 @@ std::vector<Future<Unit>> EdenServer::prepareMountsTakeover(
auto initialConfig = CheckoutConfig::loadFromClientDirectory(
AbsolutePathPiece{info.mountPath},
AbsolutePathPiece{info.stateDirectory});
return mount(std::move(initialConfig), false, std::move(info));
return mount(
std::move(initialConfig),
false,
[logger](auto msg) { logger->log(msg); },
std::move(info));
})
.thenTry([logger, mountPath = info.mountPath](
folly::Try<std::shared_ptr<EdenMount>>&& result) {
@ -911,7 +916,10 @@ std::vector<Future<Unit>> EdenServer::prepareMounts(
auto initialConfig = CheckoutConfig::loadFromClientDirectory(
AbsolutePathPiece{mountInfo.mountPoint},
AbsolutePathPiece{mountInfo.edenClientPath});
return mount(std::move(initialConfig), false);
return mount(std::move(initialConfig), false, [logger](auto msg) {
logger->log(msg);
});
})
.thenTry([logger, mountPath = client.first.asString()](
folly::Try<std::shared_ptr<EdenMount>>&& result) {
@ -1196,6 +1204,7 @@ Future<Unit> EdenServer::completeTakeoverStart(
folly::Future<std::shared_ptr<EdenMount>> EdenServer::mount(
std::unique_ptr<CheckoutConfig> initialConfig,
bool readOnly,
std::function<void(std::string)>&& progressCallback,
optional<TakeoverData::MountInfo>&& optionalTakeover) {
folly::stop_watch<> mountStopWatch;
@ -1220,7 +1229,9 @@ folly::Future<std::shared_ptr<EdenMount>> EdenServer::mount(
registerStats(edenMount);
const bool doTakeover = optionalTakeover.has_value();
auto initFuture = edenMount->initialize(
std::move(progressCallback),
doTakeover ? std::make_optional(optionalTakeover->inodeMap)
: std::nullopt);

View File

@ -31,6 +31,7 @@
#include "eden/fs/inodes/ServerState.h"
#include "eden/fs/service/EdenStateDir.h"
#include "eden/fs/service/PeriodicTask.h"
#include "eden/fs/service/StartupLogger.h"
#include "eden/fs/takeover/TakeoverHandler.h"
#include "eden/fs/telemetry/EdenStats.h"
#include "eden/fs/telemetry/RequestMetricsScope.h"
@ -220,6 +221,7 @@ class EdenServer : private TakeoverHandler {
FOLLY_NODISCARD folly::Future<std::shared_ptr<EdenMount>> mount(
std::unique_ptr<CheckoutConfig> initialConfig,
bool readOnly,
std::function<void(std::string)>&& progressCallback = nullptr,
std::optional<TakeoverData::MountInfo>&& optionalTakeover = std::nullopt);
/**

View File

@ -333,6 +333,7 @@ void EdenServiceHandler::mount(std::unique_ptr<MountArgument> argument) {
auto initialConfig = CheckoutConfig::loadFromClientDirectory(
AbsolutePathPiece{argument->mountPoint},
AbsolutePathPiece{argument->edenClientPath});
server_->mount(std::move(initialConfig), argument->readOnly).get();
} catch (const EdenError& ex) {
XLOG(ERR) << "Error: " << ex.what();

View File

@ -341,7 +341,7 @@ void TestMount::remountGracefully() {
blobCache_,
serverState_,
std::move(journal));
edenMount_->initialize(takeoverData).getVia(serverExecutor_.get());
edenMount_->initialize(nullptr, takeoverData).getVia(serverExecutor_.get());
}
#endif