From The Archives

Memcached Multiget using PHP PECL Memcache class

created December 28, 2009 at 12:57 am
updated May 24, 2010 at 1:03 am

At work I have been working with memcache quite a bit and coming up with creative ways to cache stuff. Perhaps I will elaborate on some of these in later posts, but for now I think I will focus on one interesting issue I ran into using multiget.

Using PECL Memcache extension the Memcache::get() method allows you to pass in a single key as a string or an array of keys to retrieve from cache. This can be very useful for retrieving lots of information with one request to memcache, however, there are a couple things to keep in mind. The first is something minor that I found annoying.

Let's say you request array('item_1', 'item_2') from cache. If only item 1 is in cache then the resulting array will be something like this: array('item_1' => 'this is the value for item 1'). This means you have to actually check if a key exists in the resulting array or not in order to know how to proceed.

The second thing had me banging my head against the wall for a short while since it was not possible to reproduce on a development environment. If you request multiple items from cache in one multiget request and the items requested are distributed over more than one server then they will not be returned in the same order that they were requested in.

While this seems to be the expected behavior, I couldn't find any information or documentation about this in the PHP documentation for memcache.

After a little while I thought of a workaround to this problem. The code is as follows:

<?php /** * gets multiple keys from cache and returns the values in the same order * they were requested in * * @param array $keys * @param bool $preserveOrder * @return array */ public function getMulti(array $keys, $preserveOrder = true) { // grab whatever items we can from cache $items = $this->get($keys); // if we don't care what order the keys are returned in if (!$preserveOrder) { return $items; } // set all keys to null so if something is not found in cache it won't // be set to a value $results = array_fill_keys($keys, null); // merge the two arrays so the returned values from cache overwrite // the starting values return array_merge($results, $items); }

This pretty much solves both of the problems mentioned above. By using array_fill_keys we are able to guarantee that every item will be returned in the resulting array. By using array_merge any of the items actually returned will overwrite the values in the original while preserving the same order

Please note this code is part of a Memcache wrapper class.