cppcms::cache_iface
Table of Contents
Role
This class provides access to cache API of cppcms. It is usually accessed by cache
member of application
or worker_thread
.
In order to use cache, you should enable it in CppCMS configurations, otherwise, dummy cache would be used.
Objects that are stored in cache:
Various objects can be stored in cache using unique key.
- Output pages -- including two versions compressed and not for user agents that support gzip compression or not.
- HTML Frames -- or simple strings stored in cache.
- Serializable objects.
Each one of them has little bit different semantics and API.
Note: Keys starting with underscore "_" are reserved for internal CppCMS use.
General
CppCMS provides sophisticated cache system that allows keep its consistency using special triggers that allow cleanup dependent groups of entries using single call.
However, in many cases, timeout only based approach is good enough. So, we would divide the API into two sections:
- Trigger-less cache access
- Full trigger based cache access
Trigger-less cache access
Web Page
bool fetch_page(string const &key)
-- fetch page from cache. If it is fetched,true
is returned and output is prepared, otherwise false is returned.Note: The output is prepared according to request of user agent --- compressed or not compressed format. Thus, output stream may include already compressed data, so you should not try to append any output after you use this function.
void store_page(string const &key,int timeout=-1);
-- store prepared output in cache usingtimeout
in seconds.Note: default timeout = -1 -- infinite.
For example:
if(cache.fetch_page("main")) return; ... render(...) cache.store_page("main",3600);
The page can be removed from cache calling:
void rise(string const &key)
-- that removes data associated with this key.
HTML frames and C++ Objects.
You can fetch such objects using:
bool fetch_frame(string const &key, string &result, bool notriggers=false); bool fetch_data(string const &key, serializable &data, bool notriggers=false);
Note: Because we work without triggers you should specify notriggers
as true.
For example:
roles user_roles; // some serializable object if(cache.fetch_data("user_"+user_id,user_roles,true)) ....
You can store these objects using:
void store_frame(string const &key, string const &frame, int timeout, bool notriggers=false); void store_data(string const &key, serializable const &data, int timeout, bool notriggers=false);
Notes:
- When working without triggers, specify
notriggers
totrue
, - You specify timeout in seconds, when -1 is infinity.
notriggers
option forstore_data
andstore_frame
are available from cppcms v0.0.3.
For example:
roles user_roles; // some serializable object string key="user_"+user_id; if(!cache.fetch_data(key,user_roles,true)) { load_user_roles_from_db(user_id,user_roles); cache.store_data(key,user_roles,-1,true); }
As in case of web pages you can clean data from cache using void rise(string const &key)
member function.
Triggers based cache
Concept
First of all basic concept --- every stored key has triggers --- other keys that can be risen and the cache would be clean. Each key has at least one trigger --- itself.
For example you have article #1234 in blog that may be displayed in several places:
- Summary of all topics (summary)
- Rss feed (rss)
- Summary for specific category #5 it belongs to.
- Article itself
So the structure of triggers may look like this
summary
depends onarticle_1234
,article_1233
andarticle_1232
,summary
rss
would depend onarticle_1234
up toarticle_1224
andrss
cat_5
would depend onarticle_1234
andarticle_1100
andcat_5
post_1234
would depend onarticle_1234
andpost_1234
.
So, if we "rise" trigger article_1234
by calling rise("article_1234")
, all these cached entries would be automatically dropped.
So every cached object has a set of triggers associated with it that would cause its cleanup. This is the general idea of CppCMS cache system.
Manual Triggers Management
You can add triggers to current HTML page calling:
void add_trigger(string const &trigger);
Thus, when the page is stored calling store_page(key,timeout)
, this trigger would be automatically added. For example
for(i=0;i<articles.size();i++) { content.articles_summary.push_back(articles[i]); cache.add_trigger("article_" + articles[i].id); } render("summary",content); cache.store_page("summary",3600);
Then when we update some content we simply call rise()
to cleanup all dependent pages:
void on_update_article(article a) { save_article_to_db(a); cache.rise("article_"+a.id); }
Such triggers allows keep cache consistent in relatively simple way.
Semi-automatic dependencies management
CppCMS cache system provides some automation of dependencies management.
For example, if you have general cached C++ objects or some prepared HTML parts like headers, footers, than you may want to make sure that their updates would cause cleanup of dependent pages and keeping them consistent.
When you call store_frame
, store_data
, fetch_frame
, fetch_data
with parameter notriggers
set to false (this is default) it's triggers are automatically added to dependencies of current page.
For example:
if(cache.fetch_page("main")) return; if(!cache.fetch_data("options",opts)) { load_opts(opts); cache.store_data("options",opts); } /// Generate some HTML here cache.store_page("main");
Because we call fetch_data
and store_data
with default parameter notriggers=false
--- trigger "options" is automatically added to key "main"
So next time, you update "options" and rise it's trigger, all pages that actually used options would be automatically cleaned up.
Setting Triggers for Stored Objects
You can also manage triggers for stored objects:
void store_frame(string const &key, string const &frame, set<string> const &trig=set<string>(), int timeout=-1, bool notriggers=false); void store_data(string const &key, serializable const &data, set<string> const &trig=set<string>(), int timeout=-1, bool notriggers=false);
You can specify the set of trigger for specific object and define whether you want them to be added to current page triggers set.
Note: You should specify these dependencies manually.
For example:
if(cache.fetch_page("main")) return; if(!cache.fetch_data("options",opts)) { load_opts(opts); cache.store_data("options",opts); } if(!cache.fetch_frame("sidebar",sidebar)) { /// Generate sidebar set<string> tags; tags.insert("options"); cache.store_frame("sidebar",sidebar,tags); } /// Generate some HTML here using sidebar; cache.store_page("main");
Now, in this case, main
depends on sidebar
and options
and sidebar
depends on options
only.
Some Important Notes
- Storing data is cache never rises its trigger. You should rise trigger manually
- If you manage cache consistency correctly you may never use timeouts at all
In some cases, full cache consistency may hurt performance (think of sidebar that includes hits statistics) and cleanup pages too frequently.
In such cases, it is better to work without full triggers, but in this case you must specify reasonable timeouts.
Function
void reset();
allows to clear all triggers that where added to current page.
General Operations
void clear()
-- clear all cache in the system.bool stats(unsigned &keys,unsigned &triggers)
-- fetch statistics from cache system.Note: function returns false if cache system is disabled.