@@ -214,7 +214,11 @@ set(CPPCMS_SOURCES | |||
encoding.cpp | |||
regex.cpp | |||
form.cpp | |||
filters.cpp) | |||
filters.cpp | |||
cache_pool.cpp | |||
cache_interface.cpp | |||
thread_cache.cpp | |||
) | |||
@@ -185,11 +185,15 @@ void application::render(std::string skin,std::string template_name,std::ostream | |||
service().views_pool().render(skin,template_name,out,content); | |||
} | |||
cache_interface &application::cache() | |||
{ | |||
return context().cache(); | |||
} | |||
void application::recycle() | |||
{ | |||
if(root()->d->conn) { | |||
response().out() << std::flush; | |||
response().finalize(); | |||
context().async_complete_response(); | |||
} | |||
@@ -15,6 +15,7 @@ namespace cppcms { | |||
class applications_pool; | |||
class application; | |||
class base_content; | |||
class cache_interface; | |||
namespace locale { | |||
class environment; | |||
@@ -42,6 +43,7 @@ namespace cppcms { | |||
http::request &request(); | |||
http::response &response(); | |||
url_dispatcher &dispatcher(); | |||
cache_interface &cache(); | |||
void render(std::string template_name,base_content &content); | |||
void render(std::string skin,std::string template_name,base_content &content); | |||
@@ -1,38 +0,0 @@ | |||
#include "base_cache.h" | |||
namespace cppcms { | |||
using namespace std; | |||
bool base_cache::fetch(string const &key,string &a,set<string> &tags) | |||
{ | |||
return false; | |||
}; | |||
void base_cache::clear() | |||
{ | |||
// Nothing | |||
} | |||
void base_cache::rise(string const &trigger) | |||
{ | |||
// Nothing | |||
} | |||
void base_cache::store(string const &key,set<string> const &triggers,time_t timeout,string const &a) | |||
{ | |||
// Nothing | |||
} | |||
base_cache::~base_cache() | |||
{ | |||
// Nothing | |||
} | |||
void base_cache::stats(unsigned &keys,unsigned &triggers) | |||
{ | |||
keys=0; | |||
triggers=0; | |||
} | |||
} | |||
@@ -7,17 +7,19 @@ | |||
#include "refcounted.h" | |||
namespace cppcms { | |||
namespace impl { | |||
class base_cache : public refcounted { | |||
public: | |||
virtual bool fetch(std::string const &key,std::string &a,std::set<std::string> &tags); | |||
virtual void store(std::string const &key,std::set<std::string> const &triggers,time_t timeout,std::string const &value); | |||
virtual void rise(std::string const &trigger); | |||
virtual void clear(); | |||
virtual void stats(unsigned &keys,unsigned &triggers); | |||
virtual ~base_cache(); | |||
virtual bool fetch(std::string const &key,std::string &a,std::set<std::string> *tags) = 0; | |||
virtual void store(std::string const &key,std::string const &b,std::set<std::string> const &triggers,time_t timeout) = 0; | |||
virtual void rise(std::string const &trigger) = 0; | |||
virtual void clear() = 0; | |||
virtual void stats(unsigned &keys,unsigned &triggers) = 0; | |||
virtual ~base_cache() | |||
{ | |||
} | |||
}; | |||
} | |||
} // impl | |||
} // cppcms | |||
#endif |
@@ -1,6 +1,12 @@ | |||
#define CPPCMS_SOURCE | |||
#include "cache_interface.h" | |||
#include "config.h" | |||
#include "base_cache.h" | |||
#include "cache_pool.h" | |||
#include "http_context.h" | |||
#include "http_response.h" | |||
#include "json.h" | |||
#include "service.h" | |||
#include "cppcms_error.h" | |||
#include <sstream> | |||
#include <iostream> | |||
@@ -29,7 +35,13 @@ namespace { | |||
struct cache_interface::data {}; | |||
cache_interface::cache_interface(http::context &context) : | |||
context_(context) | |||
context_(&context), | |||
page_compression_used_(0) | |||
{ | |||
cache_module_ = context_->service().cache_pool().get(); | |||
} | |||
cache_interface::~cache_interface() | |||
{ | |||
} | |||
@@ -38,14 +50,17 @@ bool cache_interface::fetch_page(string const &key) | |||
{ | |||
if(nocache()) return false; | |||
bool zip = context_->response().need_gzip(); | |||
bool gzip = context_->response().need_gzip(); | |||
page_compression_used_ = gzip; | |||
std::string r_key = (gzip ? "_Z:" : "_U:") + key; | |||
std::string tmp; | |||
if(caching_module->fetch_page(key,tmp,zip)) { | |||
if(cache_module_->fetch(r_key,tmp,0)) { | |||
if(gzip) | |||
context_->response().context_encoding("gzip"); | |||
context_->out().write(tmp.c_str(),tmp.size()); | |||
context_->response().content_encoding("gzip"); | |||
context_->response().out().write(tmp.c_str(),tmp.size()); | |||
return true; | |||
} | |||
else { | |||
@@ -59,38 +74,45 @@ void cache_interface::store_page(string const &key,int timeout) | |||
if(nocache()) return; | |||
context_->response().finalize(); | |||
bool zip = context_->response().need_gzip(); | |||
cms->caching_module->store_page(key,context->response().copied_data(),triggers_,deadtime(timeout),zip) | |||
std::string r_key = (page_compression_used_ ? "_Z:" : "_U:") + key; | |||
triggers_.insert(key); | |||
cache_module_->store(r_key,context_->response().copied_data(),triggers_,deadtime(timeout)); | |||
} | |||
void cache_interface::store_frame(std::string const &key,std::string const &frame,std::set<std::string> const &triggers,int timeout,bool notriggers) | |||
{ | |||
store(key,frame,triggers,timeout,notriggers); | |||
} | |||
void cache_interface::store_frame(std::string const &key, | |||
std::string const &frame, | |||
int timeout, | |||
bool notriggers=false) | |||
bool notriggers) | |||
{ | |||
store_frame(key,frame,set<std::string>(),timeout,notriggers); | |||
} | |||
void cache_interface::nocache() | |||
bool cache_interface::nocache() | |||
{ | |||
return caching_module_.get()!=0; | |||
return cache_module_.get()==0; | |||
} | |||
void cache_interface::has_cache() | |||
bool cache_interface::has_cache() | |||
{ | |||
return !nocache(); | |||
} | |||
void cache_interface::add_trigger(string const &t) | |||
{ | |||
if(nocache()) return false; | |||
if(nocache()) return; | |||
triggers_.insert(t); | |||
} | |||
void cache_interface::rise(string const &t) | |||
{ | |||
if(nocache()) return; | |||
caching_module_->rise(t); | |||
cache_module_->rise(t); | |||
} | |||
bool cache_interface::fetch_frame(string const &key,string &result,bool notriggers) | |||
@@ -102,7 +124,8 @@ bool cache_interface::fetch(string const &key,string &result,bool notriggers) | |||
{ | |||
if(nocache()) return false; | |||
set<string> new_trig; | |||
if(caching_module_->fetch(key,result,new_trig)) { | |||
if(cache_module_->fetch(key,result, (notriggers ? 0 : &new_trig))) { | |||
if(!notriggers) | |||
triggers_.insert(new_trig.begin(),new_trig.end()); | |||
return true; | |||
@@ -120,19 +143,19 @@ void cache_interface::store(string const &key,string const &data, | |||
this->triggers_.insert(triggers.begin(),triggers.end()); | |||
this->triggers_.insert(key); | |||
} | |||
cache_module_->store(key,triggers,deadtime(timeout),data); | |||
cache_module_->store(key,data,triggers,deadtime(timeout)); | |||
} | |||
void cache_interface::clear() | |||
{ | |||
if(nocache()) return; | |||
caching_module_->clear(); | |||
cache_module_->clear(); | |||
} | |||
bool cache_interface::stats(unsigned &k,unsigned &t) | |||
{ | |||
if(nocache()) return false; | |||
caching_module_->stats(k,t); | |||
cache_module_->stats(k,t); | |||
return true; | |||
} | |||
@@ -7,10 +7,19 @@ | |||
#include "defs.h" | |||
#include "noncopyable.h" | |||
#include "intrusive_ptr.h" | |||
#include "hold_ptr.h" | |||
namespace cppcms { | |||
class base_cache; | |||
namespace impl { | |||
class base_cache; | |||
} | |||
namespace http { | |||
class context; | |||
}; | |||
template<typename Object> | |||
struct serialization_traits; | |||
class CPPCMS_API cache_interface : public util::noncopyable { | |||
public: | |||
@@ -21,8 +30,11 @@ namespace cppcms { | |||
void rise(std::string const &trigger); | |||
void add_trigger(std::string const &trigger); | |||
void clear(); | |||
void reset(); | |||
bool stats(unsigned &keys,unsigned &triggers); | |||
bool has_cache(); | |||
bool nocache(); | |||
bool fetch_page(std::string const &key); | |||
@@ -37,7 +49,7 @@ namespace cppcms { | |||
bool notriggers=false); | |||
void store_frame(std::string const &key, | |||
string const &frame, | |||
std::string const &frame, | |||
int timeout, | |||
bool notriggers=false); | |||
@@ -64,26 +76,30 @@ namespace cppcms { | |||
template<typename Serializable> | |||
void store_data(std::string const &key,Serializable const &data,int timeout,bool notriggers=false) | |||
{ | |||
store_data<Serializable>(key,data,set<std::string>(),timeout,notriggers); | |||
store_data<Serializable>(key,data,std::set<std::string>(),timeout,notriggers); | |||
} | |||
private: | |||
void store( std::string const &key, | |||
char const *buffer, | |||
size_t size, | |||
std::string const &data, | |||
std::set<std::string> const &triggers, | |||
int timeout, | |||
bool notriggers); | |||
bool fetch( std::string const &key, | |||
std::string &buffer, | |||
bool notriggers) | |||
bool notriggers); | |||
struct data; | |||
util::hold_ptr<data> d; | |||
http::context *context_; | |||
std::set<std::string> triggers_; | |||
intrusive_ptr<base_cache> cache_module_; | |||
intrusive_ptr<impl::base_cache> cache_module_; | |||
uint32_t page_compression_used_ : 1; | |||
uint32_t reserved : 31; | |||
}; | |||
@@ -0,0 +1,40 @@ | |||
#define CPPCMS_SOURCE | |||
#include "cache_pool.h" | |||
#include "thread_cache.h" | |||
#include "base_cache.h" | |||
#include "cppcms_error.h" | |||
#include "json.h" | |||
namespace cppcms { | |||
struct cache_pool::data { | |||
intrusive_ptr<impl::base_cache> module; | |||
}; | |||
cache_pool::cache_pool(json::value const &settings) : | |||
d(new data()) | |||
{ | |||
std::string type = settings.get("cache.backend","none"); | |||
if(type == "none" ) | |||
return; | |||
if(type=="threaded") { | |||
if(settings.get("service.procs",0)>1) | |||
throw cppcms_error("Can't use `threaded' backend with more then one process"); | |||
unsigned items = settings.get("cache.limit",64); | |||
d->module=impl::thread_cache_factory(items); | |||
} | |||
else { | |||
throw cppcms_error("Unsupported cache backend `" + type + "'"); | |||
} | |||
} | |||
cache_pool::~cache_pool() | |||
{ | |||
} | |||
intrusive_ptr<impl::base_cache> cache_pool::get() | |||
{ | |||
return d->module; | |||
} | |||
} // cppcms |
@@ -0,0 +1,24 @@ | |||
#ifndef CPPCMS_CACHE_POOL_H | |||
#define CPPCMS_CACHE_POOL_H | |||
#include "defs.h" | |||
#include "noncopyable.h" | |||
#include "intrusive_ptr.h" | |||
#include "hold_ptr.h" | |||
namespace cppcms { | |||
namespace json { class value; } | |||
namespace impl { class base_cache; } | |||
class CPPCMS_API cache_pool { | |||
public: | |||
cache_pool(json::value const &settings); | |||
~cache_pool(); | |||
intrusive_ptr<impl::base_cache> get(); | |||
private: | |||
struct data; | |||
util::hold_ptr<data> d; | |||
}; | |||
} | |||
#endif |
@@ -26,6 +26,7 @@ | |||
}, | |||
"gzip" : { | |||
"enable" : true, // Default true | |||
//"enable" : false, // Default true | |||
// "level" : 1, | |||
// "buffer" : 4096 | |||
}, | |||
@@ -52,6 +53,11 @@ | |||
// "skins" : [ "skin3" ], | |||
"auto_reload" : true | |||
}, | |||
"cache" : { | |||
"backend" : "threaded", | |||
"limit" : 100, // items | |||
"memsize" : 64, // KBs | |||
}, | |||
"file_server" : { | |||
"enable" : true, | |||
"doument_root" : "." | |||
@@ -11,6 +11,7 @@ | |||
#include "aio_timer.h" | |||
#include "intrusive_ptr.h" | |||
#include "form.h" | |||
#include "cache_interface.h" | |||
#include <sstream> | |||
#include <stdexcept> | |||
#include <stdlib.h> | |||
@@ -209,12 +210,24 @@ public: | |||
dispatcher().assign("^/err$",&hello::err,this); | |||
dispatcher().assign("^/forward$",&hello::forward,this); | |||
dispatcher().assign("^/form$",&hello::form,this); | |||
dispatcher().assign("^/cache/?$",&hello::cached,this); | |||
dispatcher().assign(".*",&hello::hello_world,this); | |||
} | |||
~hello() | |||
{ | |||
} | |||
void cached() | |||
{ | |||
if(cache().fetch_page("test")) | |||
return; | |||
response().out() << | |||
"<html><body>Time :" << cppcms::locale::format("{1,time=f}") % time(0) << "</body></html>\n"; | |||
cache().store_page("test",10); | |||
} | |||
void view_test(std::string skin) | |||
{ | |||
view::hello c; | |||
@@ -1,5 +1,4 @@ | |||
#define CPPCMS_SOURCE | |||
#include "cgi_api.h" | |||
#include "service.h" | |||
#include "http_context.h" | |||
@@ -10,6 +9,7 @@ | |||
#include "thread_pool.h" | |||
#include "url_dispatcher.h" | |||
#include "views_pool.h" | |||
#include "cache_interface.h" | |||
#include "cppcms_error.h" | |||
#include "config.h" | |||
@@ -29,6 +29,7 @@ namespace http { | |||
std::string skin; | |||
http::request request; | |||
std::auto_ptr<http::response> response; | |||
std::auto_ptr<cache_interface> cache; | |||
data(context &cntx) : | |||
locale(cntx.connection().service().locale()), | |||
request(cntx.connection()) | |||
@@ -42,6 +43,7 @@ context::context(intrusive_ptr<impl::cgi::connection> conn) : | |||
d.reset(new data(*this)); | |||
d->response.reset(new http::response(*this)); | |||
skin(service().views_pool().default_skin()); | |||
d->cache.reset(new cache_interface(*this)); | |||
} | |||
std::string context::skin() | |||
@@ -49,6 +51,11 @@ std::string context::skin() | |||
return d->skin; | |||
} | |||
cache_interface &context::cache() | |||
{ | |||
return *d->cache; | |||
} | |||
void context::skin(std::string const &skin) | |||
{ | |||
d->skin=skin; | |||
@@ -14,6 +14,7 @@ namespace cppcms { | |||
class service; | |||
class application; | |||
class cache_interface; | |||
namespace json { class value; } | |||
namespace impl { namespace cgi { class connection; } } | |||
@@ -31,6 +32,7 @@ namespace cppcms { | |||
http::request &request(); | |||
http::response &response(); | |||
json::value const &settings(); | |||
cache_interface &cache(); | |||
std::locale locale(); | |||
void locale(std::locale const &new_locale); | |||
void locale(std::string const &name); | |||
@@ -91,7 +91,8 @@ response::response(context &context) : | |||
io_mode_(normal), | |||
disable_compression_(0), | |||
ostream_requested_(0), | |||
copy_to_cache_(0) | |||
copy_to_cache_(0), | |||
finalized_(0) | |||
{ | |||
set_content_header("text/html"); | |||
if(context_.settings().get("server.disable_xpowered_by",false)==0) { | |||
@@ -145,8 +146,11 @@ void response::set_header(std::string const &name,std::string const &value) | |||
void response::finalize() | |||
{ | |||
d->filter.reset(); | |||
d->output<<std::flush; | |||
if(!finalized_) { | |||
out()<<std::flush; | |||
d->filter.reset(); | |||
finalized_=1; | |||
} | |||
} | |||
std::string response::get_header(std::string const &name) | |||
@@ -207,10 +211,16 @@ void response::write_http_headers(std::ostream &out) | |||
} | |||
void response::copy_to_cache(std::string const &key) | |||
void response::copy_to_cache() | |||
{ | |||
copy_to_cache_=1; | |||
cache_key_=key; | |||
} | |||
std::string response::copied_data() | |||
{ | |||
if(!copy_to_cache_ || !ostream_requested_) | |||
return std::string(); | |||
return d->cached.str(); | |||
} | |||
std::ostream &response::out() | |||
@@ -219,6 +229,8 @@ std::ostream &response::out() | |||
if(ostream_requested_) | |||
return *stream_; | |||
if(finalized_) | |||
throw cppcms_error("Request for output stream for finalized request is illegal"); | |||
ostream_requested_=1; | |||
@@ -10,11 +10,13 @@ | |||
#include "cstdint.h" | |||
namespace cppcms { | |||
class cache_interface; | |||
namespace impl { namespace cgi { class connection; }} | |||
namespace http { | |||
class context; | |||
class cookie; | |||
class CPPCMS_API response : public util::noncopyable { | |||
public: | |||
// RFC 2616 sec. 6.1.1 | |||
@@ -120,7 +122,6 @@ namespace http { | |||
io_mode_type io_mode(); | |||
void io_mode(io_mode_type); | |||
std::ostream &out(); | |||
void copy_to_cache(std::string const &key); | |||
static std::string make_http_time(time_t); | |||
static char const *status_to_string(int status); | |||
@@ -132,10 +133,14 @@ namespace http { | |||
~response(); | |||
private: | |||
friend class impl::cgi::connection; | |||
friend class ::cppcms::cache_interface; | |||
void copy_to_cache(); | |||
std::string copied_data(); | |||
bool need_gzip(); | |||
std::pair<char const *,size_t> output(); | |||
bool need_gzip(); | |||
void write_http_headers(std::ostream &); | |||
std::string get_async_chunk(); | |||
@@ -145,12 +150,12 @@ namespace http { | |||
context &context_; | |||
std::ostream *stream_; | |||
io_mode_type io_mode_; | |||
std::string cache_key_; | |||
uint32_t disable_compression_ : 1; | |||
uint32_t ostream_requested_ : 1; | |||
uint32_t copy_to_cache_ : 1; | |||
uint32_t reserved_ : 29; | |||
uint32_t finalized_ : 1; | |||
uint32_t reserved_ : 28; | |||
}; | |||
} /* http */ | |||
@@ -9,6 +9,7 @@ | |||
#include "cgi_api.h" | |||
#include "scgi_api.h" | |||
#include "http_api.h" | |||
#include "cache_pool.h" | |||
#include "fastcgi_api.h" | |||
#include "internal_file_server.h" | |||
#include "json.h" | |||
@@ -149,6 +150,12 @@ void service::setup() | |||
int apps=settings().get("service.applications_pool_size",threads_no()*2); | |||
impl_->applications_pool_.reset(new cppcms::applications_pool(*this,apps)); | |||
impl_->views_pool_.reset(new cppcms::views_pool(settings())); | |||
impl_->cache_pool_.reset(new cppcms::cache_pool(settings())); | |||
} | |||
cppcms::cache_pool &service::cache_pool() | |||
{ | |||
return *impl_->cache_pool_; | |||
} | |||
cppcms::views_pool &service::views_pool() | |||
@@ -16,6 +16,7 @@ namespace cppcms { | |||
class applications_pool; | |||
class thread_pool; | |||
class cache_pool; | |||
class views_pool; | |||
namespace json { | |||
class value; | |||
@@ -31,10 +32,12 @@ namespace cppcms { | |||
void run(); | |||
void shutdown(); | |||
json::value const &settings(); | |||
cppcms::applications_pool &applications_pool(); | |||
cppcms::thread_pool &thread_pool(); | |||
json::value const &settings(); | |||
cppcms::views_pool &views_pool(); | |||
cppcms::cache_pool &cache_pool(); | |||
locale::generator const &generator(); | |||
std::locale locale(); | |||
@@ -36,6 +36,7 @@ namespace impl { | |||
std::auto_ptr<thread_pool> thread_pool_; | |||
std::auto_ptr<locale::generator> locale_generator_; | |||
std::auto_ptr<views_pool> views_pool_; | |||
std::auto_ptr<cache_pool> cache_pool_; | |||
std::locale default_locale_; | |||
#ifdef CPPCMS_WIN32 | |||
@@ -1,26 +1,63 @@ | |||
#define CPPCMS_SOURCE | |||
#include "config.h" | |||
#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD) | |||
#include "thread_cache.h" | |||
#ifdef CPPCMS_USE_EXTERNAL_BOOST | |||
# include <boost/thread.hpp> | |||
# include <boost/format.hpp> | |||
#else // Internal Boost | |||
# include <cppcms_boost/thread.hpp> | |||
# include <cppcms_boost/format.hpp> | |||
namespace boost = cppcms_boost; | |||
#endif | |||
#include <unistd.h> | |||
#include "posix_mutex.h" | |||
using boost::format; | |||
using boost::str; | |||
using namespace std; | |||
namespace cppcms { | |||
namespace impl { | |||
class thread_cache : public base_cache { | |||
boost::mutex lru_mutex; | |||
boost::shared_mutex access_lock; | |||
struct container { | |||
string data; | |||
typedef std::map<string,container>::iterator pointer; | |||
list<pointer>::iterator lru; | |||
list<multimap<string,pointer>::iterator> triggers; | |||
multimap<time_t,pointer>::iterator timeout; | |||
}; | |||
typedef container::pointer pointer; | |||
std::map<string,container> primary; | |||
multimap<string,pointer> triggers; | |||
typedef multimap<string,pointer>::iterator triggers_ptr; | |||
multimap<time_t,pointer> timeout; | |||
typedef multimap<time_t,pointer>::iterator timeout_ptr; | |||
list<pointer> lru; | |||
typedef list<pointer>::iterator lru_ptr; | |||
unsigned limit; | |||
string const *get(string const &key,set<string> *triggers); | |||
void delete_node(pointer p); | |||
void print_all(); | |||
bool debug_mode; | |||
int fd; | |||
public: | |||
void set_debug_mode(int fd) { debug_mode=true; this->fd=fd; }; | |||
thread_cache(unsigned pages=0) : limit(pages) { | |||
debug_mode=false; | |||
}; | |||
void set_size(unsigned l) { limit=l; }; | |||
virtual bool fetch(string const &key,string &a,std::set<std::string> *tags); | |||
virtual void rise(string const &trigger); | |||
virtual void clear(); | |||
virtual void stats(unsigned &keys,unsigned &triggers); | |||
virtual void store(string const &key,std::string const &a,set<string> const &triggers,time_t timeout); | |||
virtual ~thread_cache(); | |||
}; // thread cache | |||
thread_cache::~thread_cache() | |||
{ | |||
pthread_mutex_destroy(&lru_mutex); | |||
pthread_rwlock_destroy(&access_lock); | |||
} | |||
std::string const *thread_cache::get(string const &key,set<string> *triggers) | |||
@@ -50,13 +87,13 @@ std::string const *thread_cache::get(string const &key,set<string> *triggers) | |||
} | |||
} | |||
{ | |||
mutex_lock lock(lru_mutex); | |||
boost::unique_lock<boost::mutex> lock(lru_mutex); | |||
lru.erase(p->second.lru); | |||
lru.push_front(p); | |||
p->second.lru=lru.begin(); | |||
} | |||
if(debug_mode){ | |||
string res=str(boost::format("Fetched [%1%] triggers:") % key); | |||
string res=(boost::format("Fetched [%1%] triggers:") % key).str(); | |||
list<triggers_ptr>::iterator tp; | |||
for(tp=p->second.triggers.begin(); | |||
tp!=p->second.triggers.end();tp++) | |||
@@ -71,10 +108,10 @@ std::string const *thread_cache::get(string const &key,set<string> *triggers) | |||
} | |||
bool thread_cache::fetch(string const &key,std::string &a,set<string> &tags) | |||
bool thread_cache::fetch(string const &key,std::string &a,set<string> *tags) | |||
{ | |||
rwlock_rdlock lock(access_lock); | |||
string const *r=get(key,&tags); | |||
boost::shared_lock<boost::shared_mutex> lock(access_lock); | |||
string const *r=get(key,tags); | |||
if(!r) return false; | |||
a = *r; | |||
return true; | |||
@@ -82,7 +119,7 @@ bool thread_cache::fetch(string const &key,std::string &a,set<string> &tags) | |||
void thread_cache::clear() | |||
{ | |||
rwlock_wrlock lock(access_lock); | |||
boost::unique_lock<boost::shared_mutex> lock(access_lock); | |||
timeout.clear(); | |||
lru.clear(); | |||
primary.clear(); | |||
@@ -90,14 +127,14 @@ void thread_cache::clear() | |||
} | |||
void thread_cache::stats(unsigned &keys,unsigned &triggers) | |||
{ | |||
rwlock_rdlock lock(access_lock); | |||
boost::shared_lock<boost::shared_mutex> lock(access_lock); | |||
keys=primary.size(); | |||
triggers=this->triggers.size(); | |||
} | |||
void thread_cache::rise(string const &trigger) | |||
{ | |||
rwlock_wrlock lock(access_lock); | |||
boost::unique_lock<boost::shared_mutex> lock(access_lock); | |||
if(debug_mode) print_all(); | |||
pair<triggers_ptr,triggers_ptr> range=triggers.equal_range(trigger); | |||
triggers_ptr p; | |||
@@ -122,9 +159,9 @@ void thread_cache::rise(string const &trigger) | |||
write(fd,"\n",1); | |||
} | |||
void thread_cache::store(string const &key,set<string> const &triggers_in,time_t timeout_in,std::string const &a) | |||
void thread_cache::store(string const &key,std::string const &a,set<string> const &triggers_in,time_t timeout_in) | |||
{ | |||
rwlock_wrlock lock(access_lock); | |||
boost::unique_lock<boost::shared_mutex> lock(access_lock); | |||
if(debug_mode) print_all(); | |||
pointer main; | |||
if(debug_mode) { | |||
@@ -232,8 +269,14 @@ void thread_cache::print_all() | |||
write(fd,res.c_str(),res.size()); | |||
} | |||
}; | |||
intrusive_ptr<base_cache> thread_cache_factory(unsigned items) | |||
{ | |||
return new thread_cache(items); | |||
} | |||
} // impl | |||
} // cppcms | |||
#endif | |||
@@ -1,70 +1,17 @@ | |||
#ifndef THREAD_CHACHE_H | |||
#define THREAD_CHACHE_H | |||
#include "config.h" | |||
#include "base_cache.h" | |||
#include "cache_interface.h" | |||
#include "pthread.h" | |||
#include "intrusive_ptr.h" | |||
#include <map> | |||
#include <list> | |||
namespace cppcms { | |||
using namespace std; | |||
#if !defined(CPPCMS_EMBEDDED) || defined(CPPCMS_EMBEDDED_THREAD) | |||
class thread_cache : public base_cache { | |||
pthread_mutex_t lru_mutex; | |||
pthread_rwlock_t access_lock; | |||
struct container { | |||
string data; | |||
typedef std::map<string,container>::iterator pointer; | |||
list<pointer>::iterator lru; | |||
list<multimap<string,pointer>::iterator> triggers; | |||
multimap<time_t,pointer>::iterator timeout; | |||
}; | |||
typedef container::pointer pointer; | |||
std::map<string,container> primary; | |||
multimap<string,pointer> triggers; | |||
typedef multimap<string,pointer>::iterator triggers_ptr; | |||
multimap<time_t,pointer> timeout; | |||
typedef multimap<time_t,pointer>::iterator timeout_ptr; | |||
list<pointer> lru; | |||
typedef list<pointer>::iterator lru_ptr; | |||
unsigned limit; | |||
string const *get(string const &key,set<string> *triggers); | |||
void delete_node(pointer p); | |||
void print_all(); | |||
bool debug_mode; | |||
int fd; | |||
public: | |||
void set_debug_mode(int fd) { debug_mode=true; this->fd=fd; }; | |||
thread_cache(unsigned pages=0) : limit(pages) { | |||
pthread_mutex_init(&lru_mutex,NULL); | |||
pthread_rwlock_init(&access_lock,NULL); | |||
debug_mode=false; | |||
}; | |||
void set_size(unsigned l) { limit=l; }; | |||
virtual bool fetch(string const &key,string &a,std::set<std::string> &tags); | |||
virtual void rise(string const &trigger); | |||
virtual void clear(); | |||
virtual void stats(unsigned &keys,unsigned &triggers); | |||
virtual void store(string const &key,set<string> const &triggers,time_t timeout,std::string const &a); | |||
virtual ~thread_cache(); | |||
}; | |||
class thread_cache_factory : public cache_factory{ | |||
thread_cache *cache; | |||
public: | |||
thread_cache_factory(unsigned n) : cache(new thread_cache(n)) {}; | |||
virtual base_cache *get() const { return cache; }; | |||
virtual void del(base_cache *p) const { }; | |||
virtual ~thread_cache_factory() { delete cache; }; | |||
}; | |||
#endif | |||
} | |||
namespace cppcms { | |||
namespace impl { | |||
intrusive_ptr<base_cache> thread_cache_factory(unsigned items); | |||
} // impl | |||
} // cppcms | |||
#endif |