Use hinted linear search instead of binary search

This commit is contained in:
Sebastian Messmer 2015-10-08 01:19:44 +02:00
parent bf3a028204
commit 66cd99b0ff
2 changed files with 35 additions and 6 deletions

View File

@ -1,4 +1,5 @@
#include "DirEntryList.h" #include "DirEntryList.h"
#include <limits>
//TODO Get rid of that in favor of better error handling //TODO Get rid of that in favor of better error handling
#include <messmer/fspp/fuse/FuseErrnoException.h> #include <messmer/fspp/fuse/FuseErrnoException.h>
@ -52,9 +53,7 @@ void DirEntryList::add(const string &name, const Key &blobKey, fspp::Dir::EntryT
if (_hasChild(name)) { if (_hasChild(name)) {
throw fspp::fuse::FuseErrnoException(EEXIST); throw fspp::fuse::FuseErrnoException(EEXIST);
} }
auto insert_pos = std::upper_bound(_entries.begin(), _entries.end(), blobKey, [] (const Key &key, const DirEntry &item) { auto insert_pos = _findUpperBound(blobKey);
return std::less<Key>()(key, item.key);
});
_entries.emplace(insert_pos, entryType, name, blobKey, mode, uid, gid); _entries.emplace(insert_pos, entryType, name, blobKey, mode, uid, gid);
} }
@ -78,15 +77,42 @@ void DirEntryList::remove(const Key &key) {
} }
vector<DirEntry>::iterator DirEntryList::_find(const Key &key) { vector<DirEntry>::iterator DirEntryList::_find(const Key &key) {
auto found = std::lower_bound(_entries.begin(), _entries.end(), key, [] (const DirEntry &entry, const Key &key) { auto found = _findLowerBound(key);
return std::less<Key>()(entry.key, key);
});
if (found == _entries.end() || found->key != key) { if (found == _entries.end() || found->key != key) {
throw fspp::fuse::FuseErrnoException(ENOENT); throw fspp::fuse::FuseErrnoException(ENOENT);
} }
return found; return found;
} }
vector<DirEntry>::iterator DirEntryList::_findLowerBound(const Key &key) {
return _findFirst(key, [&key] (const DirEntry &entry) {
return !std::less<Key>()(entry.key, key);
});
}
vector<DirEntry>::iterator DirEntryList::_findUpperBound(const Key &key) {
return _findFirst(key, [&key] (const DirEntry &entry) {
return std::less<Key>()(key, entry.key);
});
}
vector<DirEntry>::iterator DirEntryList::_findFirst(const Key &hint, std::function<bool (const DirEntry&)> pred) {
//TODO Factor out a datastructure that keeps a sorted std::vector and allows these _findLowerBound()/_findUpperBound operations using this hinted linear search
if (_entries.size() == 0) {
return _entries.end();
}
double startpos_percent = static_cast<double>(*static_cast<const unsigned char*>(hint.data())) / std::numeric_limits<unsigned char>::max();
auto iter = _entries.begin() + static_cast<int>(startpos_percent * (_entries.size()-1));
ASSERT(iter >= _entries.begin() && iter < _entries.end(), "Startpos out of range");
while(iter != _entries.begin() && pred(*iter)) {
--iter;
}
while(iter != _entries.end() && !pred(*iter)) {
++iter;
}
return iter;
}
vector<DirEntry>::const_iterator DirEntryList::_find(const Key &key) const { vector<DirEntry>::const_iterator DirEntryList::_find(const Key &key) const {
return const_cast<DirEntryList*>(this)->_find(key); return const_cast<DirEntryList*>(this)->_find(key);
} }

View File

@ -37,6 +37,9 @@ namespace cryfs {
bool _hasChild(const std::string &name) const; bool _hasChild(const std::string &name) const;
std::vector<DirEntry>::iterator _find(const blockstore::Key &key); std::vector<DirEntry>::iterator _find(const blockstore::Key &key);
std::vector<DirEntry>::const_iterator _find(const blockstore::Key &key) const; std::vector<DirEntry>::const_iterator _find(const blockstore::Key &key) const;
std::vector<DirEntry>::iterator _findUpperBound(const blockstore::Key &key);
std::vector<DirEntry>::iterator _findLowerBound(const blockstore::Key &key);
std::vector<DirEntry>::iterator _findFirst(const blockstore::Key &hint, std::function<bool (const DirEntry&)> pred);
std::vector<DirEntry> _entries; std::vector<DirEntry> _entries;