Current File : /home/jvzmxxx/wiki1/extensions/Wikibase/repo/includes/ChangePruner.php
<?php

namespace Wikibase\Repo;

use InvalidArgumentException;
use Wikibase\Lib\Reporting\MessageReporter;
use Wikibase\Lib\Reporting\NullMessageReporter;

/**
 * Handles pruning wb_changes table, used by pruneChanges maintenance script.
 *
 * @license GPL-2.0+
 * @author Katie Filbert < aude.wiki@gmail.com >
 */
class ChangePruner {

	/**
	 * @var int
	 */
	private $batchSize;

	/**
	 * @var int the minimum number of seconds to keep changes for.
	 */
	private $keepSeconds;

	/**
	 * @var int the minimum number of seconds after dispatching to keep changes for.
	 */
	private $graceSeconds;

	/**
	 * @var bool whether the dispatch time should be ignored
	 */
	private $ignoreDispatch;

	/**
	 * @var MessageReporter
	 */
	private $messageReporter;

	/**
	 * @param int $batchSize
	 * @param int $keepSeconds
	 * @param int $graceSeconds
	 * @param bool $ignoreDispatch
	 *
	 * @throws InvalidArgumentException
	 */
	public function __construct( $batchSize, $keepSeconds, $graceSeconds, $ignoreDispatch ) {
		if ( !is_int( $batchSize ) || $batchSize <= 0 ) {
			throw new InvalidArgumentException( '$batchSize must be a positive integer' );
		}

		if ( !is_int( $keepSeconds ) || $keepSeconds < 0 ) {
			throw new InvalidArgumentException( '$keepSeconds must be a non-negative integer' );
		}

		if ( !is_int( $graceSeconds ) || $graceSeconds < 0 ) {
			throw new InvalidArgumentException( '$graceSeconds must be a non-negative integer' );
		}

		$this->batchSize = $batchSize;
		$this->keepSeconds = $keepSeconds;
		$this->graceSeconds = $graceSeconds;
		$this->ignoreDispatch = $ignoreDispatch;

		$this->messageReporter = new NullMessageReporter();
	}

	/**
	 * Prunes the wb_changes table.
	 */
	public function prune() {
		while ( true ) {
			wfWaitForSlaves();

			$until = $this->getCutoffTimestamp();

			$this->messageReporter->reportMessage(
				date( 'H:i:s' ) . " pruning entries older than "
				. wfTimestamp( TS_ISO_8601, $until )
			);

			$affected = $this->pruneChanges( $until );

			$this->messageReporter->reportMessage( date( 'H:i:s' ) . " $affected rows pruned." );

			if ( $affected === 0 ) {
				break;
			}
		}
	}

	/**
	 * Calculates the timestamp up to which changes can be pruned.
	 *
	 * @return string Timestamp up to which changes can be pruned (as MediaWiki concatenated string
	 * timestamp).
	 */
	private function getCutoffTimestamp() {
		$until = time() - $this->keepSeconds;

		if ( !$this->ignoreDispatch ) {
			$dbr = wfGetDB( DB_SLAVE );
			$row = $dbr->selectRow(
				array( 'wb_changes_dispatch', 'wb_changes' ),
				'min(change_time) as timestamp',
				array(
					'chd_disabled' => 0,
					'chd_seen = change_id'
				),
				__METHOD__
			);

			if ( isset( $row->timestamp ) ) {
				$dispatched = wfTimestamp( TS_UNIX, $row->timestamp ) - $this->graceSeconds;

				$until = min( $until, $dispatched );
			}
		}

		$limitedTimestamp = $this->limitCutoffTimestamp( wfTimestamp( TS_MW, $until ) );

		// Add one second just to make sure we delete at least one second worth of data
		// as sometimes there are more edits in a single second than $this->batchSize
		// (the peak on Wikidata is almost 550).
		return wfTimestamp( TS_MW, wfTimestamp( TS_UNIX, $limitedTimestamp ) + 1 );
	}

	/**
	 * Changes the cutoff timestamp to not affect more than $this->batchSize
	 * rows, if needed.
	 *
	 * @param string $until MediaWiki concatenated string timestamp
	 *
	 * @return string MediaWiki concatenated string timestamp
	 */
	private function limitCutoffTimestamp( $until ) {
		$dbr = wfGetDB( DB_SLAVE );
		$changeTime = $dbr->selectField(
			'wb_changes',
			'change_time',
			array( 'change_time < ' . $dbr->addQuotes( $until ) ),
			__METHOD__,
			array(
				'OFFSET' => $this->batchSize - 1,
				'ORDER BY' => 'change_time ASC',
			)
		);

		return $changeTime ?: $until;
	}

	/**
	 * Prunes all changes older than $until from the changes table.
	 *
	 * @param string $until MediaWiki concatenated string timestamp
	 *
	 * @return int the number of changes deleted.
	 */
	private function pruneChanges( $until ) {
		$dbw = wfGetDB( DB_MASTER );

		$dbw->delete(
			'wb_changes',
			array( 'change_time < ' . $dbw->addQuotes( $until ) ),
			__METHOD__
		);

		return $dbw->affectedRows();
	}

	/**
	 * @return MessageReporter
	 */
	public function getMessageReporter() {
		return $this->messageReporter;
	}

	/**
	 * @param MessageReporter $messageReporter
	 */
	public function setMessageReporter( MessageReporter $messageReporter ) {
		$this->messageReporter = $messageReporter;
	}

}