<?php // // memcache alike daemon // require_once($INC . "/util.inc.php"); require_once($INC . "/prof.inc.php"); // Client side can disable the cache for various reasons (unit testing etc.) if (!isset($rg_cache_enable)) $rg_cache_enable = TRUE; if (!isset($rg_cache_core_enable)) $rg_cache_core_enable = TRUE; // timeout in miliseconds $rg_cache_timeout = 500; $rg_cache_count = 0; $rg_cache_tries = 3; if (!isset($rg_cache_socket)) $rg_cache_socket = "/var/lib/rocketgit/sockets/cache.sock"; $rg_cache = array(); $rg_cache_error = ""; if (!isset($rg_cache_debug)) $rg_cache_debug = FALSE; function rg_cache_set_error($str) { global $rg_cache_error; $rg_cache_error = $str; rg_log($str); } function rg_cache_error() { global $rg_cache_error; return $rg_cache_error; } /* * Clears all core cache */ function rg_cache_core_destroy() { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; $rg_cache = array(); } /* * Dump all tables */ function rg_cache_core_dump() { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return ''; return "rg_cache:\n" . print_r($rg_cache, TRUE); } /* * Sets a variable * TODO: Prevent cache to grow and grow. */ function rg_cache_core_set($ns_var, $value) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; //rg_log_ml("cache_core_set: $ns_var = " . print_r($value, TRUE)); $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) $tree[$token] = array(); $tree = &$tree[$token]; } $tree[$var] = $value; } /* * Merges some items into a variable */ function rg_cache_core_merge($ns_var, $list) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; //rg_log_ml("cache_core_merge: $ns_var = " . print_r($list, TRUE)); $tree = &$rg_cache; $t = explode("::", $ns_var); foreach ($t as $token) { if (!isset($tree[$token])) $tree[$token] = array(); $tree = &$tree[$token]; } foreach ($list as $k => $v) $tree[$k] = $v; return TRUE; } /* * Increments a variable */ function rg_cache_core_inc($ns_var) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) $tree[$token] = array(); $tree = &$tree[$token]; } if (!isset($tree[$var])) $ret = 1; else $ret = $tree[$var] + 1; $tree[$var] = $ret; return $ret; } /* * Retrieve a variable from cache */ function rg_cache_core_get($ns_var) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return FALSE; //rg_log("cache_core_get: $ns_var"); $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) { //rg_log("CHECK: cache_core_get: token '$token' not found, return false"); return FALSE; } $tree = &$tree[$token]; } if (isset($tree[$var])) { //rg_log_ml("CHECK: cache_core_get: found key in cache: $ns_var = " . print_r($tree[$var], TRUE)); return $tree[$var]; } //rg_log_ml("CHECK: cache_core_get: [$ns_var] not found in rg_cache. rg_cache: " . print_r($rg_cache, TRUE)); return FALSE; } /* * Unset a variable in cache * Returns FALSE if not found, else TRUE. */ function rg_cache_core_unset($ns_var) { global $rg_cache_debug; global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) { //rg_log("CHECK: cache_core_unset: token [$token] not found"); return FALSE; } $tree = &$tree[$token]; } if (isset($tree[$var])) { if ($rg_cache_debug) rg_log('cache_core_unset(' . $ns_var . ')'); unset($tree[$var]); return TRUE; } //rg_log("CHECK: cache_core_unset: key [$var] not found"); return FALSE; } /* * Push a variable in a queue */ function rg_cache_core_apush($ns_var, $value) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) $tree[$token] = array(); $tree = &$tree[$token]; } if (!isset($tree[$var])) $tree[$var] = array(); array_push($tree[$var], $value); } /* * Pop a variable from the end of a queue */ function rg_cache_core_apop($ns_var) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return FALSE; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) return FALSE; $tree = &$tree[$token]; } if (!isset($tree[$var])) return FALSE; if (empty($tree[$var])) return FALSE; return array_pop($tree[$var]); } /* * Pops and returns a variable from the begining of a queue */ function rg_cache_core_ashift($ns_var) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return FALSE; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) return FALSE; $tree = &$tree[$token]; } if (!isset($tree[$var])) return FALSE; if (empty($tree[$var])) return FALSE; return array_shift($tree[$var]); } /* * Dumps a queue */ function rg_cache_core_adump($ns_var) { global $rg_cache; global $rg_cache_core_enable; if (!$rg_cache_core_enable) return FALSE; $tree = &$rg_cache; $t = explode("::", $ns_var); $var = array_pop($t); foreach ($t as $token) { if (!isset($tree[$token])) return FALSE; $tree = &$tree[$token]; } if (!isset($tree[$var])) return FALSE; return rg_array2string($tree[$var]); } /********************************* Client side functions */ /* * Prepares a string to be send to the wire (key part) */ function rg_cache_prepare_key($s) { return addcslashes($s, "\n\r\\"); } /* * Prepares a string to be send to the wire (value part) */ function rg_cache_prepare($s) { $x = serialize($s); return addcslashes($x, "\n\r\\"); } /* * Helps to send and to decode a command */ function rg_cache_send($cmd, $para, $flags) { global $rg_cache_enable; global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_tries; global $rg_cache_count; global $rg_cache_debug; if ($rg_cache_enable === FALSE) return FALSE; $rg_cache_count++; $f = ''; if ($flags & RG_SOCKET_NO_WAIT) $f .= 'W'; $xcmd = $cmd . ' F=' . $f . ' I=' . $rg_cache_count . ' ' . $para; if ($rg_cache_debug) rg_log('Sending [' . $xcmd . ']...'); $ret = rg_socket($rg_cache_socket, $xcmd . "\n", $rg_cache_timeout, $rg_cache_tries, $flags); if ($rg_cache_debug) rg_log('Received [' . $ret . ']'); if ($ret === FALSE) return FALSE; if ($flags & RG_SOCKET_NO_WAIT) return TRUE; $a = explode("\n", $ret); foreach ($a as $line) { //if ($rg_cache_debug) // rg_log('Parsing line [' . $line . ']'); $t = explode(' ', $line, 3); if (!isset($t[1])) return FALSE; $status = $t[0]; $id = intval($t[1]); if ($id < $rg_cache_count) { if ($rg_cache_debug) rg_log('DEBUG: id: ' . $id . ' < ' . $rg_cache_count); continue; } //if ($rg_cache_debug) // rg_log('DEBUG: id: ' . $id . ' == ' . $rg_cache_count); if (strcmp($status, 'OK') != 0) { //rg_log('DEBUG: not an OK answer: ' . $status); return FALSE; } if (!isset($t[2])) return TRUE; return trim(stripcslashes($t[2])); break; } } /* * Returns a variable from the cache daemon */ function rg_cache_get($ns_var) { global $rg_cache_debug; rg_prof_start('cache_get'); $ret = FALSE; while (1) { $k = rg_cache_prepare_key($ns_var); $ret = rg_cache_core_get($k); if ($ret !== FALSE) break; $flags = 0; $r = rg_cache_send('GET', $k, $flags); if ($r === FALSE) break; $ret = @unserialize($r); if ($ret === FALSE) { rg_internal_error("Cannot userialize [$r]!"); break; } rg_cache_core_set($ns_var, $ret); break; } if ($rg_cache_debug) rg_log_ml('cache_get returns: ' . print_r($ret, TRUE)); rg_prof_end('cache_get'); return $ret; } /* * Sets a variable in the cache daemon */ function rg_cache_set($ns_var, $value, $flags) { rg_prof_start('cache_set'); while (1) { $k = rg_cache_prepare_key($ns_var); rg_cache_core_set($k, $value); $para = $k . '=' . rg_cache_prepare($value); $ret = rg_cache_send('SET', $para, $flags); if ($ret === FALSE) break; $ret = TRUE; break; } rg_prof_end('cache_set'); return $ret; } /* * Increments a variable in the cache daemon */ function rg_cache_inc($ns_var) { rg_prof_start('cache_inc'); rg_cache_core_inc($vs_var); while (1) { $k = rg_cache_prepare_key($ns_var); $ret = rg_cache_send('INC', $k, $flags); if ($ret === FALSE) break; if ($ret === TRUE) break; $ret = intval($ret); break; } rg_prof_end('cache_inc'); return $ret; } /* * Unsets a variable in the cache daemon */ function rg_cache_unset($ns_var, $flags) { global $rg_cache_debug; rg_prof_start('cache_unset'); $k = rg_cache_prepare_key($ns_var); rg_cache_core_unset($k); $ret = rg_cache_send('UNSET', $k, $flags); if ($rg_cache_debug) rg_log('cache_unset(' . $k . ')'); rg_prof_end('cache_unset'); return $ret; } /* * Merge some k=v pairs into an existing cache */ function rg_cache_merge($ns_var, $list, $flags) { rg_prof_start('cache_merge'); $k = rg_cache_prepare_key($ns_var); rg_cache_core_merge($k, $list); $para = $k . '=' . rg_cache_prepare($list); $ret = rg_cache_send('MERGE', $para, $flags); rg_prof_end('cache_merge'); return $ret; } /* * Push an array in a queue */ function rg_cache_apush($ns_var, $value, $flags) { rg_prof_start('cache_apush'); $k = rg_cache_prepare_key($ns_var); rg_cache_core_apush($k, $value); $para = $k . '=' . rg_cache_prepare($value); $ret = rg_cache_send('APUSH', $para, $flags); rg_prof_end('cache_apush'); return $ret; } /* * Restarts the cache daemon */ function rg_cache_restart() { $flags = 0; $para = ''; $ret = rg_cache_send('SHUTDOWN', $para, $flags); if ($ret === FALSE) return FALSE; rg_log('Cache restarted.'); return TRUE; } /* * Just to debug stuff */ function rg_cache_sleep() { $flags = RG_SOCKET_NO_WAIT; $para = ''; $ret = rg_cache_send('SLEEP', $para, $flags); if ($ret === FALSE) return FALSE; return TRUE; } ?>