function run() { global $wgUpdateRowsPerJob; // Job to update all (or a range of) backlink pages for a page if (!empty($this->params['recursive'])) { // Carry over information for de-duplication $extraParams = $this->getRootJobParams(); // Avoid slave lag when fetching templates. // When the outermost job is run, we know that the caller that enqueued it must have // committed the relevant changes to the DB by now. At that point, record the master // position and pass it along as the job recursively breaks into smaller range jobs. // Hopefully, when leaf jobs are popped, the slaves will have reached that position. if (isset($this->params['masterPos'])) { $extraParams['masterPos'] = $this->params['masterPos']; } elseif (wfGetLB()->getServerCount() > 1) { $extraParams['masterPos'] = wfGetLB()->getMasterPos(); } else { $extraParams['masterPos'] = false; } // Convert this into no more than $wgUpdateRowsPerJob RefreshLinks per-title // jobs and possibly a recursive RefreshLinks job for the rest of the backlinks $jobs = BacklinkJobUtils::partitionBacklinkJob($this, $wgUpdateRowsPerJob, 1, array('params' => $extraParams)); JobQueueGroup::singleton()->push($jobs); // Job to update link tables for a set of titles } elseif (isset($this->params['pages'])) { foreach ($this->params['pages'] as $pageId => $nsAndKey) { list($ns, $dbKey) = $nsAndKey; $this->runForTitle(Title::makeTitleSafe($ns, $dbKey)); } // Job to update link tables for a given title } else { $this->runForTitle($this->title); } return true; }
function run() { global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery, $wgMaxBacklinksInvalidate; static $expected = array('recursive', 'pages'); // new jobs have one of these $oldRangeJob = false; if (!array_intersect(array_keys($this->params), $expected)) { // B/C for older job params formats that lack these fields: // a) base jobs with just ("table") and b) range jobs with ("table","start","end") if (isset($this->params['start']) && isset($this->params['end'])) { $oldRangeJob = true; } else { $this->params['recursive'] = true; // base job } } // Job to purge all (or a range of) backlink pages for a page if (!empty($this->params['recursive'])) { // @TODO: try to use delayed jobs if possible? if (!isset($this->params['range']) && $wgMaxBacklinksInvalidate !== false) { $numRows = $this->title->getBacklinkCache()->getNumLinks($this->params['table'], $wgMaxBacklinksInvalidate); if ($numRows > $wgMaxBacklinksInvalidate) { return true; } } // Convert this into no more than $wgUpdateRowsPerJob HTMLCacheUpdateJob per-title // jobs and possibly a recursive HTMLCacheUpdateJob job for the rest of the backlinks $jobs = BacklinkJobUtils::partitionBacklinkJob($this, $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery, array('params' => $this->getRootJobParams())); JobQueueGroup::singleton()->push($jobs); // Job to purge pages for for a set of titles } elseif (isset($this->params['pages'])) { $this->invalidateTitles($this->params['pages']); // B/C for job to purge a range of backlink pages for a given page } elseif ($oldRangeJob) { $titleArray = $this->title->getBacklinkCache()->getLinks($this->params['table'], $this->params['start'], $this->params['end']); $pages = array(); // same format BacklinkJobUtils uses foreach ($titleArray as $tl) { $pages[$tl->getArticleId()] = array($tl->getNamespace(), $tl->getDbKey()); } $jobs = array(); foreach (array_chunk($pages, $wgUpdateRowsPerJob) as $pageChunk) { $jobs[] = new HTMLCacheUpdateJob($this->title, array('table' => $this->params['table'], 'pages' => $pageChunk) + $this->getRootJobParams()); } JobQueueGroup::singleton()->push($jobs); } return true; }
/** * @dataProvider provider_backlinks */ public function testRefreshLinks($ns, $dbKey, $pages) { $title = Title::makeTitle($ns, $dbKey); foreach ($pages as $page) { list($bns, $bdbkey) = $page; $bpage = WikiPage::factory(Title::makeTitle($bns, $bdbkey)); $content = ContentHandler::makeContent("[[{$title->getPrefixedText()}]]", $bpage->getTitle()); $bpage->doEditContent($content, "test"); } $title->getBacklinkCache()->clear(); $this->assertEquals(20, $title->getBacklinkCache()->getNumLinks('pagelinks'), 'Correct number of backlinks'); $job = new RefreshLinksJob($title, array('recursive' => true, 'table' => 'pagelinks') + Job::newRootJobParams("refreshlinks:pagelinks:{$title->getPrefixedText()}")); $extraParams = $job->getRootJobParams(); $jobs = BacklinkJobUtils::partitionBacklinkJob($job, 9, 1, array('params' => $extraParams)); $this->assertEquals(10, count($jobs), 'Correct number of sub-jobs'); $this->assertEquals($pages[0], current($jobs[0]->params['pages']), 'First job is leaf job with proper title'); $this->assertEquals($pages[8], current($jobs[8]->params['pages']), 'Last leaf job is leaf job with proper title'); $this->assertEquals(true, isset($jobs[9]->params['recursive']), 'Last job is recursive sub-job'); $this->assertEquals(true, $jobs[9]->params['recursive'], 'Last job is recursive sub-job'); $this->assertEquals(true, is_array($jobs[9]->params['range']), 'Last job is recursive sub-job'); $this->assertEquals($title->getPrefixedText(), $jobs[0]->getTitle()->getPrefixedText(), 'Base job title retainend in leaf job'); $this->assertEquals($title->getPrefixedText(), $jobs[9]->getTitle()->getPrefixedText(), 'Base job title retainend recursive sub-job'); $this->assertEquals($extraParams['rootJobSignature'], $jobs[0]->params['rootJobSignature'], 'Leaf job has root params'); $this->assertEquals($extraParams['rootJobSignature'], $jobs[9]->params['rootJobSignature'], 'Recursive sub-job has root params'); $jobs2 = BacklinkJobUtils::partitionBacklinkJob($jobs[9], 9, 1, array('params' => $extraParams)); $this->assertEquals(10, count($jobs2), 'Correct number of sub-jobs'); $this->assertEquals($pages[9], current($jobs2[0]->params['pages']), 'First job is leaf job with proper title'); $this->assertEquals($pages[17], current($jobs2[8]->params['pages']), 'Last leaf job is leaf job with proper title'); $this->assertEquals(true, isset($jobs2[9]->params['recursive']), 'Last job is recursive sub-job'); $this->assertEquals(true, $jobs2[9]->params['recursive'], 'Last job is recursive sub-job'); $this->assertEquals(true, is_array($jobs2[9]->params['range']), 'Last job is recursive sub-job'); $this->assertEquals($extraParams['rootJobSignature'], $jobs2[0]->params['rootJobSignature'], 'Leaf job has root params'); $this->assertEquals($extraParams['rootJobSignature'], $jobs2[9]->params['rootJobSignature'], 'Recursive sub-job has root params'); $jobs3 = BacklinkJobUtils::partitionBacklinkJob($jobs2[9], 9, 1, array('params' => $extraParams)); $this->assertEquals(2, count($jobs3), 'Correct number of sub-jobs'); $this->assertEquals($pages[18], current($jobs3[0]->params['pages']), 'First job is leaf job with proper title'); $this->assertEquals($extraParams['rootJobSignature'], $jobs3[0]->params['rootJobSignature'], 'Leaf job has root params'); $this->assertEquals($pages[19], current($jobs3[1]->params['pages']), 'Last job is leaf job with proper title'); $this->assertEquals($extraParams['rootJobSignature'], $jobs3[1]->params['rootJobSignature'], 'Last leaf job has root params'); }
function run() { global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery; if (isset($this->params['table']) && !isset($this->params['pages'])) { $this->params['recursive'] = true; // b/c; base job } // Job to purge all (or a range of) backlink pages for a page if (!empty($this->params['recursive'])) { // Convert this into no more than $wgUpdateRowsPerJob HTMLCacheUpdateJob per-title // jobs and possibly a recursive HTMLCacheUpdateJob job for the rest of the backlinks $jobs = BacklinkJobUtils::partitionBacklinkJob($this, $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery, array('params' => $this->getRootJobParams())); JobQueueGroup::singleton()->push($jobs); // Job to purge pages for a set of titles } elseif (isset($this->params['pages'])) { $this->invalidateTitles($this->params['pages']); // Job to update a single title } else { $t = $this->title; $this->invalidateTitles(array($t->getArticleID() => array($t->getNamespace(), $t->getDBkey()))); } return true; }
function run() { global $wgUpdateRowsPerJob; // Job to update all (or a range of) backlink pages for a page if (!empty($this->params['recursive'])) { // When the base job branches, wait for the replica DBs to catch up to the master. // From then on, we know that any template changes at the time the base job was // enqueued will be reflected in backlink page parses when the leaf jobs run. if (!isset($params['range'])) { try { $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); $lbFactory->waitForReplication(['wiki' => wfWikiID(), 'timeout' => self::LAG_WAIT_TIMEOUT]); } catch (DBReplicationWaitError $e) { // only try so hard $stats = MediaWikiServices::getInstance()->getStatsdDataFactory(); $stats->increment('refreshlinks.lag_wait_failed'); } } // Carry over information for de-duplication $extraParams = $this->getRootJobParams(); $extraParams['triggeredRecursive'] = true; // Convert this into no more than $wgUpdateRowsPerJob RefreshLinks per-title // jobs and possibly a recursive RefreshLinks job for the rest of the backlinks $jobs = BacklinkJobUtils::partitionBacklinkJob($this, $wgUpdateRowsPerJob, 1, ['params' => $extraParams]); JobQueueGroup::singleton()->push($jobs); // Job to update link tables for a set of titles } elseif (isset($this->params['pages'])) { foreach ($this->params['pages'] as $pageId => $nsAndKey) { list($ns, $dbKey) = $nsAndKey; $this->runForTitle(Title::makeTitleSafe($ns, $dbKey)); } // Job to update link tables for a given title } else { $this->runForTitle($this->title); } return true; }