linksupdate.php

来自「php 开发的内容管理系统」· PHP 代码 · 共 602 行 · 第 1/2 页

PHP
602
字号
<?php/** * See deferred.txt * @package MediaWiki *//** * @todo document * @package MediaWiki */class LinksUpdate {	/**@{{	 * @private	 */	var $mId,            //!< Page ID of the article linked from		$mTitle,         //!< Title object of the article linked from		$mLinks,         //!< Map of title strings to IDs for the links in the document		$mImages,        //!< DB keys of the images used, in the array key only		$mTemplates,     //!< Map of title strings to IDs for the template references, including broken ones		$mExternals,     //!< URLs of external links, array key only		$mCategories,    //!< Map of category names to sort keys		$mInterlangs,    //!< Map of language codes to titles		$mDb,            //!< Database connection reference		$mOptions,       //!< SELECT options to be used (array)		$mRecursive;     //!< Whether to queue jobs for recursive updates	/**@}}*/	/**	 * Constructor	 * Initialize private variables	 * @param $title Integer: FIXME	 * @param $parserOutput FIXME	 * @param $recursive Boolean: FIXME, default 'true'.	 */	function LinksUpdate( $title, $parserOutput, $recursive = true ) {		global $wgAntiLockFlags;		if ( $wgAntiLockFlags & ALF_NO_LINK_LOCK ) {			$this->mOptions = array();		} else {			$this->mOptions = array( 'FOR UPDATE' );		}		$this->mDb =& wfGetDB( DB_MASTER );		if ( !is_object( $title ) ) {			throw new MWException( "The calling convention to LinksUpdate::LinksUpdate() has changed. " .				"Please see Article::editUpdates() for an invocation example.\n" );		}		$this->mTitle = $title;		$this->mId = $title->getArticleID();		$this->mLinks = $parserOutput->getLinks();		$this->mImages = $parserOutput->getImages();		$this->mTemplates = $parserOutput->getTemplates();		$this->mExternals = $parserOutput->getExternalLinks();		$this->mCategories = $parserOutput->getCategories();		# Convert the format of the interlanguage links		# I didn't want to change it in the ParserOutput, because that array is passed all 		# the way back to the skin, so either a skin API break would be required, or an 		# inefficient back-conversion.		$ill = $parserOutput->getLanguageLinks();		$this->mInterlangs = array();		foreach ( $ill as $link ) {			list( $key, $title ) = explode( ':', $link, 2 );			$this->mInterlangs[$key] = $title;		}		$this->mRecursive = $recursive;	}	/**	 * Update link tables with outgoing links from an updated article	 */	function doUpdate() {		global $wgUseDumbLinkUpdate;		if ( $wgUseDumbLinkUpdate ) {			$this->doDumbUpdate();		} else {			$this->doIncrementalUpdate();		}	}	function doIncrementalUpdate() {		$fname = 'LinksUpdate::doIncrementalUpdate';		wfProfileIn( $fname );				# Page links		$existing = $this->getExistingLinks();		$this->incrTableUpdate( 'pagelinks', 'pl', $this->getLinkDeletions( $existing ),			$this->getLinkInsertions( $existing ) );		# Image links		$existing = $this->getExistingImages();		$this->incrTableUpdate( 'imagelinks', 'il', $this->getImageDeletions( $existing ),			$this->getImageInsertions( $existing ) );		# Invalidate all image description pages which had links added or removed		$imageUpdates = array_diff_key( $existing, $this->mImages ) + array_diff_key( $this->mImages, $existing );		$this->invalidateImageDescriptions( $imageUpdates );		# External links		$existing = $this->getExistingExternals();		$this->incrTableUpdate( 'externallinks', 'el', $this->getExternalDeletions( $existing ),	        $this->getExternalInsertions( $existing ) );		# Language links		$existing = $this->getExistingInterlangs();		$this->incrTableUpdate( 'langlinks', 'll', $this->getInterlangDeletions( $existing ),			$this->getInterlangInsertions( $existing ) );		# Template links		$existing = $this->getExistingTemplates();		$this->incrTableUpdate( 'templatelinks', 'tl', $this->getTemplateDeletions( $existing ),			$this->getTemplateInsertions( $existing ) );		# Category links		$existing = $this->getExistingCategories();		$this->incrTableUpdate( 'categorylinks', 'cl', $this->getCategoryDeletions( $existing ),			$this->getCategoryInsertions( $existing ) );		# Invalidate all categories which were added, deleted or changed (set symmetric difference)		$categoryUpdates = array_diff_assoc( $existing, $this->mCategories ) + array_diff_assoc( $this->mCategories, $existing );		$this->invalidateCategories( $categoryUpdates );		# Refresh links of all pages including this page		# This will be in a separate transaction		if ( $this->mRecursive ) {			$this->queueRecursiveJobs();		}				wfProfileOut( $fname );	}	/**	 * Link update which clears the previous entries and inserts new ones	 * May be slower or faster depending on level of lock contention and write speed of DB	 * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php	 */	function doDumbUpdate() {		$fname = 'LinksUpdate::doDumbUpdate';		wfProfileIn( $fname );		# Refresh category pages and image description pages		$existing = $this->getExistingCategories();		$categoryUpdates = array_diff_assoc( $existing, $this->mCategories ) + array_diff_assoc( $this->mCategories, $existing );		$existing = $this->getExistingImages();		$imageUpdates = array_diff_key( $existing, $this->mImages ) + array_diff_key( $this->mImages, $existing );		$this->dumbTableUpdate( 'pagelinks',     $this->getLinkInsertions(),     'pl_from' );		$this->dumbTableUpdate( 'imagelinks',    $this->getImageInsertions(),    'il_from' );		$this->dumbTableUpdate( 'categorylinks', $this->getCategoryInsertions(), 'cl_from' );		$this->dumbTableUpdate( 'templatelinks', $this->getTemplateInsertions(), 'tl_from' );		$this->dumbTableUpdate( 'externallinks', $this->getExternalInsertions(), 'el_from' );		$this->dumbTableUpdate( 'langlinks',     $this->getInterlangInsertions(), 'll_from' );		# Update the cache of all the category pages and image description pages which were changed		$this->invalidateCategories( $categoryUpdates );		$this->invalidateImageDescriptions( $imageUpdates );		# Refresh links of all pages including this page		# This will be in a separate transaction		if ( $this->mRecursive ) {			$this->queueRecursiveJobs();		}		wfProfileOut( $fname );	}	function queueRecursiveJobs() {		wfProfileIn( __METHOD__ );				$batchSize = 100;		$dbr =& wfGetDB( DB_SLAVE );		$res = $dbr->select( array( 'templatelinks', 'page' ), 			array( 'page_namespace', 'page_title' ),			array( 				'page_id=tl_from', 				'tl_namespace' => $this->mTitle->getNamespace(),				'tl_title' => $this->mTitle->getDBkey()			), __METHOD__		);		$done = false;		while ( !$done ) {			$jobs = array();			for ( $i = 0; $i < $batchSize; $i++ ) {				$row = $dbr->fetchObject( $res );				if ( !$row ) {					$done = true;					break;				}				$title = Title::makeTitle( $row->page_namespace, $row->page_title );				$jobs[] = Job::factory( 'refreshLinks', $title );			}			Job::batchInsert( $jobs );		}		$dbr->freeResult( $res );		wfProfileOut( __METHOD__ );	}		/**	 * Invalidate the cache of a list of pages from a single namespace	 *	 * @param integer $namespace	 * @param array $dbkeys	 */	function invalidatePages( $namespace, $dbkeys ) {		$fname = 'LinksUpdate::invalidatePages';				if ( !count( $dbkeys ) ) {			return;		}				/**		 * Determine which pages need to be updated		 * This is necessary to prevent the job queue from smashing the DB with		 * large numbers of concurrent invalidations of the same page		 */		$now = $this->mDb->timestamp();		$ids = array();		$res = $this->mDb->select( 'page', array( 'page_id' ), 			array( 				'page_namespace' => $namespace,				'page_title IN (' . $this->mDb->makeList( $dbkeys ) . ')',				'page_touched < ' . $this->mDb->addQuotes( $now )			), $fname		);		while ( $row = $this->mDb->fetchObject( $res ) ) {			$ids[] = $row->page_id;		}		if ( !count( $ids ) ) {			return;		}				/**		 * Do the update		 * We still need the page_touched condition, in case the row has changed since 		 * the non-locking select above.		 */		$this->mDb->update( 'page', array( 'page_touched' => $now ), 			array( 				'page_id IN (' . $this->mDb->makeList( $ids ) . ')',				'page_touched < ' . $this->mDb->addQuotes( $now )			), $fname		);	}	function invalidateCategories( $cats ) {		$this->invalidatePages( NS_CATEGORY, array_keys( $cats ) );	}	function invalidateImageDescriptions( $images ) {		$this->invalidatePages( NS_IMAGE, array_keys( $images ) );	}	function dumbTableUpdate( $table, $insertions, $fromField ) {		$fname = 'LinksUpdate::dumbTableUpdate';		$this->mDb->delete( $table, array( $fromField => $this->mId ), $fname );		if ( count( $insertions ) ) {			# The link array was constructed without FOR UPDATE, so there may be collisions			# This may cause minor link table inconsistencies, which is better than			# crippling the site with lock contention.			$this->mDb->insert( $table, $insertions, $fname, array( 'IGNORE' ) );		}	}	/**	 * Make a WHERE clause from a 2-d NS/dbkey array	 *	 * @param array $arr 2-d array indexed by namespace and DB key	 * @param string $prefix Field name prefix, without the underscore	 */	function makeWhereFrom2d( &$arr, $prefix ) {		$lb = new LinkBatch;		$lb->setArray( $arr );		return $lb->constructSet( $prefix, $this->mDb );	}	/**	 * Update a table by doing a delete query then an insert query	 * @private	 */	function incrTableUpdate( $table, $prefix, $deletions, $insertions ) {		$fname = 'LinksUpdate::incrTableUpdate';		$where = array( "{$prefix}_from" => $this->mId );		if ( $table == 'pagelinks' || $table == 'templatelinks' ) {			$clause = $this->makeWhereFrom2d( $deletions, $prefix );			if ( $clause ) {				$where[] = $clause;			} else {				$where = false;			}		} else {			if ( $table == 'langlinks' ) {				$toField = 'll_lang';			} else {				$toField = $prefix . '_to';			}			if ( count( $deletions ) ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?