/**
  * 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;
 }