/** * 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; }
/** * Update the usage count in the property statistics table for all * properties. This function also initialises the required entry for * all properties that have IDs in the SMW IDs table. * * @since 1.8 * @param boolean $verbose * @param DatabaseBase $dbw used for writing */ protected function refreshPropertyStatistics($verbose, $dbw) { $this->reportProgress("Updating property statistics. This may take a while.\n", $verbose); $res = $dbw->select(SMWSql3SmwIds::tableName, array('smw_id', 'smw_title'), array('smw_namespace' => SMW_NS_PROPERTY), __METHOD__); $propertyTables = SMWSQLStore3::getPropertyTables(); foreach ($res as $row) { $this->reportProgress('.', $verbose); $usageCount = 0; foreach ($propertyTables as $propertyTable) { if ($propertyTable->isFixedPropertyTable() && $propertyTable->getFixedProperty() != $row->smw_title) { // This table cannot store values for this property continue; } $propRow = $dbw->selectRow($propertyTable->getName(), 'Count(*) as count', $propertyTable->isFixedPropertyTable() ? array() : array('p_id' => $row->smw_id), __METHOD__); $usageCount += $propRow->count; } $dbw->replace(SMWSQLStore3::PROPERTY_STATISTICS_TABLE, 'p_id', array('p_id' => $row->smw_id, 'usage_count' => $usageCount), __METHOD__); } $this->reportProgress("\nUpdated statistics for {$res->numRows()} Properties.\n", $verbose); $dbw->freeResult($res); }
/** * Create some initial DB entries for important built-in properties. Having the DB contents predefined * allows us to safe DB calls when certain data is needed. At the same time, the entries in the DB * make sure that DB-based functions work as with all other properties. */ protected function setupPredefinedProperties($verbose, DatabaseBase $db) { global $wgDBtype; $this->reportProgress("Setting up internal property indices ...\n", $verbose); // Check if we already have this structure $borderiw = $db->selectField(SMWSQLStore3::ID_TABLE, 'smw_iw', 'smw_id=' . $db->addQuotes(\SMWSql3SmwIds::FXD_PROP_BORDER_ID)); if ($borderiw != SMW_SQL3_SMWBORDERIW) { $this->reportProgress(" ... allocating space for internal properties ...\n", $verbose); $this->store->smwIds->moveSMWPageID(\SMWSql3SmwIds::FXD_PROP_BORDER_ID); // make sure position 50 is empty $db->insert(SMWSQLStore3::ID_TABLE, array('smw_id' => \SMWSql3SmwIds::FXD_PROP_BORDER_ID, 'smw_title' => '', 'smw_namespace' => 0, 'smw_iw' => SMW_SQL3_SMWBORDERIW, 'smw_subobject' => '', 'smw_sortkey' => ''), 'SMW::setup'); // put dummy "border element" on index 50 $this->reportProgress(' ', $verbose); for ($i = 0; $i < \SMWSql3SmwIds::FXD_PROP_BORDER_ID; $i++) { // make way for built-in ids $this->store->smwIds->moveSMWPageID($i); $this->reportProgress('.', $verbose); } $this->reportProgress(" done.\n", $verbose); } else { $this->reportProgress(" ... space for internal properties already allocated.\n", $verbose); } // now write actual properties; do that each time, it is cheap enough and we can update sortkeys by current language $this->reportProgress(" ... writing entries for internal properties ...", $verbose); foreach (SMWSql3SmwIds::$special_ids as $prop => $id) { $p = new SMWDIProperty($prop); $db->replace(SMWSQLStore3::ID_TABLE, array('smw_id'), array('smw_id' => $id, 'smw_title' => $p->getKey(), 'smw_namespace' => SMW_NS_PROPERTY, 'smw_iw' => $this->store->smwIds->getPropertyInterwiki($p), 'smw_subobject' => '', 'smw_sortkey' => $p->getLabel()), 'SMW::setup'); } $this->reportProgress(" done.\n", $verbose); if ($wgDBtype == 'postgres') { $sequenceIndex = SMWSQLStore3::ID_TABLE . '_smw_id_seq'; $this->reportProgress(" ... updating {$sequenceIndex} sequence accordingly.\n", $verbose); $max = $db->selectField(SMWSQLStore3::ID_TABLE, 'max(smw_id)', array(), __METHOD__); $max += 1; $db->query("ALTER SEQUENCE {$sequenceIndex} RESTART WITH {$max}", __METHOD__); } $this->reportProgress("Internal properties initialized successfully.\n", $verbose); }
function replace($table, $uniqueIndexes, $rows, $fname = 'DatabaseSqlite::replace') { if (!count($rows)) { return true; } # SQLite can't handle multi-row replaces, so divide up into multiple single-row queries if (isset($rows[0]) && is_array($rows[0])) { $ret = true; foreach ($rows as $k => $v) { if (!parent::replace($table, $uniqueIndexes, $v, "{$fname}/multi-row")) { $ret = false; } } } else { $ret = parent::replace($table, $uniqueIndexes, $rows, "{$fname}/single-row"); } return $ret; }