Main  /  Edit version 1  /  Edit version 2  /   /  Users Area

Difference "Advanced Caching" ver. 1 versus ver. 2

Content:

<!--toc-->
## Introduction
Unlike many caching systems available today in different
web frameworks that are based on "key-value-timeout"
concepts, CppCMS's cache provides "key-triggers-value-timeout"
model that provides an easy and efficient way to
invalidate cache - keep it consistent.
Each cached object has following properties:
1. The unique key that identifies it.
2. The life time of the entry that can be infinite
3. The set of triggers that can invalidate the cache.
For example we have following triggers set:
![Triggers](/pics/triggers-scheme.png)
So we can invalidate multiple keys by rising different
triggers.
For example. when we update article about `drugs` we
rise a trigger `new_drugs` and invalidate both `health`
news and `news_all` that depend on this trigger.
On the other hand the "technology" news remain untouched.
This method allows us to keep the web site both
up-to-date and fully cached.
## Managing Triggers
### Direct Handling
When you cache a page you can easily add a trigger
to it using `cppcms::cache_interface::add_trigger()` function.
For example:
if(cache().fetch_page("my_page"))
return;
// Create some content
cache().add_trigger("my_trigger");
cache().store_page("my_page");
Now the `my_page` object would depend on two triggers
`my_trigger` and `my_page` itself.
You can clear the cache by rising a trigger:
cache().rise("my_trigger");
Would create cache for all objects that depend on it
including `my_page`.
If you use cache interface to store some objects
or text frames in it you can pass a set of triggers
directly as a parameter.
std::set<std::string> my_triggers;
my_triggers.insert("my_trigger");
cache().store_data("my_object",my_object,my_triggers);
Note: `my_object` trigger would be automatically added
to the `my_object` key.
### Automatic Dependencies Tracking
CppCMS cache allows to track object dependencies
automatically.
Let's assume we have following code:
if(cache().fetch_page("foo"))
return;
if(!cache().fetch_data("settings",settings)) {
load_settings(settings);
cache().store_data("settings",settings);
}
// do something
cache().store_page("foo");
Now we use a "setting" object in order to create
"foo" page. When cal call `fetch_data()` or `store_data()`
the "settings" trigger is added as a dependency to "foo".
More then that, if "settings" has its own triggers:
if(!cache().fetch_data("settings",settings)) {
load_settings(settings);
std::set<std::string> settings_triggers;
settings_triggers.insert("bar");
cache().store_data("settings",settings);
}
Then our "foo" page would automatically depend
on "settings" and "bar" triggers, so for example
rising "bar" would invalidate both "foo" and "settings".
The automatic recording can be disabled by
setting `no_triggers` parameter to "true" for `store_data()`
and "fetch_data()" for example:
if(!cache().fetch_data("settings",settings,true)) {
load_settings(settings);
cache().store_data("settings",settings,-1,true);
// -1 for infinite timeout
}
### Nested Tacking
The triggers are recorder for the frame, but sometimes
we want to record the triggers on lower level. For example:
- "page"
- "settings"
- "local_settings"
- "global_settings"
Like:
if(cache().fetch_page("foo"))
return;
if(!cache().fetch_data("settings",settings)) {
if(!cache().fetch_data("local_settings",ls) {
...
}
if(!cache().fetch_data("global_settings",gs) {
...
}
load_settings(settings,ls,gs)
cache().store_data("settings",settings);
}
cache().store_page("foo");
But the `local_settings` and `global_settings` triggers
would not be recorder for "settings" because "store\_data()"
function does not know about them.
So in order to handle such situation we have a
[triggers\_recorder](/cppcms_ref_v0_99/classcppcms_1_1triggers__recorder.html) object:
We change our code in following way:
if(!cache().fetch_data("settings",settings)) {
cppcms::triggers_recorder rec(cache());
if(!cache().fetch_data("local_settings",ls) {
...
}
if(!cache().fetch_data("global_settings",gs) {
...
}
load_settings(settings,ls,gs);
cache().store_data("settings",settings,rec.detach());
}
We start an instance of a `triggers_recorder` and
and the end of the section we recorder the triggers
on we detach it by calling `detach()` member function
that returns a set of triggers, in our case
the `local_settings` and `global_settings`
We got all we needed
## Recording Text Frames
### From The Application
Consider we have a situation where some part
of the HTML frame is shared for many pages
and it requires some non-trivial methods
to create it (for example make some complex query
to the DB in order to fetch all the data we need).
CppCMS provides us a simple [copy_filter](/cppcms_ref_v0_99/classcppcms_1_1copy__filter.html).
We can use it as following:
std::string frame;
if(cache().fetch_frame("key",frame)) {
response().out() << frame;
}
else {
cppcms::copy_filter tee(response().out());
...
// generate something heavy
...
cache().store_frame("key",tee.detach());
}
Note: If the frame exist in the cache, we
write it to the output stream directly, but if
it does not, we generate it in a usual way,
but we attach a small filter `tee` to the
output stream that would copy all the data
to a temporary buffer and would write it
to the stream as well.
When we call `tee.detach()` we remove the filter
and return the entire frame we had recorder.
### From The View
It is much more natural to cache some frames
from the views - the template engine. CppCMS
provides such a tool.

Sidebar:

## Related
- [cache\_interface](/cppcms_ref_v0_99/classcppcms_1_1cache__interface.html)

About

CppCMS is a web development framework for performance demanding applications.

Support This Project

SourceForge.net Logo

Поддержать проект

CppCMS needs You


Navigation

Main Page


Valid CSS | Valid XHTML 1.0