mId = $id; $this->mTitle = $title; } /** * Update link tables with outgoing links from an updated article * Relies on the 'link cache' to be filled out. */ function doUpdate() { global $wgUseDumbLinkUpdate, $wgLinkCache, $wgDBtransactions; global $wgUseCategoryMagic; if ( $wgUseDumbLinkUpdate ) { $this->doDumbUpdate(); return; } $fname = 'LinksUpdate::doUpdate'; wfProfileIn( $fname ); $del = array(); $add = array(); $dbw =& wfGetDB( DB_MASTER ); $pagelinks = $dbw->tableName( 'pagelinks' ); $imagelinks = $dbw->tableName( 'imagelinks' ); $categorylinks = $dbw->tableName( 'categorylinks' ); #------------------------------------------------------------------------------ # Good links if ( $wgLinkCache->incrementalSetup( LINKCACHE_PAGE, $del, $add ) ) { # Delete where necessary if ( count( $del ) ) { $batch = new LinkBatch( $del ); $set = $batch->constructSet( 'pl', $dbw ); if ( $set ) { $sql = "DELETE FROM $pagelinks WHERE pl_from={$this->mId} AND ($set)"; $dbw->query( $sql, $fname ); } } } else { # Delete everything $dbw->delete( 'pagelinks', array( 'pl_from' => $this->mId ), $fname ); # Get the addition list $add = $wgLinkCache->getPageLinks(); } # Do the insertion if( 0 != count( $add ) ) { $arr = array(); foreach( $add as $lt => $target ) { array_push( $arr, array( 'pl_from' => $this->mId, 'pl_namespace' => $target->getNamespace(), 'pl_title' => $target->getDbKey() ) ); } # The link cache was constructed without FOR UPDATE, so there may be collisions # Ignoring for now, I'm not sure if that causes problems or not, but I'm fairly # sure it's better than without IGNORE $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) ); } #------------------------------------------------------------------------------ # Image links $dbw->delete('imagelinks',array('il_from'=>$this->mId),$fname); # Get addition list $add = $wgLinkCache->getImageLinks(); # Do the insertion $sql = ''; $image = NS_IMAGE; if ( 0 != count ( $add ) ) { $arr = array(); foreach ($add as $iname => $val ) { $nt = Title::makeTitle( $image, $iname ); if( !$nt ) continue; $nt->invalidateCache(); array_push( $arr, array( 'il_from' => $this->mId, 'il_to' => $iname ) ); } $dbw->insert('imagelinks', $arr, $fname, array('IGNORE')); } #------------------------------------------------------------------------------ # Category links if( $wgUseCategoryMagic ) { global $messageMemc, $wgDBname; # Get addition list $add = $wgLinkCache->getCategoryLinks(); # select existing catlinks for this page $res = $dbw->select( 'categorylinks', array( 'cl_to', 'cl_sortkey' ), array( 'cl_from' => $this->mId ), $fname, 'FOR UPDATE' ); $del = array(); if( 0 != $dbw->numRows( $res ) ) { while( $row = $dbw->fetchObject( $res ) ) { if( !isset( $add[$row->cl_to] ) || $add[$row->cl_to] != $row->cl_sortkey ) { // in the db, but no longer in the page // or sortkey has changed -> delete $del[] = $row->cl_to; } else { // remove already existing category memberships // from the add array unset( $add[$row->cl_to] ); } } } // delete any removed categorylinks if( count( $del ) > 0) { // delete old ones $dbw->delete( 'categorylinks', array( 'cl_from' => $this->mId, 'cl_to' => $del ), $fname ); foreach( $del as $cname ){ $nt = Title::makeTitle( NS_CATEGORY, $cname ); $nt->invalidateCache(); // update the timestamp which indicates when the last article // was added or removed to/from this article $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp'; $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 ); } } // add any new category memberships if( count( $add ) > 0 ) { $arr = array(); foreach( $add as $cname => $sortkey ) { $nt = Title::makeTitle( NS_CATEGORY, $cname ); $nt->invalidateCache(); // update the timestamp which indicates when the last article // was added or removed to/from this article $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp'; $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 ); array_push( $arr, array( 'cl_from' => $this->mId, 'cl_to' => $cname, 'cl_sortkey' => $sortkey ) ); } // do the actual sql insertion $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) ); } } 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() { global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic; $fname = 'LinksUpdate::doDumbUpdate'; wfProfileIn( $fname ); $dbw =& wfGetDB( DB_MASTER ); $pagelinks = $dbw->tableName( 'pagelinks' ); $imagelinks = $dbw->tableName( 'imagelinks' ); $categorylinks = $dbw->tableName( 'categorylinks' ); $dbw->delete('pagelinks', array('pl_from'=>$this->mId),$fname); $a = $wgLinkCache->getPageLinks(); if ( 0 != count( $a ) ) { $arr = array(); foreach( $a as $lt => $target ) { array_push( $arr, array( 'pl_from' => $this->mId, 'pl_namespace' => $target->getNamespace(), 'pl_title' => $target->getDBkey() ) ); } $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) ); } $dbw->delete('imagelinks', array('il_from'=>$this->mId),$fname); $a = $wgLinkCache->getImageLinks(); $sql = ''; if ( 0 != count ( $a ) ) { $arr = array(); foreach( $a as $iname => $val ) array_push( $arr, array( 'il_from' => $this->mId, 'il_to' => $iname ) ); $dbw->insert( 'imagelinks', $arr, $fname, array( 'IGNORE' ) ); } if( $wgUseCategoryMagic ) { $dbw->delete('categorylinks', array('cl_from'=>$this->mId),$fname); # Get addition list $add = $wgLinkCache->getCategoryLinks(); # Do the insertion $sql = ''; if ( 0 != count ( $add ) ) { $arr = array(); foreach( $add as $cname => $sortkey ) { # FIXME: Change all this to avoid unnecessary duplication $nt = Title::makeTitle( NS_CATEGORY, $cname ); if( !$nt ) continue; $nt->invalidateCache(); array_push( $arr, array( 'cl_from' => $this->mId, 'cl_to' => $cname, 'cl_sortkey' => $sortkey ) ); } $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) ); } } wfProfileOut( $fname ); } } ?>