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.
 
 
 
 
 
 

467 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #define CPPCMS_SOURCE
  9. #include <cppcms/config.h>
  10. #include <set>
  11. #ifndef CPPCMS_NO_CACHE
  12. #include "cache_storage.h"
  13. #include <booster/thread.h>
  14. #include <iostream>
  15. #if defined CPPCMS_WIN32
  16. # ifndef CPPCMS_NO_PREFOK_CACHE
  17. # define CPPCMS_NO_PREFOK_CACHE
  18. # endif
  19. #endif
  20. #ifndef CPPCMS_NO_PREFOK_CACHE
  21. # include "posix_util.h"
  22. # include "shmem_allocator.h"
  23. #endif
  24. #include <map>
  25. #include <string>
  26. #include <list>
  27. #include <limits>
  28. #include <booster/auto_ptr_inc.h>
  29. #include <time.h>
  30. #include <cppcms/cstdint.h>
  31. #include "hash_map.h"
  32. #include <string.h>
  33. namespace cppcms {
  34. namespace impl {
  35. template<typename String>
  36. struct copy_traits {
  37. static String to_int(std::string const &other)
  38. {
  39. return String(other.c_str(),other.size());
  40. }
  41. static std::string to_std(String const &other)
  42. {
  43. return std::string(other.c_str(),other.size());
  44. }
  45. };
  46. template<>
  47. struct copy_traits<std::string>
  48. {
  49. static std::string to_int(std::string const &a) { return a; }
  50. static std::string to_std(std::string const &a) { return a; }
  51. };
  52. struct string_equal {
  53. template<typename S1,typename S2>
  54. bool operator()(S1 const &s1,S2 const &s2) const
  55. {
  56. return s1.size() == s2.size() && memcmp(s1.c_str(),s2.c_str(),s1.size()) == 0;
  57. }
  58. };
  59. #ifndef CPPCMS_NO_PREFOK_CACHE
  60. struct process_settings {
  61. static shmem_control *process_memory;
  62. typedef ::cppcms::impl::mutex mutex_type;
  63. typedef ::cppcms::impl::shared_mutex shared_mutex_type;
  64. typedef mutex_type::guard lock_guard;
  65. typedef shared_mutex_type::shared_guard rdlock_guard;
  66. typedef shared_mutex_type::unique_guard wrlock_guard;
  67. typedef shmem_allocator<char,process_memory> allocator;
  68. static bool not_enough_memory()
  69. {
  70. return process_memory->max_available() < process_memory->size() / 10;
  71. }
  72. static size_t size_limit()
  73. {
  74. return process_memory->size() / 20;
  75. }
  76. static void init(size_t size)
  77. {
  78. if(process_memory)
  79. return;
  80. process_memory=new shmem_control(size);
  81. }
  82. static const bool process_shared = true;
  83. };
  84. shmem_control *process_settings::process_memory=0;
  85. #endif
  86. struct thread_settings {
  87. typedef booster::mutex mutex_type;
  88. typedef booster::shared_mutex shared_mutex_type;
  89. typedef booster::unique_lock<booster::mutex> lock_guard;
  90. typedef booster::shared_lock<booster::shared_mutex> rdlock_guard;
  91. typedef booster::unique_lock<booster::shared_mutex> wrlock_guard;
  92. typedef std::allocator<char> allocator;
  93. static bool not_enough_memory() { return false; }
  94. static size_t size_limit() { return std::numeric_limits<size_t>::max(); }
  95. static const bool process_shared = false;
  96. };
  97. template<typename Setup>
  98. class mem_cache : public base_cache {
  99. typedef typename Setup::mutex_type mutex_type;
  100. typedef typename Setup::shared_mutex_type shared_mutex_type;
  101. std::auto_ptr<mutex_type> lru_mutex;
  102. std::auto_ptr<shared_mutex_type> access_lock;
  103. typedef typename Setup::allocator allocator;
  104. typedef typename Setup::lock_guard lock_guard;
  105. typedef typename Setup::rdlock_guard rdlock_guard;
  106. typedef typename Setup::wrlock_guard wrlock_guard;
  107. typedef typename allocator::template rebind<mem_cache>::other this_allocator;
  108. bool not_enough_memory()
  109. {
  110. return Setup::not_enough_memory();
  111. }
  112. size_t size_limit()
  113. {
  114. return Setup::size_limit();
  115. }
  116. struct container;
  117. typedef std::basic_string<char,std::char_traits<char>,allocator > string_type;
  118. typedef hash_map<
  119. string_type,
  120. container,
  121. string_hash,
  122. string_equal,
  123. typename allocator::template rebind<std::pair<const string_type,container> >::other
  124. > map_type;
  125. typedef typename map_type::iterator pointer;
  126. typedef std::list<
  127. pointer,
  128. typename allocator::template rebind<pointer>::other
  129. > pointer_list_type;
  130. typedef hash_map<
  131. string_type,
  132. pointer_list_type,
  133. string_hash,
  134. string_equal,
  135. typename allocator::template rebind<std::pair<const string_type,pointer_list_type> >::other
  136. > triggers_map_type;
  137. typedef std::pair<
  138. typename triggers_map_type::iterator,
  139. typename pointer_list_type::iterator
  140. > trigger_ptr_type;
  141. typedef std::list<
  142. trigger_ptr_type,
  143. typename allocator::template rebind<trigger_ptr_type>::other
  144. > triggers_list_type;
  145. typedef std::multimap<
  146. time_t,
  147. pointer,
  148. std::less<time_t>,
  149. typename allocator::template rebind<std::pair<const time_t,pointer> >::other
  150. > timeout_mmap_type;
  151. struct container {
  152. string_type data;
  153. typedef typename map_type::iterator pointer;
  154. typename pointer_list_type::iterator lru;
  155. triggers_list_type triggers;
  156. typename timeout_mmap_type::iterator timeout;
  157. uint64_t generation;
  158. };
  159. map_type primary;
  160. triggers_map_type triggers;
  161. typedef typename triggers_map_type::iterator triggers_ptr;
  162. timeout_mmap_type timeout;
  163. typedef typename timeout_mmap_type::iterator timeout_ptr;
  164. pointer_list_type lru;
  165. typedef typename pointer_list_type::iterator lru_ptr;
  166. unsigned limit;
  167. size_t size;
  168. size_t triggers_count;
  169. int refs;
  170. uint64_t generation;
  171. string_type to_int(std::string const &other)
  172. {
  173. return copy_traits<string_type>::to_int(other);
  174. }
  175. std::string to_std(string_type const &other)
  176. {
  177. return copy_traits<string_type>::to_std(other);
  178. }
  179. void delete_node(pointer p)
  180. {
  181. lru.erase(p->second.lru);
  182. timeout.erase(p->second.timeout);
  183. typename triggers_list_type::iterator i;
  184. for(i=p->second.triggers.begin();i!=p->second.triggers.end();i++) {
  185. i->first->second.erase(i->second);
  186. triggers_count --;
  187. if(i->first->second.empty())
  188. triggers.erase(i->first);
  189. }
  190. primary.erase(p);
  191. size--;
  192. }
  193. public:
  194. mem_cache(unsigned pages=0) :
  195. lru_mutex(new mutex_type()),
  196. access_lock(new shared_mutex_type()),
  197. limit(pages),
  198. size(0),
  199. refs(0),
  200. generation(0)
  201. {
  202. nl_clear();
  203. }
  204. ~mem_cache()
  205. {
  206. }
  207. void set_size(unsigned l)
  208. {
  209. limit = l;
  210. nl_clear();
  211. };
  212. virtual bool fetch(std::string const &key,std::string *a,std::set<std::string> *triggers,time_t *timeout_out,uint64_t *gen)
  213. {
  214. rdlock_guard lock(*access_lock);
  215. pointer p;
  216. time_t now;
  217. time(&now);
  218. if((p=primary.find(key))==primary.end() || p->second.timeout->first < now) {
  219. return false;
  220. }
  221. { // Update LRU
  222. lock_guard lock(*lru_mutex);
  223. lru.erase(p->second.lru);
  224. lru.push_front(p);
  225. p->second.lru=lru.begin();
  226. }
  227. if(a)
  228. *a=to_std(p->second.data);
  229. if(triggers) {
  230. typename triggers_list_type::iterator tp;
  231. for(tp=p->second.triggers.begin();tp!=p->second.triggers.end();tp++) {
  232. triggers->insert(to_std(tp->first->first));
  233. }
  234. }
  235. if(timeout_out) {
  236. *timeout_out=p->second.timeout->first;
  237. }
  238. if(gen)
  239. *gen=p->second.generation;
  240. return true;
  241. }
  242. virtual void rise(std::string const &trigger)
  243. {
  244. wrlock_guard lock(*access_lock);
  245. triggers_ptr p = triggers.find(trigger);
  246. if(p==triggers.end())
  247. return;
  248. std::list<pointer> kill_list;
  249. for(typename pointer_list_type::iterator it=p->second.begin();it!=p->second.end();++it) {
  250. kill_list.push_back(*it);
  251. }
  252. typename std::list<pointer>::iterator lptr;
  253. for(lptr=kill_list.begin();lptr!=kill_list.end();lptr++) {
  254. delete_node(*lptr);
  255. }
  256. }
  257. void nl_clear()
  258. {
  259. timeout.clear();
  260. lru.clear();
  261. primary.clear();
  262. primary.rehash(limit);
  263. triggers.clear();
  264. triggers.rehash(limit);
  265. size = 0;
  266. triggers_count = 0;
  267. }
  268. virtual void clear()
  269. {
  270. wrlock_guard lock(*access_lock);
  271. nl_clear();
  272. }
  273. virtual void stats(unsigned &keys,unsigned &triggers)
  274. {
  275. rdlock_guard lock(*access_lock);
  276. keys=size;
  277. triggers = triggers_count;
  278. }
  279. void check_limits()
  280. {
  281. pointer main=primary.end();
  282. time_t now;
  283. time(&now);
  284. while(size > 0 && (not_enough_memory() || (size>=limit && limit>0)))
  285. {
  286. if(!timeout.empty() && timeout.begin()->first<now) {
  287. main=timeout.begin()->second;
  288. }
  289. else if(!lru.empty()){
  290. main=*lru.rbegin();
  291. }
  292. else
  293. break;
  294. delete_node(main);
  295. }
  296. }
  297. virtual void remove(std::string const &key)
  298. {
  299. wrlock_guard lock(*access_lock);
  300. pointer p=primary.find(key);
  301. if(p==primary.end())
  302. return;
  303. delete_node(p);
  304. }
  305. void add_trigger(pointer p,std::string const &key)
  306. {
  307. std::pair<string_type,pointer_list_type> tr(to_int(key),pointer_list_type());
  308. std::pair<triggers_ptr,bool> r=triggers.insert(tr);
  309. triggers_ptr it = r.first;
  310. it->second.push_front(p);
  311. p->second.triggers.push_back(trigger_ptr_type(it,it->second.begin()));
  312. triggers_count++;
  313. }
  314. virtual void store( std::string const &key,
  315. std::string const &a,
  316. std::set<std::string> const &triggers_in,
  317. time_t timeout_in,
  318. uint64_t const *gen)
  319. {
  320. string_type ar;
  321. try {
  322. string_type tmp = to_int(a);
  323. ar.swap(tmp);
  324. }
  325. catch(std::bad_alloc const &) {
  326. return;
  327. }
  328. wrlock_guard lock(*access_lock);
  329. try {
  330. pointer main;
  331. main=primary.find(key);
  332. if(main!=primary.end())
  333. delete_node(main);
  334. if(size > size_limit())
  335. return;
  336. check_limits();
  337. string_type int_key = to_int(key);
  338. std::pair<pointer,bool> res=primary.insert(std::pair<string_type,container>(int_key,container()));
  339. size ++;
  340. main=res.first;
  341. container &cont=main->second;
  342. cont.data.swap(ar);
  343. if(gen)
  344. cont.generation=*gen;
  345. else
  346. cont.generation=generation++;
  347. lru.push_front(main);
  348. cont.lru=lru.begin();
  349. cont.timeout=timeout.insert(std::pair<time_t,pointer>(timeout_in,main));
  350. if(triggers_in.find(key)==triggers_in.end()){
  351. add_trigger(main,key);
  352. }
  353. std::set<std::string>::const_iterator si;
  354. for(si=triggers_in.begin();si!=triggers_in.end();si++) {
  355. add_trigger(main,*si);
  356. }
  357. }
  358. catch(std::bad_alloc const &e)
  359. {
  360. nl_clear();
  361. }
  362. }
  363. virtual void add_ref()
  364. {
  365. if(Setup::process_shared)
  366. return;
  367. wrlock_guard lock(*access_lock);
  368. refs++;
  369. }
  370. virtual bool del_ref()
  371. {
  372. // This object should not be deleted because it is created only once
  373. // and exists in memory
  374. if(Setup::process_shared)
  375. return false;
  376. wrlock_guard lock(*access_lock);
  377. refs--;
  378. if(refs==0)
  379. return true;
  380. return false;
  381. }
  382. void *operator new(size_t /*n*/)
  383. {
  384. return this_allocator().allocate(1);
  385. }
  386. void operator delete(void *p)
  387. {
  388. this_allocator().deallocate(reinterpret_cast<mem_cache *>(p),1);
  389. }
  390. }; // mem cache
  391. booster::intrusive_ptr<base_cache> thread_cache_factory(unsigned items)
  392. {
  393. return new mem_cache<thread_settings>(items);
  394. }
  395. #if !defined(CPPCMS_NO_PREFOK_CACHE)
  396. booster::intrusive_ptr<base_cache> process_cache_factory(size_t memory,unsigned items)
  397. {
  398. process_settings::init(memory);
  399. return new mem_cache<process_settings>(items);
  400. }
  401. #endif
  402. } // impl
  403. } // cppcms
  404. #endif // CPPCMS_NO_PREFOK_CACHE