diff --git a/other/cachetools/MemcacheAdmin/Config/Memcache.php b/other/cachetools/MemcacheAdmin/Config/Memcache.php new file mode 100644 index 000000000..14a4fa9cf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Config/Memcache.php @@ -0,0 +1,28 @@ + 'Server', + 'slabs_api' => 'Server', + 'items_api' => 'Server', + 'get_api' => 'Server', + 'set_api' => 'Server', + 'delete_api' => 'Server', + 'flush_all_api' => 'Server', + 'connection_timeout' => '1', + 'max_item_dump' => '100', + 'refresh_rate' => 5, + 'memory_alert' => '80', + 'hit_rate_alert' => '90', + 'eviction_alert' => '0', + 'file_path' => 'Temp/', + 'servers' => + array ( + 'Default' => + array ( + '127.0.0.1:11211' => + array ( + 'hostname' => '127.0.0.1', + 'port' => '11211', + ), + ), + ), +); \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Analysis.php b/other/cachetools/MemcacheAdmin/Library/Analysis.php new file mode 100644 index 000000000..5d5689bcd --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Analysis.php @@ -0,0 +1,332 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Analysis of memcached command response + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Analysis +{ + /** + * Merge two arrays of stats from MemCacheAdmin_ServerCommands::stats() + * + * @param $array Statistic from MemCacheAdmin_ServerCommands::stats() + * @param $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function merge($array, $stats) + { + # Checking input + if(!is_array($array)) + { + return $stats; + } + elseif(!is_array($stats)) + { + return $array; + } + + # Merging Stats + foreach($stats as $key => $value) + { + if(isset($array[$key]) && ($key != 'version') && ($key != 'uptime')) + { + $array[$key] += $value; + } + else + { + $array[$key] = $value; + } + } + return $array; + } + + /** + * Diff two arrays of stats from MemCacheAdmin_ServerCommands::stats() + * + * @param Array $array Statistic from MemCacheAdmin_ServerCommands::stats() + * @param Array $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function diff($array, $stats) + { + # Checking input + if(!is_array($array)) + { + return $stats; + } + elseif(!is_array($stats)) + { + return $array; + } + + # Diff for each key + foreach($stats as $key => $value) + { + if(isset($array[$key])) + { + $stats[$key] = $value - $array[$key]; + } + } + + return $stats; + } + + /** + * Analyse and return memcache stats command + * + * @param Array $stats Statistic from MemCacheAdmin_ServerCommands::stats() + * + * @return Array + */ + public static function stats($stats) + { + if(!is_array($stats) || (count($stats) == 0)) + { + return false; + } + + # Command set() + $stats['set_rate'] = ($stats['cmd_set'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_set'] / $stats['uptime'], 1); + + # Command get() + $stats['get_hits_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_hits'] / $stats['cmd_get'] * 100, 1); + $stats['get_misses_percent'] = ($stats['cmd_get'] == 0) ? ' - ' : sprintf('%.1f', $stats['get_misses'] / $stats['cmd_get'] * 100, 1); + $stats['get_rate'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_get'] / $stats['uptime'], 1); + + # Command delete(), version > 1.2.X + if(isset($stats['delete_hits'], $stats['delete_misses'])) + { + $stats['cmd_delete'] = $stats['delete_hits'] + $stats['delete_misses']; + $stats['delete_hits_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_hits'] / $stats['cmd_delete'] * 100, 1); + $stats['delete_misses_percent'] = ($stats['cmd_delete'] == 0) ? ' - ' : sprintf('%.1f', $stats['delete_misses'] / $stats['cmd_delete'] * 100, 1); + } + else + { + $stats['cmd_delete'] = 0; + $stats['delete_hits_percent'] = ' - '; + $stats['delete_misses_percent'] = ' - '; + } + $stats['delete_rate'] = ($stats['cmd_delete'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_delete'] / $stats['uptime'], 1); + + # Command cas(), version > 1.2.X + if(isset($stats['cas_hits'], $stats['cas_misses'], $stats['cas_badval'])) + { + $stats['cmd_cas'] = $stats['cas_hits'] + $stats['cas_misses'] + $stats['cas_badval']; + $stats['cas_hits_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_hits'] / $stats['cmd_cas'] * 100, 1); + $stats['cas_misses_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_misses'] / $stats['cmd_cas'] * 100, 1); + $stats['cas_badval_percent'] = ($stats['cmd_cas'] == 0) ? ' - ' : sprintf('%.1f', $stats['cas_badval'] / $stats['cmd_cas'] * 100, 1); + } + else + { + $stats['cmd_cas'] = 0; + $stats['cas_hits_percent'] = ' - '; + $stats['cas_misses_percent'] = ' - '; + $stats['cas_badval_percent'] = ' - '; + } + $stats['cas_rate'] = ($stats['cmd_cas'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_cas'] / $stats['uptime'], 1); + + # Command increment(), version > 1.2.X + if(isset($stats['incr_hits'], $stats['incr_misses'])) + { + $stats['cmd_incr'] = $stats['incr_hits'] + $stats['incr_misses']; + $stats['incr_hits_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_hits'] / $stats['cmd_incr'] * 100, 1); + $stats['incr_misses_percent'] = ($stats['cmd_incr'] == 0) ? ' - ' : sprintf('%.1f', $stats['incr_misses'] / $stats['cmd_incr'] * 100, 1); + } + else + { + $stats['cmd_incr'] = 0; + $stats['incr_hits_percent'] = ' - '; + $stats['incr_misses_percent'] = ' - '; + + } + $stats['incr_rate'] = ($stats['cmd_incr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_incr'] / $stats['uptime'], 1); + + # Command decrement(), version > 1.2.X + if(isset($stats['decr_hits'], $stats['decr_misses'])) + { + $stats['cmd_decr'] = $stats['decr_hits'] + $stats['decr_misses']; + $stats['decr_hits_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_hits'] / $stats['cmd_decr'] * 100, 1); + $stats['decr_misses_percent'] = ($stats['cmd_decr'] == 0) ? ' - ' : sprintf('%.1f', $stats['decr_misses'] / $stats['cmd_decr'] * 100, 1); + } + else + { + $stats['cmd_decr'] = 0; + $stats['decr_hits_percent'] = ' - '; + $stats['decr_misses_percent'] = ' - '; + } + $stats['decr_rate'] = ($stats['cmd_decr'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_decr'] / $stats['uptime'], 1); + + # Total hit & miss + #$stats['cmd_total'] = $stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr']; + #$stats['hit_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_hits']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1); + #$stats['miss_percent'] = ($stats['cmd_get'] == 0) ? '0.0' : sprintf('%.1f', ($stats['get_misses']) / ($stats['get_hits'] + $stats['get_misses']) * 100, 1); + + # Command flush_all + if(isset($stats['cmd_flush'])) + { + $stats['flush_rate'] = ($stats['cmd_flush'] == 0) ? '0.0' : sprintf('%.1f', $stats['cmd_flush'] / $stats['uptime'], 1); + } + else + { + $stats['flush_rate'] = '0.0'; + } + + # Cache size + $stats['bytes_percent'] = ($stats['limit_maxbytes'] == 0) ? '0.0' : sprintf('%.1f', $stats['bytes'] / $stats['limit_maxbytes'] * 100, 1); + + # Request rate + $stats['request_rate'] = sprintf('%.1f', ($stats['cmd_get'] + $stats['cmd_set'] + $stats['cmd_delete'] + $stats['cmd_cas'] + $stats['cmd_incr'] + $stats['cmd_decr']) / $stats['uptime'], 1); + $stats['hit_rate'] = sprintf('%.1f', ($stats['get_hits']) / $stats['uptime'], 1); + $stats['miss_rate'] = sprintf('%.1f', ($stats['get_misses']) / $stats['uptime'], 1); + + # Eviction & reclaimed rate + $stats['eviction_rate'] = ($stats['evictions'] == 0) ? '0.0' : sprintf('%.1f', $stats['evictions'] / $stats['uptime'], 1); + $stats['reclaimed_rate'] = (!isset($stats['reclaimed']) || ($stats['reclaimed'] == 0)) ? '0.0' : sprintf('%.1f', $stats['reclaimed'] / $stats['uptime'], 1); + + return $stats; + } + + /** + * Analyse and return memcache slabs command + * + * @param Array $slabs Statistic from MemCacheAdmin_ServerCommands::slabs() + * + * @return Array + */ + public static function slabs($slabs) + { + # Initializing Used Slabs + $slabs['used_slabs'] = 0; + $slabs['total_wasted'] = 0; + # Request Rate par Slabs + foreach($slabs as $id => $slab) + { + # Check if it's a Slab + if(is_numeric($id)) + { + # Check if Slab is used + if($slab['used_chunks'] > 0) + { + $slabs['used_slabs']++; + } + $slabs[$id]['request_rate'] = sprintf('%.1f', ($slab['get_hits'] + $slab['cmd_set'] + $slab['delete_hits'] + $slab['cas_hits'] + $slab['cas_badval'] + $slab['incr_hits'] + $slab['decr_hits']) / $slabs['uptime'], 1); + $slabs[$id]['mem_wasted'] = (($slab['total_chunks'] * $slab['chunk_size']) < $slab['mem_requested']) ?(($slab['total_chunks'] - $slab['used_chunks']) * $slab['chunk_size']):(($slab['total_chunks'] * $slab['chunk_size']) - $slab['mem_requested']); + $slabs['total_wasted'] += $slabs[$id]['mem_wasted']; + } + } + return $slabs; + } + + /** + * Calculate Uptime + * + * @param Integer $uptime Uptime timestamp + * + * @return String + */ + public static function uptime($uptime) + { + if($uptime > 0) + { + $days = floor($uptime/60/60/24); + $hours = $uptime/60/60%24; + $mins = $uptime/60%60; + if(($days + $hours + $mins) == 0) + { + return ' less than 1 min'; + } + return $days . ' days ' . $hours . ' hrs ' . $mins . ' min'; + } + return ' - '; + } + + /** + * Resize a byte value + * + * @param Integer $value Value to resize + * + * @return String + */ + public static function byteResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 1024) + { + break; + } + $value /= 1024; + } + return sprintf('%.1f %s', $value, $unit); + } + + /** + * Resize a value + * + * @param Integer $value Value to resize + * + * @return String + */ + public static function valueResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 1000) + { + break; + } + $value /= 1000; + } + return sprintf('%.1f%s', $value, $unit); + } + + /** + * Resize a hit value + * + * @param Integer $value Hit value to resize + * + * @return String + */ + public static function hitResize($value) + { + # Unit list + $units = array('', 'K', 'M', 'G', 'T'); + + # Resizing + foreach($units as $unit) + { + if($value < 10000000) + { + break; + } + $value /= 1000; + } + return sprintf('%.0f%s', $value, $unit); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Factory.php b/other/cachetools/MemcacheAdmin/Library/Command/Factory.php new file mode 100644 index 000000000..a94d930d2 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Factory.php @@ -0,0 +1,111 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Factory for communication with Memcache Server + * + * @author c.mahieux@of2m.fr + * @since 30/03/2010 + */ +class Library_Command_Factory +{ + private static $_object = array(); + + # No explicit call of constructor + private function __construct() {} + + # No explicit call of clone() + private function __clone() {} + + /** + * Accessor to command class instance by command type + * + * @param String $command Type of command + * + * @return void + */ + public static function instance($command) + { + # Importing configuration + $_ini = Library_Configuration_Loader::singleton(); + + # Instance does not exists + if(!isset(self::$_object[$_ini->get($command)]) || ($_ini->get($command) != 'Server')) + { + # Switching by API + switch($_ini->get($command)) + { + case 'Memcache': + # PECL Memcache API + require_once 'Memcache.php'; + self::$_object['Memcache'] = new Library_Command_Memcache(); + break; + + case 'Memcached': + # PECL Memcached API + require_once 'Memcached.php'; + self::$_object['Memcached'] = new Library_Command_Memcached(); + break; + + case 'Server': + default: + # Server API (eg communicating directly with the memcache server) + require_once 'Server.php'; + self::$_object['Server'] = new Library_Command_Server(); + break; + } + } + return self::$_object[$_ini->get($command)]; + } + + /** + * Accessor to command class instance by type + * + * @param String $command Type of command + * + * @return void + */ + public static function api($api) + { + # Instance does not exists + if(!isset(self::$_object[$api]) || ($api != 'Server')) + { + # Switching by API + switch($api) + { + case 'Memcache': + # PECL Memcache API + require_once 'Memcache.php'; + self::$_object['Memcache'] = new Library_Command_Memcache(); + break; + + case 'Memcached': + # PECL Memcached API + require_once 'Memcached.php'; + self::$_object['Memcached'] = new Library_Command_Memcached(); + break; + + case 'Server': + default: + # Server API (eg communicating directly with the memcache server) + require_once 'Server.php'; + self::$_object['Server'] = new Library_Command_Server(); + break; + } + } + return self::$_object[$api]; + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Interface.php b/other/cachetools/MemcacheAdmin/Library/Command/Interface.php new file mode 100644 index 000000000..cf080c903 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Interface.php @@ -0,0 +1,139 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Interface of communication to MemCache Server + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +interface Library_Command_Interface +{ + /** + * Constructor + * + * @return void + */ + function __construct(); + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + function stats($server, $port); + + /** + * Retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + function slabs($server, $port); + + /** + * Retrieve items from a slabs + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $slab Slab ID + * + * @return Array|Boolean + */ + function items($server, $port, $slab); + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + function get($server, $port, $key); + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration); + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + function delete($server, $port, $key); + + /** + * Flush all items on a server after delay + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay); + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search); + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command); +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php b/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php new file mode 100644 index 000000000..5808cb042 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Memcache.php @@ -0,0 +1,257 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Memcache implements Library_Command_Interface +{ + private static $_ini; + private static $_memcache; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + + # Initializing + self::$_memcache = new Memcache(); + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command + if(($return = self::$_memcache->getExtendedStats())) + { + # Delete server key based + $stats = $return[$server.':'.$port]; + return $stats; + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + # Initializing + $slabs = array(); + + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : slabs + if(($slabs = self::$_memcache->getStats('slabs'))) + { + # Finding uptime + $stats = $this->stats($server, $port); + $slabs['uptime'] = $stats['uptime']; + unset($stats); + + # Executing command : items + if(($result = self::$_memcache->getStats('items'))) + { + # Indexing by slabs + foreach($result['items'] as $id => $items) + { + foreach($items as $key => $value) + { + $slabs[$id]['items:' . $key] = $value; + } + } + return $slabs; + } + } + return false; + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + # Initializing + $items = false; + + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : slabs stats + if(($items = self::$_memcache->getStats('cachedump', $slab, self::$_ini->get('max_item_dump')))) + { + return $items; + } + return false; + } + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : get + if($item = self::$_memcache->get($key)) + { + return print_r($item, true); + } + return 'NOT_FOUND'; + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : set + if(self::$_memcache->set($key, $data, 0, $duration)) + { + return 'STORED'; + } + return 'ERROR'; + } + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + if(self::$_memcache->delete($key)) + { + return 'DELETED'; + } + return 'NOT_FOUND'; + } + + /** + * Flush all items on a server + * Warning, delay won't work with Memcache API + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : flush_all + self::$_memcache->flush(); + return 'OK'; + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + throw new Exception('PECL Memcache does not support search function, use Server instead'); + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + throw new Exception('PECL Memcache does not support telnet, use Server instead'); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php b/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php new file mode 100644 index 000000000..2493b1740 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Memcached.php @@ -0,0 +1,226 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server via PECL memcache API http://pecl.php.net/package/memcache + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Memcached implements Library_Command_Interface +{ + private static $_ini; + private static $_memcache; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + + # Initializing + self::$_memcache = new Memcached(); + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command + if(($return = self::$_memcache->getStats())) + { + # Delete server key based + $stats = $return[$server.':'.$port]; + + # Adding value that miss + $stats['delete_hits'] = ''; + $stats['delete_misses'] = ''; + $stats['incr_hits'] = ''; + $stats['incr_misses'] = ''; + $stats['decr_hits'] = ''; + $stats['decr_misses'] = ''; + $stats['cas_hits'] = ''; + $stats['cas_misses'] = ''; + $stats['cas_badval'] = ''; + + return $stats; + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + throw new Exception('PECL Memcache does not support slabs stats, use Server or Memcache instead'); + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + throw new Exception('PECL Memcache does not support slabs items stats, use Server or Memcache instead'); + } + + /** + * Send get command to server to retrieve an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : get + if($item = self::$_memcache->get($key)) + { + return print_r($item, true); + } + return self::$_memcache->getResultMessage(); + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Checking duration + if($duration == '') { $duration = 0; } + + # Executing command : set + self::$_memcache->set($key, $data, $duration); + return self::$_memcache->getResultMessage(); + } + + /** + * Delete an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + self::$_memcache->delete($key); + return self::$_memcache->getResultMessage(); + } + + /** + * Flush all items on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + public function flush_all($server, $port, $delay) + { + # Adding server + self::$_memcache->addServer($server, $port); + + # Executing command : delete + self::$_memcache->flush($delay); + return self::$_memcache->getResultMessage(); + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + throw new Exception('PECL Memcached does not support search function, use Server instead'); + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + throw new Exception('PECL Memcached does not support telnet, use Server instead'); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Command/Server.php b/other/cachetools/MemcacheAdmin/Library/Command/Server.php new file mode 100644 index 000000000..7d44f2076 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Command/Server.php @@ -0,0 +1,443 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Sending command to memcache server + * + * @author c.mahieux@of2m.fr + * @since 20/03/2010 + */ +class Library_Command_Server implements Library_Command_Interface +{ + private static $_ini; + private static $_log; + + /** + * Constructor + * + * @param Array $ini Array from ini_parse + * + * @return void + */ + public function __construct() + { + # Importing configuration + self::$_ini = Library_Configuration_Loader::singleton(); + } + + /** + * Executing a Command on a MemCache Server + * With the help of http://github.com/memcached/memcached/blob/master/doc/protocol.txt + * Return the response, or false otherwise + * + * @param String $command Command + * @param String $server Server Hostname + * @param Integer $port Server Port + * + * @return String|Boolean + */ + public function exec($command, $server, $port) + { + # Variables + $buffer = ''; + $handle = null; + + # Socket Opening + if(!($handle = @fsockopen($server, $port, $errno, $errstr, self::$_ini->get('connection_timeout')))) + { + # Adding error to log + self::$_log = utf8_encode($errstr); + Library_Data_Error::add(utf8_encode($errstr)); + return false; + } + + # Sending Command ... + fwrite($handle, $command . "\r\n"); + + # Getting first line + $buffer = fgets($handle); + + # Checking if result is valid + if($this->end($buffer)) + { + # Closing socket + fclose($handle); + + # Adding error to log + self::$_log = $buffer; + + return false; + } + + # Reading Results + while((!feof($handle))) + { + # Getting line + $line = fgets($handle); + $buffer .= $line; + + # Checking for end of MemCache command + if($this->end($line)) + { + break; + } + } + # Closing socket + fclose($handle); + + return $buffer; + } + + /** + * Check if response is at the end from memcache server + * Return true if response end, true otherwise + * + * @param String $buffer Buffer received from memcache server + * + * @return Boolean + */ + private function end($buffer) + { + # Checking command response end + if(preg_match('/(END|DELETED|OK|ERROR|SERVER_ERROR|CLIENT_ERROR|NOT_FOUND|STORED|RESET)\r\n$/', $buffer)) + { + return true; + } + return false; + } + + /** + * Parse result to make an array + * + * @param String $string String to parse + * @param Boolean $string (optionnal) Parsing stats ? + * + * @return Array + */ + public function parse($string, $stats = true) + { + # Variable + $return = array(); + + # Exploding by \r\n + $lines = preg_split('/\r\n/', $string); + + # Stats + if($stats) + { + # Browsing each line + foreach($lines as $line) + { + $data = preg_split('/ /', $line); + if(isset($data[2])) + { + $return[$data[1]] = $data[2]; + } + } + } + # Items + else + { + # Browsing each line + foreach($lines as $line) + { + $data = preg_split('/ /', $line); + if(isset($data[1])) + { + $return[$data[1]] = array(substr($data[2], 1), $data[4]); + } + } + } + return $return; + } + + /** + * Send stats command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function stats($server, $port) + { + # Executing command + if(($return = $this->exec('stats', $server, $port))) + { + return $this->parse($return); + } + return false; + } + + /** + * Send stats settings command to server + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function settings($server, $port) + { + # Executing command + if(($return = $this->exec('stats settings', $server, $port))) + { + return $this->parse($return); + } + return false; + } + + /** + * Send stats items command to server to retrieve slabs stats + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * + * @return Array|Boolean + */ + public function slabs($server, $port) + { + # Initializing + $slabs = array(); + + # Finding uptime + $stats = $this->stats($server, $port); + $slabs['uptime'] = $stats['uptime']; + unset($stats); + + # Executing command : slabs stats + if(($result = $this->exec('stats slabs', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + $slabs['active_slabs'] = $result['active_slabs']; + $slabs['total_malloced'] = $result['total_malloced']; + unset($result['active_slabs']); + unset($result['total_malloced']); + + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[0]][$key[1]] = $value; + } + + # Executing command : items stats + if(($result = $this->exec('stats items', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[1]]['items:' . $key[2]] = $value; + } + + return $slabs; + } + } + return false; + } + + /** + * Send stats cachedump command to server to retrieve slabs items + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Interger $slab Slab ID + * + * @return Array|Boolean + */ + public function items($server, $port, $slab) + { + # Initializing + $items = false; + + # Executing command : stats cachedump + if(($result = $this->exec('stats cachedump ' . $slab . ' ' . self::$_ini->get('max_item_dump'), $server, $port))) + { + # Parsing result + $items = $this->parse($result, false); + } + return $items; + } + + /** + * Send get command to server to retrieve an item + * Return the result if successful or false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to retrieve + * + * @return String + */ + public function get($server, $port, $key) + { + # Executing command : get + if(($string = $this->exec('get ' . $key, $server, $port))) + { + return preg_replace('/^VALUE ' . preg_quote($key, '/') . '[0-9 ]*\r\n/', '', $string); + } + return self::$_log; + } + + /** + * Set an item + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to store + * @param Mixed $data Data to store + * @param Integer $duration Duration + * + * @return String + */ + function set($server, $port, $key, $data, $duration) + { + # Formatting data + $data = preg_replace('/\r/', '', $data); + + # Executing command : set + if(($result = $this->exec('set ' . $key . ' 0 ' . $duration . ' ' . strlen($data) . "\r\n" . $data, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Delete an item + * Return true if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to delete + * + * @return String + */ + public function delete($server, $port, $key) + { + # Executing command : delete + if(($result = $this->exec('delete ' . $key, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Flush all items on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param Integer $delay Delay before flushing server + * + * @return String + */ + function flush_all($server, $port, $delay) + { + # Executing command : flush_all + if(($result = $this->exec('flush_all ' . $delay, $server, $port))) + { + return $result; + } + return self::$_log; + } + + /** + * Search for item + * Return all the items matching parameters if successful, false otherwise + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $key Key to search + * + * @return array + */ + function search($server, $port, $search) + { + $slabs = array(); + $items = false; + + # Executing command : slabs stats + if(($result = $this->exec('stats slabs', $server, $port))) + { + # Parsing result + $result = $this->parse($result); + unset($result['active_slabs']); + unset($result['total_malloced']); + # Indexing by slabs + foreach($result as $key => $value) + { + $key = preg_split('/:/', $key); + $slabs[$key[0]] = true; + } + } + + # Exploring each slabs + foreach($slabs as $slab => $unused) + { + # Executing command : stats cachedump + if(($result = $this->exec('stats cachedump ' . $slab . ' 0', $server, $port))) + { + # Parsing result + preg_match_all('/^ITEM ((?:.*)' . preg_quote($search, '/') . '(?:.*)) \[(?:.*)\]\r\n/mU', $result, $matchs, PREG_SET_ORDER); + + foreach($matchs as $item) + { + $items[] = $item[1]; + } + } + unset($slabs[$slab]); + } + + if(is_array($items)) + { + sort($items); + } + + return $items; + } + + /** + * Execute a telnet command on a server + * Return the result + * + * @param String $server Hostname + * @param Integer $port Hostname Port + * @param String $command Command to execute + * + * @return String + */ + function telnet($server, $port, $command) + { + # Executing command + if(($result = $this->exec($command, $server, $port))) + { + return $result; + } + return self::$_log; + } +} diff --git a/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php b/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php new file mode 100644 index 000000000..9e2a91baf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Configuration/Loader.php @@ -0,0 +1,187 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Configuration class for editing, saving, ... + * + * @author c.mahieux@of2m.fr + * @since 19/05/2010 + */ +class Library_Configuration_Loader +{ + # Singleton + protected static $_instance = null; + + # Configuration file + protected static $_iniPath = './Config/Memcache.php'; + + # Configuration needed keys + protected static $_iniKeys = array('stats_api', + 'slabs_api', + 'items_api', + 'get_api', + 'set_api', + 'delete_api', + 'flush_all_api', + 'connection_timeout', + 'max_item_dump', + 'refresh_rate', + 'memory_alert', + 'hit_rate_alert', + 'eviction_alert', + 'file_path', + 'servers'); + + # Storage + protected static $_ini = array(); + + /** + * Constructor, load configuration file and parse server list + * + * @return Void + */ + protected function __construct() + { + # Opening ini file + self::$_ini = require self::$_iniPath; + } + + /** + * Get Library_Configuration_Loader singleton + * + * @return Library_Configuration_Loader + */ + public static function singleton() + { + if(!isset(self::$_instance)) + { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * Config key to retrieve + * Return the value, or false if does not exists + * + * @param String $key Key to get + * + * @return Mixed + */ + public function get($key) + { + if(isset(self::$_ini[$key])) + { + return self::$_ini[$key]; + } + return false; + } + + /** + * Servers to retrieve from cluster + * Return the value, or false if does not exists + * + * @param String $cluster Cluster to retreive + * + * @return Array + */ + public function cluster($cluster) + { + if(isset(self::$_ini['servers'][$cluster])) + { + return self::$_ini['servers'][$cluster]; + } + return array(); + } + + /** + * Check and return server data + * Return the value, or false if does not exists + * + * @param String $server Server to retreive + * + * @return Array + */ + public function server($server) + { + foreach(self::$_ini['servers'] as $cluster => $servers) + { + if(isset(self::$_ini['servers'][$cluster][$server])) + { + return self::$_ini['servers'][$cluster][$server]; + } + } + return array(); + } + + /** + * Config key to set + * + * @param String $key Key to set + * @param Mixed $value Value to set + * + * @return Boolean + */ + public function set($key, $value) + { + self::$_ini[$key] = $value; + } + + /** + * Return actual ini file path + * + * @return String + */ + public function path() + { + return self::$_iniPath; + } + + /** + * Check if every ini keys are set + * Return true if ini is correct, false otherwise + * + * @return Boolean + */ + public function check() + { + # Checking configuration keys + foreach(self::$_iniKeys as $iniKey) + { + # Ini file key not set + if(!isset(self::$_ini[$iniKey])) + { + return false; + } + } + return true; + } + + /** + * Write ini file + * Return true if written, false otherwise + * + * @return Boolean + */ + public function write() + { + if($this->check()) + { + return is_numeric(file_put_contents(self::$_iniPath, '<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Error container + * + * @author elijaa@free.fr + * @since 11/10/2010 + */ +class Library_Data_Error +{ + private static $_errors = array(); + + /** + * Add an error to the container + * Return true if successful, false otherwise + * + * @param String $error Error message + * + * @return Boolean + */ + public static function add($error) + { + return array_push(self::$_errors, $error); + } + + /** + * Return last Error message + * + * @return Mixed + */ + public static function last() + { + return (isset(self::$_errors[count(self::$_errors) - 1])) ? self::$_errors[count(self::$_errors) - 1] : null; + } + + /** + * Return errors count + * + * @return Integer + */ + public static function count() + { + return count(self::$_errors); + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/HTML/Components.php b/other/cachetools/MemcacheAdmin/Library/HTML/Components.php new file mode 100644 index 000000000..a94597aaf --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/HTML/Components.php @@ -0,0 +1,147 @@ +<)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> ><)))°> + * + * Manipulation of HTML + * + * @author c.mahieux@of2m.fr + * @since 05/04/2010 + */ +class Library_HTML_Components +{ + /** + * Dump server list in an HTML select + * + * @return string + */ + public static function serverSelect($name, $selected = '', $class = '', $events = '') + { + # Loading ini file + $_ini = Library_Configuration_Loader::singleton(); + + # Select Name + $serverList = ''; + } + + /** + * Dump cluster list in an HTML select + * + * @return string + */ + public static function clusterSelect($name, $selected = '', $class = '', $events = '') + { + # Loading ini file + $_ini = Library_Configuration_Loader::singleton(); + + # Select Name + $clusterList = ''; + } + + /** + * Dump server response in proper formatting + * + * @param string $hostname Hostname + * @param string $port Port + * @param mixed $data Data (reponse) + * + * @return string + */ + public static function serverResponse($hostname, $port, $data) + { + $header = 'Server ' . $hostname . ':' . $port . "\r\n"; + $return = ''; + if(is_array($data)) + { + foreach($data as $string) + { + $return .= $string . "\r\n"; + } + return $header . htmlentities($return, ENT_NOQUOTES | ENT_IGNORE, "UTF-8") . "\r\n"; + } + return $header . $return . $data . "\r\n"; + } + + /** + * Dump api list un HTML select with select name + * + * @param String $iniAPI API Name from ini file + * @param String $id Select ID + * + * @return String + */ + public static function apiList($iniAPI = '', $id) + { + return ''; + } + + /** + * Used to see if an option is selected + * + * @param String $actual Actual value + * @param String $selected Selected value + * + * @return String + */ + private static function selected($actual, $selected) + { + if($actual == $selected) + { + return 'selected="selected"'; + } + } +} \ No newline at end of file diff --git a/other/cachetools/MemcacheAdmin/Library/Loader.php b/other/cachetools/MemcacheAdmin/Library/Loader.php new file mode 100644 index 000000000..24b766374 --- /dev/null +++ b/other/cachetools/MemcacheAdmin/Library/Loader.php @@ -0,0 +1,9 @@ +Cluster '+''+'
+ + | +
+
+ + |
+
+
+ Execute telnet command on one or all memcached servers
+ + +
+
+
+
+ Server
+
+
+
+
+
+
+ + + |
+
+ You can use this thing to execute any telnet command to any memcached server
+ + It will connect to the server, execute the command and return it in the console + + + + + For more informations about memcached commands, see memcached protocol + here + |
+
+
+ Search for a key on one or all memcached servers
+ + +
+ Key
+
+
+
+
+
+ Server
+
+
+
+
+
+
+ + + |
+
+ Warning ! This thing is only for debuging issue, do not use it in a production environment as it can lock + or impact your memcached servers performances. + Also keep in mind that it does not list all keys. It lists keys up to a certain buffer size (1 or 2MB), and it list key that are expired. + + You can also use a PCRE regular expression + |
+