/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #ifndef CPPCMS_CACHE_INTERFACE_H #define CPPCMS_CACHE_INTERFACE_H #include #include #include #include #include #include #include #include namespace cppcms { class service; namespace impl { class base_cache; } namespace http { class context; }; class cache_interface; /// /// \brief triggers_recorder is a class that allows you to record all triggers added in certain scope. /// /// It is useful to have have "sub-dependencies" for smaller parts. /// /// For example: /// /// \code /// /// if(cache().fetch_page("news")) /// return; /// // something there /// if(cache().fetch_frame("politics",text)) /// response().out() << text; /// else { /// copy_filter politics(respone().out()); /// triggers_recorder politics_triggers(cache()); /// // some thing else there /// for(int i=0;i detach(); private: friend class cache_interface; void add(std::string const &t); struct data; booster::hold_ptr d; std::set triggers_; cache_interface *cache_; }; /// /// \brief This class is the major gateway of the application to CppCMS caching abilities. Any access too cache /// would be done via this class. /// /// CppCMS cache model supports following concepts: /// /// - \a key the unique identification of the object in cache /// - \a timeout -- the maximal time the cached object remains valid /// - \a trigger -- special key that allows fast invalidation of multiple cache objects. /// /// The first two concepts are quite popular and available in most of Web framework, but the last one is very /// unique to CppCMS that gives fine grained cache invalidation tools. /// /// Each time the page is created it automatically receives some triggers during the process of creation. /// When some object is fetched from the cache or stored into it, it adds triggers to the major page. This provides /// semi-automatic triggers management. /// /// For example: /// /// \code /// if(cache().fetch_page("main_page")) /// return; /// if(!cache().fetch_frame("article_"+id,article)) { /// article=generate_article_from_data_base(id); /// cache.store_frame("article_"+id,article); /// } /// // Generate some HTML here using article /// cache.store_page("main"); /// \endcode /// /// Let's assume that "main_page" wasn't found in cache, then we try to fetch a frame that holds only a single /// article "article_123", if it is fetched, the result is stored in a string article and the trigger "article_123" /// is automatically added to set of triggers that "main_page" depends on them. /// /// When the article updated, and "article_123" key is risen, it would automatically invalidate "main_page" as well. /// /// CppCMS cache_interface allows storing arbitrary object in cache, For this purpose they should be "serializable". /// This can be done by specializing a class cppcms::setialization_traits /// class CPPCMS_API cache_interface : public booster::noncopyable { public: /// /// Create interface object without a context, everything but /// fetch_page and store_page would work, it is not possible to /// handle pages without full i/o context /// /// \ver{v1_2} cache_interface(cppcms::service &srv); /// /// \cond INTERNAL /// /// Internal API, don't use it /// cache_interface(http::context &context); ~cache_interface(); /// \endcond /// /// Rise a trigger \a trigger. All cached objects that depend on this trigger would be invalidated /// void rise(std::string const &trigger); /// /// Add a trigger \a trigger to the list of dependencies of current page. /// void add_trigger(std::string const &trigger); /// /// Clear all CppCMS cache - use carefully /// void clear(); /// /// Remove all triggers added to current page so far /// void reset(); /// /// Get statistics about items stored in cache. May require O(n) complexity, use with care. /// /// \param keys -- the number of items stored in cache /// \param triggers -- the number of various triggers existing in the cache. /// /// Returns false if caching system is disabled. /// bool stats(unsigned &keys,unsigned &triggers); /// /// Returns true if caching system is enabled /// bool has_cache(); /// /// Opposite of \a has_cache /// bool nocache(); /// /// Fetch a page from the cache with a key \a key. If the page exists, it is written to output /// and true is returned. Otherwise false is returned. /// bool fetch_page(std::string const &key); /// /// Store page with key \a akey in cache, with timeout \a timeout. /// /// This function stores a page with dependencies on all triggers that were added so far. /// /// \param key -- the key that defines the cache. /// \param timeout -- maximal valid time of the page. \a timeout=-1 means infinite. Use with care. /// /// Note: store_page does not rise the trigger \a key, only replaces the value. /// void store_page(std::string const &key,int timeout=-1); /// /// Fetch a string (usually some HTML part) from the cache. /// /// \param key -- the key that uniquely defines the frame. /// \param result -- string to store fetched value /// \param notriggers -- if true, no triggers that a frame is dependent on would be added to dependencies of /// the current page, otherwise (false, default), the all triggers that page is dependent on, including /// the \a key itself would be added as dependent triggers to current rendered page. /// \return returns true if the entry was found. /// bool fetch_frame(std::string const &key,std::string &result,bool notriggers=false); /// /// Store a string (usually some HTML part) to the cache. /// /// \param key -- the key that uniquely defines the frame. /// \param frame -- the actual value /// \param triggers -- the set of triggers that the key should depend on (\a key is added automatically) /// \param timeout -- maximal object lifetime, -1 is infinity /// \param notriggers -- if \a notriggers is true no frame dependent triggers would be added to the current /// page trigger set. Otherwise (default) current page would depend on the \a key and \a triggers as its /// dependent triggers. /// void store_frame(std::string const &key, std::string const &frame, std::set const &triggers=std::set(), int timeout=-1, bool notriggers=false); /// /// Store a string (usually some HTML part) to the cache. /// /// \param key -- the key that uniquely defines the frame. /// \param frame -- the actual value /// \param timeout -- maximal object lifetime, -1 is infinity /// \param notriggers -- if \a notriggers is true \a key added to the current /// page trigger set. Otherwise (default) current page would depend on the \a key /// void store_frame(std::string const &key, std::string const &frame, int timeout, bool notriggers=false); /// /// Fetch a serializeable object from the cache. /// /// \param key -- the key that uniquely defines the frame. /// \param data -- an object store fetched data /// \param notriggers -- if true, no triggers that an object is dependent on would be added to dependencies of /// the current page, otherwise (false, default), the all triggers that the object is dependent on, including /// the \a key itself would be added as dependent triggers to current rendered page. /// \return returns true if the entry was found. /// template bool fetch_data(std::string const &key,Serializable &data,bool notriggers=false) { std::string buffer; if(!fetch(key,buffer,notriggers)) return false; serialization_traits::load(buffer,data); return true; } /// /// Store a serializeable object to the cache. /// /// \param key -- the key that uniquely defines the object. /// \param data -- the actual object /// \param triggers -- the set of triggers that the key should depend on (\a key is added automatically) /// \param timeout -- maximal object lifetime, -1 is infinity /// \param notriggers -- if \a notriggers is true no frame dependent triggers would be added to the current /// page trigger set. Otherwise (default) current page would depend on the \a key and \a triggers as its /// dependent triggers. /// template void store_data(std::string const &key,Serializable const &data, std::set const &triggers=std::set(), int timeout=-1,bool notriggers=false) { std::string buffer; serialization_traits::save(data,buffer); store(key,buffer,triggers,timeout,notriggers); } /// /// Store a serializeable object to the cache. /// /// \param key -- the key that uniquely defines the object. /// \param data -- the actual object /// \param timeout -- maximal object lifetime, -1 is infinity /// \param notriggers -- if \a notriggers is true \a key added to the current /// page trigger set. Otherwise (default) current page would depend on the \a key /// template void store_data(std::string const &key,Serializable const &data,int timeout,bool notriggers=false) { store_data(key,data,std::set(),timeout,notriggers); } private: friend class triggers_recorder; void add_triggers_recorder(triggers_recorder *rec); void remove_triggers_recorder(triggers_recorder *rec); void store( std::string const &key, std::string const &data, std::set const &triggers, int timeout, bool notriggers); bool fetch( std::string const &key, std::string &buffer, bool notriggers); struct _data; booster::hold_ptr<_data> d; http::context *context_; std::set triggers_; std::set recorders_; booster::intrusive_ptr cache_module_; uint32_t page_compression_used_ : 1; CPPCMS_UNUSED_MEMBER uint32_t reserved : 31; }; } #endif