How do you invalidate your cache when there are database changes?<br><br><div><span class="gmail_quote">On 10/31/07, <b class="gmail_sendername">mike</b> <<a href="mailto:mike503@gmail.com">mike503@gmail.com</a>> wrote:
</span><blockquote class="gmail_quote" style="margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">I have a functional implementation of a generic cache wrapper that<br>supports multiget transparently. Since it mixes both cache calls and
<br>database calls, this now becomes a full out "data access layer" type<br>function I believe.<br><br>I'm wondering if there are any additional optimizations I can do here,<br>or if anyone has some pointers. I could have missed something VERY
<br>obvious and overengineered this :)<br><br>Primarily, I use a key prefix of "tablename:" for the row information,<br>for example. I suppose this is where namespaces would come in handy,<br>so I don't have to iterate through the array to strip off the key
<br>prefix when doing the last array_diff_key() to look for the ones<br>missing from the memcache_get().<br><br>Has anyone else done anything like this and have it work properly with<br>minimal overhead?<br><br>I know of the the following caveats:
<br>- Still not reusable as it could be, I think.<br>- I could add some typeof($var) to determine the key type. Right now I<br>assume it is numeric.<br><br>I just hate having to swap back and forth removing key prefixes and
<br>looping through the arrays. I don't think there is any way in PHP to<br>rename array keys without that (unless it's just some array_walk type<br>callback, but even then it's still a loop, maybe just less internal
<br>overhead?)<br><br>Any help is appreciated. Thank you :)<br><br>~~~<br><br>echo "<pre>\n";<br>$foo = episode_get(Array(1000000004, 1000000006, 1000000014, 1000000011));<br>var_dump($foo);<br>echo "</pre>\n";
<br><br>function episode_get($keys) {<br> $table = "episodes";<br> $column = "ID";<br> return db_cache_get($table, $column, $keys);<br>}<br><br>function db_cache_get($table, $column, $requested_keys) {
<br><br> $prefix = $table.':';<br><br> if(!isset($GLOBALS['ch'])) {<br> cache_open();<br> }<br><br> if(!is_array($requested_keys)) {<br> if(!$result = memcache_get($GLOBALS['ch'], $requested_keys)) {
<br> $q = db_query("SELECT * FROM $table WHERE<br>$column=$requested_keys");<br> list($result) = db_rows($q);<br> db_free($q);<br> }
<br> return $result;<br> }<br><br>echo "key request array:\n";<br>var_dump($requested_keys);<br>echo "\n";<br> // build the key list<br> foreach(array_values($requested_keys) as $key) {
<br> $cache_keys[$prefix.$key] = $prefix.$key;<br> }<br><br>echo "cache key array:\n";<br>var_dump($cache_keys);<br>echo "\n";<br><br> // do a multiget<br> $cache_array = memcache_get($GLOBALS['ch'], $cache_keys);
<br><br> // if the result count is the same we have no need to go to the database<br> if(count($cache_keys) != count($cache_array)) {<br><br>echo "cache returned array:\n";<br>var_dump($cache_array);
<br>echo "\n";<br><br> $need_array = array_diff_key($cache_keys, $cache_array);<br><br> if(count($need_array) > 0) {<br> $query_keys = '';<br> foreach($need_array as $need_key) {
<br> $k = str_replace($prefix, '', $need_key);<br> if(!empty($k)) { $query_keys .= $k.','; }<br> }<br> $query_keys = substr($query_keys, 0,
<br>strlen($query_keys)-1);<br> $q = db_query("SELECT * FROM $table WHERE<br>$column IN($query_keys)");<br> while($r = db_rows_assoc($q)) {<br> $k = $prefix.$r[$column];
<br> cache_set($k, $r);<br> $cache_array[$k] = $r;<br> }<br> db_free($q);<br> }<br> }<br><br>
$return = array();<br> foreach(array_keys($cache_array) as $item) {<br> $newindex = str_replace($prefix, '', $item);<br> $return[$newindex] = $cache_array[$item];<br> unset($cache_array[$item]);
<br> }<br> return $return;<br>}<br><br>function cache_set($key, $value, $flags = 0, $expiry = 2592000) {<br> if(!isset($GLOBALS['ch'])) {<br> cache_open();<br> }<br> memcache_set($GLOBALS['ch'], $key, $value, $flags, $expiry);
<br> return false;<br>}<br><br>function cache_open() {<br> $GLOBALS['ch'] = memcache_pconnect('localhost', 11211);<br>}<br></blockquote></div><br>