sapling/eden/fs/inodes/overlay/OverlayChecker.h
Ailin Zhang 763f855e5a show fsck progress animation bars
Summary: This diff updated `eden start` to show animated fsck progress bars

Reviewed By: genevievehelsel

Differential Revision: D22357699

fbshipit-source-id: f399cc78fc25c85100e5931505ce787899c3fff4
2020-07-09 14:43:42 -07:00

223 lines
6.5 KiB
C++

/*
* 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
#include <memory>
#include <optional>
#include <folly/CppAttributes.h>
#include <folly/small_vector.h>
#include "eden/fs/fuse/InodeNumber.h"
#include "eden/fs/inodes/overlay/gen-cpp2/overlay_types.h"
#include "eden/fs/utils/PathFuncs.h"
namespace folly {
class File;
}
namespace facebook {
namespace eden {
class FsOverlay;
/**
* OverlayChecker performs "fsck" operations on the on-disk overlay data.
*
* This class scans the on-disk data for errors, and repairs problems that are
* found.
*/
class OverlayChecker {
private:
class RepairState;
public:
class Error {
public:
virtual ~Error() {}
virtual std::string getMessage(OverlayChecker* checker) const = 0;
virtual bool repair(RepairState& repair) const = 0;
};
class RepairResult {
public:
AbsolutePath repairDir;
uint32_t totalErrors{0};
uint32_t fixedErrors{0};
};
/**
* Create a new OverlayChecker.
*
* The OverlayChecker stores a raw pointer to the FsOverlay for the duration
* of the check operation. The caller is responsible for ensuring that the
* FsOverlay object exists for at least as long as the OverlayChecker object.
*/
OverlayChecker(FsOverlay* fs, std::optional<InodeNumber> nextInodeNumber);
~OverlayChecker();
using ProgressCallback = std::function<void(uint16_t)>;
/**
* Scan the overlay for problems.
*/
void scanForErrors(const ProgressCallback& progressCallback = [](auto) {});
/**
* Attempt to repair the errors that were found by scanForErrors().
*
* Returns std::nullopt if repairErrors() is called when there are no errors
* to repair, otherwise returns a RepairResult.
*/
std::optional<RepairResult> repairErrors();
/**
* Log the errors that were found by scanForErrors(), without fixing them.
*
* The repairErrors() call will also handle logging the errors. The
* logErrors() method only needs to be called when doing a dry-run where you
* want to report errors without attempting to fix any problems.
*/
void logErrors();
/**
* Return a reference to the list of errors.
*
* scanForErrors() should be called first to populate the error list.
*/
const std::vector<std::unique_ptr<Error>>& getErrors() const {
return errors_;
}
/**
* Get the correct next inode number that was computed by scanForErrors()
*/
InodeNumber getNextInodeNumber() const {
return InodeNumber(maxInodeNumber_ + 1);
}
/**
* A structure to represent best-effort computed paths for inodes.
*
* We cannot always compute the full path to some inodes if some of their
* ancestors have been unlinked or orphaned.
*
* If we can compute the full path to an inode, parent will be kRootNodeId.
* Otherwise, parent will be the inode number for the first ancestor that is
* unlinked or orphaned (such that we cannot determine its path).
*
* path will be the path to this inode, relative to parent.
* path may be empty if computePath() was called on an orphaned inode.
*/
struct PathInfo {
explicit PathInfo(InodeNumber number) : parent(number) {}
explicit PathInfo(const PathInfo& parentInfo, PathComponentPiece child)
: parent(parentInfo.parent), path(parentInfo.path + child) {}
std::string toString() const;
InodeNumber parent{kRootNodeId};
RelativePath path;
};
/**
* Compute the path to a given inode.
*
* scanForErrors() must have been called first to scan the inode data.
*/
PathInfo computePath(InodeNumber number);
PathInfo computePath(InodeNumber parent, PathComponentPiece child);
/**
* Compute the path to a given child inode number in a parent directory.
*
* This version is primarily useful only when there are hard links and you
* wish to identify a specific path to the linked child inode.
*/
PathInfo computePath(InodeNumber parent, InodeNumber child);
private:
class ShardDirectoryEnumerationError;
class UnexpectedOverlayFile;
class UnexpectedInodeShard;
class InodeDataError;
class MissingMaterializedInode;
class OrphanInode;
class HardLinkedInode;
class BadNextInodeNumber;
enum class InodeType {
File,
Dir,
Error,
};
struct InodeInfo {
InodeInfo(InodeNumber num, InodeType t) : number(num), type(t) {}
InodeInfo(InodeNumber num, overlay::OverlayDir&& c)
: number(num), type(InodeType::Dir), children(std::move(c)) {}
void addParent(InodeNumber parent, mode_t mode) {
parents.push_back(parent);
modeFromParent = mode;
}
InodeNumber number;
InodeType type{InodeType::Error};
mode_t modeFromParent{0};
overlay::OverlayDir children;
folly::small_vector<InodeNumber, 1> parents;
};
OverlayChecker(OverlayChecker const&) = delete;
OverlayChecker& operator=(OverlayChecker const&) = delete;
// Get the InodeInfo object for the specified InodeNumber.
// Returns null if no info for this inode number is present.
// readInodes() must have been called for inode info to be populated.
InodeInfo* FOLLY_NULLABLE getInodeInfo(InodeNumber number);
PathInfo computePath(const InodeInfo& info);
PathComponent findChildName(const InodeInfo& parentInfo, InodeNumber child);
template <typename Fn>
PathInfo cachedPathComputation(InodeNumber number, Fn&& fn);
using ShardID = uint32_t;
void readInodes(const ProgressCallback& progressCallback = [](auto) {});
void readInodeSubdir(const AbsolutePath& path, ShardID shardID);
void loadInode(InodeNumber number, ShardID shardID);
InodeInfo loadInodeInfo(InodeNumber number);
overlay::OverlayDir loadDirectoryChildren(folly::File& file);
void linkInodeChildren();
void scanForParentErrors();
void checkNextInodeNumber();
template <typename ErrorType, typename... Args>
void addError(Args&&... args) {
addError(std::make_unique<ErrorType>(std::forward<Args>(args)...));
}
void addError(std::unique_ptr<Error> error);
void updateMaxInodeNumber(InodeNumber number) {
if (number.get() > maxInodeNumber_) {
maxInodeNumber_ = number.get();
}
}
FsOverlay* const fs_;
std::optional<InodeNumber> loadedNextInodeNumber_;
std::unordered_map<InodeNumber, InodeInfo> inodes_;
std::vector<std::unique_ptr<Error>> errors_;
uint64_t maxInodeNumber_{kRootNodeId.get()};
std::unordered_map<InodeNumber, PathInfo> pathCache_;
};
} // namespace eden
} // namespace facebook