mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 06:18:07 +03:00
edenfs: change PathMap CaseSensitivity to runtime option
Summary: This commit moves a compile-time template parameter to be a runtime boolean parameter. There's a bit of fan-out that, while I don't think it is super awesome, isn't super terrible either. The case sensitivity value is read from the checkout config added in the prior diff in this stack. Reviewed By: xavierd Differential Revision: D23751192 fbshipit-source-id: 46f6fe25bfa6666305096ad9c416b510cd3aac8f
This commit is contained in:
parent
7b6868f452
commit
0f2f5b9330
@ -236,7 +236,9 @@ static_assert(sizeof(DirEntry) == 32, "DirEntry is four words");
|
||||
/**
|
||||
* Represents a directory in the overlay.
|
||||
*/
|
||||
struct DirContents : PathMap<DirEntry> {};
|
||||
struct DirContents : PathMap<DirEntry> {
|
||||
explicit DirContents(bool caseSensitive) : PathMap(caseSensitive) {}
|
||||
};
|
||||
|
||||
} // namespace eden
|
||||
} // namespace facebook
|
||||
|
@ -202,7 +202,9 @@ EdenMount::EdenMount(
|
||||
objectStore_{std::move(objectStore)},
|
||||
blobCache_{std::move(blobCache)},
|
||||
blobAccess_{objectStore_, blobCache_},
|
||||
overlay_{Overlay::create(config_->getOverlayPath())},
|
||||
overlay_{Overlay::create(
|
||||
config_->getOverlayPath(),
|
||||
config_->getCaseSensitive())},
|
||||
#ifndef _WIN32
|
||||
overlayFileAccess_{overlay_.get()},
|
||||
#endif
|
||||
|
@ -102,7 +102,7 @@ class InodeLoader {
|
||||
// for this to avoid creating a self-referential type and fail to
|
||||
// compile. This happens to have the nice property of maintaining
|
||||
// a stable address for the contents of the InodeLoader.
|
||||
PathMap<std::unique_ptr<InodeLoader>> children_;
|
||||
PathMap<std::unique_ptr<InodeLoader>> children_{kPathMapCaseSensitive};
|
||||
// promises for the inode load attempts
|
||||
std::vector<folly::Promise<InodePtr>> promises_;
|
||||
|
||||
|
@ -40,15 +40,18 @@ constexpr uint64_t ioClosedMask = 1ull << 63;
|
||||
using folly::Unit;
|
||||
using std::optional;
|
||||
|
||||
std::shared_ptr<Overlay> Overlay::create(AbsolutePathPiece localDir) {
|
||||
std::shared_ptr<Overlay> Overlay::create(
|
||||
AbsolutePathPiece localDir,
|
||||
bool caseSensitive) {
|
||||
struct MakeSharedEnabler : public Overlay {
|
||||
explicit MakeSharedEnabler(AbsolutePathPiece localDir)
|
||||
: Overlay(localDir) {}
|
||||
explicit MakeSharedEnabler(AbsolutePathPiece localDir, bool caseSensitive)
|
||||
: Overlay(localDir, caseSensitive) {}
|
||||
};
|
||||
return std::make_shared<MakeSharedEnabler>(localDir);
|
||||
return std::make_shared<MakeSharedEnabler>(localDir, caseSensitive);
|
||||
}
|
||||
|
||||
Overlay::Overlay(AbsolutePathPiece localDir) : backingOverlay_{localDir} {}
|
||||
Overlay::Overlay(AbsolutePathPiece localDir, bool caseSensitive)
|
||||
: backingOverlay_{localDir}, caseSensitive_{caseSensitive} {}
|
||||
|
||||
Overlay::~Overlay() {
|
||||
close();
|
||||
@ -204,7 +207,7 @@ optional<DirContents> Overlay::loadOverlayDir(InodeNumber inodeNumber) {
|
||||
|
||||
bool shouldMigrateToNewFormat = false;
|
||||
|
||||
DirContents result;
|
||||
DirContents result(caseSensitive_);
|
||||
for (auto& iter : *dir.entries_ref()) {
|
||||
const auto& name = iter.first;
|
||||
const auto& value = iter.second;
|
||||
|
@ -74,7 +74,9 @@ class Overlay : public std::enable_shared_from_this<Overlay> {
|
||||
* The caller must call initialize() after creating the Overlay and wait for
|
||||
* it to succeed before using any other methods.
|
||||
*/
|
||||
static std::shared_ptr<Overlay> create(AbsolutePathPiece localDir);
|
||||
static std::shared_ptr<Overlay> create(
|
||||
AbsolutePathPiece localDir,
|
||||
bool caseSensitive);
|
||||
|
||||
~Overlay();
|
||||
|
||||
@ -217,7 +219,7 @@ class Overlay : public std::enable_shared_from_this<Overlay> {
|
||||
struct statfs statFs();
|
||||
#endif // !_WIN32
|
||||
private:
|
||||
explicit Overlay(AbsolutePathPiece localDir);
|
||||
explicit Overlay(AbsolutePathPiece localDir, bool caseSensitive);
|
||||
|
||||
/**
|
||||
* A request for the background GC thread. There are two types of requests:
|
||||
@ -298,6 +300,7 @@ class Overlay : public std::enable_shared_from_this<Overlay> {
|
||||
mutable std::atomic<uint64_t> outstandingIORequests_{0};
|
||||
|
||||
folly::Baton<> lastOutstandingRequestIsComplete_;
|
||||
bool caseSensitive_;
|
||||
|
||||
friend class IORequest;
|
||||
};
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <folly/logging/xlog.h>
|
||||
#include <vector>
|
||||
|
||||
#include "eden/fs/config/CheckoutConfig.h"
|
||||
#include "eden/fs/inodes/CheckoutAction.h"
|
||||
#include "eden/fs/inodes/CheckoutContext.h"
|
||||
#include "eden/fs/inodes/DeferredDiffEntry.h"
|
||||
@ -422,7 +423,9 @@ void TreeInode::loadUnlinkedChildInode(
|
||||
name,
|
||||
mode,
|
||||
std::nullopt,
|
||||
std::move(overlayContents).value_or(DirContents{}),
|
||||
std::move(overlayContents)
|
||||
.value_or(
|
||||
DirContents(getMount()->getConfig()->getCaseSensitive())),
|
||||
hash);
|
||||
promises = getInodeMap()->inodeLoadComplete(tree.get());
|
||||
inodePtr = InodePtr::takeOwnership(std::move(tree));
|
||||
@ -859,13 +862,17 @@ DirContents TreeInode::saveDirFromTree(
|
||||
const Tree* tree,
|
||||
EdenMount* mount) {
|
||||
auto overlay = mount->getOverlay();
|
||||
auto dir = buildDirFromTree(tree, overlay);
|
||||
auto dir =
|
||||
buildDirFromTree(tree, overlay, mount->getConfig()->getCaseSensitive());
|
||||
// buildDirFromTree just allocated inode numbers; they should be saved.
|
||||
overlay->saveOverlayDir(inodeNumber, dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
DirContents TreeInode::buildDirFromTree(const Tree* tree, Overlay* overlay) {
|
||||
DirContents TreeInode::buildDirFromTree(
|
||||
const Tree* tree,
|
||||
Overlay* overlay,
|
||||
bool caseSensitive) {
|
||||
CHECK(tree);
|
||||
|
||||
// A future optimization is for this code to allocate all of the inode numbers
|
||||
@ -873,7 +880,7 @@ DirContents TreeInode::buildDirFromTree(const Tree* tree, Overlay* overlay) {
|
||||
// of atomic operations from N to 1, though if the atomic is issued with the
|
||||
// other work this loop is doing it may not matter much.
|
||||
|
||||
DirContents dir;
|
||||
DirContents dir(caseSensitive);
|
||||
// TODO: O(N^2)
|
||||
for (const auto& treeEntry : tree->getTreeEntries()) {
|
||||
dir.emplace(
|
||||
@ -1077,7 +1084,7 @@ TreeInodePtr TreeInode::mkdir(
|
||||
mode = S_IFDIR | (07777 & mode);
|
||||
|
||||
// Store the overlay entry for this dir
|
||||
DirContents emptyDir;
|
||||
DirContents emptyDir(getMount()->getConfig()->getCaseSensitive());
|
||||
saveOverlayDir(childNumber, emptyDir);
|
||||
|
||||
// Add a new entry to contents_.entries
|
||||
|
@ -479,7 +479,8 @@ class TreeInode final : public InodeBaseMetadata<DirContents> {
|
||||
|
||||
/** Translates a Tree object from our store into a Dir object
|
||||
* used to track the directory in the inode */
|
||||
static DirContents buildDirFromTree(const Tree* tree, Overlay* overlay);
|
||||
static DirContents
|
||||
buildDirFromTree(const Tree* tree, Overlay* overlay, bool caseSensitive);
|
||||
|
||||
#ifndef _WIN32
|
||||
void updateAtime();
|
||||
|
@ -26,13 +26,13 @@ void benchmarkOverlayTreeWrites(AbsolutePathPiece overlayPath) {
|
||||
//
|
||||
// overlayPath is parameterized to measure on different filesystem types.
|
||||
|
||||
auto overlay = Overlay::create(overlayPath);
|
||||
auto overlay = Overlay::create(overlayPath, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
|
||||
Hash hash1{folly::ByteRange{"abcdabcdabcdabcdabcd"_sp}};
|
||||
Hash hash2{folly::ByteRange{"01234012340123401234"_sp}};
|
||||
|
||||
DirContents contents;
|
||||
DirContents contents(kPathMapDefaultCaseSensitive);
|
||||
contents.emplace(
|
||||
PathComponent{"one"},
|
||||
S_IFREG | 0644,
|
||||
|
@ -61,8 +61,9 @@ TEST(OverlayGoldMasterTest, can_load_overlay_v2) {
|
||||
tmpdir.path().string()});
|
||||
EXPECT_EQ(tarProcess.wait().str(), "exited with status 0");
|
||||
|
||||
auto overlay =
|
||||
Overlay::create(realpath(tmpdir.path().string()) + "overlay-v2"_pc);
|
||||
auto overlay = Overlay::create(
|
||||
realpath(tmpdir.path().string()) + "overlay-v2"_pc,
|
||||
kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
|
||||
Hash hash1{folly::ByteRange{"abcdabcdabcdabcdabcd"_sp}};
|
||||
@ -217,7 +218,7 @@ TEST_F(OverlayTest, roundTripThroughSaveAndLoad) {
|
||||
auto ino2 = overlay->allocateInodeNumber();
|
||||
auto ino3 = overlay->allocateInodeNumber();
|
||||
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapDefaultCaseSensitive);
|
||||
dir.emplace("one"_pc, S_IFREG | 0644, ino2, hash);
|
||||
dir.emplace("two"_pc, S_IFDIR | 0755, ino3);
|
||||
|
||||
@ -255,7 +256,8 @@ TEST_F(OverlayTest, getFilePath) {
|
||||
|
||||
TEST(PlainOverlayTest, new_overlay_is_clean) {
|
||||
folly::test::TemporaryDirectory testDir;
|
||||
auto overlay = Overlay::create(AbsolutePath{testDir.path().string()});
|
||||
auto overlay = Overlay::create(
|
||||
AbsolutePath{testDir.path().string()}, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
EXPECT_TRUE(overlay->hadCleanStartup());
|
||||
}
|
||||
@ -263,11 +265,13 @@ TEST(PlainOverlayTest, new_overlay_is_clean) {
|
||||
TEST(PlainOverlayTest, reopened_overlay_is_clean) {
|
||||
folly::test::TemporaryDirectory testDir;
|
||||
{
|
||||
auto overlay = Overlay::create(AbsolutePath{testDir.path().string()});
|
||||
auto overlay = Overlay::create(
|
||||
AbsolutePath{testDir.path().string()}, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
}
|
||||
|
||||
auto overlay = Overlay::create(AbsolutePath{testDir.path().string()});
|
||||
auto overlay = Overlay::create(
|
||||
AbsolutePath{testDir.path().string()}, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
EXPECT_TRUE(overlay->hadCleanStartup());
|
||||
}
|
||||
@ -277,7 +281,8 @@ TEST(PlainOverlayTest, unclean_overlay_is_dirty) {
|
||||
auto localDir = AbsolutePath{testDir.path().string()};
|
||||
|
||||
{
|
||||
auto overlay = Overlay::create(AbsolutePath{testDir.path().string()});
|
||||
auto overlay = Overlay::create(
|
||||
AbsolutePath{testDir.path().string()}, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
}
|
||||
|
||||
@ -285,7 +290,8 @@ TEST(PlainOverlayTest, unclean_overlay_is_dirty) {
|
||||
folly::throwSystemError("removing saved inode numebr");
|
||||
}
|
||||
|
||||
auto overlay = Overlay::create(AbsolutePath{testDir.path().string()});
|
||||
auto overlay = Overlay::create(
|
||||
AbsolutePath{testDir.path().string()}, kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
EXPECT_FALSE(overlay->hadCleanStartup());
|
||||
}
|
||||
@ -322,7 +328,7 @@ class RawOverlayTest : public ::testing::TestWithParam<OverlayRestartMode> {
|
||||
}
|
||||
|
||||
void loadOverlay() {
|
||||
overlay = Overlay::create(getLocalDir());
|
||||
overlay = Overlay::create(getLocalDir(), kPathMapDefaultCaseSensitive);
|
||||
overlay->initialize().get();
|
||||
}
|
||||
|
||||
@ -447,7 +453,7 @@ TEST_P(RawOverlayTest, cannot_save_overlay_dir_when_closed) {
|
||||
auto ino2 = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(2_ino, ino2);
|
||||
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapDefaultCaseSensitive);
|
||||
EXPECT_THROW_RE(
|
||||
overlay->saveOverlayDir(ino2, dir),
|
||||
std::system_error,
|
||||
@ -499,7 +505,7 @@ TEST_P(RawOverlayTest, remembers_max_inode_number_of_tree_inodes) {
|
||||
auto ino2 = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(2_ino, ino2);
|
||||
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapDefaultCaseSensitive);
|
||||
overlay->saveOverlayDir(ino2, dir);
|
||||
|
||||
recreate();
|
||||
@ -513,7 +519,7 @@ TEST_P(RawOverlayTest, remembers_max_inode_number_of_tree_entries) {
|
||||
auto ino3 = overlay->allocateInodeNumber();
|
||||
auto ino4 = overlay->allocateInodeNumber();
|
||||
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapDefaultCaseSensitive);
|
||||
dir.emplace(PathComponentPiece{"f"}, S_IFREG | 0644, ino3);
|
||||
dir.emplace(PathComponentPiece{"d"}, S_IFDIR | 0755, ino4);
|
||||
overlay->saveOverlayDir(kRootNodeId, dir);
|
||||
@ -546,11 +552,12 @@ TEST_P(
|
||||
auto rootIno = kRootNodeId;
|
||||
ASSERT_GT(subdirectoryIno, rootIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace("subdirectory"_pc, S_IFDIR | 0755, subdirectoryIno);
|
||||
overlay->saveOverlayDir(rootIno, root);
|
||||
|
||||
overlay->saveOverlayDir(subdirectoryIno, DirContents{});
|
||||
overlay->saveOverlayDir(
|
||||
subdirectoryIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
|
||||
unloadOverlay();
|
||||
corruptOverlayFile(subdirectoryIno);
|
||||
@ -590,7 +597,7 @@ TEST_P(
|
||||
auto corruptedByDeletionIno = InodeNumber{};
|
||||
|
||||
auto setUpOverlay = [&](const PathNames& pathNames) {
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace(
|
||||
pathNames.corruptedByTruncationName,
|
||||
S_IFDIR | 0755,
|
||||
@ -598,14 +605,16 @@ TEST_P(
|
||||
root.emplace(pathNames.tempName, S_IFDIR | 0755, tempDirIno);
|
||||
overlay->saveOverlayDir(rootIno, root);
|
||||
|
||||
overlay->saveOverlayDir(corruptedByTruncationIno, DirContents{});
|
||||
overlay->saveOverlayDir(
|
||||
corruptedByTruncationIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
|
||||
DirContents tempDir;
|
||||
DirContents tempDir(kPathMapDefaultCaseSensitive);
|
||||
tempDir.emplace(
|
||||
"corrupted_by_deletion"_pc, S_IFDIR | 0755, corruptedByDeletionIno);
|
||||
overlay->saveOverlayDir(tempDirIno, tempDir);
|
||||
|
||||
overlay->saveOverlayDir(corruptedByDeletionIno, DirContents{});
|
||||
overlay->saveOverlayDir(
|
||||
corruptedByDeletionIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
};
|
||||
|
||||
const PathNames pathNamesToTest[] = {
|
||||
@ -653,7 +662,7 @@ TEST_P(RawOverlayTest, inode_numbers_not_reused_after_unclean_shutdown) {
|
||||
overlay->createOverlayFile(ino5, folly::ByteRange{"contents"_sp});
|
||||
|
||||
// The subdir is written next.
|
||||
DirContents subdir;
|
||||
DirContents subdir(kPathMapDefaultCaseSensitive);
|
||||
subdir.emplace(PathComponentPiece{"f"}, S_IFREG | 0644, ino5);
|
||||
overlay->saveOverlayDir(ino4, subdir);
|
||||
|
||||
@ -674,12 +683,12 @@ TEST_P(RawOverlayTest, inode_numbers_after_takeover) {
|
||||
auto ino5 = overlay->allocateInodeNumber();
|
||||
|
||||
// Write a subdir.
|
||||
DirContents subdir;
|
||||
DirContents subdir(kPathMapDefaultCaseSensitive);
|
||||
subdir.emplace(PathComponentPiece{"f"}, S_IFREG | 0644, ino5);
|
||||
overlay->saveOverlayDir(ino4, subdir);
|
||||
|
||||
// Write the root.
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapDefaultCaseSensitive);
|
||||
dir.emplace(PathComponentPiece{"f"}, S_IFREG | 0644, ino3);
|
||||
dir.emplace(PathComponentPiece{"d"}, S_IFDIR | 0755, ino4);
|
||||
overlay->saveOverlayDir(kRootNodeId, dir);
|
||||
@ -688,7 +697,7 @@ TEST_P(RawOverlayTest, inode_numbers_after_takeover) {
|
||||
|
||||
// Rewrite the root (say, after a takeover) without the file.
|
||||
|
||||
DirContents newroot;
|
||||
DirContents newroot(kPathMapDefaultCaseSensitive);
|
||||
newroot.emplace(PathComponentPiece{"d"}, S_IFDIR | 0755, 4_ino);
|
||||
overlay->saveOverlayDir(kRootNodeId, newroot);
|
||||
|
||||
@ -719,7 +728,9 @@ class DebugDumpOverlayInodesTest : public ::testing::Test {
|
||||
public:
|
||||
DebugDumpOverlayInodesTest()
|
||||
: testDir_{makeTempDir("eden_DebugDumpOverlayInodesTest")},
|
||||
overlay{Overlay::create(AbsolutePathPiece{testDir_.path().string()})} {
|
||||
overlay{Overlay::create(
|
||||
AbsolutePathPiece{testDir_.path().string()},
|
||||
kPathMapDefaultCaseSensitive)} {
|
||||
overlay->initialize().get();
|
||||
}
|
||||
|
||||
@ -731,7 +742,7 @@ TEST_F(DebugDumpOverlayInodesTest, dump_empty_directory) {
|
||||
auto ino = kRootNodeId;
|
||||
EXPECT_EQ(1_ino, ino);
|
||||
|
||||
overlay->saveOverlayDir(ino, DirContents{});
|
||||
overlay->saveOverlayDir(ino, DirContents(kPathMapDefaultCaseSensitive));
|
||||
EXPECT_EQ(
|
||||
"/\n"
|
||||
" Inode number: 1\n"
|
||||
@ -749,7 +760,7 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_3_regular_files) {
|
||||
auto fileCIno = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(4_ino, fileCIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
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);
|
||||
@ -775,11 +786,11 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_an_empty_subdirectory) {
|
||||
auto subdirIno = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(2_ino, subdirIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace("subdir"_pc, S_IFDIR | 0755, subdirIno);
|
||||
overlay->saveOverlayDir(rootIno, root);
|
||||
|
||||
overlay->saveOverlayDir(subdirIno, DirContents{});
|
||||
overlay->saveOverlayDir(subdirIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
|
||||
EXPECT_EQ(
|
||||
"/\n"
|
||||
@ -798,7 +809,7 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_subdirectory) {
|
||||
auto directoryDoesNotExistIno = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(2_ino, directoryDoesNotExistIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace(
|
||||
"directory_does_not_exist"_pc, S_IFDIR | 0755, directoryDoesNotExistIno);
|
||||
overlay->saveOverlayDir(rootIno, root);
|
||||
@ -819,7 +830,7 @@ TEST_F(DebugDumpOverlayInodesTest, dump_directory_with_unsaved_regular_file) {
|
||||
auto regularFileDoesNotExistIno = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(2_ino, regularFileDoesNotExistIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace(
|
||||
"regular_file_does_not_exist"_pc,
|
||||
S_IFREG | 0644,
|
||||
@ -848,23 +859,26 @@ TEST_F(DebugDumpOverlayInodesTest, directories_are_dumped_depth_first) {
|
||||
auto subdirBXIno = overlay->allocateInodeNumber();
|
||||
EXPECT_EQ(6_ino, subdirBXIno);
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapDefaultCaseSensitive);
|
||||
root.emplace("subdir_a"_pc, S_IFDIR | 0755, subdirAIno);
|
||||
root.emplace("subdir_b"_pc, S_IFDIR | 0755, subdirBIno);
|
||||
overlay->saveOverlayDir(rootIno, root);
|
||||
|
||||
DirContents subdirA;
|
||||
DirContents subdirA(kPathMapDefaultCaseSensitive);
|
||||
subdirA.emplace("x"_pc, S_IFDIR | 0755, subdirAXIno);
|
||||
subdirA.emplace("y"_pc, S_IFDIR | 0755, subdirAYIno);
|
||||
overlay->saveOverlayDir(subdirAIno, subdirA);
|
||||
|
||||
DirContents subdirB;
|
||||
DirContents subdirB(kPathMapDefaultCaseSensitive);
|
||||
subdirB.emplace("x"_pc, S_IFDIR | 0755, subdirBXIno);
|
||||
overlay->saveOverlayDir(subdirBIno, subdirB);
|
||||
|
||||
overlay->saveOverlayDir(subdirAXIno, DirContents{});
|
||||
overlay->saveOverlayDir(subdirAYIno, DirContents{});
|
||||
overlay->saveOverlayDir(subdirBXIno, DirContents{});
|
||||
overlay->saveOverlayDir(
|
||||
subdirAXIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
overlay->saveOverlayDir(
|
||||
subdirAYIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
overlay->saveOverlayDir(
|
||||
subdirBXIno, DirContents(kPathMapDefaultCaseSensitive));
|
||||
|
||||
EXPECT_EQ(
|
||||
"/\n"
|
||||
|
@ -39,7 +39,7 @@ static TreeEntry makeTreeEntry(folly::StringPiece name) {
|
||||
}
|
||||
|
||||
TEST(TreeInode, findEntryDifferencesWithSameEntriesReturnsNone) {
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapCaseSensitive);
|
||||
dir.emplace("one"_pc, makeDirEntry());
|
||||
dir.emplace("two"_pc, makeDirEntry());
|
||||
Tree tree{{makeTreeEntry("one"), makeTreeEntry("two")}};
|
||||
@ -48,7 +48,7 @@ TEST(TreeInode, findEntryDifferencesWithSameEntriesReturnsNone) {
|
||||
}
|
||||
|
||||
TEST(TreeInode, findEntryDifferencesReturnsAdditionsAndSubtractions) {
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapCaseSensitive);
|
||||
dir.emplace("one"_pc, makeDirEntry());
|
||||
dir.emplace("two"_pc, makeDirEntry());
|
||||
Tree tree{{makeTreeEntry("one"), makeTreeEntry("three")}};
|
||||
@ -59,7 +59,7 @@ TEST(TreeInode, findEntryDifferencesReturnsAdditionsAndSubtractions) {
|
||||
}
|
||||
|
||||
TEST(TreeInode, findEntryDifferencesWithOneSubtraction) {
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapCaseSensitive);
|
||||
dir.emplace("one"_pc, makeDirEntry());
|
||||
dir.emplace("two"_pc, makeDirEntry());
|
||||
Tree tree{{makeTreeEntry("one")}};
|
||||
@ -70,7 +70,7 @@ TEST(TreeInode, findEntryDifferencesWithOneSubtraction) {
|
||||
}
|
||||
|
||||
TEST(TreeInode, findEntryDifferencesWithOneAddition) {
|
||||
DirContents dir;
|
||||
DirContents dir(kPathMapCaseSensitive);
|
||||
dir.emplace("one"_pc, makeDirEntry());
|
||||
dir.emplace("two"_pc, makeDirEntry());
|
||||
Tree tree{
|
||||
|
@ -37,7 +37,7 @@ void createGoldMasterOverlay(AbsolutePath overlayPath) {
|
||||
Hash hash3{folly::ByteRange{"e0e0e0e0e0e0e0e0e0e0"_sp}};
|
||||
Hash hash4{folly::ByteRange{"44444444444444444444"_sp}};
|
||||
|
||||
auto overlay = Overlay::create(overlayPath);
|
||||
auto overlay = Overlay::create(overlayPath, kPathMapCaseSensitive);
|
||||
|
||||
auto fileInode = overlay->allocateInodeNumber();
|
||||
CHECK_EQ(2_ino, fileInode);
|
||||
@ -45,15 +45,15 @@ void createGoldMasterOverlay(AbsolutePath overlayPath) {
|
||||
auto emptyDirInode = overlay->allocateInodeNumber();
|
||||
auto helloInode = overlay->allocateInodeNumber();
|
||||
|
||||
DirContents root;
|
||||
DirContents root(kPathMapCaseSensitive);
|
||||
root.emplace("file"_pc, S_IFREG | 0644, fileInode, hash1);
|
||||
root.emplace("subdir"_pc, S_IFDIR | 0755, subdirInode, hash2);
|
||||
|
||||
DirContents subdir;
|
||||
DirContents subdir(kPathMapCaseSensitive);
|
||||
subdir.emplace("empty"_pc, S_IFDIR | 0755, emptyDirInode, hash3);
|
||||
subdir.emplace("hello"_pc, S_IFREG | 0644, helloInode, hash4);
|
||||
|
||||
DirContents emptyDir;
|
||||
DirContents emptyDir(kPathMapCaseSensitive);
|
||||
|
||||
overlay->saveOverlayDir(kRootNodeId, root);
|
||||
overlay->saveOverlayDir(subdirInode, subdir);
|
||||
|
@ -262,14 +262,14 @@ StoredBlob* FakeTreeBuilder::getStoredBlob(RelativePathPiece path) {
|
||||
|
||||
FakeTreeBuilder::EntryInfo::EntryInfo(TreeEntryType fileType) : type(fileType) {
|
||||
if (type == TreeEntryType::TREE) {
|
||||
entries = make_unique<PathMap<EntryInfo>>();
|
||||
entries = make_unique<PathMap<EntryInfo>>(kPathMapDefaultCaseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
FakeTreeBuilder::EntryInfo::EntryInfo(ExplicitClone, const EntryInfo& orig)
|
||||
: type(orig.type), contents(orig.contents) {
|
||||
if (orig.entries) {
|
||||
entries = make_unique<PathMap<EntryInfo>>();
|
||||
entries = make_unique<PathMap<EntryInfo>>(kPathMapDefaultCaseSensitive);
|
||||
for (const auto& e : *orig.entries) {
|
||||
auto ret = entries->emplace(e.first, EntryInfo{CLONE, e.second});
|
||||
CHECK(ret.second) << "failed to insert " << e.first;
|
||||
|
@ -18,6 +18,8 @@ namespace facebook {
|
||||
namespace eden {
|
||||
|
||||
constexpr bool kPathMapDefaultCaseSensitive = !folly::kIsWindows;
|
||||
constexpr bool kPathMapCaseSensitive = true;
|
||||
constexpr bool kPathMapCaseInSensitive = !kPathMapCaseSensitive;
|
||||
|
||||
/** An associative container that maps from one of our path types to an
|
||||
* arbitrary value type.
|
||||
@ -33,10 +35,7 @@ constexpr bool kPathMapDefaultCaseSensitive = !folly::kIsWindows;
|
||||
* - Since insert and erase operations move the vector contents around,
|
||||
* those operations invalidate iterators.
|
||||
*/
|
||||
template <
|
||||
typename Value,
|
||||
typename Key = PathComponent,
|
||||
bool CaseSensitive = kPathMapDefaultCaseSensitive>
|
||||
template <typename Value, typename Key = PathComponent>
|
||||
class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
using Pair = std::pair<Key, Value>;
|
||||
using Vector = folly::fbvector<Pair>;
|
||||
@ -79,6 +78,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
// Hold an instance of the comparator. It doesn't actually
|
||||
// occupy any space.
|
||||
Compare compare_;
|
||||
bool caseSensitive_{kPathMapDefaultCaseSensitive};
|
||||
|
||||
public:
|
||||
// Various type aliases to satisfy container concepts.
|
||||
@ -99,15 +99,16 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
using const_reverse_iterator = typename Vector::const_reverse_iterator;
|
||||
|
||||
// Construct empty.
|
||||
PathMap() {}
|
||||
PathMap(bool caseSensitive) : caseSensitive_(caseSensitive) {}
|
||||
|
||||
// Populate from an initializer_list.
|
||||
PathMap(std::initializer_list<value_type> init)
|
||||
: PathMap(init.begin(), init.end()) {}
|
||||
PathMap(std::initializer_list<value_type> init, bool caseSensitive)
|
||||
: PathMap(init.begin(), init.end(), caseSensitive) {}
|
||||
|
||||
// Populate from a pair of input iterators.
|
||||
template <typename InputIterator>
|
||||
PathMap(InputIterator first, InputIterator last) {
|
||||
PathMap(InputIterator first, InputIterator last, bool caseSensitive)
|
||||
: caseSensitive_(caseSensitive) {
|
||||
// The std::distance call is O(1) if the iterators are random-access, but
|
||||
// O(n) otherwise. We're fine with the O(n) on the basis that if n is large
|
||||
// enough to matter, the cost of iterating will be dwarfed by the cost
|
||||
@ -150,6 +151,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
// Swap contents with another map.
|
||||
void swap(PathMap& other) noexcept {
|
||||
Vector::swap(other);
|
||||
std::swap(caseSensitive_, other.caseSensitive_);
|
||||
}
|
||||
|
||||
// lower_bound performs the binary search for locating keys.
|
||||
@ -170,8 +172,8 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
// Found it
|
||||
return iter;
|
||||
}
|
||||
if (!CaseSensitive) {
|
||||
// When !CaseSensitive, for performance, we will do a case sensitive
|
||||
if (!caseSensitive_) {
|
||||
// When !caseSensitive_, for performance, we will do a case sensitive
|
||||
// search first which should cover most of the cases and if not found then
|
||||
// do a case insensitive search.
|
||||
for (iter = begin(); iter != end(); ++iter) {
|
||||
@ -193,7 +195,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
// Found it
|
||||
return iter;
|
||||
}
|
||||
if (!CaseSensitive) {
|
||||
if (!caseSensitive_) {
|
||||
for (iter = begin(); iter != end(); ++iter) {
|
||||
if (key.stringPiece().equals(
|
||||
iter->first.stringPiece(), folly::AsciiCaseInsensitive())) {
|
||||
@ -216,7 +218,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
return std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
if (!CaseSensitive) {
|
||||
if (!caseSensitive_) {
|
||||
for (auto insens = begin(); insens != end(); ++insens) {
|
||||
if (val.first.stringPiece().equals(
|
||||
insens->first.stringPiece(), folly::AsciiCaseInsensitive())) {
|
||||
@ -245,7 +247,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
return std::make_pair(iter, false);
|
||||
}
|
||||
|
||||
if (!CaseSensitive) {
|
||||
if (!caseSensitive_) {
|
||||
for (auto insens = begin(); insens != end(); ++insens) {
|
||||
if (key.stringPiece().equals(
|
||||
insens->first.stringPiece(), folly::AsciiCaseInsensitive())) {
|
||||
@ -271,7 +273,7 @@ class PathMap : private folly::fbvector<std::pair<Key, Value>> {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
if (!CaseSensitive) {
|
||||
if (!caseSensitive_) {
|
||||
// Case insensitive lookup
|
||||
for (auto insens = begin(); insens != end(); ++insens) {
|
||||
if (key.stringPiece().equals(
|
||||
|
@ -9,14 +9,12 @@
|
||||
#include <folly/portability/Unistd.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using facebook::eden::PathComponent;
|
||||
using facebook::eden::PathComponentPiece;
|
||||
using facebook::eden::PathMap;
|
||||
using namespace facebook::eden;
|
||||
using namespace facebook::eden::path_literals;
|
||||
|
||||
TEST(PathMap, caseSensitive) {
|
||||
// Explicitly a case sensitive map, regardless of the host OS
|
||||
PathMap<bool, PathComponent, true> map;
|
||||
PathMap<bool> map(kPathMapCaseSensitive);
|
||||
|
||||
map.insert(std::make_pair(PathComponent("foo"), true));
|
||||
EXPECT_TRUE(map.at("foo"_pc));
|
||||
@ -36,7 +34,7 @@ TEST(PathMap, caseSensitive) {
|
||||
|
||||
TEST(PathMap, caseInSensitive) {
|
||||
// Explicitly a case IN-sensitive map, regardless of the host OS
|
||||
PathMap<bool, PathComponent, false> map;
|
||||
PathMap<bool> map(kPathMapCaseInSensitive);
|
||||
|
||||
map.insert(std::make_pair(PathComponent("foo"), true));
|
||||
EXPECT_TRUE(map.at("foo"_pc));
|
||||
@ -63,7 +61,7 @@ TEST(PathMap, caseInSensitive) {
|
||||
}
|
||||
|
||||
TEST(PathMap, insert) {
|
||||
PathMap<bool> map;
|
||||
PathMap<bool> map(kPathMapDefaultCaseSensitive);
|
||||
|
||||
EXPECT_TRUE(map.empty());
|
||||
|
||||
@ -94,11 +92,13 @@ TEST(PathMap, insert) {
|
||||
}
|
||||
|
||||
TEST(PathMap, iteration_and_erase) {
|
||||
PathMap<int> map{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
};
|
||||
PathMap<int> map(
|
||||
{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
},
|
||||
kPathMapDefaultCaseSensitive);
|
||||
|
||||
std::vector<PathComponentPiece> keys;
|
||||
for (const auto& it : map) {
|
||||
@ -123,22 +123,26 @@ TEST(PathMap, iteration_and_erase) {
|
||||
}
|
||||
|
||||
TEST(PathMap, copy) {
|
||||
PathMap<int> map{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
};
|
||||
PathMap<int> map(
|
||||
{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
},
|
||||
kPathMapDefaultCaseSensitive);
|
||||
PathMap<int> other = map;
|
||||
EXPECT_EQ(3, other.size());
|
||||
EXPECT_EQ(map, other);
|
||||
}
|
||||
|
||||
TEST(PathMap, move) {
|
||||
PathMap<int> map{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
};
|
||||
PathMap<int> map(
|
||||
{
|
||||
std::make_pair(PathComponent("foo"), 1),
|
||||
std::make_pair(PathComponent("bar"), 2),
|
||||
std::make_pair(PathComponent("baz"), 3),
|
||||
},
|
||||
kPathMapDefaultCaseSensitive);
|
||||
PathMap<int> other = std::move(map);
|
||||
EXPECT_EQ(3, other.size());
|
||||
EXPECT_EQ(0, map.size());
|
||||
@ -158,7 +162,7 @@ struct EmplaceTest {
|
||||
int EmplaceTest::counter = 0;
|
||||
|
||||
TEST(PathMap, emplace) {
|
||||
PathMap<EmplaceTest> map;
|
||||
PathMap<EmplaceTest> map(kPathMapDefaultCaseSensitive);
|
||||
|
||||
auto result = map.emplace("one"_pc, true, 42);
|
||||
EXPECT_EQ(1, EmplaceTest::counter)
|
||||
@ -176,7 +180,9 @@ TEST(PathMap, emplace) {
|
||||
}
|
||||
|
||||
TEST(PathMap, swap) {
|
||||
PathMap<std::string> b, a{std::make_pair(PathComponent("foo"), "foo")};
|
||||
PathMap<std::string> b(kPathMapDefaultCaseSensitive),
|
||||
a({std::make_pair(PathComponent("foo"), "foo")},
|
||||
kPathMapDefaultCaseSensitive);
|
||||
|
||||
b.swap(a);
|
||||
EXPECT_EQ(0, a.size()) << "a now has 0 elements";
|
||||
|
Loading…
Reference in New Issue
Block a user