[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/libraries/Smarty/libs/sysplugins/ -> smarty_cacheresource_keyvaluestore.php (source)

   1  <?php
   2  /**
   3   * Smarty Internal Plugin
   4   *
   5   * @package Smarty
   6   * @subpackage Cacher
   7   */
   8  
   9  /**
  10   * Smarty Cache Handler Base for Key/Value Storage Implementations
  11   *
  12   * This class implements the functionality required to use simple key/value stores
  13   * for hierarchical cache groups. key/value stores like memcache or APC do not support
  14   * wildcards in keys, therefore a cache group cannot be cleared like "a|*" - which
  15   * is no problem to filesystem and RDBMS implementations.
  16   *
  17   * This implementation is based on the concept of invalidation. While one specific cache
  18   * can be identified and cleared, any range of caches cannot be identified. For this reason
  19   * each level of the cache group hierarchy can have its own value in the store. These values
  20   * are nothing but microtimes, telling us when a particular cache group was cleared for the
  21   * last time. These keys are evaluated for every cache read to determine if the cache has
  22   * been invalidated since it was created and should hence be treated as inexistent.
  23   *
  24   * Although deep hierarchies are possible, they are not recommended. Try to keep your
  25   * cache groups as shallow as possible. Anything up 3-5 parents should be ok. So
  26   * »a|b|c« is a good depth where »a|b|c|d|e|f|g|h|i|j|k« isn't. Try to join correlating
  27   * cache groups: if your cache groups look somewhat like »a|b|$page|$items|$whatever«
  28   * consider using »a|b|c|$page-$items-$whatever« instead.
  29   *
  30   * @package Smarty
  31   * @subpackage Cacher
  32   * @author Rodney Rehm
  33   */
  34  abstract class Smarty_CacheResource_KeyValueStore extends Smarty_CacheResource {
  35  
  36      /**
  37       * cache for contents
  38       * @var array
  39       */
  40      protected $contents = array();
  41      /**
  42       * cache for timestamps
  43       * @var array
  44       */
  45      protected $timestamps = array();
  46  
  47      /**
  48       * populate Cached Object with meta data from Resource
  49       *
  50       * @param Smarty_Template_Cached   $cached    cached object
  51       * @param Smarty_Internal_Template $_template template object
  52       * @return void
  53       */
  54      public function populate(Smarty_Template_Cached $cached, Smarty_Internal_Template $_template)
  55      {
  56          $cached->filepath = $_template->source->uid
  57                  . '#' . $this->sanitize($cached->source->name)
  58                  . '#' . $this->sanitize($cached->cache_id)
  59                  . '#' . $this->sanitize($cached->compile_id);
  60  
  61          $this->populateTimestamp($cached);
  62      }
  63  
  64      /**
  65       * populate Cached Object with timestamp and exists from Resource
  66       *
  67       * @param Smarty_Template_Cached $cached cached object
  68       * @return void
  69       */
  70      public function populateTimestamp(Smarty_Template_Cached $cached)
  71      {
  72          if (!$this->fetch($cached->filepath, $cached->source->name, $cached->cache_id, $cached->compile_id, $content, $timestamp, $cached->source->uid)) {
  73              return;
  74          }
  75          $cached->content = $content;
  76          $cached->timestamp = (int) $timestamp;
  77          $cached->exists = $cached->timestamp;
  78      }
  79  
  80      /**
  81       * Read the cached template and process the header
  82       *
  83       * @param Smarty_Internal_Template $_template template object
  84       * @param Smarty_Template_Cached $cached cached object
  85       * @return booelan true or false if the cached content does not exist
  86       */
  87      public function process(Smarty_Internal_Template $_template, Smarty_Template_Cached $cached=null)
  88      {
  89          if (!$cached) {
  90              $cached = $_template->cached;
  91          }
  92          $content = $cached->content ? $cached->content : null;
  93          $timestamp = $cached->timestamp ? $cached->timestamp : null;
  94          if ($content === null || !$timestamp) {
  95              if (!$this->fetch($_template->cached->filepath, $_template->source->name, $_template->cache_id, $_template->compile_id, $content, $timestamp, $_template->source->uid)) {
  96                  return false;
  97              }
  98          }
  99          if (isset($content)) {
 100              $_smarty_tpl = $_template;
 101              eval("?>" . $content);
 102              return true;
 103          }
 104          return false;
 105      }
 106  
 107      /**
 108       * Write the rendered template output to cache
 109       *
 110       * @param Smarty_Internal_Template $_template template object
 111       * @param string $content content to cache
 112       * @return boolean success
 113       */
 114      public function writeCachedContent(Smarty_Internal_Template $_template, $content)
 115      {
 116          $this->addMetaTimestamp($content);
 117          return $this->write(array($_template->cached->filepath => $content), $_template->properties['cache_lifetime']);
 118      }
 119  
 120      /**
 121       * Empty cache
 122       *
 123       * {@internal the $exp_time argument is ignored altogether }}
 124       *
 125       * @param Smarty  $smarty   Smarty object
 126       * @param integer $exp_time expiration time [being ignored]
 127       * @return integer number of cache files deleted [always -1]
 128       * @uses purge() to clear the whole store
 129       * @uses invalidate() to mark everything outdated if purge() is inapplicable
 130       */
 131      public function clearAll(Smarty $smarty, $exp_time=null)
 132      {
 133          if (!$this->purge()) {
 134              $this->invalidate(null);
 135          }
 136          return -1;
 137      }
 138  
 139      /**
 140       * Empty cache for a specific template
 141       *
 142       * {@internal the $exp_time argument is ignored altogether}}
 143       *
 144       * @param Smarty  $smarty        Smarty object
 145       * @param string  $resource_name template name
 146       * @param string  $cache_id      cache id
 147       * @param string  $compile_id    compile id
 148       * @param integer $exp_time      expiration time [being ignored]
 149       * @return integer number of cache files deleted [always -1]
 150       * @uses buildCachedFilepath() to generate the CacheID
 151       * @uses invalidate() to mark CacheIDs parent chain as outdated
 152       * @uses delete() to remove CacheID from cache
 153       */
 154      public function clear(Smarty $smarty, $resource_name, $cache_id, $compile_id, $exp_time)
 155      {
 156          $uid = $this->getTemplateUid($smarty, $resource_name, $cache_id, $compile_id);
 157          $cid = $uid . '#' . $this->sanitize($resource_name) . '#' . $this->sanitize($cache_id) . '#' . $this->sanitize($compile_id);
 158          $this->delete(array($cid));
 159          $this->invalidate($cid, $resource_name, $cache_id, $compile_id, $uid);
 160          return -1;
 161      }
 162      /**
 163       * Get template's unique ID
 164       *
 165       * @param Smarty $smarty        Smarty object
 166       * @param string $resource_name template name
 167       * @param string $cache_id      cache id
 168       * @param string $compile_id    compile id
 169       * @return string filepath of cache file
 170       */
 171      protected function getTemplateUid(Smarty $smarty, $resource_name, $cache_id, $compile_id)
 172      {
 173          $uid = '';
 174          if (isset($resource_name)) {
 175              $tpl = new $smarty->template_class($resource_name, $smarty);
 176              if ($tpl->source->exists) {
 177                  $uid = $tpl->source->uid;
 178              }
 179              
 180              // remove from template cache
 181              if ($smarty->allow_ambiguous_resources) {
 182                  $_templateId = $tpl->source->unique_resource . $tpl->cache_id . $tpl->compile_id;
 183              } else {
 184                  $_templateId = $smarty->joined_template_dir . '#' . $resource_name . $tpl->cache_id . $tpl->compile_id;
 185              }
 186              if (isset($_templateId[150])) {
 187                  $_templateId = sha1($_templateId);
 188              }
 189              unset($smarty->template_objects[$_templateId]);
 190          }
 191          return $uid;
 192      }
 193  
 194      /**
 195       * Sanitize CacheID components
 196       *
 197       * @param string $string CacheID component to sanitize
 198       * @return string sanitized CacheID component
 199       */
 200      protected function sanitize($string)
 201      {
 202          // some poeple smoke bad weed
 203          $string = trim($string, '|');
 204          if (!$string) {
 205              return null;
 206          }
 207          return preg_replace('#[^\w\|]+#S', '_', $string);
 208      }
 209  
 210      /**
 211       * Fetch and prepare a cache object.
 212       *
 213       * @param string  $cid           CacheID to fetch
 214       * @param string  $resource_name template name
 215       * @param string  $cache_id      cache id
 216       * @param string  $compile_id    compile id
 217       * @param string  $content       cached content
 218       * @param integer &$timestamp    cached timestamp (epoch)
 219       * @param string  $resource_uid  resource's uid
 220       * @return boolean success
 221       */
 222      protected function fetch($cid, $resource_name = null, $cache_id = null, $compile_id = null, &$content = null, &$timestamp = null, $resource_uid = null)
 223      {
 224          $t = $this->read(array($cid));
 225          $content = !empty($t[$cid]) ? $t[$cid] : null;
 226          $timestamp = null;
 227  
 228          if ($content && ($timestamp = $this->getMetaTimestamp($content))) {
 229              $invalidated = $this->getLatestInvalidationTimestamp($cid, $resource_name, $cache_id, $compile_id, $resource_uid);
 230              if ($invalidated > $timestamp) {
 231                  $timestamp = null;
 232                  $content = null;
 233              }
 234          }
 235  
 236          return !!$content;
 237      }
 238  
 239      /**
 240       * Add current microtime to the beginning of $cache_content
 241       *
 242       * {@internal the header uses 8 Bytes, the first 4 Bytes are the seconds, the second 4 Bytes are the microseconds}}
 243       *
 244       * @param string &$content the content to be cached
 245       */
 246      protected function addMetaTimestamp(&$content)
 247      {
 248          $mt = explode(" ", microtime());
 249          $ts = pack("NN", $mt[1], (int) ($mt[0] * 100000000));
 250          $content = $ts . $content;
 251      }
 252  
 253      /**
 254       * Extract the timestamp the $content was cached
 255       *
 256       * @param string &$content the cached content
 257       * @return float the microtime the content was cached
 258       */
 259      protected function getMetaTimestamp(&$content)
 260      {
 261          $s = unpack("N", substr($content, 0, 4));
 262          $m = unpack("N", substr($content, 4, 4));
 263          $content = substr($content, 8);
 264          return $s[1] + ($m[1] / 100000000);
 265      }
 266  
 267      /**
 268       * Invalidate CacheID
 269       *
 270       * @param string $cid           CacheID
 271       * @param string $resource_name template name
 272       * @param string $cache_id      cache id
 273       * @param string $compile_id    compile id
 274       * @param string $resource_uid  source's uid
 275       * @return void
 276       */
 277      protected function invalidate($cid = null, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
 278      {
 279          $now = microtime(true);
 280          $key = null;
 281          // invalidate everything
 282          if (!$resource_name && !$cache_id && !$compile_id) {
 283              $key = 'IVK#ALL';
 284          }
 285          // invalidate all caches by template
 286          else if ($resource_name && !$cache_id && !$compile_id) {
 287              $key = 'IVK#TEMPLATE#' . $resource_uid . '#' . $this->sanitize($resource_name);
 288          }
 289          // invalidate all caches by cache group
 290          else if (!$resource_name && $cache_id && !$compile_id) {
 291              $key = 'IVK#CACHE#' . $this->sanitize($cache_id);
 292          }
 293          // invalidate all caches by compile id
 294          else if (!$resource_name && !$cache_id && $compile_id) {
 295              $key = 'IVK#COMPILE#' . $this->sanitize($compile_id);
 296          }
 297          // invalidate by combination
 298          else {
 299              $key = 'IVK#CID#' . $cid;
 300          }
 301          $this->write(array($key => $now));
 302      }
 303  
 304      /**
 305       * Determine the latest timestamp known to the invalidation chain
 306       *
 307       * @param string $cid           CacheID to determine latest invalidation timestamp of
 308       * @param string $resource_name template name
 309       * @param string $cache_id      cache id
 310       * @param string $compile_id    compile id
 311       * @param string $resource_uid  source's filepath
 312       * @return float the microtime the CacheID was invalidated
 313       */
 314      protected function getLatestInvalidationTimestamp($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
 315      {
 316          // abort if there is no CacheID
 317          if (false && !$cid) {
 318              return 0;
 319          }
 320          // abort if there are no InvalidationKeys to check
 321          if (!($_cid = $this->listInvalidationKeys($cid, $resource_name, $cache_id, $compile_id, $resource_uid))) {
 322              return 0;
 323          }
 324          
 325          // there are no InValidationKeys
 326          if (!($values = $this->read($_cid))) {
 327              return 0;
 328          }
 329          // make sure we're dealing with floats
 330          $values = array_map('floatval', $values);
 331          return max($values);
 332      }
 333  
 334      /**
 335       * Translate a CacheID into the list of applicable InvalidationKeys.
 336       *
 337       * Splits "some|chain|into|an|array" into array( '#clearAll#', 'some', 'some|chain', 'some|chain|into', ... )
 338       *
 339       * @param string $cid           CacheID to translate
 340       * @param string $resource_name template name
 341       * @param string $cache_id      cache id
 342       * @param string $compile_id    compile id
 343       * @param string $resource_uid  source's filepath
 344       * @return array list of InvalidationKeys
 345       * @uses $invalidationKeyPrefix to prepend to each InvalidationKey
 346       */
 347      protected function listInvalidationKeys($cid, $resource_name = null, $cache_id = null, $compile_id = null, $resource_uid = null)
 348      {
 349          $t = array('IVK#ALL');
 350          $_name = $_compile = '#';
 351          if ($resource_name) {
 352              $_name .= $resource_uid . '#' . $this->sanitize($resource_name);
 353              $t[] = 'IVK#TEMPLATE' . $_name;
 354          }
 355          if ($compile_id) {
 356              $_compile .= $this->sanitize($compile_id);
 357              $t[] = 'IVK#COMPILE' . $_compile;
 358          }
 359          $_name .= '#';
 360          // some poeple smoke bad weed
 361          $cid = trim($cache_id, '|');
 362          if (!$cid) {
 363              return $t;
 364          }
 365          $i = 0;
 366          while (true) {
 367              // determine next delimiter position
 368              $i = strpos($cid, '|', $i);
 369              // add complete CacheID if there are no more delimiters
 370              if ($i === false) {
 371                  $t[] = 'IVK#CACHE#' . $cid;
 372                  $t[] = 'IVK#CID' . $_name . $cid . $_compile;
 373                  $t[] = 'IVK#CID' . $_name . $_compile;
 374                  break;
 375              }
 376              $part = substr($cid, 0, $i);
 377              // add slice to list
 378              $t[] = 'IVK#CACHE#' . $part;
 379              $t[] = 'IVK#CID' . $_name . $part . $_compile;
 380              // skip past delimiter position
 381              $i++;
 382          }
 383          return $t;
 384      }
 385  
 386      /**
 387       * Check is cache is locked for this template
 388       *
 389       * @param Smarty $smarty Smarty object
 390       * @param Smarty_Template_Cached $cached cached object
 391       * @return booelan true or false if cache is locked
 392       */
 393      public function hasLock(Smarty $smarty, Smarty_Template_Cached $cached)
 394      {
 395          $key = 'LOCK#' . $cached->filepath;
 396          $data = $this->read(array($key));
 397          return $data && time() - $data[$key] < $smarty->locking_timeout;
 398      }
 399  
 400      /**
 401       * Lock cache for this template
 402       *
 403       * @param Smarty $smarty Smarty object
 404       * @param Smarty_Template_Cached $cached cached object
 405       */
 406      public function acquireLock(Smarty $smarty, Smarty_Template_Cached $cached)
 407      {
 408          $cached->is_locked = true;
 409          $key = 'LOCK#' . $cached->filepath;
 410          $this->write(array($key => time()), $smarty->locking_timeout);
 411      }
 412  
 413      /**
 414       * Unlock cache for this template
 415       *
 416       * @param Smarty $smarty Smarty object
 417       * @param Smarty_Template_Cached $cached cached object
 418       */
 419      public function releaseLock(Smarty $smarty, Smarty_Template_Cached $cached)
 420      {
 421          $cached->is_locked = false;
 422          $key = 'LOCK#' . $cached->filepath;
 423          $this->delete(array($key));
 424      }
 425  
 426      /**
 427       * Read values for a set of keys from cache
 428       *
 429       * @param array $keys list of keys to fetch
 430       * @return array list of values with the given keys used as indexes
 431       */
 432      protected abstract function read(array $keys);
 433  
 434      /**
 435       * Save values for a set of keys to cache
 436       *
 437       * @param array $keys   list of values to save
 438       * @param int   $expire expiration time
 439       * @return boolean true on success, false on failure
 440       */
 441      protected abstract function write(array $keys, $expire=null);
 442  
 443      /**
 444       * Remove values from cache
 445       *
 446       * @param array $keys list of keys to delete
 447       * @return boolean true on success, false on failure
 448       */
 449      protected abstract function delete(array $keys);
 450  
 451      /**
 452       * Remove *all* values from cache
 453       *
 454       * @return boolean true on success, false on failure
 455       */
 456      protected function purge()
 457      {
 458          return false;
 459      }
 460  
 461  }
 462  
 463  ?>


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1