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.
 
 
 
 
 
 

352 lines
12 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. #ifndef CPPCMS_CACHE_INTERFACE_H
  9. #define CPPCMS_CACHE_INTERFACE_H
  10. #include <string>
  11. #include <set>
  12. #include <cppcms/defs.h>
  13. #include <cppcms/serialization_classes.h>
  14. #include <booster/noncopyable.h>
  15. #include <booster/intrusive_ptr.h>
  16. #include <booster/hold_ptr.h>
  17. #include <cppcms/cstdint.h>
  18. namespace cppcms {
  19. class service;
  20. namespace impl {
  21. class base_cache;
  22. }
  23. namespace http {
  24. class context;
  25. };
  26. class cache_interface;
  27. ///
  28. /// \brief triggers_recorder is a class that allows you to record all triggers added in certain scope.
  29. ///
  30. /// It is useful to have have "sub-dependencies" for smaller parts.
  31. ///
  32. /// For example:
  33. ///
  34. /// \code
  35. ///
  36. /// if(cache().fetch_page("news"))
  37. /// return;
  38. /// // something there
  39. /// if(cache().fetch_frame("politics",text))
  40. /// response().out() << text;
  41. /// else {
  42. /// copy_filter politics(respone().out());
  43. /// triggers_recorder politics_triggers(cache());
  44. /// // some thing else there
  45. /// for(int i=0;i<articles.size();i++) {
  46. /// if(cache().fetch_frame(article_tag,text);
  47. /// response().out() << text;
  48. /// else {
  49. /// copy_filter article(respone().out());
  50. /// // generate article
  51. /// cache().store_frame(article_tag,article.detach());
  52. /// }
  53. /// }
  54. /// cache().store_frame("polotics",
  55. /// politics.detach(), // the recorded content of politics
  56. /// politics_triggers.detach());
  57. /// }
  58. /// ...
  59. /// \endcode
  60. ///
  61. /// So tag "politics" records all added triggers like "article_234" and
  62. /// now rise of "article_234" would invalidate "politics" section as well
  63. /// as we automatically record all triggers inserted in triggers_recorder scope.
  64. ///
  65. ///
  66. class CPPCMS_API triggers_recorder : public booster::noncopyable {
  67. public:
  68. ///
  69. /// Start recording all triggers
  70. ///
  71. triggers_recorder(cache_interface &);
  72. ///
  73. /// Stop recording triggers
  74. ///
  75. ~triggers_recorder();
  76. ///
  77. /// Stop recording triggers and get the set of all triggers
  78. /// being added in its scope
  79. ///
  80. std::set<std::string> detach();
  81. private:
  82. friend class cache_interface;
  83. void add(std::string const &t);
  84. struct data;
  85. booster::hold_ptr<data> d;
  86. std::set<std::string> triggers_;
  87. cache_interface *cache_;
  88. };
  89. ///
  90. /// \brief This class is the major gateway of the application to CppCMS caching abilities. Any access too cache
  91. /// would be done via this class.
  92. ///
  93. /// CppCMS cache model supports following concepts:
  94. ///
  95. /// - \a key the unique identification of the object in cache
  96. /// - \a timeout -- the maximal time the cached object remains valid
  97. /// - \a trigger -- special key that allows fast invalidation of multiple cache objects.
  98. ///
  99. /// The first two concepts are quite popular and available in most of Web framework, but the last one is very
  100. /// unique to CppCMS that gives fine grained cache invalidation tools.
  101. ///
  102. /// Each time the page is created it automatically receives some triggers during the process of creation.
  103. /// When some object is fetched from the cache or stored into it, it adds triggers to the major page. This provides
  104. /// semi-automatic triggers management.
  105. ///
  106. /// For example:
  107. ///
  108. /// \code
  109. /// if(cache().fetch_page("main_page"))
  110. /// return;
  111. /// if(!cache().fetch_frame("article_"+id,article)) {
  112. /// article=generate_article_from_data_base(id);
  113. /// cache.store_frame("article_"+id,article);
  114. /// }
  115. /// // Generate some HTML here using article
  116. /// cache.store_page("main");
  117. /// \endcode
  118. ///
  119. /// Let's assume that "main_page" wasn't found in cache, then we try to fetch a frame that holds only a single
  120. /// article "article_123", if it is fetched, the result is stored in a string article and the trigger "article_123"
  121. /// is automatically added to set of triggers that "main_page" depends on them.
  122. ///
  123. /// When the article updated, and "article_123" key is risen, it would automatically invalidate "main_page" as well.
  124. ///
  125. /// CppCMS cache_interface allows storing arbitrary object in cache, For this purpose they should be "serializable".
  126. /// This can be done by specializing a class cppcms::setialization_traits
  127. ///
  128. class CPPCMS_API cache_interface : public booster::noncopyable {
  129. public:
  130. ///
  131. /// Create interface object without a context, everything but
  132. /// fetch_page and store_page would work, it is not possible to
  133. /// handle pages without full i/o context
  134. ///
  135. /// \ver{v1_2}
  136. cache_interface(cppcms::service &srv);
  137. ///
  138. /// \cond INTERNAL
  139. ///
  140. /// Internal API, don't use it
  141. ///
  142. cache_interface(http::context &context);
  143. ~cache_interface();
  144. /// \endcond
  145. ///
  146. /// Rise a trigger \a trigger. All cached objects that depend on this trigger would be invalidated
  147. ///
  148. void rise(std::string const &trigger);
  149. ///
  150. /// Add a trigger \a trigger to the list of dependencies of current page.
  151. ///
  152. void add_trigger(std::string const &trigger);
  153. ///
  154. /// Clear all CppCMS cache - use carefully
  155. ///
  156. void clear();
  157. ///
  158. /// Remove all triggers added to current page so far
  159. ///
  160. void reset();
  161. ///
  162. /// Get statistics about items stored in cache. May require O(n) complexity, use with care.
  163. ///
  164. /// \param keys -- the number of items stored in cache
  165. /// \param triggers -- the number of various triggers existing in the cache.
  166. ///
  167. /// Returns false if caching system is disabled.
  168. ///
  169. bool stats(unsigned &keys,unsigned &triggers);
  170. ///
  171. /// Returns true if caching system is enabled
  172. ///
  173. bool has_cache();
  174. ///
  175. /// Opposite of \a has_cache
  176. ///
  177. bool nocache();
  178. ///
  179. /// Fetch a page from the cache with a key \a key. If the page exists, it is written to output
  180. /// and true is returned. Otherwise false is returned.
  181. ///
  182. bool fetch_page(std::string const &key);
  183. ///
  184. /// Store page with key \a akey in cache, with timeout \a timeout.
  185. ///
  186. /// This function stores a page with dependencies on all triggers that were added so far.
  187. ///
  188. /// \param key -- the key that defines the cache.
  189. /// \param timeout -- maximal valid time of the page. \a timeout=-1 means infinite. Use with care.
  190. ///
  191. /// Note: store_page does not rise the trigger \a key, only replaces the value.
  192. ///
  193. void store_page(std::string const &key,int timeout=-1);
  194. ///
  195. /// Fetch a string (usually some HTML part) from the cache.
  196. ///
  197. /// \param key -- the key that uniquely defines the frame.
  198. /// \param result -- string to store fetched value
  199. /// \param notriggers -- if true, no triggers that a frame is dependent on would be added to dependencies of
  200. /// the current page, otherwise (false, default), the all triggers that page is dependent on, including
  201. /// the \a key itself would be added as dependent triggers to current rendered page.
  202. /// \return returns true if the entry was found.
  203. ///
  204. bool fetch_frame(std::string const &key,std::string &result,bool notriggers=false);
  205. ///
  206. /// Store a string (usually some HTML part) to the cache.
  207. ///
  208. /// \param key -- the key that uniquely defines the frame.
  209. /// \param frame -- the actual value
  210. /// \param triggers -- the set of triggers that the key should depend on (\a key is added automatically)
  211. /// \param timeout -- maximal object lifetime, -1 is infinity
  212. /// \param notriggers -- if \a notriggers is true no frame dependent triggers would be added to the current
  213. /// page trigger set. Otherwise (default) current page would depend on the \a key and \a triggers as its
  214. /// dependent triggers.
  215. ///
  216. void store_frame(std::string const &key,
  217. std::string const &frame,
  218. std::set<std::string> const &triggers=std::set<std::string>(),
  219. int timeout=-1,
  220. bool notriggers=false);
  221. ///
  222. /// Store a string (usually some HTML part) to the cache.
  223. ///
  224. /// \param key -- the key that uniquely defines the frame.
  225. /// \param frame -- the actual value
  226. /// \param timeout -- maximal object lifetime, -1 is infinity
  227. /// \param notriggers -- if \a notriggers is true \a key added to the current
  228. /// page trigger set. Otherwise (default) current page would depend on the \a key
  229. ///
  230. void store_frame(std::string const &key,
  231. std::string const &frame,
  232. int timeout,
  233. bool notriggers=false);
  234. ///
  235. /// Fetch a serializeable object from the cache.
  236. ///
  237. /// \param key -- the key that uniquely defines the frame.
  238. /// \param data -- an object store fetched data
  239. /// \param notriggers -- if true, no triggers that an object is dependent on would be added to dependencies of
  240. /// the current page, otherwise (false, default), the all triggers that the object is dependent on, including
  241. /// the \a key itself would be added as dependent triggers to current rendered page.
  242. /// \return returns true if the entry was found.
  243. ///
  244. template<typename Serializable>
  245. bool fetch_data(std::string const &key,Serializable &data,bool notriggers=false)
  246. {
  247. std::string buffer;
  248. if(!fetch(key,buffer,notriggers))
  249. return false;
  250. serialization_traits<Serializable>::load(buffer,data);
  251. return true;
  252. }
  253. ///
  254. /// Store a serializeable object to the cache.
  255. ///
  256. /// \param key -- the key that uniquely defines the object.
  257. /// \param data -- the actual object
  258. /// \param triggers -- the set of triggers that the key should depend on (\a key is added automatically)
  259. /// \param timeout -- maximal object lifetime, -1 is infinity
  260. /// \param notriggers -- if \a notriggers is true no frame dependent triggers would be added to the current
  261. /// page trigger set. Otherwise (default) current page would depend on the \a key and \a triggers as its
  262. /// dependent triggers.
  263. ///
  264. template<typename Serializable>
  265. void store_data(std::string const &key,Serializable const &data,
  266. std::set<std::string> const &triggers=std::set<std::string>(),
  267. int timeout=-1,bool notriggers=false)
  268. {
  269. std::string buffer;
  270. serialization_traits<Serializable>::save(data,buffer);
  271. store(key,buffer,triggers,timeout,notriggers);
  272. }
  273. ///
  274. /// Store a serializeable object to the cache.
  275. ///
  276. /// \param key -- the key that uniquely defines the object.
  277. /// \param data -- the actual object
  278. /// \param timeout -- maximal object lifetime, -1 is infinity
  279. /// \param notriggers -- if \a notriggers is true \a key added to the current
  280. /// page trigger set. Otherwise (default) current page would depend on the \a key
  281. ///
  282. template<typename Serializable>
  283. void store_data(std::string const &key,Serializable const &data,int timeout,bool notriggers=false)
  284. {
  285. store_data<Serializable>(key,data,std::set<std::string>(),timeout,notriggers);
  286. }
  287. private:
  288. friend class triggers_recorder;
  289. void add_triggers_recorder(triggers_recorder *rec);
  290. void remove_triggers_recorder(triggers_recorder *rec);
  291. void store( std::string const &key,
  292. std::string const &data,
  293. std::set<std::string> const &triggers,
  294. int timeout,
  295. bool notriggers);
  296. bool fetch( std::string const &key,
  297. std::string &buffer,
  298. bool notriggers);
  299. struct _data;
  300. booster::hold_ptr<_data> d;
  301. http::context *context_;
  302. std::set<std::string> triggers_;
  303. std::set<triggers_recorder *> recorders_;
  304. booster::intrusive_ptr<impl::base_cache> cache_module_;
  305. uint32_t page_compression_used_ : 1;
  306. CPPCMS_UNUSED_MEMBER uint32_t reserved : 31;
  307. };
  308. }
  309. #endif