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.
 
 
 
 
 
 

279 lines
6.1 KiB

  1. #include "process_cache.h"
  2. #include <boost/format.hpp>
  3. #include <unistd.h>
  4. #ifdef HAVE_PTHREADS_PSHARED
  5. # include "posix_mutex.h"
  6. #else
  7. # include "fcntl_mutex.h"
  8. using namespace cppcms::fcntl;
  9. #endif
  10. #include <errno.h>
  11. #include <iostream>
  12. using boost::format;
  13. using boost::str;
  14. namespace cppcms {
  15. shmem_control *process_cache_factory::mem(NULL);
  16. ::pid_t process_cache_factory::owner_pid(0);
  17. process_cache_factory::process_cache_factory(size_t memsize,char const *file)
  18. {
  19. cache=NULL;
  20. if(memsize<8*1024) {
  21. throw cppcms_error("Cache size too small -- need at least 8K");
  22. }
  23. if(!mem) {
  24. mem=new shmem_control(memsize,file);
  25. owner_pid=getpid();
  26. }
  27. else {
  28. throw cppcms_error("The memory initilized -- can't use more then once cache in same time");
  29. }
  30. cache=new process_cache(memsize);
  31. };
  32. process_cache_factory::~process_cache_factory()
  33. {
  34. // Only parent process can kill memory
  35. // forked childs should never do it.
  36. if(owner_pid==getpid()) {
  37. delete cache;
  38. delete mem;
  39. mem=NULL;
  40. }
  41. }
  42. base_cache *process_cache_factory::get() const
  43. {
  44. return cache;
  45. };
  46. void process_cache_factory::del(base_cache *p) const
  47. {
  48. };
  49. process_cache::process_cache(size_t m) :
  50. memsize(m)
  51. {
  52. #ifdef HAVE_PTHREADS_PSHARED
  53. pthread_mutexattr_t a;
  54. pthread_rwlockattr_t al;
  55. if(
  56. pthread_mutexattr_init(&a)
  57. || pthread_mutexattr_setpshared(&a,PTHREAD_PROCESS_SHARED)
  58. || pthread_mutex_init(&lru_mutex,&a)
  59. || pthread_mutexattr_destroy(&a)
  60. || pthread_rwlockattr_init(&al)
  61. || pthread_rwlockattr_setpshared(&al,PTHREAD_PROCESS_SHARED)
  62. || pthread_rwlock_init(&access_lock,&al)
  63. || pthread_rwlockattr_destroy(&al))
  64. {
  65. throw cppcms_error(errno,"Failed setup mutexes --- is this system "
  66. "supports process shared mutex/rwlock?");
  67. }
  68. #else
  69. if((lru_mutex=tmpfile())==NULL || (access_lock=tmpfile())==NULL) {
  70. throw cppcms_error(errno,"Failed to create temporary file");
  71. }
  72. #endif
  73. };
  74. process_cache::~process_cache()
  75. {
  76. #ifdef HAVE_PTHREADS_PSHARED
  77. pthread_mutex_destroy(&lru_mutex);
  78. pthread_rwlock_destroy(&access_lock);
  79. #else
  80. fclose(lru_mutex);
  81. fclose(access_lock);
  82. #endif
  83. }
  84. process_cache::shr_string *process_cache::get(string const &key,set<string> *triggers)
  85. {
  86. pointer p;
  87. time_t now;
  88. time(&now);
  89. if((p=primary.find(key.c_str()))==primary.end() || p->second.timeout->first < now) {
  90. return NULL;
  91. }
  92. if(triggers) {
  93. list<triggers_ptr>::iterator tp;
  94. for(tp=p->second.triggers.begin();tp!=p->second.triggers.end();tp++) {
  95. triggers->insert((*tp)->first.c_str());
  96. }
  97. }
  98. {
  99. mutex_lock lock(lru_mutex);
  100. lru.erase(p->second.lru);
  101. lru.push_front(p);
  102. p->second.lru=lru.begin();
  103. }
  104. return &(p->second.data);
  105. }
  106. namespace {
  107. template<typename T>
  108. T unaligned(T const *p)
  109. {
  110. T tmp;
  111. memcpy(&tmp,p,sizeof(T));
  112. return tmp;
  113. }
  114. }
  115. bool process_cache::fetch_page(string const &key,string &out,bool gzip)
  116. {
  117. rwlock_rdlock lock(access_lock);
  118. shr_string *r=get(key,NULL);
  119. if(!r) return false;
  120. size_t size=r->size();
  121. size_t s;
  122. char const *ptr=r->c_str();
  123. if(size<sizeof(size_t) || (s=unaligned((size_t const *)ptr))>size-sizeof(size_t))
  124. return false;
  125. if(!gzip){
  126. out.assign(ptr+sizeof(size_t),s);
  127. }
  128. else {
  129. ptr+=s+sizeof(size_t);
  130. size-=s+sizeof(size_t);
  131. if(size<sizeof(size_t) || (s=unaligned((size_t const *)ptr))!=size-sizeof(size_t))
  132. return false;
  133. out.assign(ptr+sizeof(size_t),s);
  134. }
  135. return true;
  136. }
  137. bool process_cache::fetch(string const &key,archive &a,set<string> &tags)
  138. {
  139. rwlock_rdlock lock(access_lock);
  140. shr_string *r=get(key,&tags);
  141. if(!r) return false;
  142. a.set(r->c_str(),r->size());
  143. return true;
  144. }
  145. void process_cache::clear()
  146. {
  147. rwlock_wrlock lock(access_lock);
  148. timeout.clear();
  149. lru.clear();
  150. primary.clear();
  151. triggers.clear();
  152. }
  153. void process_cache::stats(unsigned &keys,unsigned &triggers)
  154. {
  155. rwlock_rdlock lock(access_lock);
  156. keys=primary.size();
  157. triggers=this->triggers.size();
  158. }
  159. void process_cache::rise(string const &trigger)
  160. {
  161. rwlock_wrlock lock(access_lock);
  162. pair<triggers_ptr,triggers_ptr> range=triggers.equal_range(trigger.c_str());
  163. triggers_ptr p;
  164. list<pointer> kill_list;
  165. for(p=range.first;p!=range.second;p++) {
  166. kill_list.push_back(p->second);
  167. }
  168. list<pointer>::iterator lptr;
  169. for(lptr=kill_list.begin();lptr!=kill_list.end();lptr++) {
  170. delete_node(*lptr);
  171. }
  172. }
  173. void process_cache::store(string const &key,set<string> const &triggers_in,time_t timeout_in,archive const &a)
  174. {
  175. rwlock_wrlock lock(access_lock);
  176. pointer main;
  177. main=primary.find(key.c_str());
  178. if(main!=primary.end())
  179. delete_node(main);
  180. if(a.get().size()>memsize/20) {
  181. return;
  182. }
  183. time_t now;
  184. time(&now);
  185. // Make sure there is at least 10% avalible
  186. // And there is a block that is big enough to allocate 5% of memory
  187. for(;;) {
  188. if(process_cache_factory::mem->available() > memsize / 10) {
  189. void *p=process_cache_factory::mem->malloc(memsize/20);
  190. if(p) {
  191. process_cache_factory::mem->free(p);
  192. break;
  193. }
  194. }
  195. if(timeout.begin()->first<now) {
  196. main=timeout.begin()->second;
  197. }
  198. else {
  199. main=lru.back();
  200. }
  201. delete_node(main);
  202. }
  203. try {
  204. pair<pointer,bool> res=primary.insert(pair<shr_string,container>(key.c_str(),container()));
  205. main=res.first;
  206. container &cont=main->second;
  207. cont.data.assign(a.get().c_str(),a.get().size());
  208. lru.push_front(main);
  209. cont.lru=lru.begin();
  210. cont.timeout=timeout.insert(pair<time_t,pointer>(timeout_in,main));
  211. if(triggers_in.find(key)==triggers_in.end()){
  212. cont.triggers.push_back(triggers.insert(
  213. pair<shr_string,pointer>(key.c_str(),main)));
  214. }
  215. set<string>::const_iterator si;
  216. for(si=triggers_in.begin();si!=triggers_in.end();si++) {
  217. cont.triggers.push_back(triggers.insert(
  218. pair<shr_string,pointer>(si->c_str(),main)));
  219. }
  220. }
  221. catch(std::bad_alloc const &e) {
  222. clear();
  223. }
  224. }
  225. void process_cache::delete_node(pointer p)
  226. {
  227. lru.erase(p->second.lru);
  228. timeout.erase(p->second.timeout);
  229. list<triggers_ptr>::iterator i;
  230. for(i=p->second.triggers.begin();i!=p->second.triggers.end();i++) {
  231. triggers.erase(*i);
  232. }
  233. primary.erase(p);
  234. }
  235. void *process_cache::operator new(size_t n) {
  236. void *p=process_cache_factory::mem->malloc(n);
  237. if(!p)
  238. throw std::bad_alloc();
  239. return p;
  240. }
  241. void process_cache::operator delete (void *p) {
  242. process_cache_factory::mem->free(p);
  243. }
  244. };