wiki.techinc.nl/includes/SqlDataUpdate.php
daniel a12ce17c6e Generalizing LinksUpdate to allow extensions to add arbitrary update handlers.
This supercedes I6d03bf2a, using better names for the new classes and
incorporating the changes requested by Aaron.

This change introduces the base class SecondaryDataUpdate to be used for any
updates that need to be applied when a page is changed or deleted. Until now,
this was done by the LinksUpdate class for updates and WikiPage::doDeletionUpdates
upon deletion. This patch uses a list of SecondaryDataUpdates in both cases.

This allows extensions (e.g. via the ContentHandler facility, once that is in) to
easily specify what needs to be done when a page is updated or deleted in order to
keep any secondary data stores (such as link tables) in sync.

Note that limited transactional logic is also introduced, so SecondaryDataUpdate
can be implemented to only commit their changes if all updates were performed
sucessfully.

Patch Set 2: fixing some coding style issues mentioned by Nikerabbit.

Patch Set 4: some stuff I kept from the old LinksUpdate class needs cleanup,
             but might break extensions when changed. Marking as todo for now.

Patch Set 5: fixed misnamed member in LinksDeletionUpdate (thanks Aaron).

Change-Id: Ibe3e88fadd8c1d4063cf13bb6972f2a23569a73f
2012-05-13 20:53:37 +02:00

127 lines
3.7 KiB
PHP

<?php
/**
* See docs/deferred.txt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* Abstract base class for update jobs that put some secondary data extracted
* from article content into the database.
*/
abstract class SqlDataUpdate extends DataUpdate {
protected $mDb; //!< Database connection reference
protected $mOptions; //!< SELECT options to be used (array)
private $mHasTransaction; //!< bool whether a transaction is open on this object (internal use only!)
/**
* Constructor
**/
public function __construct( ) {
global $wgAntiLockFlags;
parent::__construct( );
if ( $wgAntiLockFlags & ALF_NO_LINK_LOCK ) {
$this->mOptions = array();
} else {
$this->mOptions = array( 'FOR UPDATE' );
}
// @todo: get connection only when it's needed? make sure that doesn't break anything, especially transactions!
$this->mDb = wfGetDB( DB_MASTER );
$this->mHasTransaction = false;
}
/**
* Begin a database transaction.
*
* Because nested transactions are not supportred by the Database class, this implementation
* checkes Database::trxLevel() and only opens a transaction if none is yet active.
*/
public function beginTransaction() {
// NOTE: nested transactions are not supported, only start a transaction if none is open
if ( $this->mDb->trxLevel() === 0 ) {
$this->mDb->begin( get_class( $this ) . '::beginTransaction' );
$this->mHasTransaction = true;
}
}
/**
* Commit the database transaction started via beginTransaction (if any).
*/
public function commitTransaction() {
if ( $this->mHasTransaction ) {
$this->mDb->commit( get_class( $this ) . '::commitTransaction' );
}
}
/**
* Abort the database transaction started via beginTransaction (if any).
*/
public function abortTransaction() {
if ( $this->mHasTransaction ) {
$this->mDb->rollback( get_class( $this ) . '::abortTransaction' );
}
}
/**
* Invalidate the cache of a list of pages from a single namespace.
* This is intended for use by subclasses.
*
* @param $namespace Integer
* @param $dbkeys Array
*/
protected function invalidatePages( $namespace, Array $dbkeys ) {
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' => $dbkeys,
'page_touched < ' . $this->mDb->addQuotes( $now )
), __METHOD__
);
foreach ( $res as $row ) {
$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' => $ids,
'page_touched < ' . $this->mDb->addQuotes( $now )
), __METHOD__
);
}
}