• how to enable caching with memcached?#

  • redman Reply #1, 4 years, 1 month ago

    Reply
    hi,

    i'm considering running memcache daemon on a site, so i'm just trying to get my head around caching objects. i've got a few questions:

      [list]
    • do i have to manually add things to the cache with xpdo->toCache() and xpdo->fromCache(), or do i only need to specify cache time-to-live values as part of xpdo->getObject()?
    • do i need to initialise the cache manager first? From the docs i can see that xpdo->$_cacheEnabled is false by default - how do i enable caching? do i just set $xpdo->$_cacheEnabled = true?
    • i can see the xpdo->getCacheManager method, but how could i override it with my own that inherits from xpdoCacheManager? to enable use of memcache do i just have to set $xpdo->config['cache_db_handler'] to Memcache?
    [/list]

    are there any examples of this in the 0.9.7 code or anywhere else i can have a look at?

    cheers


  • splittingred Reply #2, 4 years, 1 month ago

    Reply
    Quote from: redman at Apr 10, 2008, 04:16 AM
    hi,

    i'm considering running memcache daemon on a site, so i'm just trying to get my head around caching objects. i've got a few questions:

      [list]
    • do i have to manually add things to the cache with xpdo->toCache() and xpdo->fromCache(), or do i only need to specify cache time-to-live values as part of xpdo->getObject()?
    • do i need to initialise the cache manager first? From the docs i can see that xpdo->$_cacheEnabled is false by default - how do i enable caching? do i just set $xpdo->$_cacheEnabled = true?
    • i can see the xpdo->getCacheManager method, but how could i override it with my own that inherits from xpdoCacheManager? to enable use of memcache do i just have to set $xpdo->config['cache_db_handler'] to Memcache?
    [/list]

    are there any examples of this in the 0.9.7 code or anywhere else i can have a look at?

    cheers

    To turn on DB caching, in your xPDO constructor, make sure the $config param (the 4th one) has this key:

    XPDO_OPT_CACHE_DB => true


    As for using a custom CacheManager, it's pretty easy. Just create a class for your framework that extends the xPDO class, and then override the getCacheManager function. For example, I have one in my framework that goes like this:

    class LTC extends xPDO {
        function __construct() {    
            
            $this->_loadConfig();
            $this->config = array_merge(array(
                XPDO_OPT_CACHE_DB => $this->config['db_cache'],
                XPDO_OPT_CACHE_PATH => $this->config['lib_path'].'cache/',
                XPDO_OPT_HYDRATE_FIELDS => true,
                XPDO_OPT_HYDRATE_ADHOC_FIELDS => true,
                XPDO_OPT_HYDRATE_RELATED_OBJECTS => true,
                XPDO_OPT_TABLE_PREFIX => '',
                XPDO_OPT_VALIDATOR_CLASS => 'validation.iltcvalidator',
                XPDO_OPT_VALIDATE_ON_SAVE => true,
            ),$this->config);
    
           $host = $this->config['db_type'] .
                    ':host='.$this->config['db_host'] .
                    ';dbname='.$this->config['db_name'];
    	parent::__construct(
    		$host,
    		$this->config['db_user'],
    		$this->config['db_pass'],
    		$this->config,
    		array(
    			PDO_ATTR_ERRMODE => PDO_ERRMODE_SILENT,
    			PDO_ATTR_PERSISTENT => false,
    			PDO_MYSQL_ATTR_USE_BUFFERED_QUERY => true
    		));
    
    	$this->setPackage('ltc',$this->config['lib_path'].'/model/');
        }
    
       ...
    
        function getCacheManager$class = 'cache.xPDOCacheManager') {
            if (isset($this->config['cache_disabled']) && $this->config['cache_disabled']) {
                $this->_cacheEnabled = false;
                return null;
            }
            if ($this->cacheManager === null) {
                if ($this->loadClass($class, XPDO_CORE_PATH, true, true)) {
                    // can override the cache manager, if you want
                    $cacheManagerClass = isset($this->config['CacheManager.class']) ? $this->config['CacheManager.class'] : 'cache.ltcCacheManager';
                    if ($className = $this->loadClass($cacheManagerClass, '', false, true)) {
                        if ($this->cacheManager = new $className($this)) {
                            $this->_cacheEnabled = true;
                        }
                    } else {
                        $this->_log(XPDO_LOG_LEVEL_FATAL,sprintf($ltc->lexicon['cachemanager_err_nf'],$class));
                    }
                }
            }
            return $this->cacheManager;
        }
    }
    


    Then you can use this object anywhere, instead of $xpdo = new xPDO, use it like: $ltc = new LTC

    which then you can customize the object there to override/utilize xPDO methods to your framework.

    Hope that helps!




  • redman Reply #3, 4 years, 1 month ago

    Reply
    thanks, i'll give this a go.


  • redman Reply #4, 4 years, 1 month ago

    Reply
    thought i'd post a follow-up for anyone who wanted to do this too.

    here's the really simple way of implementing memcache daemon with xpdo:

    1) install memcached and the memcache pecl package.
    2) start memcached with a command like:
    memcached -d -m 1024 -l 10.0.0.1 -p 11211
    note: change 10.0.0.1 to the IP address of the server you've started memcached on, and 11211 is the port.

    3) extend the xPDO object. in the constructor of your custom class, initialise and connect to memcached as follows:
    class MyXPDO extends xPDO
    {
        function __construct($dsn, $username= '', $password= '', $tablePrefix= '', $driverOptions= null) 
    	{
    		parent::__construct($dsn, $username, $password, $tablePrefix, $driverOptions);
    
    		// set the name of the caching system to use to Memcache.
    		$this->config = array_merge(array('cache_db_handler' => 'Memcache'), $this->config);
    
    		// connect to the cache manager.
    		if ($cacheManager = $this->getCacheManager())
    			$cacheManager->objcache->connect('10.0.0.1', 11211);
    	}
    }
    


    Now, when you want to cache an object, just specify a time-to-live parameter, e.g.
      // retrieve user and cache their object for half an hour
      $user = $xpdo->get('User', array('id' => $modx->getUserLoginID()), 1800);
    


    xpdo will handle the details of caching the object with memcached as long as a time-to-live is given, and it will automatically retrieve objects from the cache too if objects are still fresh.

    hope this helps someone...


  • sirlancelot Reply #5, 4 years, 1 month ago

    Reply
    Wow, this is absolutely awesome. I had no idea that the xPDOFileCache methods were named after the Memcache class methods. Every day I work with xPDO I am amazed!


  • opengeek Reply #6, 4 years, 1 month ago

    Reply
    As an aside, for more recent versions of xPDO from SVN, the constructor has changed slightly, though it still works if you just pass a string table_prefix. Here is an alternative constructor for an extended xPDO class if you are passing an options array:
    <?php
    class MyXPDO extends xPDO {
        function __construct($dsn, $username= '', $password= '', $options= array(), $driverOptions= null) {
            // set the name of the caching system to use to Memcache.
            $options[XPDO_OPT_DB_CACHE_HANDLER]= 'Memcache';
    
            parent::__construct($dsn, $username, $password, $options, $driverOptions);
    
            // connect to the cache manager.
            if ($this->getCacheManager()) {
                $this->cacheManager->objcache->connect('10.0.0.1', 11211);
    	}
    }
    ?>

    I also modified it so that in PHP 4, the objcache->connect() will be called on the reference to the cache manager, rather than a copy (not an issue in PHP 5).


  • redman Reply #7, 4 years ago

    Reply
    here's a follow-up to my follow-up:

    you aren't restricted to only caching objects. if you have say, a blog, and want to cache headlines to display in a most recent entries box, you could cache the entire html output, so your function could be as follows:

    // snippet to return latest articles
    include_once(/path/to/MyXPDO.class.php)
    $xpdo = $MyXPDO();
    
    echo getRecentArticles($xpdo, 5);
    
    // params are an xPDO object, and the number of recent articles to return
    function getRecentArticles($xpdo, $num)
    {
    	// we can't cache this using xPDO directly since we aren't retrieving an object. So we'll do it ourselves.
    	// first, check whether there is data in the cache
    	if($cacheManager = $xpdo->getCacheManager())
    	{
    		// creating a key like this means a unique key will be created depending on the parameters the function was called with.
    		$key = md5('blogs::getRecentArticles: num: '.$num);
    		
    		// if the html isn't already in the cache, set a flag so we can cache the result after generating it.
    		if ($html = $cacheManager->get($key))
    		{
    			return $html;
    		}
    		else
    		{
    			$inCache = false;
    		}
    	}
    
    	// not in the cache, so perform query, then cache the final output
    	$sql = 'SELECT ...';
    	// process and format output and put it in $html
    	$html = ...
    
    	if (is_object($cacheManager) && !$inCache)
    		$cacheManager->set($key, $html, 1800);
    
    	return $html;
    }
    


    Doing your own caching like this means that your site should fly since the complex data is already cached.

    Extensions of this would be to delete the entry in the cache when saving a new blog post to keep the site dynamic and up-to-date while still retaining the benefits of caching.


  • jusmeig Reply #8, 7 months, 2 weeks ago

    Reply
    Does there exist a step by step guide to enabling memcache as a caching solution in Revolution?
    I see the Cache Handler Class in system setting, this needs to change?



  • stefanp_safilo Reply #9, 3 months, 3 weeks ago

    Reply
    Quote from: jusmeig at Oct 05, 2011, 03:56 AM
    Does there exist a step by step guide to enabling memcache as a caching solution in Revolution?
    I see the Cache Handler Class in system setting, this needs to change?

    I'm interested in an answer to this question... since no one seemed to read mine here: http://forums.modx.com/thread/73459/memcached-and-persistent-db-connect-howto#dis-post-408155