ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

303 lines
7.3 KiB

  1. #define CPPCMS_SOURCE
  2. #include "process_cache.h"
  3. #include "config.h"
  4. #include <errno.h>
  5. #include <iostream>
  6. namespace cppcms {
  7. namespace impl {
  8. class process_cache_impl : public base_cache {
  9. mutex &lru_mutex;
  10. shared_mutex &access_lock;
  11. typedef std::basic_string<char,std::char_traits<char>,shmem_allocator<char,process_cache_factory::mem> > shr_string;
  12. struct container {
  13. shr_string data;
  14. typedef map<shr_string,container,std::less<shr_string>,
  15. shmem_allocator<std::pair<shr_string,container>,process_cache_factory::mem > > primary_map;
  16. typedef primary_map::iterator pointer;
  17. typedef list<pointer,shmem_allocator<pointer,process_cache_factory::mem> > pointer_list;
  18. pointer_list::iterator lru;
  19. typedef multimap<shr_string,pointer,std::less<shr_string>,
  20. shmem_allocator<std::pair<shr_string,pointer>,process_cache_factory::mem > > secondary_map;
  21. list<secondary_map::iterator,shmem_allocator<secondary_map::iterator,process_cache_factory::mem> > triggers;
  22. typedef multimap<time_t,pointer,std::less<time_t>,
  23. shmem_allocator<std::pair<time_t,pointer>,process_cache_factory::mem > > timeout_map;
  24. timeout_map::iterator timeout;
  25. };
  26. typedef container::pointer pointer;
  27. container::primary_map primary;
  28. container::secondary_map triggers;
  29. typedef container::secondary_map::iterator triggers_ptr;
  30. container::timeout_map timeout;
  31. typedef container::timeout_map::iterator timeout_ptr;
  32. container::pointer_list lru;
  33. typedef container::pointer_list::iterator lru_ptr;
  34. unsigned memsize;
  35. shr_string *get(string const &key,set<string> *triggers);
  36. void delete_node(pointer p);
  37. int fd;
  38. public:
  39. process_cache(size_t memsize,mutex &m,shared_mutex &a);
  40. virtual bool fetch(string const &key,string &a,set<string> *tags);
  41. virtual void rise(string const &trigger);
  42. virtual void clear();
  43. virtual void stats(unsigned &keys,unsigned &triggers);
  44. virtual void store(string const &key,set<string> const &triggers,time_t timeout,archive const &a);
  45. virtual ~process_cache();
  46. void *operator new(size_t n);
  47. void operator delete (void *p);
  48. };
  49. shmem_control *process_cache_factory::mem(NULL);
  50. ::pid_t process_cache_factory::owner_pid(0);
  51. process_cache_factory::process_cache_factory(size_t memsize,char const *file)
  52. {
  53. cache=NULL;
  54. if(memsize<8*1024) {
  55. throw cppcms_error("Cache size too small -- need at least 8K");
  56. }
  57. if(!mem) {
  58. mem=new shmem_control(memsize,file);
  59. owner_pid=getpid();
  60. }
  61. else {
  62. throw cppcms_error("The memory initilized -- can't use more then once cache in same time");
  63. }
  64. cache=new process_cache(memsize);
  65. };
  66. process_cache_factory::~process_cache_factory()
  67. {
  68. // Only parent process can kill memory
  69. // forked childs should never do it.
  70. if(owner_pid==getpid()) {
  71. delete cache;
  72. delete mem;
  73. mem=NULL;
  74. }
  75. }
  76. base_cache *process_cache_factory::get() const
  77. {
  78. return cache;
  79. };
  80. void process_cache_factory::del(base_cache *p) const
  81. {
  82. };
  83. process_cache::process_cache(size_t s,mutex &m,shared_mutex &a) :
  84. memsize(s),
  85. lru_mutex(m),
  86. access_lock(a)
  87. {
  88. };
  89. process_cache::~process_cache()
  90. {
  91. }
  92. process_cache::shr_string *process_cache::get(string const &key,set<string> *triggers)
  93. {
  94. pointer p;
  95. time_t now;
  96. time(&now);
  97. if((p=primary.find(key.c_str()))==primary.end() || p->second.timeout->first < now) {
  98. return NULL;
  99. }
  100. if(triggers) {
  101. list<triggers_ptr>::iterator tp;
  102. for(tp=p->second.triggers.begin();tp!=p->second.triggers.end();tp++) {
  103. triggers->insert((*tp)->first.c_str());
  104. }
  105. }
  106. {
  107. mutex::guard lock(lru_mutex);
  108. lru.erase(p->second.lru);
  109. lru.push_front(p);
  110. p->second.lru=lru.begin();
  111. }
  112. return &(p->second.data);
  113. }
  114. bool process_cache::fetch(string const &key,archive &a,set<string> &tags)
  115. {
  116. shared_mutex::shared_guard lock(access_lock);
  117. shr_string *r=get(key,&tags);
  118. if(!r) return false;
  119. a.set(r->c_str(),r->size());
  120. return true;
  121. }
  122. void process_cache::clear()
  123. {
  124. shared_mutex::unique_guard lock(access_lock);
  125. timeout.clear();
  126. lru.clear();
  127. primary.clear();
  128. triggers.clear();
  129. }
  130. void process_cache::stats(unsigned &keys,unsigned &triggers)
  131. {
  132. shared_mutex::shared_guard lock(access_lock);
  133. keys=primary.size();
  134. triggers=this->triggers.size();
  135. }
  136. void process_cache::rise(string const &trigger)
  137. {
  138. shared_mutex::unique_guard lock(access_lock);
  139. pair<triggers_ptr,triggers_ptr> range=triggers.equal_range(trigger.c_str());
  140. triggers_ptr p;
  141. list<pointer> kill_list;
  142. for(p=range.first;p!=range.second;p++) {
  143. kill_list.push_back(p->second);
  144. }
  145. list<pointer>::iterator lptr;
  146. for(lptr=kill_list.begin();lptr!=kill_list.end();lptr++) {
  147. delete_node(*lptr);
  148. }
  149. }
  150. void process_cache::store(string const &key,set<string> const &triggers_in,time_t timeout_in,archive const &a)
  151. {
  152. shared_mutex::unique_guard lock(access_lock);
  153. pointer main;
  154. main=primary.find(key.c_str());
  155. if(main!=primary.end())
  156. delete_node(main);
  157. if(a.get().size()>memsize/20) {
  158. return;
  159. }
  160. time_t now;
  161. time(&now);
  162. // Make sure there is at least 10% avalible
  163. // And there is a block that is big enough to allocate 5% of memory
  164. for(;;) {
  165. if(process_cache_factory::mem->available() > memsize / 10) {
  166. try {
  167. void *p=process_cache_factory::mem->malloc(memsize/20);
  168. process_cache_factory::mem->free(p);
  169. break;
  170. }
  171. catch(std::bad_alloc const &e)
  172. {
  173. }
  174. }
  175. if(timeout.begin()->first<now) {
  176. main=timeout.begin()->second;
  177. }
  178. else {
  179. main=lru.back();
  180. }
  181. delete_node(main);
  182. }
  183. try {
  184. pair<pointer,bool> res=primary.insert(pair<shr_string,container>(key.c_str(),container()));
  185. main=res.first;
  186. container &cont=main->second;
  187. cont.data.assign(a.get().c_str(),a.get().size());
  188. lru.push_front(main);
  189. cont.lru=lru.begin();
  190. cont.timeout=timeout.insert(pair<time_t,pointer>(timeout_in,main));
  191. if(triggers_in.find(key)==triggers_in.end()){
  192. cont.triggers.push_back(triggers.insert(
  193. pair<shr_string,pointer>(key.c_str(),main)));
  194. }
  195. set<string>::const_iterator si;
  196. for(si=triggers_in.begin();si!=triggers_in.end();si++) {
  197. cont.triggers.push_back(triggers.insert(
  198. pair<shr_string,pointer>(si->c_str(),main)));
  199. }
  200. }
  201. catch(std::bad_alloc const &e) {
  202. clear();
  203. }
  204. }
  205. void process_cache::delete_node(pointer p)
  206. {
  207. lru.erase(p->second.lru);
  208. timeout.erase(p->second.timeout);
  209. list<triggers_ptr>::iterator i;
  210. for(i=p->second.triggers.begin();i!=p->second.triggers.end();i++) {
  211. triggers.erase(*i);
  212. }
  213. primary.erase(p);
  214. }
  215. void *process_cache::operator new(size_t n) {
  216. void *p=process_cache_factory::mem->malloc(n);
  217. if(!p)
  218. throw std::bad_alloc();
  219. return p;
  220. }
  221. void process_cache::operator delete (void *p) {
  222. process_cache_factory::mem->free(p);
  223. }
  224. class process_cache_holder : public base_cache {
  225. public:
  226. process_cache_holder(size_t memory_size)
  227. {
  228. lru_ = new mutex(true);
  229. access_ = new shared_mutex(true);
  230. impl_ = new process_cache(memory_size,*lru_,*access_);
  231. pid_ = ::getpid();
  232. }
  233. ~process_cache_holder()
  234. {
  235. if(pid_ == ::getpid())
  236. }
  237. virtual bool fetch(std::string const &key,std::string &a,std::set<std::string> *tags)
  238. {
  239. return impl_->fetch(ket,a,tags);
  240. }
  241. virtual void store(std::string const &key,std::string const &b,std::set<std::string> const &triggers,time_t timeout)
  242. {
  243. return impl_->store(key,b,triggers,timeout);
  244. }
  245. virtual void rise(std::string const &trigger)
  246. {
  247. return impl_->rise(trigger);
  248. }
  249. virtual void clear()
  250. {
  251. return impl_->clear();
  252. }
  253. virtual void stats(unsigned &keys,unsigned &triggers)
  254. {
  255. return impl_->stats;
  256. }
  257. virtual ~base_cache()
  258. {
  259. }
  260. static mem-
  261. };
  262. } // impl
  263. } // cppcms