diff --git a/fs/bootfs.cc b/fs/bootfs.cc index 1b563fc4439b3eee2432dab157e4457da44d2018..8159f8d26750fa8018d7771c30954be4cbb04690 100644 --- a/fs/bootfs.cc +++ b/fs/bootfs.cc @@ -53,7 +53,7 @@ bootfs::dir::dir(bootfs& fs, std::string path) { } -fileref bootfs::dir::open(std::string name) +fileref bootfs::dir::do_open(std::string name) { return _fs.do_open(_path + name); } diff --git a/fs/bootfs.hh b/fs/bootfs.hh index a3d332eb71f8c7b3707004721ccb5d7ef3dffd9b..63f29cdc83555c4f95daead502a697e4e85ea39a 100644 --- a/fs/bootfs.hh +++ b/fs/bootfs.hh @@ -33,7 +33,7 @@ private: class bootfs::dir : public ::dir { public: dir(bootfs& fs, std::string path); - virtual fileref open(std::string name); + virtual fileref do_open(std::string name); virtual uint64_t size(); virtual void read(void* buffer, uint64_t offset, uint64_t len); private: diff --git a/fs/fs.cc b/fs/fs.cc index 68c2af78cbb41b223945410638fb4b19a36647b4..2dab7d45118a5ef4982b99544a3033dde5067c7e 100644 --- a/fs/fs.cc +++ b/fs/fs.cc @@ -2,6 +2,18 @@ filesystem* rootfs; +namespace std { + +template <> +struct hash<file::cache_key> { + size_t operator()(file::cache_key k) const { + return reinterpret_cast<uintptr_t>(k.first.get()) + ^ std::hash<std::string>()(k.second); + } +}; + +} + file::file() : _refs(0) { @@ -43,8 +55,21 @@ fileref filesystem::open(std::string name) return d->open(name.substr(s, name.npos)); } +fileref dir::open(std::string name) +{ + cache_key key(this, name); + auto ret = _cache.find(key); + if (ret == _cache.end()) { + auto f = do_open(name); + ret = _cache.insert(cache_type::value_type(key, f)).first; + } + return ret->second; +} + dirref dir::subdir(std::string name) { // trivial implementation, can be overridden return boost::dynamic_pointer_cast<dir>(open(name)); } + +file::cache_type file::_cache; diff --git a/fs/fs.hh b/fs/fs.hh index 85d1ccc77eed23aab36297f08a5c2b52099bb5eb..570f35ac98c6b75c764fc641997db2b54f95f761 100644 --- a/fs/fs.hh +++ b/fs/fs.hh @@ -4,6 +4,7 @@ #include <string> #include <cstdint> #include <boost/intrusive_ptr.hpp> +#include <unordered_map> class file; class dir; @@ -24,12 +25,23 @@ private: unsigned _refs; // FIXME: make atomic friend void intrusive_ptr_add_ref(file* f) { f->ref(); } friend void intrusive_ptr_release(file* f) { f->unref(); } + friend class dir; +private: + typedef std::pair<dirref, std::string> cache_key; + // FIXME: an intrusive container + typedef std::unordered_map<cache_key, fileref> cache_type; + static cache_type _cache; + friend struct std::hash<cache_key>; }; class dir : public file { public: - virtual fileref open(std::string name) = 0; + fileref open(std::string name); + virtual fileref do_open(std::string name) = 0; dirref subdir(std::string name); +private: + dirref _parent; + std::string _name; }; class filesystem {