public static function getCachedQueryResults(Criteria $criteria, $queryType, $peerClassName, &$cacheKey, &$queryDB) { if (!kConf::get("query_cache_enabled")) { return null; } // if the criteria has an empty IN, no need to go to the DB or memcache - return an empty array foreach ($criteria->getMap() as $criterion) { if (in_array(Criterion::ODER, $criterion->getConjunctions())) { continue; } if ($criterion->getComparison() == Criteria::IN && !$criterion->getValue()) { KalturaLog::debug("kQueryCache: criteria has empty IN, returning empty result set, peer={$peerClassName}"); return array(); } } // initialize $invalidationKeyRules = call_user_func(array($peerClassName, 'getCacheInvalidationKeys')); $invalidationKeys = self::getInvalidationKeysForQuery($invalidationKeyRules, $criteria); if (!$invalidationKeys) { return null; } self::initGlobalMemcache(); if (self::$s_memcacheQueries === null) { return null; } // build memcache query foreach ($invalidationKeys as $index => $invalidationKey) { $invalidationKeys[$index] = self::CACHE_PREFIX_INVALIDATION_KEY . $invalidationKey; } $keysToGet = $invalidationKeys; $keysToGet[] = self::DONT_CACHE_KEY; $queryStart = microtime(true); $cacheResult = self::$s_memcacheKeys->multiGet($keysToGet); KalturaLog::debug("kQueryCache: keys query took " . (microtime(true) - $queryStart) . " seconds"); if ($cacheResult === false) { KalturaLog::debug("kQueryCache: failed to query keys memcache, not using query cache"); return null; } // don't cache the result if the 'dont cache' flag is enabled $cacheQuery = true; if (array_key_exists(self::DONT_CACHE_KEY, $cacheResult)) { if ($cacheResult[self::DONT_CACHE_KEY]) { KalturaLog::debug("kQueryCache: dontCache key is set -> not caching the result"); if (class_exists('KalturaResponseCacher')) { KalturaResponseCacher::disableConditionalCache(); } $cacheQuery = false; } unset($cacheResult[self::DONT_CACHE_KEY]); } // check whether we should query the master $queryDB = self::QUERY_DB_SLAVE; $currentTime = time(); foreach ($cacheResult as $invalidationKey => $invalidationTime) { if ($currentTime < $invalidationTime + self::QUERY_MASTER_TIME_MARGIN_SEC) { KalturaLog::debug("kQueryCache: changed recently -> query master, peer={$peerClassName}, invkey={$invalidationKey} querytime={$currentTime} invtime={$invalidationTime}"); $queryDB = self::QUERY_DB_MASTER; if ($currentTime < $invalidationTime + self::INVALIDATION_TIME_MARGIN_SEC) { return null; // The query won't be cached since cacheKey is null, it's ok cause it won't be used anyway } } } if (class_exists('KalturaResponseCacher')) { $invalidationTime = 0; if ($cacheResult) { $invalidationTime = max($cacheResult); } KalturaResponseCacher::addInvalidationKeys($invalidationKeys, $invalidationTime); } // check whether we have a valid cached query $origCacheKey = self::CACHE_PREFIX_QUERY . $queryType . md5(serialize($criteria) . self::CACHE_VERSION); if ($cacheQuery) { $cacheKey = $origCacheKey; } $queryStart = microtime(true); $queryResult = self::$s_memcacheQueries->get($origCacheKey); KalturaLog::debug("kQueryCache: query took " . (microtime(true) - $queryStart) . " seconds"); if (!$queryResult) { KalturaLog::debug("kQueryCache: cache miss, peer={$peerClassName}, key={$origCacheKey}"); return null; } list($queryResult, $queryTime, $debugInfo) = $queryResult; $existingInvKeys = array(); foreach ($cacheResult as $invalidationKey => $invalidationTime) { $existingInvKeys[] = "{$invalidationKey}:{$invalidationTime}"; if ($queryTime < $invalidationTime + self::INVALIDATION_TIME_MARGIN_SEC) { KalturaLog::debug("kQueryCache: cached query invalid, peer={$peerClassName}, key={$origCacheKey}, invkey={$invalidationKey} querytime={$queryTime} debugInfo={$debugInfo} invtime={$invalidationTime}"); return null; } } // return from memcache $existingInvKeys = implode(',', $existingInvKeys); KalturaLog::debug("kQueryCache: returning from memcache, peer={$peerClassName}, key={$origCacheKey} queryTime={$queryTime} debugInfo={$debugInfo} invkeys=[{$existingInvKeys}]"); return $queryResult; }