<?php // // memcache alike daemon // require_once($INC . "/util.inc.php"); require_once($INC . "/sql.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; // timeout in miliseconds $rg_cache_timeout = 100; 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 = TRUE; 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; } /* * Dump all tables */ function rg_cache_core_dump() { global $rg_cache; 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; //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; //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; } /* * Increments a variable */ function rg_cache_core_inc($ns_var) { global $rg_cache; $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; //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; $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])) { 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; $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; $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]); } /* * Pop a variable from the begining of a queue */ function rg_cache_core_ashift($ns_var) { global $rg_cache; $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; $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 implode(",", $tree[$var]); } /********************************* Client side functions */ /* * Returns a variable from the cache daemon * @timeout_in_ms is the connection timeout not variable timeout. */ function rg_cache_get($ns_var) { global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_enable; global $rg_cache_debug; rg_prof_start("cache_get"); if ($rg_cache_debug) rg_log_enter("cache_get($ns_var)"); $ret = FALSE; while (1) { $ret = rg_cache_core_get($ns_var); if ($ret !== FALSE) break; if ($rg_cache_enable === FALSE) break; $c = rg_socket($rg_cache_socket, "GET " . $ns_var . "\n", $rg_cache_timeout, 1); if ($c === FALSE) break; $t = explode(" ", $c, 2); if (strcmp($t[0], "OK") != 0) break; if (!isset($t[1])) break; $x = trim(stripcslashes($t[1])); $ret = @unserialize($x); if ($ret === FALSE) { rg_internal_error("Cannot userialize [$x]!"); break; } rg_cache_core_set($ns_var, $ret); break; } if ($rg_cache_debug) { rg_log("ret=" . rg_array2string($ret)); rg_log_exit(); } rg_prof_end("cache_get"); return $ret; } /* * Prepares a string to be send to the wire */ function rg_cache_prepare($s) { $x = serialize($s); return addcslashes($x, "\n\r\\"); } /* * Sets a variable in the cache daemon */ function rg_cache_set($ns_var, $value) { global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_enable; global $rg_cache_debug; rg_prof_start("cache_set"); if ($rg_cache_debug) rg_log_ml_enter("cache_set: $ns_var = " . print_r($value, TRUE)); $ret = FALSE; while (1) { rg_cache_core_set($ns_var, $value); if ($rg_cache_enable === FALSE) break; $c = rg_socket($rg_cache_socket, "SET " . $ns_var . "=" . rg_cache_prepare($value) . "\n", $rg_cache_timeout, 3); if ($c === FALSE) break; if (strncmp($c, "OK", 2) != 0) break; $ret = TRUE; break; } if ($rg_cache_debug) rg_log_exit(); rg_prof_end("cache_set"); return $ret; } /* * Increments a variable in the cache daemon */ function rg_cache_inc($ns_var) { global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_enable; global $rg_cache_debug; rg_prof_start("cache_inc"); if ($rg_cache_debug) rg_log_enter("cache_inc($ns_var)"); $ret = FALSE; while (1) { rg_cache_core_inc($vs_var); if ($rg_cache_enable === FALSE) break; $c = rg_socket($rg_cache_socket, "INC " . $ns_var . "\n", $rg_cache_timeout, 1); if ($c === FALSE) break; if (strncmp($c, "OK", 2) != 0) break; $v = strstr($c, " v="); if ($v === FALSE) break; $ret = intval($v); break; } if ($rg_cache_debug) rg_log_exit(); rg_prof_end("cache_inc"); return $ret; } /* * Unsets a variable in the cache daemon */ function rg_cache_unset($ns_var) { global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_enable; global $rg_cache_debug; rg_prof_start("cache_unset"); if ($rg_cache_debug) rg_log_enter("cache_unset($ns_var)" . " enable=" . ($rg_cache_enable ? "true" : "false")); $ret = FALSE; while (1) { rg_cache_core_unset($ns_var); if ($rg_cache_enable === FALSE) break; $ret = rg_socket($rg_cache_socket, "UNSET " . $ns_var . "\n", $rg_cache_timeout, 1); if ($ret === FALSE) break; if (strncmp($ret, "NOT_FOUND", 9) == 0) break; // TODO: return old value? if (strncmp($ret, "OK", 2) != 0) { rg_internal_error("Invalid answer: $ret"); break; } $ret = TRUE; break; } if ($rg_cache_debug) { rg_log($ret === TRUE ? "success" : "fail"); rg_log_exit(); } rg_prof_end("cache_unset"); return $ret; } /* * Merge some k=v pairs into an existing cache */ function rg_cache_merge($ns_var, $list) { global $rg_cache_socket; global $rg_cache_timeout; global $rg_cache_enable; global $rg_cache_debug; rg_prof_start("cache_merge"); if ($rg_cache_debug) rg_log_ml_enter("cache_merge: $ns_var = " . print_r($list, TRUE)); $ret = FALSE; while (1) { rg_cache_core_merge($ns_var, $list); if ($rg_cache_enable === FALSE) break; $c = rg_socket($rg_cache_socket, "MERGE " . $ns_var . "=" . rg_cache_prepare($list) . "\n", $rg_cache_timeout, 1); if ($c === FALSE) break; if (strncmp($c, "OK", 2) != 0) break; $ret = TRUE; break; } if ($rg_cache_debug) rg_log_exit(); rg_prof_end("cache_merge"); return $ret; } ?>