summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project2/files/presenterCache.cpp115
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)