diff --git a/CHANGELOG b/CHANGELOG index 9014509aa..726b8c44d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Implemented memcache_debug and apc_debug options for cache operations tracking - Installer: Remove system() function use (#1490139) - Password plugin: Added 'kpasswd' driver by Peter Allgeyer - Add initdb.sh to create database from initial.sql script with prefix support (#1490188) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index eceae4465..39e541c1b 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -108,6 +108,13 @@ $config['ldap_debug'] = false; // Log SMTP conversation to /smtp or to syslog $config['smtp_debug'] = false; +// Log Memcache conversation to /memcache or to syslog +$config['memcache_debug'] = false; + +// Log APC conversation to /apc or to syslog +$config['apc_debug'] = false; + + // ---------------------------------- // IMAP // ---------------------------------- diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php index 303abdac4..b3afd3fa3 100644 --- a/program/lib/Roundcube/rcube_cache.php +++ b/program/lib/Roundcube/rcube_cache.php @@ -42,11 +42,14 @@ class rcube_cache private $ttl; private $packed; private $index; + private $debug; private $cache = array(); private $cache_changes = array(); private $cache_sums = array(); private $max_packet = -1; + const DEBUG_LINE_LENGTH = 4096; + /** * Object constructor. @@ -65,12 +68,14 @@ class rcube_cache $type = strtolower($type); if ($type == 'memcache') { - $this->type = 'memcache'; - $this->db = $rcube->get_memcache(); + $this->type = 'memcache'; + $this->db = $rcube->get_memcache(); + $this->debug = $rcube->config->get('memcache_debug'); } else if ($type == 'apc') { - $this->type = 'apc'; - $this->db = function_exists('apc_exists'); // APC 3.1.4 required + $this->type = 'apc'; + $this->db = function_exists('apc_exists'); // APC 3.1.4 required + $this->debug = $rcube->config->get('apc_debug'); } else { $this->type = 'db'; @@ -261,10 +266,20 @@ class rcube_cache if ($this->type != 'db') { if ($this->type == 'memcache') { - $data = $this->db->get($this->ckey($key)); + $ckey = $this->ckey($key); + $data = $this->db->get($ckey); + + if ($this->debug) { + $this->debug('get', $ckey, $data); + } } else if ($this->type == 'apc') { - $data = apc_fetch($this->ckey($key)); + $ckey = $this->ckey($key); + $data = apc_fetch($ckey); + + if ($this->debug) { + $this->debug('fetch', $ckey, $data); + } } if ($data) { @@ -451,11 +466,19 @@ class rcube_cache $result = $this->db->replace($key, $data, MEMCACHE_COMPRESSED, $this->ttl); if (!$result) $result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl); + + if ($this->debug) { + $this->debug('set', $key, $data, $result); + } } else if ($this->type == 'apc') { if (apc_exists($key)) apc_delete($key); $result = apc_store($key, $data, $this->ttl); + + if ($this->debug) { + $this->debug('store', $key, $data, $result); + } } // Update index @@ -479,11 +502,21 @@ class rcube_cache private function delete_record($key, $index=true) { if ($this->type == 'memcache') { + $ckey = $this->ckey($key); // #1488592: use 2nd argument - $this->db->delete($this->ckey($key), 0); + $result = $this->db->delete($ckey, 0); + + if ($this->debug) { + $this->debug('delete', $ckey, null, $result); + } } else { - apc_delete($this->ckey($key)); + $ckey = $this->ckey($key); + $result = apc_delete($ckey); + + if ($this->debug) { + $this->debug('delete', $ckey, null, $result); + } } if ($index) { @@ -539,9 +572,17 @@ class rcube_cache $index_key = $this->ikey(); if ($this->type == 'memcache') { $data = $this->db->get($index_key); + + if ($this->debug) { + $this->debug('get', $index_key, $data); + } } else if ($this->type == 'apc') { $data = apc_fetch($index_key); + + if ($this->debug) { + $this->debug('fetch', $index_key, $data); + } } $this->index = $data ? unserialize($data) : array(); @@ -623,4 +664,27 @@ class rcube_cache return $this->max_packet; } + + /** + * Write memcache/apc debug info to the log + */ + private function debug($type, $key, $data = null, $result = null) + { + $line = strtoupper($type) . ' ' . $key; + + if ($data !== null) { + $line .= ' ' . ($this->packed ? $data : serialize($data)); + + if (($len = strlen($line)) > self::DEBUG_LINE_LENGTH) { + $diff = $len - self::DEBUG_LINE_LENGTH; + $line = substr($line, 0, self::DEBUG_LINE_LENGTH) . "... [truncated $diff bytes]"; + } + } + + if ($result !== null) { + $line .= ' [' . ($result ? 'TRUE' : 'FALSE') . ']'; + } + + rcube::write_log($this->type, $line); + } } diff --git a/program/lib/Roundcube/rcube_cache_shared.php b/program/lib/Roundcube/rcube_cache_shared.php index 3f0f20e41..37eb4bd53 100644 --- a/program/lib/Roundcube/rcube_cache_shared.php +++ b/program/lib/Roundcube/rcube_cache_shared.php @@ -41,11 +41,14 @@ class rcube_cache_shared private $packed; private $index; private $table; + private $debug; private $cache = array(); private $cache_changes = array(); private $cache_sums = array(); private $max_packet = -1; + const DEBUG_LINE_LENGTH = 4096; + /** * Object constructor. @@ -63,12 +66,14 @@ class rcube_cache_shared $type = strtolower($type); if ($type == 'memcache') { - $this->type = 'memcache'; - $this->db = $rcube->get_memcache(); + $this->type = 'memcache'; + $this->db = $rcube->get_memcache(); + $this->debug = $rcube->config->get('memcache_debug'); } else if ($type == 'apc') { - $this->type = 'apc'; - $this->db = function_exists('apc_exists'); // APC 3.1.4 required + $this->type = 'apc'; + $this->db = function_exists('apc_exists'); // APC 3.1.4 required + $this->debug = $rcube->config->get('apc_debug'); } else { $this->type = 'db'; @@ -256,10 +261,20 @@ class rcube_cache_shared if ($this->type != 'db') { if ($this->type == 'memcache') { - $data = $this->db->get($this->ckey($key)); + $ckey = $this->ckey($key); + $data = $this->db->get($ckey); + + if ($this->debug) { + $this->debug('get', $ckey, $data); + } } else if ($this->type == 'apc') { - $data = apc_fetch($this->ckey($key)); + $ckey = $this->ckey($key); + $data = apc_fetch($ckey); + + if ($this->debug) { + $this->debug('fetch', $ckey, $data); + } } if ($data) { @@ -439,12 +454,19 @@ class rcube_cache_shared if (!$result) { $result = $this->db->set($key, $data, MEMCACHE_COMPRESSED, $this->ttl); } + if ($this->debug) { + $this->debug('set', $key, $data, $result); + } } else if ($this->type == 'apc') { if (apc_exists($key)) { apc_delete($key); } $result = apc_store($key, $data, $this->ttl); + + if ($this->debug) { + $this->debug('store', $key, $data, $result); + } } // Update index @@ -468,11 +490,21 @@ class rcube_cache_shared private function delete_record($key, $index=true) { if ($this->type == 'memcache') { + $ckey = $this->ckey($key); // #1488592: use 2nd argument - $this->db->delete($this->ckey($key), 0); + $result = $this->db->delete($ckey, 0); + + if ($this->debug) { + $this->debug('delete', $ckey, null, $result); + } } else { - apc_delete($this->ckey($key)); + $ckey = $this->ckey($key); + $result = apc_delete($ckey); + + if ($this->debug) { + $this->debug('delete', $ckey, null, $result); + } } if ($index) { @@ -529,9 +561,17 @@ class rcube_cache_shared if ($this->type == 'memcache') { $data = $this->db->get($index_key); + + if ($this->debug) { + $this->debug('get', $index_key, $data); + } } else if ($this->type == 'apc') { $data = apc_fetch($index_key); + + if ($this->debug) { + $this->debug('fetch', $index_key, $data); + } } $this->index = $data ? unserialize($data) : array(); @@ -613,4 +653,27 @@ class rcube_cache_shared return $this->max_packet; } + + /** + * Write memcache/apc debug info to the log + */ + private function debug($type, $key, $data = null, $result = null) + { + $line = strtoupper($type) . ' ' . $key; + + if ($data !== null) { + $line .= ' ' . ($this->packed ? $data : serialize($data)); + + if (($len = strlen($line)) > self::DEBUG_LINE_LENGTH) { + $diff = $len - self::DEBUG_LINE_LENGTH; + $line = substr($line, 0, self::DEBUG_LINE_LENGTH) . "... [truncated $diff bytes]"; + } + } + + if ($result !== null) { + $line .= ' [' . ($result ? 'TRUE' : 'FALSE') . ']'; + } + + rcube::write_log($this->type, $line); + } }