store weak overlay in OverlayFile

Summary: changes `overlay_` to be stored as a `std::shared_ptr` in order to safely create and pass `std::weak_ptr`s of the overlay to OverlayFiles that are being created.

Reviewed By: chadaustin

Differential Revision: D18302732

fbshipit-source-id: 495b613914771714ba8a8d1beb1c7a0cd72b33d4
This commit is contained in:
Genevieve Helsel 2019-11-06 18:21:39 -08:00 committed by Facebook Github Bot
parent 2c54a86698
commit 0f78403480
9 changed files with 89 additions and 71 deletions

View File

@ -192,7 +192,7 @@ EdenMount::EdenMount(
objectStore_{std::move(objectStore)},
blobCache_{std::move(blobCache)},
blobAccess_{objectStore_, blobCache_},
overlay_{std::make_unique<Overlay>(config_->getOverlayPath())},
overlay_{Overlay::create(config_->getOverlayPath())},
overlayFileAccess_{overlay_.get()},
journal_{std::move(journal)},
mountGeneration_{globalProcessGeneration | ++mountGeneration},

View File

@ -731,7 +731,7 @@ class EdenMount {
std::shared_ptr<ObjectStore> objectStore_;
std::shared_ptr<BlobCache> blobCache_;
BlobAccess blobAccess_;
std::unique_ptr<Overlay> overlay_;
std::shared_ptr<Overlay> overlay_;
OverlayFileAccess overlayFileAccess_;
InodeNumber dotEdenInodeNumber_{};

View File

@ -31,6 +31,14 @@ namespace eden {
using folly::Unit;
using std::optional;
std::shared_ptr<Overlay> Overlay::create(AbsolutePathPiece localDir) {
struct MakeSharedEnabler : public Overlay {
explicit MakeSharedEnabler(AbsolutePathPiece localDir)
: Overlay(localDir) {}
};
return std::make_shared<MakeSharedEnabler>(localDir);
}
Overlay::Overlay(AbsolutePathPiece localDir) : fsOverlay_{localDir} {}
Overlay::~Overlay() {
@ -260,11 +268,13 @@ bool Overlay::hasOverlayData(InodeNumber inodeNumber) {
OverlayFile Overlay::openFile(
InodeNumber inodeNumber,
folly::StringPiece headerId) {
return OverlayFile(fsOverlay_.openFile(inodeNumber, headerId));
return OverlayFile(
fsOverlay_.openFile(inodeNumber, headerId), weak_from_this());
}
OverlayFile Overlay::openFileNoVerify(InodeNumber inodeNumber) {
return OverlayFile(fsOverlay_.openFileNoVerify(inodeNumber));
return OverlayFile(
fsOverlay_.openFileNoVerify(inodeNumber), weak_from_this());
}
OverlayFile Overlay::createOverlayFile(
@ -272,7 +282,8 @@ OverlayFile Overlay::createOverlayFile(
folly::ByteRange contents) {
CHECK_LT(inodeNumber.get(), nextInodeNumber_.load(std::memory_order_relaxed))
<< "createOverlayFile called with unallocated inode number";
return OverlayFile(fsOverlay_.createOverlayFile(inodeNumber, contents));
return OverlayFile(
fsOverlay_.createOverlayFile(inodeNumber, contents), weak_from_this());
}
OverlayFile Overlay::createOverlayFile(
@ -280,7 +291,8 @@ OverlayFile Overlay::createOverlayFile(
const folly::IOBuf& contents) {
CHECK_LT(inodeNumber.get(), nextInodeNumber_.load(std::memory_order_relaxed))
<< "createOverlayFile called with unallocated inode number";
return OverlayFile(fsOverlay_.createOverlayFile(inodeNumber, contents));
return OverlayFile(
fsOverlay_.createOverlayFile(inodeNumber, contents), weak_from_this());
}
InodeNumber Overlay::getMaxInodeNumber() {

View File

@ -54,7 +54,7 @@ class OverlayFile;
* of files in the root, the list of files in "foo", the list of files in
* "foo/bar" and finally materializes "foo/bar/baz".
*/
class Overlay {
class Overlay : public std::enable_shared_from_this<Overlay> {
public:
/**
* Create a new Overlay object.
@ -62,7 +62,8 @@ class Overlay {
* The caller must call initialize() after creating the Overlay and wait for
* it to succeed before using any other methods.
*/
explicit Overlay(AbsolutePathPiece localDir);
static std::shared_ptr<Overlay> create(AbsolutePathPiece localDir);
~Overlay();
Overlay(const Overlay&) = delete;
@ -185,6 +186,8 @@ class Overlay {
struct statfs statFs() const;
private:
explicit Overlay(AbsolutePathPiece localDir);
/**
* A request for the background GC thread. There are two types of requests:
* recursively forget data underneath an given directory, or complete a

View File

@ -14,7 +14,8 @@
namespace facebook {
namespace eden {
OverlayFile::OverlayFile(folly::File file) : file_{std::move(file)} {}
OverlayFile::OverlayFile(folly::File file, std::weak_ptr<Overlay> overlay)
: file_{std::move(file)}, overlay_{overlay} {}
folly::Expected<struct stat, int> OverlayFile::fstat() const {
struct stat st {};

View File

@ -23,7 +23,7 @@ class Overlay;
class OverlayFile {
public:
OverlayFile() = default;
explicit OverlayFile(folly::File file);
explicit OverlayFile(folly::File file, std::weak_ptr<Overlay> overlay);
folly::Expected<struct stat, int> fstat() const;
folly::Expected<ssize_t, int> preadNoInt(void* buf, size_t n, off_t offset)
@ -38,6 +38,7 @@ class OverlayFile {
private:
folly::File file_;
std::weak_ptr<Overlay> overlay_;
};
} // namespace eden
} // namespace facebook

View File

@ -26,8 +26,8 @@ void benchmarkOverlayTreeWrites(AbsolutePathPiece overlayPath) {
//
// overlayPath is parameterized to measure on different filesystem types.
Overlay overlay{overlayPath};
overlay.initialize().get();
auto overlay = Overlay::create(overlayPath);
overlay->initialize().get();
Hash hash1{folly::ByteRange{"abcdabcdabcdabcdabcd"_sp}};
Hash hash2{folly::ByteRange{"01234012340123401234"_sp}};
@ -36,12 +36,12 @@ void benchmarkOverlayTreeWrites(AbsolutePathPiece overlayPath) {
contents.emplace(
PathComponent{"one"},
S_IFREG | 0644,
overlay.allocateInodeNumber(),
overlay->allocateInodeNumber(),
hash1);
contents.emplace(
PathComponent{"two"},
S_IFDIR | 0755,
overlay.allocateInodeNumber(),
overlay->allocateInodeNumber(),
hash2);
uint64_t N = 500000;
@ -49,8 +49,8 @@ void benchmarkOverlayTreeWrites(AbsolutePathPiece overlayPath) {
folly::stop_watch<> timer;
for (uint64_t i = 1; i <= N; i++) {
auto ino = overlay.allocateInodeNumber();
overlay.saveOverlayDir(ino, contents);
auto ino = overlay->allocateInodeNumber();
overlay->saveOverlayDir(ino, contents);
}
auto elapsed = timer.elapsed();

View File

@ -60,19 +60,20 @@ TEST(OverlayGoldMasterTest, can_load_overlay_v2) {
tmpdir.path().string()});
tarProcess.waitChecked();
Overlay overlay{realpath(tmpdir.path().string()) + "overlay-v2"_pc};
overlay.initialize().get();
auto overlay =
Overlay::create(realpath(tmpdir.path().string()) + "overlay-v2"_pc);
overlay->initialize().get();
Hash hash1{folly::ByteRange{"abcdabcdabcdabcdabcd"_sp}};
Hash hash2{folly::ByteRange{"01234012340123401234"_sp}};
Hash hash3{folly::ByteRange{"e0e0e0e0e0e0e0e0e0e0"_sp}};
Hash hash4{folly::ByteRange{"44444444444444444444"_sp}};
auto rootTree = overlay.loadOverlayDir(kRootNodeId);
auto file = overlay.openFile(2_ino, FsOverlay::kHeaderIdentifierFile);
auto subdir = overlay.loadOverlayDir(3_ino);
auto emptyDir = overlay.loadOverlayDir(4_ino);
auto hello = overlay.openFile(5_ino, FsOverlay::kHeaderIdentifierFile);
auto rootTree = overlay->loadOverlayDir(kRootNodeId);
auto file = overlay->openFile(2_ino, FsOverlay::kHeaderIdentifierFile);
auto subdir = overlay->loadOverlayDir(3_ino);
auto emptyDir = overlay->loadOverlayDir(4_ino);
auto hello = overlay->openFile(5_ino, FsOverlay::kHeaderIdentifierFile);
ASSERT_TRUE(rootTree);
EXPECT_EQ(2, rootTree->size());
@ -270,7 +271,7 @@ class RawOverlayTest : public ::testing::TestWithParam<OverlayRestartMode> {
void unloadOverlay(
std::optional<OverlayRestartMode> restartMode = std::nullopt) {
overlay->close();
overlay.reset();
overlay = nullptr;
switch (restartMode.value_or(GetParam())) {
case OverlayRestartMode::CLEAN:
break;
@ -283,7 +284,7 @@ class RawOverlayTest : public ::testing::TestWithParam<OverlayRestartMode> {
}
void loadOverlay() {
overlay = std::make_unique<Overlay>(getLocalDir());
overlay = Overlay::create(getLocalDir());
overlay->initialize().get();
}
@ -312,7 +313,7 @@ class RawOverlayTest : public ::testing::TestWithParam<OverlayRestartMode> {
}
folly::test::TemporaryDirectory testDir_;
std::unique_ptr<Overlay> overlay;
std::shared_ptr<Overlay> overlay;
};
TEST_P(RawOverlayTest, max_inode_number_is_1_if_overlay_is_empty) {
@ -554,45 +555,45 @@ class DebugDumpOverlayInodesTest : public ::testing::Test {
public:
DebugDumpOverlayInodesTest()
: testDir_{makeTempDir("eden_DebugDumpOverlayInodesTest")},
overlay{AbsolutePathPiece{testDir_.path().string()}} {
overlay.initialize().get();
overlay{Overlay::create(AbsolutePathPiece{testDir_.path().string()})} {
overlay->initialize().get();
}
folly::test::TemporaryDirectory testDir_;
Overlay overlay;
std::shared_ptr<Overlay> overlay;
};
TEST_F(DebugDumpOverlayInodesTest, dump_empty_directory) {
auto ino = kRootNodeId;
EXPECT_EQ(1_ino, ino);
overlay.saveOverlayDir(ino, DirContents{});
overlay->saveOverlayDir(ino, DirContents{});
EXPECT_EQ(
"/\n"
" Inode number: 1\n"
" Entries (0 total):\n",
debugDumpOverlayInodes(overlay, ino));
debugDumpOverlayInodes(*overlay, ino));
}
TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_3_regular_files) {
auto rootIno = kRootNodeId;
EXPECT_EQ(1_ino, rootIno);
auto fileAIno = overlay.allocateInodeNumber();
auto fileAIno = overlay->allocateInodeNumber();
EXPECT_EQ(2_ino, fileAIno);
auto fileBIno = overlay.allocateInodeNumber();
auto fileBIno = overlay->allocateInodeNumber();
EXPECT_EQ(3_ino, fileBIno);
auto fileCIno = overlay.allocateInodeNumber();
auto fileCIno = overlay->allocateInodeNumber();
EXPECT_EQ(4_ino, fileCIno);
DirContents root;
root.emplace("file_a"_pc, S_IFREG | 0644, fileAIno);
root.emplace("file_b"_pc, S_IFREG | 0644, fileBIno);
root.emplace("file_c"_pc, S_IFREG | 0644, fileCIno);
overlay.saveOverlayDir(rootIno, root);
overlay->saveOverlayDir(rootIno, root);
overlay.createOverlayFile(fileAIno, folly::ByteRange{""_sp});
overlay.createOverlayFile(fileBIno, folly::ByteRange{""_sp});
overlay.createOverlayFile(fileCIno, folly::ByteRange{""_sp});
overlay->createOverlayFile(fileAIno, folly::ByteRange{""_sp});
overlay->createOverlayFile(fileBIno, folly::ByteRange{""_sp});
overlay->createOverlayFile(fileCIno, folly::ByteRange{""_sp});
EXPECT_EQ(
"/\n"
@ -601,20 +602,20 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_3_regular_files) {
" 2 f 644 file_a\n"
" 3 f 644 file_b\n"
" 4 f 644 file_c\n",
debugDumpOverlayInodes(overlay, rootIno));
debugDumpOverlayInodes(*overlay, rootIno));
}
TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_an_empty_subdirectory) {
auto rootIno = kRootNodeId;
EXPECT_EQ(1_ino, rootIno);
auto subdirIno = overlay.allocateInodeNumber();
auto subdirIno = overlay->allocateInodeNumber();
EXPECT_EQ(2_ino, subdirIno);
DirContents root;
root.emplace("subdir"_pc, S_IFDIR | 0755, subdirIno);
overlay.saveOverlayDir(rootIno, root);
overlay->saveOverlayDir(rootIno, root);
overlay.saveOverlayDir(subdirIno, DirContents{});
overlay->saveOverlayDir(subdirIno, DirContents{});
EXPECT_EQ(
"/\n"
@ -624,19 +625,19 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_an_empty_subdirectory) {
"/subdir\n"
" Inode number: 2\n"
" Entries (0 total):\n",
debugDumpOverlayInodes(overlay, rootIno));
debugDumpOverlayInodes(*overlay, rootIno));
}
TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_subdirectory) {
auto rootIno = kRootNodeId;
EXPECT_EQ(1_ino, rootIno);
auto directoryDoesNotExistIno = overlay.allocateInodeNumber();
auto directoryDoesNotExistIno = overlay->allocateInodeNumber();
EXPECT_EQ(2_ino, directoryDoesNotExistIno);
DirContents root;
root.emplace(
"directory_does_not_exist"_pc, S_IFDIR | 0755, directoryDoesNotExistIno);
overlay.saveOverlayDir(rootIno, root);
overlay->saveOverlayDir(rootIno, root);
EXPECT_EQ(
"/\n"
@ -645,13 +646,13 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_subdirectory) {
" 2 d 755 directory_does_not_exist\n"
"/directory_does_not_exist\n"
" Inode number: 2\n",
debugDumpOverlayInodes(overlay, rootIno));
debugDumpOverlayInodes(*overlay, rootIno));
}
TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_regular_file) {
auto rootIno = kRootNodeId;
EXPECT_EQ(1_ino, rootIno);
auto regularFileDoesNotExistIno = overlay.allocateInodeNumber();
auto regularFileDoesNotExistIno = overlay->allocateInodeNumber();
EXPECT_EQ(2_ino, regularFileDoesNotExistIno);
DirContents root;
@ -659,47 +660,47 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_regular_file) {
"regular_file_does_not_exist"_pc,
S_IFREG | 0644,
regularFileDoesNotExistIno);
overlay.saveOverlayDir(rootIno, root);
overlay->saveOverlayDir(rootIno, root);
EXPECT_EQ(
"/\n"
" Inode number: 1\n"
" Entries (1 total):\n"
" 2 f 644 regular_file_does_not_exist\n",
debugDumpOverlayInodes(overlay, rootIno));
debugDumpOverlayInodes(*overlay, rootIno));
}
TEST_F(DebugDumpOverlayInodesTest, directories_are_dumped_depth_first) {
auto rootIno = kRootNodeId;
EXPECT_EQ(1_ino, rootIno);
auto subdirAIno = overlay.allocateInodeNumber();
auto subdirAIno = overlay->allocateInodeNumber();
EXPECT_EQ(2_ino, subdirAIno);
auto subdirAXIno = overlay.allocateInodeNumber();
auto subdirAXIno = overlay->allocateInodeNumber();
EXPECT_EQ(3_ino, subdirAXIno);
auto subdirAYIno = overlay.allocateInodeNumber();
auto subdirAYIno = overlay->allocateInodeNumber();
EXPECT_EQ(4_ino, subdirAYIno);
auto subdirBIno = overlay.allocateInodeNumber();
auto subdirBIno = overlay->allocateInodeNumber();
EXPECT_EQ(5_ino, subdirBIno);
auto subdirBXIno = overlay.allocateInodeNumber();
auto subdirBXIno = overlay->allocateInodeNumber();
EXPECT_EQ(6_ino, subdirBXIno);
DirContents root;
root.emplace("subdir_a"_pc, S_IFDIR | 0755, subdirAIno);
root.emplace("subdir_b"_pc, S_IFDIR | 0755, subdirBIno);
overlay.saveOverlayDir(rootIno, root);
overlay->saveOverlayDir(rootIno, root);
DirContents subdirA;
subdirA.emplace("x"_pc, S_IFDIR | 0755, subdirAXIno);
subdirA.emplace("y"_pc, S_IFDIR | 0755, subdirAYIno);
overlay.saveOverlayDir(subdirAIno, subdirA);
overlay->saveOverlayDir(subdirAIno, subdirA);
DirContents subdirB;
subdirB.emplace("x"_pc, S_IFDIR | 0755, subdirBXIno);
overlay.saveOverlayDir(subdirBIno, subdirB);
overlay->saveOverlayDir(subdirBIno, subdirB);
overlay.saveOverlayDir(subdirAXIno, DirContents{});
overlay.saveOverlayDir(subdirAYIno, DirContents{});
overlay.saveOverlayDir(subdirBXIno, DirContents{});
overlay->saveOverlayDir(subdirAXIno, DirContents{});
overlay->saveOverlayDir(subdirAYIno, DirContents{});
overlay->saveOverlayDir(subdirBXIno, DirContents{});
EXPECT_EQ(
"/\n"
@ -725,7 +726,7 @@ TEST_F(DebugDumpOverlayInodesTest, directories_are_dumped_depth_first) {
"/subdir_b/x\n"
" Inode number: 6\n"
" Entries (0 total):\n",
debugDumpOverlayInodes(overlay, rootIno));
debugDumpOverlayInodes(*overlay, rootIno));
}
namespace {

View File

@ -37,13 +37,13 @@ void createGoldMasterOverlay(AbsolutePath overlayPath) {
Hash hash3{folly::ByteRange{"e0e0e0e0e0e0e0e0e0e0"_sp}};
Hash hash4{folly::ByteRange{"44444444444444444444"_sp}};
Overlay overlay{overlayPath};
auto overlay = Overlay::create(overlayPath);
auto fileInode = overlay.allocateInodeNumber();
auto fileInode = overlay->allocateInodeNumber();
CHECK_EQ(2_ino, fileInode);
auto subdirInode = overlay.allocateInodeNumber();
auto emptyDirInode = overlay.allocateInodeNumber();
auto helloInode = overlay.allocateInodeNumber();
auto subdirInode = overlay->allocateInodeNumber();
auto emptyDirInode = overlay->allocateInodeNumber();
auto helloInode = overlay->allocateInodeNumber();
DirContents root;
root.emplace("file"_pc, S_IFREG | 0644, fileInode, hash1);
@ -55,12 +55,12 @@ void createGoldMasterOverlay(AbsolutePath overlayPath) {
DirContents emptyDir;
overlay.saveOverlayDir(kRootNodeId, root);
overlay.saveOverlayDir(subdirInode, subdir);
overlay.saveOverlayDir(emptyDirInode, emptyDir);
overlay->saveOverlayDir(kRootNodeId, root);
overlay->saveOverlayDir(subdirInode, subdir);
overlay->saveOverlayDir(emptyDirInode, emptyDir);
overlay.createOverlayFile(fileInode, folly::ByteRange{"contents"_sp});
overlay.createOverlayFile(helloInode, folly::ByteRange{"world"_sp});
overlay->createOverlayFile(fileInode, folly::ByteRange{"contents"_sp});
overlay->createOverlayFile(helloInode, folly::ByteRange{"world"_sp});
}
int main(int argc, char* argv[]) {