Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
deja_vu.inc
1 <?php
17 // We use a control file to enable/disable Deja Vu, since it must be flushed
18 // each time it is turned off. See scripts/dejavu_management.php
19 define('SQ_DEJA_VU_CONTROL', SQ_DATA_PATH.'/private/conf/.dejavu');
20 define('SQ_DEJA_VU_MEMCACHE_PREFIX', 'sq_deja_vu|');
21 
22 // Storage types
23 define('SQ_DEJA_VU_ASSET', 'asset');
24 define('SQ_DEJA_VU_LOCALE', 'locale_manager');
25 
40 class Deja_Vu extends MySource_Object
41 {
47  private $_memcache;
48 
49 
55  private $_enabled;
56 
57 
66  function __construct()
67  {
68  $this->_enabled = 0;
69  if (is_file(SQ_DEJA_VU_CONTROL)) {
70  $this->_enabled = (int) file_get_contents(SQ_DEJA_VU_CONTROL);
71  if ($this->_enabled !== 1) $this->_enabled = 0;
72  }
73 
74  if ($this->enabled() === 1) {
75  assert_true(extension_loaded('memcache'), 'Cannot use Deja Vu; it requires the memcache PECL extension installed within , which is not installed');
76  assert_true(file_exists(SQ_DATA_PATH.'/private/conf/memcache.inc'), 'Cannot use Deja Vu; the Memcache configuration file is not set');
77 
78  $memcache_conf = require(SQ_DATA_PATH.'/private/conf/memcache.inc');
79  $hosts =& $memcache_conf['hosts'];
80  $services =& $memcache_conf['services'];
81 
82  assert_true(count($hosts) > 0, 'Cannot use Deja Vu; no hosts are defined in the Memcache configuration file');
83  assert_true(array_key_exists('deja_vu', $services) === TRUE, 'Cannot use Deja Vu; no Memcache hosts are assigned');
84  assert_true(count($services['deja_vu']) > 0, 'Cannot use Deja Vu; no Memcache hosts are assigned');
85 
86  // If has the memcache module installed, instantiate it and try to load some config.
87  $this->_memcache = new Memcache;
88 
89  foreach ($services['deja_vu'] as $host_key => $weight) {
90  assert_true(array_key_exists($host_key, $hosts) === TRUE, 'Cannot use Deja Vu; host key "'.$host_key.'" assigned for use for Deja Vu but not defined as a host');
91  $host = $hosts[$host_key];
92  $this->_memcache->addServer($host['host'], $host['port'], $host['persistent'], $weight, $host['timeout'], $host['retry_interval'], $host['status'], Array($this, 'failureCallback'));
93  }
94 
95  $this->_memcache->setCompressThreshold($memcache_conf['compression_threshold'], $memcache_conf['compression_min_saving']);
96 
97  // Register for updates, so that we can keep our memories fresh.
98  $em = $GLOBALS['SQ_SYSTEM']->getEventManager();
99  $em->addEventListener($this, Array( 'AssetStatusUpdate',
100  'assetDeleted',
101  'AssetUpdate',
102  'ContentsUpdated',
103  'attributeChange',
104  'AssetTypeUpdate',
105  'MetadataUpdate',
106  'MetadataDeleted',
107  )
108  );
109  }
110 
111  }//end constructor
112 
113 
120  public function enabled()
121  {
122  return $this->_enabled;
123 
124  }//end enabled()
125 
126 
136  public function recall($type, $assetid = NULL, $contextid = NULL)
137  {
138  //ignore shadow assets
139  if (strpos($assetid, ':') !== FALSE) return NULL;
140  // bug fix #5831 Inconsistent contents when using Deja Vu and Rollback
141  // If in rollback don't worry about getting cached content for assets
142  if (defined('SQ_ROLLBACK_VIEW') && SQ_ROLLBACK_VIEW) return null;
143  $cache_key = $this->_getCacheKey($type, $assetid, $contextid);
144  switch ($type) {
145  case 'asset':
146  $obj = $this->_memcache->get($cache_key);
147  if (!$obj) {
148  // Cache miss for $cache_key
149  return NULL;
150  }
151 
152  // If $obj is an undefined object, it's an asset stored without the class being included yet.
153  // We must include the correct asset and try again.
154  if ($obj instanceof __PHP_Incomplete_Class) {
155  $obj_def = (array) $obj;
156  // Determine the correct type code
157  $type_code = strtolower($obj_def['__PHP_Incomplete_Class_Name']);
158 
159  $am =& $GLOBALS['SQ_SYSTEM']->am;
160  if ($am->installed($type_code)) {
161  $am->includeAsset($type_code);
162 
163  // We need to re-get the object to re-unserialize.
164  $obj = $this->_memcache->get($cache_key);
165  } else {
166  // Should never happen, but just in case..
167  log_error('Deja Vu could not load asset type "'.$type_code.'" for #'.$assetid.'. Assuming the asset type has been uninstalled, so forgetting this asset.');
168  $this->forget($assetid, $type);
169  return NULL;
170  }
171  }//end if
172 
173  return $obj;
174  break;
175 
176  default:
177  $data = $this->_memcache->get($cache_key);
178 
179  if (!$data) {
180  return NULL;
181  } else {
182  return $data;
183  }
184  break;
185 
186  }//end switch
187 
188  }//end recall
189 
190 
201  public function remember($type, $assetid, $object, $contextid = NULL)
202  {
203  //ignore shadow assets
204  if (strpos($assetid, ':') !== FALSE) return NULL;
205  // bug fix #5831 Inconsistent contents when using Deja Vu and Rollback
206  // If in rollback we shouldn't be really caching the content for asset
207  if (defined('SQ_ROLLBACK_VIEW') && SQ_ROLLBACK_VIEW) return null;
208  return $this->_memcache->set($this->_getCacheKey($type, $assetid, $contextid), $object);
209  }//end remember()
210 
211 
220  public function forget($type, $assetid = NULL, $contextid = NULL)
221  {
222  return $this->_memcache->delete($this->_getCacheKey($type, $assetid, $contextid));
223  }//end forget()
224 
225 
232  public function forgetAll()
233  {
234  return $this->_memcache->flush();
235 
236  }//end forgetAll()
237 
238 
249  private function _getCacheKey($type, $assetid = NULL, $contextid = NULL)
250  {
251  switch ($type) {
252  case SQ_DEJA_VU_LOCALE:
253  return SQ_DEJA_VU_MEMCACHE_PREFIX.'|'.$type;
254  break;
255  default:
256  $contextid = is_null($contextid) ? $GLOBALS['SQ_SYSTEM']->getContextId() : $contextid;
257  return SQ_DEJA_VU_MEMCACHE_PREFIX.$contextid.'\\'.$assetid.'|'.$type;
258  break;
259  }
260 
261  }//end _getCacheKey()
262 
263 
264  /******* EVENT HANDLERS *************************************************/
265 
266 
275  public function onAssetStatusUpdate(&$broadcaster, $vars)
276  {
277  // Status is non contextable, so forget everything..
278  $contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
279  foreach ($contexts as $contextid => $context) {
280  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id, $contextid);
281  }
282 
283  }//end onAssetStatusUpdate
284 
293  public function onAssetDeleted(&$broadcaster, $vars)
294  {
295  $contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
296  foreach ($contexts as $contextid => $context) {
297  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id, $contextid);
298  }
299 
300  }//end onAssetDeleted
301 
302 
311  public function onAssetUpdate(&$broadcaster, $vars = Array())
312  {
313  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id);
314 
315  }//end onAssetUpdate
316 
317 
326  public function onContentsUpdated(&$broadcaster, $vars)
327  {
328  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id);
329 
330  }//end onContentsUpdated
331 
332 
341  public function onAttributeChange(&$broadcaster, $vars)
342  {
343  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id);
344 
345  }//end onAttributeChange
346 
347 
356  public function onAssetTypeUpdate(&$broadcaster, $vars = Array())
357  {
358  $contexts = $GLOBALS['SQ_SYSTEM']->getAllContexts();
359  foreach ($contexts as $contextid => $context) {
360  $this->forget(SQ_DEJA_VU_ASSET, $broadcaster->id, $contextid);
361  }
362 
363  }//end onAssetTypeUpdate
364 
365 
366  /******* UTILITIES *************************************************/
367 
368 
375  public function enable()
376  {
377  if (!$this->enabled()) {
378  $rv = (bool) file_put_contents(SQ_DEJA_VU_CONTROL, '1');
379  if ($rv) {
380  $this->_enabled = 1;
381  }
382  }
383  return $rv;
384 
385  }//end enable()
386 
387 
394  public function disable()
395  {
396  $rv = FALSE;
397  if ($this->enabled()) {
398  $rv = (bool) file_put_contents(SQ_DEJA_VU_CONTROL, '0');
399  if ($rv) {
400  $this->_enabled = 0;
401  }
402  }
403  return $rv;
404 
405  }//end disable()
406 
407 
417  function failureCallback($hostname, $port)
418  {
419  log_error(get_class()." failure communicating with $hostname:$port", E_USER_WARNING);
420 
421  }//end failureCallback()
422 
423 
424 }//end class
425 
426 ?>