/** * @param array $cacheKeys * @param callable $loadCallback * @return array */ public function getByKey(array $cacheKeys, $loadCallback) { if (!$cacheKeys) { return array(); } $result = array(); $multiRes = $this->cache->getMulti(array_keys($cacheKeys)); if ($multiRes === false) { // Falls through to query only backend wfDebugLog('Flow', __METHOD__ . ': Failure querying memcache'); } else { // Memcached BagOStuff only returns found keys, but the redis bag // returns false for not found keys. $multiRes = array_filter($multiRes, function ($val) { return $val !== false; }); foreach ($multiRes as $key => $value) { $idx = $cacheKeys[$key]; if ($idx instanceof UUID) { $idx = $idx->getAlphadecimal(); } $result[$idx] = $value; unset($cacheKeys[$key]); } } if (count($cacheKeys) === 0) { return $result; } $res = call_user_func($loadCallback, array_values($cacheKeys)); if (!$res) { // storage failure of some sort return $result; } $invCacheKeys = array(); foreach ($cacheKeys as $cacheKey => $id) { if ($id instanceof UUID) { $id = $id->getAlphadecimal(); } $invCacheKeys[$id] = $cacheKey; } foreach ($res as $id => $row) { // If we failed contacting memcache a moment ago don't bother trying to // push values either. if ($multiRes !== false) { $this->cache->set($invCacheKeys[$id], $row); } $result[$id] = $row; } return $result; }
/** * Given a list of nodes, find the path from each node to the root of its tree. * the root must be the first element of the array, $node must be the last element. * @param UUID[] $descendants Array of UUID objects to find the root paths for. * @return UUID[][] Associative array, key is the post ID in hex, value is the path as an array. */ public function findRootPaths(array $descendants) { // alphadecimal => cachekey $cacheKeys = array(); // alphadecimal => cache result ( distance => parent uuid obj ) $cacheValues = array(); // list of binary values for db query $missingValues = array(); // alphadecimal => distance => parent uuid obj $paths = array(); foreach ($descendants as $descendant) { $cacheKeys[$descendant->getAlphadecimal()] = $this->cacheKey('rootpath', $descendant); } $cacheResult = $this->cache->getMulti(array_values($cacheKeys)); foreach ($descendants as $descendant) { $alpha = $descendant->getAlphadecimal(); if (isset($cacheResult[$cacheKeys[$alpha]])) { $cacheValues[$alpha] = $cacheResult[$cacheKeys[$alpha]]; } else { $missingValues[] = $descendant->getBinary(); $paths[$alpha] = array(); } } if (!count($missingValues)) { return $cacheValues; } $dbr = $this->dbFactory->getDB(DB_SLAVE); $res = $dbr->select($this->tableName, array('tree_descendant_id', 'tree_ancestor_id', 'tree_depth'), array('tree_descendant_id' => $missingValues), __METHOD__); if (!$res || $res->numRows() === 0) { return $cacheValues; } foreach ($res as $row) { $alpha = UUID::create($row->tree_descendant_id)->getAlphadecimal(); $paths[$alpha][$row->tree_depth] = UUID::create($row->tree_ancestor_id); } foreach ($paths as $descendantId => &$path) { if (!$path) { $path = null; continue; } // sort by reverse distance, so furthest away // parent (root) is at position 0. ksort($path); $path = array_reverse($path); $this->cache->set($cacheKeys[$descendantId], $path); } return $paths + $cacheValues; }