/** * Gets multiple values from memcached in one request. * * See the buildKeys method definition to understand the $keys/$groups parameters. * * @link http://www.php.net/manual/en/memcached.getmulti.php * * @param array $keys Array of keys to retrieve. * @param string|array $groups If string, used for all keys. If arrays, corresponds with the $keys array. * @param string $server_key The key identifying the server to store the value on. * @param null|array $cas_tokens The variable to store the CAS tokens for the found items. * @param int $flags The flags for the get operation. * @return bool|array Returns the array of found items or FALSE on failure. */ public function getMulti($keys, $groups = 'default', $server_key = '', &$cas_tokens = NULL, $flags = NULL) { $derived_keys = $this->buildKeys($keys, $groups); /** * If either $cas_tokens, or $flags is set, must hit Memcached and bypass runtime cache. Note that * this will purposely ignore no_mc_groups values as they cannot handle CAS tokens or the special * flags; however, if the groups of groups contains a no_mc_group, this is bypassed. */ if (func_num_args() > 3 && !$this->contains_no_mc_group($groups)) { if (!empty($server_key)) { $values = $this->mc->getMultiByKey($server_key, $derived_keys, $cas_tokens, $flags); } else { $values = $this->mc->getMulti($derived_keys, $cas_tokens, $flags); } } else { $values = array(); $need_to_get = array(); // Pull out values from runtime cache, or mark for retrieval foreach ($derived_keys as $key) { if (isset($this->cache[$key])) { $values[$key] = $this->cache[$key]; } else { $need_to_get[$key] = $key; } } // Get those keys not found in the runtime cache if (!empty($need_to_get)) { if (!empty($server_key)) { $result = $this->mc->getMultiByKey($server_key, array_keys($need_to_get)); } else { $result = $this->mc->getMulti(array_keys($need_to_get)); } } // Merge with values found in runtime cache if (isset($result) && Memcached::RES_SUCCESS === $this->getResultCode()) { $values = array_merge($values, $result); } // If order should be preserved, reorder now if (!empty($need_to_get) && $flags === Memcached::GET_PRESERVE_ORDER) { $ordered_values = array(); foreach ($derived_keys as $key) { if (isset($values[$key])) { $ordered_values[$key] = $values[$key]; } } $values = $ordered_values; unset($ordered_values); } } // Add the values to the runtime cache $this->cache = array_merge($this->cache, $values); return $values; }
/** * * * @param string $key * @param array $options * @return array|bool|mixed */ public function get($key, $options = array()) { if (!$this->online()) { return Gdn_Cache::CACHEOP_FAILURE; } $startTime = microtime(true); $finalOptions = array_merge($this->StoreDefaults, $options); $useLocal = (bool) $finalOptions[Gdn_Cache::FEATURE_LOCAL]; $localData = array(); $realKeys = array(); if (is_array($key)) { $multi = true; foreach ($key as $multiKey) { $realKey = $this->makeKey($multiKey, $finalOptions); // Skip this key if we already have it if ($useLocal) { $local = $this->localGet($realKey); if ($local !== Gdn_Cache::CACHEOP_FAILURE) { $localData[$realKey] = $local; continue; } } $realKeys[] = $realKey; } } else { $multi = false; $realKey = $this->makeKey($key, $finalOptions); // Completely short circuit if we already have everything if ($useLocal) { $local = $this->localGet($realKey); if ($local !== false) { return $local; } } $realKeys = array($realKey); } $data = array(); $hitCache = false; $numKeys = sizeof($realKeys); if ($numKeys) { $hitCache = true; if ($numKeys > 1) { $data = $this->memcache->getMulti($realKeys); $ok = $this->lastAction(); } else { $data = $this->memcache->get($realKey); // Check if things went ok $ok = $this->lastAction($realKey); $data = array($realKey => $data); } if (!$ok) { return Gdn_Cache::CACHEOP_FAILURE; } $storeData = array(); foreach ($data as $localKey => &$localValue) { // Is this a sharded key manifest? if (is_object($localValue) && $localValue instanceof MemcachedShard) { $manifest = $localValue; // MultiGet sub-keys $shardKeys = array(); foreach ($manifest->keys as $serverKey => $keys) { $serverKeys = $this->memcache->getMultiByKey($serverKey, $keys); $shardKeys = array_merge($shardKeys, $serverKeys); } ksort($shardKeys, SORT_NATURAL); // Check subkeys for validity $shardData = implode('', array_values($shardKeys)); unset($shardKeys); $dataHash = md5($shardData); if ($dataHash != $manifest->hash) { continue; } $localValue = unserialize($shardData); } if ($localValue !== false) { $storeData[$localKey] = $localValue; } } $data = $storeData; unset($storeData); // Cache in process memory if ($useLocal && sizeof($data)) { $this->localSet($data); } } // Merge in local data $data = array_merge($data, $localData); // Track debug stats $elapsedTime = microtime(true) - $startTime; if (Gdn_Cache::$trace) { Gdn_Cache::$trackTime += $elapsedTime; Gdn_Cache::$trackGets++; $keyTime = sizeof($realKeys) ? $elapsedTime / sizeof($realKeys) : $elapsedTime; foreach ($realKeys as $realKey) { TouchValue($realKey, Gdn_Cache::$trackGet, array('hits' => 0, 'time' => 0, 'keysize' => null, 'transfer' => 0, 'wasted' => 0)); $keyData = val($realKey, $data, false); Gdn_Cache::$trackGet[$realKey]['hits']++; Gdn_Cache::$trackGet[$realKey]['time'] += $keyTime; if ($keyData !== false) { $keyData = serialize($keyData); $keySize = strlen($keyData); if (is_null(Gdn_Cache::$trackGet[$realKey]['keysize'])) { Gdn_Cache::$trackGet[$realKey]['keysize'] = $keySize; } else { Gdn_Cache::$trackGet[$realKey]['wasted'] += $keySize; } Gdn_Cache::$trackGet[$realKey]['transfer'] += Gdn_Cache::$trackGet[$realKey]['keysize']; } } } // Miss: return the fallback if ($data === false) { return $this->fallback($key, $options); } // Hit: Single key. Return the value if (!$multi) { $val = sizeof($data) ? array_pop($data) : false; return $val; } // Hit: Multi key. Return stripped array. $dataStripped = array(); foreach ($data as $index => $value) { $dataStripped[$this->stripKey($index, $finalOptions)] = $value; } $data = $dataStripped; unset($dataStripped); return $data; }
return true; } $data = array('foo' => 'foo-data', 'bar' => 'bar-data', 'baz' => 'baz-data', 'lol' => 'lol-data', 'kek' => 'kek-data'); $keys = array_keys($data); $null = null; $m->setMulti($data, 3600); /* Check that all keys were stored */ var_dump(has_all_keys($keys, $m->getMulti($keys))); /* Check that all keys get deleted */ $deleted = $m->deleteMulti($keys); var_dump(has_all_keys($keys, $deleted, true)); /* Try to get the deleted keys, should give empty array */ var_dump($m->getMulti($keys)); /* ---- same tests for byKey variants ---- */ $m->setMultiByKey("hi", $data, 3600); var_dump(has_all_keys($keys, $m->getMultiByKey('hi', $keys))); /* Check that all keys get deleted */ $deleted = $m->deleteMultiByKey('hi', $keys); var_dump(has_all_keys($keys, $deleted, true)); /* Try to get the deleted keys, should give empty array */ var_dump($m->getMultiByKey('hi', $keys)); /* Test deleting non-existent keys */ $keys = array(); $keys[] = "nothere"; $keys[] = "nothere2"; $retval = $m->deleteMulti($keys); foreach ($retval as $key => $value) { if ($value === Memcached::RES_NOTFOUND) { echo "{$key} NOT FOUND\n"; } }
/** * @inheritdoc */ public function getMultiByKey($server_key, array $keys, &$cas_tokens = array(), $flags = null) { $keys = $this->prefixArrayOfKeys($keys); return parent::getMultiByKey($server_key, $keys, $cas_tokens, $flags); }