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:
Wez Furlong 2020-09-18 08:39:07 -07:00 committed by Facebook GitHub Bot
parent 7b6868f452
commit 0f2f5b9330
14 changed files with 141 additions and 101 deletions

View File

@ -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

View File

@ -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

View File

@ -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_;

View File

@ -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;

View File

@ -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;
};

View File

@ -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

View File

@ -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();

View File

@ -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,

View File

@ -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"

View File

@ -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{

View File

@ -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);

View File

@ -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;

View File

@ -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(

View File

@ -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";