Smarty Forum Index Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon.

cache Handler for APC

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Tips and Tricks
View previous topic :: View next topic  
Author Message
dragon001
Smarty Rookie


Joined: 12 Feb 2005
Posts: 5

PostPosted: Sat Jan 13, 2007 12:09 pm    Post subject: cache Handler for APC Reply with quote

I was using eAccelarator as Cache Engine to now, but since i install php5 there was the apc package already included.
So I removed eaccelerator and utilized apc more then before.
But i didn't find an alternativ solution to the cache handler,
so here is the apc cache handler for Smarty:

Code:
<?php
  /**
   * Smarty Cache Handler<br>
   * utilizing APC extension (http://apc.net/HomeUk)<br>
   *
   * @package    Smarty
   * @subpackage plugins
   */
  /**
  * Modifikations by
  *     Chris Westerfield
  */
 
  /**
   * Helper function for smarty_cache_APC()
   * Clears a whole hierarchy of cache entries.
   *
   * @access  private
   * @param   array  $hierarchy      hierarchical array of cache ids
   * @return  void
   *
   * @see     smarty_cache_apc()
   */
  function _APC_clear_cache(&$hierarchy) {
    foreach ($hierarchy as $key => $value) {
      if (is_array($value)) {
        _APC_clear_cache($value);
      }
      else {
        apc_delete($value);
      }
    }
  }

  /**
   * Helper function for smarty_cache_apc()
   * Checks whether a cached content has been expired by reading the content's header.
   *
   * @access  private
   * @param   string    $cache_content      the cached content
   * @return  boolean                       TRUE if cache has been expired, FALSE otherwise
   *
   * @see     smarty_cache_apc()
   */
  function _apc_hasexpired(&$cache_content) {
    $split      = explode("\n", $cache_content, 2);
    $attributes = unserialize($split[0]);

    if ($attributes['expires'] > 0 && time() > $attributes['expires'])
      return true;
    else
      return false;
  }

  /**
   * Smarty Cache Handler<br>
   * utilizing apc extension (http://apc.net/HomeUk)<br>
   *
   * Name:     smarty_cache_apc<br>
   * Type:     Cache Handler<br>
   * Purpose:  Replacement for the file based cache handling of Smarty. smarty_cache_apc() is
   *           using Turck apc extension to minimize disk usage.
   * File:     cache.apc.php<br>
   * Date:     Dec 2, 2003<br>
   *
   * Usage Example<br>
   * <pre>
   * $smarty = new Smarty;
   * $smarty->cache_handler_func = 'smarty_cache_apc';
   * $smarty->caching = true;
   * $smarty->display('index.tpl');
   * </pre>
   *
   * @author   André Rabold
   * @version  RC-1
   *
   * @param    string   $action         Cache operation to perform ( read | write | clear )
   * @param    mixed    $smarty         Reference to an instance of Smarty
   * @param    string   $cache_content  Reference to cached contents
   * @param    string   $tpl_file       Template file name
   * @param    string   $cache_id       Cache identifier
   * @param    string   $compile_id     Compile identifier
   * @param    integer  $exp_time       Expiration time
   * @return   boolean                  TRUE on success, FALSE otherwise
   *
   * @link     http://apc.net/HomeUk
   *           (apc homepage)
   * @link     http://smarty.php.net/manual/en/section.template.cache.handler.func.php
   *           (Smarty online manual)
   */
  function smarty_cache_apc($action, &$smarty, &$cache_content, $tpl_file=null, $cache_id=null, $compile_id=null, $exp_time=null)
  {
    if(!function_exists("apc")) {
      $smarty->trigger_error("cache_handler: PHP Extension \"apc\" (http://apc.net/HomeUk) not installed.");
      return false;
    }

    // Create unique cache id:
    // We are using smarty's internal functions here to be as compatible as possible.
    $_auto_id    = $smarty->_get_auto_id($cache_id, $compile_id);
    $_cache_file = substr($smarty->_get_auto_filename(".", $tpl_file, $_auto_id),2);
    $apc_id  = "smarty_apc|".$_cache_file;

    // The index contains all stored cache ids in a hierarchy and can be iterated later
    $apc_index_id = "smarty_apc_index";

    switch ($action) {

      case 'read':
        // read cache from shared memory
        $cache_content = apc_get($apc_id);
        if (!is_null($cache_content) && _apc_hasexpired($cache_content)) {
          // Cache has been expired so we clear it now by calling ourself with another parameter :)
          $cache_content = null;
          smarty_cache_apc('clear', $smarty, $cache_content, $tpl_file, $cache_id, $compile_id);
        }

        $return = true;
        break;

      case 'write':
        // save cache to shared memory
        $current_time = time();
        if (is_null($exp_time) || $exp_time < $current_time)
          $ttl = 0;
        else
          $ttl = $exp_time - time();

        // First run garbage collection
        #apc_gc();

        // Put content into cache
        #apc_lock($apc_id);
        apc_store($apc_id, $cache_content, $ttl);

        // Create an index association
        #apc_lock($apc_index_id);
        $apc_index = apc_get($apc_index_id);
        if (!is_array($apc_index))
          $apc_index = array();
        $indexes = explode(DIRECTORY_SEPARATOR, $_cache_file);
        $_pointer =& $apc_index;
        foreach ($indexes as $index) {
          if (!isset($_pointer[$index]))
            $_pointer[$index] = array();
          $_pointer =& $_pointer[$index];
        }
        $_pointer = $apc_id;
        apc_store($apc_index_id, $apc_index, 0);
        #apc_unlock($apc_index_id);

        #apc_unlock($apc_id);
        break;

      case 'clear':
        // clear cache info
        apc_lock($apc_index_id);
        $apc_index = apc_get($apc_index_id);
        if (is_array($apc_index)) {
          if (empty($cache_id) && empty($compile_id) && empty($tpl_file)) {
            // clear all cache
            #apc_lock($apc_id);
            _APC_clear_cache($apc_index);
            #apc_unlock($apc_id);
            $apc_index = array();
          }
          else {
            // clear single file or cache group
            $indexes = explode(DIRECTORY_SEPARATOR, $_cache_file);
            if (is_null($tpl_file))
              array_pop($indexes);

            $_pointer =& $apc_index;
            $_failed = false;
            foreach ($indexes as $index) {
              if (!isset($_pointer[$index])) {
                $_failed = true;
                break;
              }
              $_pointer =& $_pointer[$index];
            }

            if (!$_failed) {
              if (is_array($_pointer)) {
                // Clear cache group
                _APC_clear_cache($_pointer);
              }
              else {
                // Clear single file
                #apc_lock($_pointer);
                apc_delete($_pointer);
                #apc_unlock($_pointer);
              }
              $_pointer = null;
            }
          }
        }
        apc_ store ($apc_index_id, $apc_index, 0);
        #apc_unlock($apc_index_id);

        $return = true;
        break;

      default:
        // error, unknown action
        $smarty->trigger_error("cache_handler: unknown action \"$action\"");
        $return = false;
        break;
    }
    return $return;
  }
?>

I didn't test it jet, so be warned
Back to top
View user's profile Send private message
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Sat Jan 13, 2007 8:01 pm    Post subject: Reply with quote

Ahh. Cool.

I've been meaning to do a port of this but haven't had the time. I'll have to test it to see how it goes.

Thanks!
Back to top
View user's profile Send private message
dragon001
Smarty Rookie


Joined: 12 Feb 2005
Posts: 5

PostPosted: Sat Jan 13, 2007 8:11 pm    Post subject: Reply with quote

it should work fine.
the only thing i recognized is,
that apc doesn't have a gc command to remove old scripts.
I removed them via # (but left them in the script).

storage and deleting functions where replaced by there corresponding funktions.

renamed also the eaccelerator in variables and function defnitions to keep the distanz between the handlers
^^

have fun

^^
Back to top
View user's profile Send private message
boots
Administrator


Joined: 16 Apr 2003
Posts: 5611
Location: Toronto, Canada

PostPosted: Sat Jan 13, 2007 10:11 pm    Post subject: Reply with quote

btw: at one point, I considered creating a generalized cache handler using something like http://pear.php.net/package/System_SharedMemory (I'm not sure if I would use that package, but it contains the main idea). As I don't change the shared memory options on my servers that often, I never got around to it.
Back to top
View user's profile Send private message
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Tips and Tricks All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP