mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
a29d465ee8
Summary: With Facebook having been renamed Meta Platforms, we need to change the license headers. Reviewed By: fanzeyi Differential Revision: D33407812 fbshipit-source-id: b11bfbbf13a48873f0cea75f212cc7b07a68fb2e
287 lines
8.5 KiB
C++
287 lines
8.5 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <folly/File.h>
|
|
#include <folly/Range.h>
|
|
#include <gtest/gtest_prod.h>
|
|
#include <array>
|
|
#include <condition_variable>
|
|
#include <optional>
|
|
#include "eden/fs/inodes/IOverlay.h"
|
|
#include "eden/fs/inodes/InodeNumber.h"
|
|
#include "eden/fs/inodes/overlay/gen-cpp2/overlay_types.h"
|
|
#include "eden/fs/utils/DirType.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
#ifdef __APPLE__
|
|
#include <sys/mount.h>
|
|
#include <sys/param.h>
|
|
#else
|
|
#include <sys/vfs.h>
|
|
#endif
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
namespace overlay {
|
|
class OverlayDir;
|
|
}
|
|
class InodePath;
|
|
|
|
/**
|
|
* FsOverlay provides interfaces to manipulate the overlay. It stores the
|
|
* overlay's file system attributes and is responsible for obtaining and
|
|
* releasing its locks ("initOverlay" and "close" respectively).
|
|
*/
|
|
class FsOverlay : public IOverlay {
|
|
public:
|
|
explicit FsOverlay(AbsolutePathPiece localDir) : localDir_{localDir} {}
|
|
|
|
bool supportsSemanticOperations() const override {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Initialize the overlay, acquire the "info" file lock and load the
|
|
* nextInodeNumber. The "close" method should be used to release these
|
|
* resources and persist the nextInodeNumber.
|
|
*
|
|
* Returns the next inode number to start at when allocating new inodes.
|
|
* If the overlay was not shutdown cleanly by the previous user then
|
|
* std::nullopt is returned. In this case, the caller should re-scan
|
|
* the overlay to check for issues and compute the next inode number.
|
|
*/
|
|
std::optional<InodeNumber> initOverlay(bool createIfNonExisting) override;
|
|
|
|
/**
|
|
* Gracefully, shutdown the overlay, persisting the overlay's
|
|
* nextInodeNumber.
|
|
*/
|
|
void close(std::optional<InodeNumber> nextInodeNumber) override;
|
|
|
|
/**
|
|
* Was FsOverlay initialized - i.e., is cleanup (close) necessary.
|
|
*/
|
|
bool initialized() const override {
|
|
return bool(infoFile_);
|
|
}
|
|
|
|
const AbsolutePath& getLocalDir() const override {
|
|
return localDir_;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
/**
|
|
* call statfs(2) on the filesystem in which the overlay is located
|
|
*/
|
|
struct statfs statFs() const override;
|
|
#endif
|
|
|
|
/**
|
|
* Get the name of the subdirectory to use for the overlay data for the
|
|
* specified inode number.
|
|
*
|
|
* We shard the inode files across the 256 subdirectories using the least
|
|
* significant byte. Inode numbers are allocated in monotonically
|
|
* increasing order, so this helps spread them out across the subdirectories.
|
|
*
|
|
* The shard directory paths are always exactly kShardDirPathLength bytes
|
|
* long: the `subdirPath` argument must point to a buffer exactly
|
|
* kShardDirPathLength bytes long. This function will write to those bytes,
|
|
* and no null terminator is included in the output.
|
|
*/
|
|
static void formatSubdirPath(
|
|
InodeNumber inodeNum,
|
|
folly::MutableStringPiece subdirPath);
|
|
|
|
/**
|
|
* Format the subdir shard path given a shard ID from 0 to 255.
|
|
*
|
|
* The shard directory paths are always exactly kShardDirPathLength bytes
|
|
* long: the `subdirPath` argument must point to a buffer exactly
|
|
* kShardDirPathLength bytes long. This function will write to those bytes,
|
|
* and no null terminator is included in the output.
|
|
*/
|
|
using ShardID = uint32_t;
|
|
static void formatSubdirShardPath(
|
|
ShardID shardID,
|
|
folly::MutableStringPiece subdirPath);
|
|
|
|
void initNewOverlay();
|
|
|
|
void saveOverlayDir(InodeNumber inodeNumber, const overlay::OverlayDir& odir)
|
|
override;
|
|
|
|
std::optional<overlay::OverlayDir> loadOverlayDir(
|
|
InodeNumber inodeNumber) override;
|
|
|
|
std::optional<overlay::OverlayDir> loadAndRemoveOverlayDir(
|
|
InodeNumber inodeNumber) override;
|
|
|
|
void saveNextInodeNumber(InodeNumber nextInodeNumber);
|
|
|
|
void writeNextInodeNumber(InodeNumber nextInodeNumber);
|
|
|
|
/**
|
|
* Return the next inode number from the kNextInodeNumberFile. If the file
|
|
* exists and contains a valid InodeNumber, that value is returned. If the
|
|
* file does not exist, the optional will not have a value. If the file cannot
|
|
* be opened or does not contain a valid InodeNumber, a SystemError is thrown.
|
|
*/
|
|
std::optional<InodeNumber> tryLoadNextInodeNumber();
|
|
|
|
/**
|
|
* Validate an existing overlay's info file exists, is valid and contains the
|
|
* correct version.
|
|
*/
|
|
void readExistingOverlay(int infoFD);
|
|
|
|
/**
|
|
* Helper function that creates an overlay file for a new FileInode.
|
|
*/
|
|
folly::File createOverlayFile(
|
|
InodeNumber inodeNumber,
|
|
folly::ByteRange contents) override;
|
|
|
|
/**
|
|
* Helper function to write an overlay file for a FileInode with existing
|
|
* contents.
|
|
*/
|
|
folly::File createOverlayFile(
|
|
InodeNumber inodeNumber,
|
|
const folly::IOBuf& contents) override;
|
|
|
|
/**
|
|
* Remove the overlay data associated with the passed InodeNumber.
|
|
*/
|
|
void removeOverlayData(InodeNumber inodeNumber) override;
|
|
|
|
/**
|
|
* Validates an entry's header.
|
|
*/
|
|
static void validateHeader(
|
|
InodeNumber inodeNumber,
|
|
folly::StringPiece contents,
|
|
folly::StringPiece headerId);
|
|
|
|
/**
|
|
* Helper function that opens an existing overlay file,
|
|
* checks if the file has valid header, and returns the file.
|
|
*/
|
|
folly::File openFile(InodeNumber inodeNumber, folly::StringPiece headerId)
|
|
override;
|
|
|
|
/**
|
|
* Open an existing overlay file without verifying the header.
|
|
*/
|
|
folly::File openFileNoVerify(InodeNumber inodeNumber) override;
|
|
|
|
/**
|
|
* Get the absolute path to a file to the overlay file for a given inode
|
|
* number.
|
|
*
|
|
* Note that this method should not be needed in most normal circumstances:
|
|
* most internal operation is done using getFilePath(), which returns relative
|
|
* paths that are guaranteed to always fit in a fixed length.
|
|
* getAbsoluteFilePath() is primarily intended for the fsck logic, where it is
|
|
* sometimes useful to be able to get absolute paths to be able to move broken
|
|
* files out of the overlay.
|
|
*/
|
|
AbsolutePath getAbsoluteFilePath(InodeNumber inodeNumber) const;
|
|
|
|
bool hasOverlayData(InodeNumber inodeNumber) override;
|
|
|
|
static constexpr folly::StringPiece kMetadataFile{"metadata.table"};
|
|
|
|
/**
|
|
* Constants for an header in overlay file.
|
|
*/
|
|
static constexpr folly::StringPiece kHeaderIdentifierDir{"OVDR"};
|
|
static constexpr folly::StringPiece kHeaderIdentifierFile{"OVFL"};
|
|
static constexpr uint32_t kHeaderVersion = 1;
|
|
static constexpr size_t kHeaderLength = 64;
|
|
static constexpr uint32_t kNumShards = 256;
|
|
static constexpr size_t kShardDirPathLength = 2;
|
|
|
|
/**
|
|
* The number of digits required for a decimal representation of an
|
|
* inode number.
|
|
*/
|
|
static constexpr size_t kMaxDecimalInodeNumberLength = 20;
|
|
|
|
private:
|
|
FRIEND_TEST(OverlayTest, getFilePath);
|
|
friend class RawOverlayTest;
|
|
|
|
/**
|
|
* Creates header for the files stored in Overlay
|
|
*/
|
|
static std::array<uint8_t, kHeaderLength> createHeader(
|
|
folly::StringPiece identifier,
|
|
uint32_t version);
|
|
|
|
/**
|
|
* Get the path to the file for the given inode, relative to localDir.
|
|
*
|
|
* Returns a null-terminated InodePath value.
|
|
*/
|
|
static InodePath getFilePath(InodeNumber inodeNumber);
|
|
|
|
std::optional<overlay::OverlayDir> deserializeOverlayDir(
|
|
InodeNumber inodeNumber);
|
|
|
|
folly::File
|
|
createOverlayFileImpl(InodeNumber inodeNumber, iovec* iov, size_t iovCount);
|
|
|
|
private:
|
|
/** Path to ".eden/CLIENT/local" */
|
|
const AbsolutePath localDir_;
|
|
|
|
/**
|
|
* An open file descriptor to the overlay info file.
|
|
*
|
|
* This is primarily used to hold a lock on the overlay for as long as we
|
|
* are using it. We want to ensure that only one eden process accesses the
|
|
* Overlay directory at a time.
|
|
*/
|
|
folly::File infoFile_;
|
|
|
|
/**
|
|
* An open file to the overlay directory.
|
|
*
|
|
* We maintain this so we can use openat(), unlinkat(), etc.
|
|
*/
|
|
folly::File dirFile_;
|
|
};
|
|
|
|
class InodePath {
|
|
public:
|
|
explicit InodePath() noexcept;
|
|
|
|
/**
|
|
* The maximum path length for the path to a file inside the overlay
|
|
* directory.
|
|
*
|
|
* This is 2 bytes for the initial subdirectory name, 1 byte for the '/',
|
|
* 20 bytes for the inode number, and 1 byte for a null terminator.
|
|
*/
|
|
static constexpr size_t kMaxPathLength =
|
|
2 + 1 + FsOverlay::kMaxDecimalInodeNumberLength + 1;
|
|
|
|
const char* c_str() const noexcept;
|
|
/* implicit */ operator RelativePathPiece() const noexcept;
|
|
|
|
std::array<char, kMaxPathLength>& rawData() noexcept;
|
|
|
|
private:
|
|
std::array<char, kMaxPathLength> path_;
|
|
};
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|