]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/InProcessCache/InProcessCachePlugin.php
Merge remote branch 'origin/master' into 0.9.x
[quix0rs-gnu-social.git] / plugins / InProcessCache / InProcessCachePlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * Extra level of caching, in memory
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Cache
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2010 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Extra level of caching
39  *
40  * This plugin adds an extra level of in-process caching to any regular
41  * cache system like APC, XCache, or Memcache.
42  * 
43  * Note that since most caching plugins return false for StartCache*
44  * methods, you should add this plugin before them, i.e.
45  *
46  *     addPlugin('InProcessCache');
47  *     addPlugin('XCache');
48  *
49  * @category  Cache
50  * @package   StatusNet
51  * @author    Evan Prodromou <evan@status.net>
52  * @copyright 2010 StatusNet, Inc.
53  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
54  * @link      http://status.net/
55  */
56
57 class InProcessCachePlugin extends Plugin
58 {
59     private $_items = array();
60     private $_hits  = array();
61     private $active;
62
63     /**
64      * Constructor checks if it's safe to use the in-process cache.
65      * On CLI scripts, we'll disable ourselves to avoid data corruption
66      * due to keeping stale data around.
67      *
68      * On web requests we'll roll the dice; they're short-lived so have
69      * less chance of stale data. Race conditions are still possible,
70      * so beware!
71      */
72     function __construct()
73     {
74         parent::__construct();
75         $this->active = (PHP_SAPI != 'cli');
76     }
77
78     /**
79      * Get an item from the cache
80      * 
81      * Called before other cache systems are called (iif this
82      * plugin was loaded correctly, see class comment). If we
83      * have the data, return it, and don't hit the other cache
84      * systems.
85      *
86      * @param string &$key   Key to fetch
87      * @param mixed  &$value Resulting value or false for miss
88      *
89      * @return boolean false if found, else true
90      */
91
92     function onStartCacheGet(&$key, &$value)
93     {
94         if ($this->active && array_key_exists($key, $this->_items)) {
95             $value = $this->_items[$key];
96             if (array_key_exists($key, $this->_hits)) {
97                 $this->_hits[$key]++;
98             } else {
99                 $this->_hits[$key] = 1;
100             }
101             Event::handle('EndCacheGet', array($key, &$value));
102             return false;
103         }
104         return true;
105     }
106
107     /**
108      * Called at the end of a cache get
109      *
110      * If we don't already have the data, we cache it. This
111      * keeps us from having to call the external cache if the
112      * key is requested again.
113      *
114      * @param string $key    Key to fetch
115      * @param mixed  &$value Resulting value or false for miss
116      *
117      * @return boolean hook value, true
118      */
119
120     function onEndCacheGet($key, &$value)
121     {
122         if ($this->active && (!array_key_exists($key, $this->_items) ||
123             $this->_items[$key] != $value)) {
124             $this->_items[$key] = $value;
125         }
126         return true;
127     }
128
129     /**
130      * Called at the end of setting a cache element
131      * 
132      * Always set the cache element; may overwrite existing
133      * data.
134      *
135      * @param string  $key    Key to fetch
136      * @param mixed   $value  Resulting value or false for miss
137      * @param integer $flag   ignored
138      * @param integer $expiry ignored
139      *
140      * @return boolean true
141      */
142
143     function onEndCacheSet($key, $value, $flag, $expiry)
144     {
145         if ($this->active) {
146             $this->_items[$key] = $value;
147         }
148         return true;
149     }
150
151     /**
152      * Called at the end of deleting a cache element
153      *
154      * If stuff's deleted from the other cache, we
155      * delete it too.
156      *
157      * @param string  &$key     Key to delete
158      * @param boolean &$success Success flag; ignored
159      *
160      * @return boolean true
161      */
162      
163     function onStartCacheDelete(&$key, &$success)
164     {
165         if ($this->active && array_key_exists($key, $this->_items)) {
166             unset($this->_items[$key]);
167         }
168         return true;
169     }
170
171     /**
172      * Version info
173      *
174      * @param array &$versions Array of version blocks
175      *
176      * @return boolean true
177      */
178
179     function onPluginVersion(&$versions)
180     {
181         $url = 'http://status.net/wiki/Plugin:InProcessCache';
182
183         $versions[] = array('name' => 'InProcessCache',
184                             'version' => STATUSNET_VERSION,
185                             'author' => 'Evan Prodromou',
186                             'homepage' => $url,
187                             'description' =>
188                             _m('Additional in-process cache for plugins.'));
189         return true;
190     }
191
192     /**
193      * Cleanup function; called at end of process
194      *
195      * If the inprocess/stats config value is true, we dump
196      * stats to the log file
197      *
198      * @return boolean true
199      */
200
201     function cleanup()
202     {
203         if ($this->active && common_config('inprocess', 'stats')) {
204             $this->log(LOG_INFO, "cache size: " . 
205                        count($this->_items));
206             $sum = 0;
207             foreach ($this->_hits as $hitcount) {
208                 $sum += $hitcount;
209             }
210             $this->log(LOG_INFO, $sum . " hits on " . 
211                        count($this->_hits) . " keys");
212         }
213         return true;
214     }
215 }