diff options
-rw-r--r-- | project2/files/presenterCache.cpp | 115 |
1 files changed, 80 insertions, 35 deletions
diff --git a/project2/files/presenterCache.cpp b/project2/files/presenterCache.cpp index 9505496..b90e29d 100644 --- a/project2/files/presenterCache.cpp +++ b/project2/files/presenterCache.cpp @@ -1,6 +1,7 @@ #include "../common/presenterCache.h" #include "../common/exceptions.h" #include "../common/options.h" +#include "../common/safeMapFind.h" #include "../common/environment.h" #include <fcntl.h> #include <attr/xattr.h> @@ -10,6 +11,7 @@ #include <boost/filesystem/path.hpp> #include <boost/filesystem/operations.hpp> #include <boost/bind.hpp> +#include <boost/tuple/tuple_comparison.hpp> #include <glibmm/convert.h> #include <sys/file.h> @@ -29,78 +31,91 @@ int safesys(int n, int r) { class FilePresenterCache : public PresenterCache, public StaticContent, public SourceOf<StaticContent> { public: + typedef std::vector<std::string> Path; + typedef std::map<std::string, VariableType> Parameters; + typedef boost::tuple<Path, Parameters> Key; + class CacheFile : public IntrusivePtrBase { + public: + CacheFile(int f) : fd(f) { + } + ~CacheFile() { + close(fd); + } + operator int() const { return fd; } + const int fd; + }; + typedef boost::intrusive_ptr<CacheFile> CacheFilePtr; + typedef std::map<Key, CacheFilePtr> OpenCaches; + FilePresenterCache(ScriptNodePtr s) : PresenterCache(s), - readcachefd(0), writecache(NULL) { } ~FilePresenterCache() { - if (readcachefd) { - close(readcachefd); - } delete writecache; } bool check(time_t scriptMtime) const { + Key key = getCacheKey(); try { - if (readcachefd == 0) { - readcachefd = safesys<OpenCacheFile>(-1, open(getCacheFile().string().c_str(), O_RDONLY)); + CacheFilePtr f = defaultMapFind(openCaches, key); + if (!f) { + f = openCacheFile(key); } struct stat st; - safesys<StatCacheFile>(-1, fstat(readcachefd, &st)); + safesys<StatCacheFile>(-1, fstat(*f, &st)); if (st.st_nlink == 0) { - close(readcachefd); - readcachefd = 0; - readcachefd = safesys<OpenCacheFile>(-1, open(getCacheFile().string().c_str(), O_RDONLY)); + f = openCacheFile(key); + safesys<StatCacheFile>(-1, fstat(*f, &st)); } if ((st.st_mtime < (time(NULL) - FilePresenterCache::CacheLife)) || (st.st_mtime < scriptMtime)) { unlink(getCacheFile().string().c_str()); - close(readcachefd); - readcachefd = 0; + openCaches.erase(key); + f.reset(); return false; } + myCache = f; return true; } catch (...) { - if (readcachefd) { - close(readcachefd); - readcachefd = 0; - } + openCaches.erase(key); + myCache.reset(); return false; } } Glib::ustring getEncoding() const { - char buf[BUFSIZ]; - buf[safesys<CacheFileXAttr>(-1, fgetxattr(readcachefd, "user.encoding", buf, sizeof(buf)))] = 0; - return buf; + return getXAttr("user.encoding"); } Glib::ustring getContentType() const { + return getXAttr("user.content-type"); + } + Glib::ustring getXAttr(const char * attr) const + { char buf[BUFSIZ]; - buf[safesys<CacheFileXAttr>(-1, fgetxattr(readcachefd, "user.content-type", buf, sizeof(buf)))] = 0; + buf[safesys<CacheFileXAttr>(-1, fgetxattr(*myCache, attr, buf, sizeof(buf)))] = 0; return buf; } size_t getSizeInBytes() const { struct stat st; - safesys<CacheFileXAttr>(-1, fstat(readcachefd, &st)); + safesys<CacheFileXAttr>(-1, fstat(*myCache, &st)); return st.st_size; } void writeTo(std::ostream & o) const { - safesys<LockCacheFile>(-1, ::flock(readcachefd, LOCK_SH)); - boost::iostreams::stream<boost::iostreams::file_descriptor_source> cache(readcachefd, boost::iostreams::never_close_handle); + safesys<LockCacheFile>(-1, ::flock(*myCache, LOCK_SH)); + boost::iostreams::stream<boost::iostreams::file_descriptor_source> cache(*myCache, boost::iostreams::never_close_handle); cache.seekg(0); o << cache.rdbuf(); - safesys<LockCacheFile>(-1, ::flock(readcachefd, LOCK_UN)); + safesys<LockCacheFile>(-1, ::flock(*myCache, LOCK_UN)); } operator const StaticContent * () const { return this; } - mutable int readcachefd; std::ostream & writeCache(const std::string & ct, const std::string & enc) { @@ -121,33 +136,58 @@ class FilePresenterCache : public PresenterCache, public StaticContent, public S std::ostream * writecache; private: + Key getCacheKey() const + { + Key key; + unsigned int puc = Environment::getCurrent()->getParamUriCount(); + key.get<0>().reserve(puc); + for (unsigned int i = 0; i < puc; i += 1) { + key.get<0>()[i] = Environment::getCurrent()->getParamUri(i).raw(); + } + applyKeys(boost::bind(&appendParams, &key.get<1>(), _1, _2)); + return key; + } + CacheFilePtr openCacheFile(const Key & key) const + { + CacheFilePtr c = new CacheFile(safesys<OpenCacheFile>(-1, open(getCacheFile().string().c_str(), O_RDONLY))); + openCaches[key] = c; + return c; + } boost::filesystem::path getCacheFile() const { - if (cache.empty()) { - cache = Store; - unsigned int puc = Environment::getCurrent()->getParamUriCount(); - for (unsigned int i = 0; i < puc; i += 1) { - cache /= Environment::getCurrent()->getParamUri(i).raw(); - } - applyKeys(boost::bind(&appendPath, &cache, _1, _2)); - boost::filesystem::create_directories(cache); - cache /= FileName; + boost::filesystem::path cache; + cache = Store; + unsigned int puc = Environment::getCurrent()->getParamUriCount(); + for (unsigned int i = 0; i < puc; i += 1) { + cache /= Environment::getCurrent()->getParamUri(i).raw(); } + applyKeys(boost::bind(&appendPath, &cache, _1, _2)); + boost::filesystem::create_directories(cache); + cache /= FileName; return cache; } + static void appendParams(Parameters * cache, const std::string & n, const VariableType & v) + { + cache->insert(Parameters::value_type(n, v)); + } + static void appendPath(boost::filesystem::path * cache, const std::string & n, const VariableType & v) { *cache /= n; *cache /= v.operator const std::string &(); } - mutable boost::filesystem::path cache; + static OpenCaches openCaches; + mutable CacheFilePtr myCache; + + // Config static boost::filesystem::path Store; static std::string FileName; static time_t CacheLife; friend class FilePresenterCacheLoader; }; +FilePresenterCache::OpenCaches FilePresenterCache::openCaches; boost::filesystem::path FilePresenterCache::Store; std::string FilePresenterCache::FileName; time_t FilePresenterCache::CacheLife; @@ -175,6 +215,11 @@ class FilePresenterCacheLoader : public ElementLoader::For<FilePresenterCache> { void onIdle() { emptyDir(FilePresenterCache::Store); + FilePresenterCache::openCaches.clear(); + } + void onConfigLoad() + { + FilePresenterCache::openCaches.clear(); } bool emptyDir(const boost::filesystem::path & dir) |