public function apply() { if ($this->_cacheStatus == self::CACHE_STATUS_DISABLED) { kApiCache::disableCache(); return; } // common cache fields foreach ($this->_extraFields as $extraField) { call_user_func_array(array('kApiCache', 'addExtraField'), $extraField); } // anonymous cache fields if ($this->_expiry) { kApiCache::setExpiry($this->_expiry); } if ($this->_cacheStatus == self::CACHE_STATUS_ANONYMOUS_ONLY) { kApiCache::disableConditionalCache(); return; } // conditional cache fields if ($this->_conditionalCacheExpiry) { kApiCache::setConditionalCacheExpiry($this->_conditionalCacheExpiry); } kApiCache::addInvalidationKeys(array_keys($this->_invalidationKeys), $this->_invalidationTime); kApiCache::addSqlQueryConditions($this->_sqlConditions); }
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; $keysToGet[] = self::MAX_SLAVE_LAG_KEY; $queryStart = microtime(true); $cacheResult = self::$s_memcacheKeys->multiGet($keysToGet); KalturaLog::debug("kQueryCache: keys query took " . (microtime(true) - $queryStart) . " seconds"); if ($cacheResult === false) { KalturaLog::log("kQueryCache: failed to query keys memcache, not using query cache"); return null; } // get max slave lag $queryMasterThreshold = self::MAX_QUERY_MASTER_TIME_MARGIN_SEC; $maxSlaveLag = null; if (array_key_exists(self::MAX_SLAVE_LAG_KEY, $cacheResult) && strlen($cacheResult[self::MAX_SLAVE_LAG_KEY]) && is_numeric($cacheResult[self::MAX_SLAVE_LAG_KEY])) { $maxSlaveLag = $cacheResult[self::MAX_SLAVE_LAG_KEY]; $maxSlaveLag += self::SLAVE_LAG_TIME_MARGIN_SEC; $queryMasterThreshold = min($maxSlaveLag, $queryMasterThreshold); } unset($cacheResult[self::MAX_SLAVE_LAG_KEY]); // don't cache the result if the 'dont cache' flag is enabled $cacheQuery = true; if (array_key_exists(self::DONT_CACHE_KEY, $cacheResult) && $cacheResult[self::DONT_CACHE_KEY]) { KalturaLog::log("kQueryCache: dontCache key is set -> not caching the result"); $cacheQuery = false; } unset($cacheResult[self::DONT_CACHE_KEY]); // get max invalidation time $maxInvalidationTime = null; $maxInvalidationKey = null; if (count($cacheResult)) { $maxInvalidationTime = max($cacheResult); $maxInvalidationKey = array_search($maxInvalidationTime, $cacheResult); } // check whether we should query the master $queryDB = self::QUERY_DB_SLAVE; $currentTime = time(); if (!is_null($maxInvalidationTime) && $currentTime < $maxInvalidationTime + $queryMasterThreshold) { KalturaLog::debug("kQueryCache: changed recently -> query master, peer={$peerClassName}, invkey={$maxInvalidationKey} querytime={$currentTime} invtime={$maxInvalidationTime} threshold={$queryMasterThreshold}"); $queryDB = self::QUERY_DB_MASTER; if ($currentTime < $maxInvalidationTime + self::CLOCK_SYNC_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 ($queryDB == self::QUERY_DB_SLAVE && !is_null($maxInvalidationTime) && $currentTime < $maxInvalidationTime + $maxSlaveLag) { KalturaLog::debug("kQueryCache: using an out of date slave -> not caching the result, peer={$peerClassName}, invkey={$maxInvalidationKey} querytime={$currentTime} invtime={$maxInvalidationTime} slavelag={$maxSlaveLag}"); $cacheQuery = false; } // get the cache key and update the api cache $origCacheKey = self::CACHE_PREFIX_QUERY . $queryType . md5(serialize($criteria) . self::CACHE_VERSION); if ($cacheQuery) { kApiCache::addInvalidationKeys($invalidationKeys, $maxInvalidationTime); $cacheKey = new kQueryCacheKey($origCacheKey); } else { kApiCache::disableConditionalCache(); } // check whether we have a valid cached query $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; if (!is_null($maxInvalidationTime) && $queryTime < $maxInvalidationTime + self::CLOCK_SYNC_TIME_MARGIN_SEC) { KalturaLog::debug("kQueryCache: cached query invalid, peer={$peerClassName}, key={$origCacheKey}, invkey={$maxInvalidationKey} querytime={$queryTime} debugInfo={$debugInfo} invtime={$maxInvalidationTime}"); return null; } // return from memcache $existingInvKeys = array(); foreach ($cacheResult as $invalidationKey => $invalidationTime) { $existingInvKeys[] = "{$invalidationKey}:{$invalidationTime}"; } $existingInvKeys = implode(',', $existingInvKeys); KalturaLog::debug("kQueryCache: returning from memcache, peer={$peerClassName}, key={$origCacheKey} queryTime={$queryTime} debugInfo={$debugInfo} invkeys=[{$existingInvKeys}]"); return $queryResult; }