]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/InProcessCache/InProcessCachePlugin.php
Profile::current() suits better here.
[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 class InProcessCachePlugin extends Plugin
57 {
58     private $_items = array();
59     private $_hits  = array();
60     private $active;
61
62     /**
63      * Constructor checks if it's safe to use the in-process cache.
64      * On CLI scripts, we'll disable ourselves to avoid data corruption
65      * due to keeping stale data around.
66      *
67      * On web requests we'll roll the dice; they're short-lived so have
68      * less chance of stale data. Race conditions are still possible,
69      * so beware!
70      */
71     function __construct()
72     {
73         parent::__construct();
74         $this->active = (PHP_SAPI != 'cli');
75     }
76
77     /**
78      * Get an item from the cache
79      *
80      * Called before other cache systems are called (iif this
81      * plugin was loaded correctly, see class comment). If we
82      * have the data, return it, and don't hit the other cache
83      * systems.
84      *
85      * @param string &$key   Key to fetch
86      * @param mixed  &$value Resulting value or false for miss
87      *
88      * @return boolean false if found, else true
89      */
90     function onStartCacheGet(&$key, &$value)
91     {
92         if ($this->active && array_key_exists($key, $this->_items)) {
93             $value = $this->_items[$key];
94             if (array_key_exists($key, $this->_hits)) {
95                 $this->_hits[$key]++;
96             } else {
97                 $this->_hits[$key] = 1;
98             }
99             Event::handle('EndCacheGet', array($key, &$value));
100             return false;
101         }
102         return true;
103     }
104
105     /**
106      * Called at the end of a cache get
107      *
108      * If we don't already have the data, we cache it. This
109      * keeps us from having to call the external cache if the
110      * key is requested again.
111      *
112      * @param string $key    Key to fetch
113      * @param mixed  &$value Resulting value or false for miss
114      *
115      * @return boolean hook value, true
116      */
117     function onEndCacheGet($key, &$value)
118     {
119         if ($this->active && (!array_key_exists($key, $this->_items) ||
120             $this->_items[$key] != $value)) {
121             $this->_items[$key] = $value;
122         }
123         return true;
124     }
125
126     /**
127      * Called at the end of setting a cache element
128      *
129      * Always set the cache element; may overwrite existing
130      * data.
131      *
132      * @param string  $key    Key to fetch
133      * @param mixed   $value  Resulting value or false for miss
134      * @param integer $flag   ignored
135      * @param integer $expiry ignored
136      *
137      * @return boolean true
138      */
139     function onEndCacheSet($key, $value, $flag, $expiry)
140     {
141         if ($this->active) {
142             $this->_items[$key] = $value;
143         }
144         return true;
145     }
146
147     /**
148      * Called at the end of deleting a cache element
149      *
150      * If stuff's deleted from the other cache, we
151      * delete it too.
152      *
153      * @param string  &$key     Key to delete
154      * @param boolean &$success Success flag; ignored
155      *
156      * @return boolean true
157      */
158     function onStartCacheDelete(&$key, &$success)
159     {
160         if ($this->active && array_key_exists($key, $this->_items)) {
161             unset($this->_items[$key]);
162         }
163         return true;
164     }
165
166     /**
167      * Version info
168      *
169      * @param array &$versions Array of version blocks
170      *
171      * @return boolean true
172      */
173     function onPluginVersion(array &$versions)
174     {
175         $url = 'http://status.net/wiki/Plugin:InProcessCache';
176
177         $versions[] = array('name' => 'InProcessCache',
178                             'version' => GNUSOCIAL_VERSION,
179                             'author' => 'Evan Prodromou',
180                             'homepage' => $url,
181                             'description' =>
182                             // TRANS: Plugin dscription.
183                             _m('Additional in-process cache for plugins.'));
184         return true;
185     }
186
187     /**
188      * Cleanup function; called at end of process
189      *
190      * If the inprocess/stats config value is true, we dump
191      * stats to the log file
192      *
193      * @return boolean true
194      */
195     function cleanup()
196     {
197         if ($this->active && common_config('inprocess', 'stats')) {
198             $this->log(LOG_INFO, "cache size: " .
199                        count($this->_items));
200             $sum = 0;
201             foreach ($this->_hits as $hitcount) {
202                 $sum += $hitcount;
203             }
204             $this->log(LOG_INFO, $sum . " hits on " .
205                        count($this->_hits) . " keys");
206         }
207         return true;
208     }
209 }