/////////////////////////////////////////////////////////////////////////////////// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>//// See accompanying file COPYING.TXT file for licensing details./////////////////////////////////////////////////////////////////////////////////#define CPPCMS_SOURCE#include <cppcms/config.h>#include <set>#ifndef CPPCMS_NO_CACHE#include "cache_storage.h"#include <booster/thread.h>#include <iostream>#if defined CPPCMS_WIN32# ifndef CPPCMS_NO_PREFOK_CACHE# define CPPCMS_NO_PREFOK_CACHE# endif#endif#ifndef CPPCMS_NO_PREFOK_CACHE# include "posix_util.h"# include "shmem_allocator.h"#endif#include <map>#include <string>#include <list>#include <limits>#include <booster/auto_ptr_inc.h>#include <time.h>#include <cppcms/cstdint.h>#include "hash_map.h"#include <string.h>namespace cppcms {namespace impl {template<typename String>struct copy_traits {static String to_int(std::string const &other){return String(other.c_str(),other.size());}static std::string to_std(String const &other){return std::string(other.c_str(),other.size());}};template<>struct copy_traits<std::string>{static std::string to_int(std::string const &a) { return a; }static std::string to_std(std::string const &a) { return a; }};struct string_equal {template<typename S1,typename S2>bool operator()(S1 const &s1,S2 const &s2) const{return s1.size() == s2.size() && memcmp(s1.c_str(),s2.c_str(),s1.size()) == 0;}};#ifndef CPPCMS_NO_PREFOK_CACHEstruct process_settings {static shmem_control *process_memory;typedef ::cppcms::impl::mutex mutex_type;typedef ::cppcms::impl::shared_mutex shared_mutex_type;typedef mutex_type::guard lock_guard;typedef shared_mutex_type::shared_guard rdlock_guard;typedef shared_mutex_type::unique_guard wrlock_guard;typedef shmem_allocator<char,process_memory> allocator;static bool not_enough_memory(){return process_memory->max_available() < process_memory->size() / 10;}static size_t size_limit(){return process_memory->size() / 20;}static void init(size_t size){if(process_memory)return;process_memory=new shmem_control(size);}static const bool process_shared = true;};shmem_control *process_settings::process_memory=0;#endifstruct thread_settings {typedef booster::mutex mutex_type;typedef booster::shared_mutex shared_mutex_type;typedef booster::unique_lock<booster::mutex> lock_guard;typedef booster::shared_lock<booster::shared_mutex> rdlock_guard;typedef booster::unique_lock<booster::shared_mutex> wrlock_guard;typedef std::allocator<char> allocator;static bool not_enough_memory() { return false; }static size_t size_limit() { return std::numeric_limits<size_t>::max(); }static const bool process_shared = false;};template<typename Setup>class mem_cache : public base_cache {typedef typename Setup::mutex_type mutex_type;typedef typename Setup::shared_mutex_type shared_mutex_type;std::auto_ptr<mutex_type> lru_mutex;std::auto_ptr<shared_mutex_type> access_lock;typedef typename Setup::allocator allocator;typedef typename Setup::lock_guard lock_guard;typedef typename Setup::rdlock_guard rdlock_guard;typedef typename Setup::wrlock_guard wrlock_guard;typedef typename allocator::template rebind<mem_cache>::other this_allocator;bool not_enough_memory(){return Setup::not_enough_memory();}size_t size_limit(){return Setup::size_limit();}struct container;typedef std::basic_string<char,std::char_traits<char>,allocator > string_type;typedef hash_map<string_type,container,string_hash,string_equal,typename allocator::template rebind<std::pair<const string_type,container> >::other> map_type;typedef typename map_type::iterator pointer;typedef std::list<pointer,typename allocator::template rebind<pointer>::other> pointer_list_type;typedef hash_map<string_type,pointer_list_type,string_hash,string_equal,typename allocator::template rebind<std::pair<const string_type,pointer_list_type> >::other> triggers_map_type;typedef std::pair<typename triggers_map_type::iterator,typename pointer_list_type::iterator> trigger_ptr_type;typedef std::list<trigger_ptr_type,typename allocator::template rebind<trigger_ptr_type>::other> triggers_list_type;typedef std::multimap<time_t,pointer,std::less<time_t>,typename allocator::template rebind<std::pair<const time_t,pointer> >::other> timeout_mmap_type;struct container {string_type data;typedef typename map_type::iterator pointer;typename pointer_list_type::iterator lru;triggers_list_type triggers;typename timeout_mmap_type::iterator timeout;uint64_t generation;};map_type primary;triggers_map_type triggers;typedef typename triggers_map_type::iterator triggers_ptr;timeout_mmap_type timeout;typedef typename timeout_mmap_type::iterator timeout_ptr;pointer_list_type lru;typedef typename pointer_list_type::iterator lru_ptr;unsigned limit;size_t size;size_t triggers_count;int refs;uint64_t generation;string_type to_int(std::string const &other){return copy_traits<string_type>::to_int(other);}std::string to_std(string_type const &other){return copy_traits<string_type>::to_std(other);}void delete_node(pointer p){lru.erase(p->second.lru);timeout.erase(p->second.timeout);typename triggers_list_type::iterator i;for(i=p->second.triggers.begin();i!=p->second.triggers.end();i++) {i->first->second.erase(i->second);triggers_count --;if(i->first->second.empty())triggers.erase(i->first);}primary.erase(p);size--;}public:mem_cache(unsigned pages=0) :lru_mutex(new mutex_type()),access_lock(new shared_mutex_type()),limit(pages),size(0),refs(0),generation(0){nl_clear();}~mem_cache(){}void set_size(unsigned l){limit = l;nl_clear();};virtual bool fetch(std::string const &key,std::string *a,std::set<std::string> *triggers,time_t *timeout_out,uint64_t *gen){rdlock_guard lock(*access_lock);pointer p;time_t now;time(&now);if((p=primary.find(key))==primary.end() || p->second.timeout->first < now) {return false;}{ // Update LRUlock_guard lock(*lru_mutex);lru.erase(p->second.lru);lru.push_front(p);p->second.lru=lru.begin();}if(a)*a=to_std(p->second.data);if(triggers) {typename triggers_list_type::iterator tp;for(tp=p->second.triggers.begin();tp!=p->second.triggers.end();tp++) {triggers->insert(to_std(tp->first->first));}}if(timeout_out) {*timeout_out=p->second.timeout->first;}if(gen)*gen=p->second.generation;return true;}virtual void rise(std::string const &trigger){wrlock_guard lock(*access_lock);triggers_ptr p = triggers.find(trigger);if(p==triggers.end())return;std::list<pointer> kill_list;for(typename pointer_list_type::iterator it=p->second.begin();it!=p->second.end();++it) {kill_list.push_back(*it);}typename std::list<pointer>::iterator lptr;for(lptr=kill_list.begin();lptr!=kill_list.end();lptr++) {delete_node(*lptr);}}void nl_clear(){timeout.clear();lru.clear();primary.clear();primary.rehash(limit);triggers.clear();triggers.rehash(limit);size = 0;triggers_count = 0;}virtual void clear(){wrlock_guard lock(*access_lock);nl_clear();}virtual void stats(unsigned &keys,unsigned &triggers){rdlock_guard lock(*access_lock);keys=size;triggers = triggers_count;}void check_limits(){pointer main=primary.end();time_t now;time(&now);while(size > 0 && (not_enough_memory() || (size>=limit && limit>0))){if(!timeout.empty() && timeout.begin()->first<now) {main=timeout.begin()->second;}else if(!lru.empty()){main=*lru.rbegin();}elsebreak;delete_node(main);}}virtual void remove(std::string const &key){wrlock_guard lock(*access_lock);pointer p=primary.find(key);if(p==primary.end())return;delete_node(p);}void add_trigger(pointer p,std::string const &key){std::pair<string_type,pointer_list_type> tr(to_int(key),pointer_list_type());std::pair<triggers_ptr,bool> r=triggers.insert(tr);triggers_ptr it = r.first;it->second.push_front(p);p->second.triggers.push_back(trigger_ptr_type(it,it->second.begin()));triggers_count++;}virtual void store( std::string const &key,std::string const &a,std::set<std::string> const &triggers_in,time_t timeout_in,uint64_t const *gen){string_type ar;try {string_type tmp = to_int(a);ar.swap(tmp);}catch(std::bad_alloc const &) {return;}wrlock_guard lock(*access_lock);try {pointer main;main=primary.find(key);if(main!=primary.end())delete_node(main);if(size > size_limit())return;check_limits();string_type int_key = to_int(key);std::pair<pointer,bool> res=primary.insert(std::pair<string_type,container>(int_key,container()));size ++;main=res.first;container &cont=main->second;cont.data.swap(ar);if(gen)cont.generation=*gen;elsecont.generation=generation++;lru.push_front(main);cont.lru=lru.begin();cont.timeout=timeout.insert(std::pair<time_t,pointer>(timeout_in,main));if(triggers_in.find(key)==triggers_in.end()){add_trigger(main,key);}std::set<std::string>::const_iterator si;for(si=triggers_in.begin();si!=triggers_in.end();si++) {add_trigger(main,*si);}}catch(std::bad_alloc const &e){nl_clear();}}virtual void add_ref(){if(Setup::process_shared)return;wrlock_guard lock(*access_lock);refs++;}virtual bool del_ref(){// This object should not be deleted because it is created only once// and exists in memoryif(Setup::process_shared)return false;wrlock_guard lock(*access_lock);refs--;if(refs==0)return true;return false;}void *operator new(size_t /*n*/){return this_allocator().allocate(1);}void operator delete(void *p){this_allocator().deallocate(reinterpret_cast<mem_cache *>(p),1);}}; // mem cachebooster::intrusive_ptr<base_cache> thread_cache_factory(unsigned items){return new mem_cache<thread_settings>(items);}#if !defined(CPPCMS_NO_PREFOK_CACHE)booster::intrusive_ptr<base_cache> process_cache_factory(size_t memory,unsigned items){process_settings::init(memory);return new mem_cache<process_settings>(items);}#endif} // impl} // cppcms#endif // CPPCMS_NO_PREFOK_CACHE
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。