Cache duration and configuration tips
Posted by primeminister | Filed under Cake-Toppings
As you know you can cache several elements in you application. When I wrote a value to the cache I did it by setting the duration in the third parameter of write:
Cache::write('cache_key', 'value to cache',array(
'config'=>'default',
'duration'=>'+1 day')
);
But today I learned a lesson from Mark Story that this was a bug and it is fixed and doens’t work anymore. It is ignored.
So how do I set the duration before read/write for specific data in my code?
First of all you have to set the Cache engine in APP/config/core.php to the engine you want to use. I mostly use the File engine:
Cache::config('default', array(
'engine' => 'File',
'duration'=> '+2 hours',
'probability'=> 100,
'path' => CACHE,
'prefix' => 'cake_',
'lock' => false,
'serialize' => true)
);
Then use Cache::set() to set the duration before every read/write action
Cache::set(array('duration' => '+1 day'));
if (!$cachedata = Cache::read(('cache_key','default')) {
// retrieve data if cache is empty
$data = $this->Model->read(null, $id);
Cache::set(array('duration' => '+1 day'));
Cache::write('cache_key', $data, 'default');
}
So you have to set the duration before read AND write. Not very DRY and short code IMHO.
Then Mark Story told his secret how he uses cache durations etc. It was a nice one. Just define a couple of cache configurations and set the duration you need for every configuration. Most of the time I need three: 2 hours, 1 day and 1 week. So here it is:
// File engine caching
// short
Cache::config('short', array(
'engine' => 'File',
'duration'=> '+2 hours',
'probability'=> 100,
'path' => CACHE,
'prefix' => 'cake_',
'lock' => false,
'serialize' => true)
);
// medium
Cache::config('medium', array(
'engine' => 'File',
'duration'=> '+1 day',
'probability'=> 100,
'path' => CACHE,
'prefix' => 'cake_',
'lock' => false,
'serialize' => true)
);
// long
Cache::config('long', array(
'engine' => 'File',
'duration'=> '+1 week',
'probability'=> 100,
'path' => CACHE,
'prefix' => 'cake_',
'lock' => false,
'serialize' => true)
);
// default = medium
Cache::config('default', Cache::settings('medium'));
And then you can just use the config name to set the duration:
if (!$cachedata = Cache::read(('cache_key','short')) {
// retrieve data if cache is empty
$data = $this->Model->read(null, $id);
Cache::write('cache_key', $data, 'short');
}
How genius is that! :) And if you want to change the duration you just change it in the core.php Cache::config or add another one with different duration.
Thanks a lot to Phally and Mark Story!
March 19th, 2009 at 22:12
[...] Cache duration and configuration tips [...]
March 31st, 2009 at 12:44
I’m trying to achieve the same functionality with multiple file cache storages different by the duration. And I found interesting thing in the \cake\libs\cache.php (CakePHP 1.2.2.8120) in the Cache::read method
$success = $_this->_Engine[$engine]->read($settings['prefix'] . $key);
It looks for me that it uses engine only to check the data and doesn’t take into account actual storage.
Next, let’s take a look at at \cake\libs\cache\file.php, FileEngine::read method, there is a line there:
if ($cachetime !== false && ($cachetime settings['duration']) < $cachetime))
I’m thinking about the part of the code after || sign and can’t find an explanation for it.
But because of this part if you will try to reverse cache storage definition (long, medium, short), you will find the problem I did – cache doesn’t work. I.e. cached data is treated as invalid.
E.g. we have “+1 month” and “+1 day” storages, first storage has got file that was cached until 2009-05-01 15:29:44 ($cachetime), and today is 2009-03-31 15:37:31 ($time) when it’s time to check the data for validness, it’s calculated:
- $cachetime !== false is true and OK
- $cachetime settings['duration']) < $cachetime) becomes 2009-03-31 15:37:31 + 86400 < 2009-05-01 15:29:44 and it’s true. So, the entire expression is true and file goes to dev/null
On the other hand I’m new to CakePHP and probably I’ve just missed something and I would appreciate any help here.
March 31st, 2009 at 12:49
It’s stripped tags in last line of code, so you can take a look at line #169 (the next after $cachetime = intval($this->__File->read(11)); one)
March 31st, 2009 at 23:05
Hi Taras: best way to find out is entering the IRC channel #cakephp on freenode. A lot of people there that can help you more quickly then I can now..
April 1st, 2009 at 05:27
Thank you for the hint, I’ll definitely find the answer somewhere. But I just want to mention again, that multiple file cache storages must be defined in the way you shown in your post – in ascending order by duration, otherwise it won’t work.
April 1st, 2009 at 08:39
@Taras: You read and write and set the cache config explicitly. SO how come that the order of the configs in core.php will be of any influence?
April 1st, 2009 at 08:49
When Cache::read calls FileEngine::read actual storage’s settings aren’t passed there (I understand that I probably missed something), but when I added a dump to the FileEngine::read method to show me the actual settings it’s shown data the was defined in the _last_ file storage defined in core.php
So, when it evaluates line #169 (that I explained above) it uses incorrect values.
April 1st, 2009 at 08:50
Interesting Taras… I will dive into that myself. If this is true, it is a bug.
April 1st, 2009 at 21:14
Taras: you were right. I made a ticket with a testcase patch: https://trac.cakephp.org/ticket/6262
April 1st, 2009 at 21:23
Charlie,
Thank you for your help in clarifying the issue.
April 2nd, 2009 at 07:38
@Taras: Sorry, my bad. It is working perfectly. I used it wrong. If you use the config name for every read and write action it is wroking fine.
If you are not sure, make a testcase (or change my patch at https://trac.cakephp.org/ticket/6262 )
April 2nd, 2009 at 13:11
Charlie,
You probably won’t believe in this, but according to my tests – cache works fine when defined right in the action, but doesn’t work when defined in the core.php. Moreover, even if you initialize another storage engine right in the action – other ones will work fine.
Btw, I used storage names in the read/write from the beginning.
April 2nd, 2009 at 13:13
File a ticket on trac.cakephp.org. Reference to my ticket and specify this. They will help you
April 2nd, 2009 at 13:15
Charlie,
Thank you again for your help. And you are right that we probably need to finish the conversation here.
April 3rd, 2009 at 20:40
I came across the same “problem”. I don’t know if it is really a problem but it IS making most of my cache writes register as expired.. and it makes using Cache a bit more of a headache.
Seems to be that when you READ a cache file it will check against two values to see if should be expired. First it will compare to the defined expiration… if you set one, ie:
Cache::write(‘filename’, ‘data’, ‘+1 day’);
Then it ALSO checks against the DEFAULT expiration duration + current time. It is 3600 (1 hour) by default.
Strange thing (to me) is that it is checking if cachetime (+1 day) is greater than time + duration (current time + 3600). If it is.. it is considered expired. So, if I write a cache that expires in +1 day.. and try to read that cache within 23 hours, it will be considered expired.
I’m still trying to wrap my head around this but so far a workaround seems to be if you set the default duration for your cache config to something longer than you typically use in your app.. like +1 month. Then, as long as you aren’t caching anything longer than that, it will work as it had previously (and you can just write in the duration as your third param in Cache::write)