/** * Update the query cache as needed * * @param DatabaseBase $dbw * @param int $days How many days user must be idle before he is considered inactive * @param int $window Maximum time range of new data to scan (in seconds) * @return int|bool UNIX timestamp the cache is now up-to-date as of (false on error) */ protected static function doQueryCacheUpdate(DatabaseBase $dbw, $days, $window) { $lockKey = wfWikiID() . '-activeusers'; if (!$dbw->lock($lockKey, __METHOD__, 1)) { return false; // exclusive update (avoids duplicate entries) } $now = time(); $cTime = $dbw->selectField('querycache_info', 'qci_timestamp', array('qci_type' => 'activeusers')); $cTimeUnix = $cTime ? wfTimestamp(TS_UNIX, $cTime) : 1; // Pick the date range to fetch from. This is normally from the last // update to till the present time, but has a limited window for sanity. // If the window is limited, multiple runs are need to fully populate it. $sTimestamp = max($cTimeUnix, $now - $days * 86400); $eTimestamp = min($sTimestamp + $window, $now); // Get all the users active since the last update $res = $dbw->select(array('recentchanges'), array('rc_user_text', 'lastedittime' => 'MAX(rc_timestamp)'), array('rc_user > 0', 'rc_type != ' . $dbw->addQuotes(RC_EXTERNAL), 'rc_log_type IS NULL OR rc_log_type != ' . $dbw->addQuotes('newusers'), 'rc_timestamp >= ' . $dbw->addQuotes($dbw->timestamp($sTimestamp)), 'rc_timestamp <= ' . $dbw->addQuotes($dbw->timestamp($eTimestamp))), __METHOD__, array('GROUP BY' => array('rc_user_text'), 'ORDER BY' => 'NULL')); $names = array(); foreach ($res as $row) { $names[$row->rc_user_text] = $row->lastedittime; } // Rotate out users that have not edited in too long (according to old data set) $dbw->delete('querycachetwo', array('qcc_type' => 'activeusers', 'qcc_value < ' . $dbw->addQuotes($now - $days * 86400)), __METHOD__); // Find which of the recently active users are already accounted for if (count($names)) { $res = $dbw->select('querycachetwo', array('user_name' => 'qcc_title'), array('qcc_type' => 'activeusers', 'qcc_namespace' => NS_USER, 'qcc_title' => array_keys($names)), __METHOD__); foreach ($res as $row) { unset($names[$row->user_name]); } } // Insert the users that need to be added to the list (which their last edit time if (count($names)) { $newRows = array(); foreach ($names as $name => $lastEditTime) { $newRows[] = array('qcc_type' => 'activeusers', 'qcc_namespace' => NS_USER, 'qcc_title' => $name, 'qcc_value' => wfTimestamp(TS_UNIX, $lastEditTime), 'qcc_namespacetwo' => 0, 'qcc_titletwo' => ''); } foreach (array_chunk($newRows, 500) as $rowBatch) { $dbw->insert('querycachetwo', $rowBatch, __METHOD__); if (!$dbw->trxLevel()) { wfWaitForSlaves(); } } } // Touch the data freshness timestamp $dbw->replace('querycache_info', array('qci_type'), array('qci_type' => 'activeusers', 'qci_timestamp' => $dbw->timestamp($eTimestamp)), __METHOD__); $dbw->unlock($lockKey, __METHOD__); return $eTimestamp; }