'GenericArrayObject' => __DIR__ . '/includes/libs/GenericArrayObject.php',
'GetConfiguration' => __DIR__ . '/maintenance/getConfiguration.php',
'GetLagTimes' => __DIR__ . '/maintenance/getLagTimes.php',
- 'GetSlaveServer' => __DIR__ . '/maintenance/getSlaveServer.php',
+ 'GetSlaveServer' => __DIR__ . '/maintenance/getReplicaServer.php',
'GetTextMaint' => __DIR__ . '/maintenance/getText.php',
'GitInfo' => __DIR__ . '/includes/GitInfo.php',
'GlobalDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
'ORAResult' => __DIR__ . '/includes/db/DatabaseOracle.php',
'ObjectCache' => __DIR__ . '/includes/objectcache/ObjectCache.php',
'ObjectFactory' => __DIR__ . '/includes/libs/ObjectFactory.php',
- 'ObjectFileCache' => __DIR__ . '/includes/cache/ObjectFileCache.php',
'OldChangesList' => __DIR__ . '/includes/changes/OldChangesList.php',
'OldLocalFile' => __DIR__ . '/includes/filerepo/file/OldLocalFile.php',
'OracleInstaller' => __DIR__ . '/includes/installer/OracleInstaller.php',
+++ /dev/null
-<!DOCTYPE html>
-<html lang="en" dir="ltr">
-<head>
- <meta charset="utf-8">
- <link rel="stylesheet" href="../../resources/src/mediawiki.action/mediawiki.action.history.diff.css">
- <link rel="stylesheet" media="print" href="../../resources/src/mediawiki.action/mediawiki.action.history.diff.print.css">
-</head>
-<body>
-
-<p>This show various styles for our diff action. Style sheet: <code><a href="../../resources/src/mediawiki.action/mediawiki.action.history.diff.css">resources/src/mediawiki.action/mediawiki.action.history.diff.css</a></code>.</p>
-<p>This file might help us fix our diff colors which have been a recurring issues among the community for a loooong time.</p>
-<p>Try it out in print mode, too. Style sheet: <code><a href="../../resources/src/mediawiki.action/mediawiki.action.history.diff.print.css">resources/src/mediawiki.action/mediawiki.action.history.diff.print.css</a></code>.</p>
-
-<p>Practical example copied from MediaWiki's HTML output:</p>
-
-<table class="diff diff-contentalign-left">
- <colgroup><col class="diff-marker">
- <col class="diff-content">
- <col class="diff-marker">
- <col class="diff-content">
- </colgroup>
-<tbody>
-<tr>
- <td class="diff-marker">−</td>
- <td class="diff-deletedline"><div>Lorem ipsum dolor sit amet<del class="diffchange diffchange-inline">, consectetur adipisicing elit</del>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
- <td class="diff-marker">+</td>
- <td class="diff-addedline"><div>Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
-</tr>
-<tr>
- <td class="diff-marker">−</td>
- <td class="diff-deletedline"></td>
- <td colspan="2" class="diff-empty"> </td>
-</tr>
-<tr>
- <td class="diff-marker">−</td>
- <td class="diff-deletedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
- <td colspan="2" class="diff-empty"> </td>
-</tr>
-<tr>
- <td class="diff-marker"> </td>
- <td class="diff-context"></td>
- <td class="diff-marker"> </td>
- <td class="diff-context"></td>
-</tr>
-<tr>
- <td class="diff-marker"> </td>
- <td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
- <td class="diff-marker"> </td>
- <td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
-</tr>
-<tr>
- <td class="diff-marker"> </td>
- <td class="diff-context"></td>
- <td class="diff-marker"> </td>
- <td class="diff-context"></td>
-</tr>
-<tr>
- <td class="diff-marker">−</td>
- <td class="diff-deletedline"><div>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim<del class="diffchange diffchange-inline"> id est laborum</del>.</div></td>
- <td class="diff-marker">+</td>
- <td class="diff-addedline"><div>Excepteur sint occaecat cupidatat non proident, sunt<ins class="diffchange diffchange-inline"> reprehenderit in voluptate</ins> in culpa qui officia deserunt mollit anim.</div></td>
-</tr>
-<tr>
- <td colspan="2" class="diff-empty"> </td>
- <td class="diff-marker">+</td>
- <td class="diff-addedline"></td>
-</tr>
-<tr>
- <td colspan="2" class="diff-empty"> </td>
- <td class="diff-marker">+</td>
- <td class="diff-addedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
-</tr>
-</tbody></table>
-
-<p>Below are some basic lines being applied one or two classes. Mainly for debugging purposes.</p>
-
-<table class="diff">
- <tr><th>Diff</th></tr>
-
- <tr><td class="diff-addedline"><code>diff-addedline</code>: added line</td></tr>
- <tr><td class="diff-deletedline"><code>diff-deletedline</code>: deleted line</td></tr>
- <tr><td class="diff-context"><code>diff-context</code>: context</td></tr>
-
- <tr><th>Same as above with a <code><ins></code> or <code><del></code> child element having the <code>diffchange</code> class:</th></tr>
-
- <tr><td class="diffchange">Diffchange</td></tr>
- <tr><td class="diff-addedline"><ins class="diffchange">Added line + diffchange</ins></td></tr>
- <tr><td class="diff-deletedline"><del class="diffchange">Deleted line + diffchange</del></td></tr>
-</table>
-
-</body>
-</html>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="../../resources/src/mediawiki/mediawiki.diff.styles.css">
+ <link rel="stylesheet" media="print" href="../../resources/src/mediawiki/mediawiki.diff.styles.print.css">
+</head>
+<body>
+
+<p>This show various styles for our diff action. Style sheet: <code><a href="../../resources/src/mediawiki/mediawiki.diff.styles.css">resources/src/mediawiki/mediawiki.diff.styles.css</a></code>.</p>
+<p>This file might help us fix our diff colors which have been a recurring issues among the community for a loooong time.</p>
+<p>Try it out in print mode, too. Style sheet: <code><a href="../../resources/src/mediawiki/mediawiki.diff.styles.print.css">resources/src/mediawiki/mediawiki.diff.styles.print.css</a></code>.</p>
+
+<p>Practical example copied from MediaWiki's HTML output:</p>
+
+<table class="diff diff-contentalign-left">
+ <colgroup><col class="diff-marker">
+ <col class="diff-content">
+ <col class="diff-marker">
+ <col class="diff-content">
+ </colgroup>
+<tbody>
+<tr>
+ <td class="diff-marker">−</td>
+ <td class="diff-deletedline"><div>Lorem ipsum dolor sit amet<del class="diffchange diffchange-inline">, consectetur adipisicing elit</del>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
+ <td class="diff-marker">+</td>
+ <td class="diff-addedline"><div>Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></td>
+</tr>
+<tr>
+ <td class="diff-marker">−</td>
+ <td class="diff-deletedline"></td>
+ <td colspan="2" class="diff-empty"> </td>
+</tr>
+<tr>
+ <td class="diff-marker">−</td>
+ <td class="diff-deletedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
+ <td colspan="2" class="diff-empty"> </td>
+</tr>
+<tr>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"></td>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"></td>
+</tr>
+<tr>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"><div>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div></td>
+</tr>
+<tr>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"></td>
+ <td class="diff-marker"> </td>
+ <td class="diff-context"></td>
+</tr>
+<tr>
+ <td class="diff-marker">−</td>
+ <td class="diff-deletedline"><div>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim<del class="diffchange diffchange-inline"> id est laborum</del>.</div></td>
+ <td class="diff-marker">+</td>
+ <td class="diff-addedline"><div>Excepteur sint occaecat cupidatat non proident, sunt<ins class="diffchange diffchange-inline"> reprehenderit in voluptate</ins> in culpa qui officia deserunt mollit anim.</div></td>
+</tr>
+<tr>
+ <td colspan="2" class="diff-empty"> </td>
+ <td class="diff-marker">+</td>
+ <td class="diff-addedline"></td>
+</tr>
+<tr>
+ <td colspan="2" class="diff-empty"> </td>
+ <td class="diff-marker">+</td>
+ <td class="diff-addedline"><div>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</div></td>
+</tr>
+</tbody></table>
+
+<p>Below are some basic lines being applied one or two classes. Mainly for debugging purposes.</p>
+
+<table class="diff">
+ <tr><th>Diff</th></tr>
+
+ <tr><td class="diff-addedline"><code>diff-addedline</code>: added line</td></tr>
+ <tr><td class="diff-deletedline"><code>diff-deletedline</code>: deleted line</td></tr>
+ <tr><td class="diff-context"><code>diff-context</code>: context</td></tr>
+
+ <tr><th>Same as above with a <code><ins></code> or <code><del></code> child element having the <code>diffchange</code> class:</th></tr>
+
+ <tr><td class="diffchange">Diffchange</td></tr>
+ <tr><td class="diff-addedline"><ins class="diffchange">Added line + diffchange</ins></td></tr>
+ <tr><td class="diff-deletedline"><del class="diffchange">Deleted line + diffchange</del></td></tr>
+</table>
+
+</body>
+</html>
$this->mReason = $options['reason'];
$this->mTimestamp = wfTimestamp( TS_MW, $options['timestamp'] );
- $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $options['expiry'] );
+ $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $options['expiry'] );
# Boolean settings
$this->mAuto = (bool)$options['auto'];
* @return Block|null
*/
public static function newFromID( $id ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->selectRow(
'ipblocks',
self::selectFields(),
* @return bool Whether a relevant block was found
*/
protected function newLoad( $vagueTarget = null ) {
- $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( $this->mFromMaster ? DB_MASTER : DB_REPLICA );
if ( $this->type !== null ) {
$conds = [
# range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
# so we can improve performance by filtering on a LIKE clause
$chunk = self::getIpFragment( $start );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$like = $dbr->buildLike( $chunk, $dbr->anyString() );
# Fairly hard to make a malicious SQL statement out of hex characters,
$this->mParentBlockId = $row->ipb_parent_block_id;
// I wish I didn't have to do this
- $this->mExpiry = wfGetDB( DB_SLAVE )->decodeExpiry( $row->ipb_expiry );
+ $this->mExpiry = wfGetDB( DB_REPLICA )->decodeExpiry( $row->ipb_expiry );
$this->isHardblock( !$row->ipb_anon_only );
$this->isAutoblocking( $row->ipb_enable_autoblock );
*/
protected function getDatabaseArray( $db = null ) {
if ( !$db ) {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
}
$expiry = $db->encodeExpiry( $this->mExpiry );
return;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$options = [ 'ORDER BY' => 'rc_timestamp DESC' ];
$conds = [ 'rc_user_text' => (string)$block->getTarget() ];
* @param array $ipChain List of IPs (strings), usually retrieved from the
* X-Forwarded-For header of the request
* @param bool $isAnon Exclude anonymous-only blocks if false
- * @param bool $fromMaster Whether to query the master or slave database
+ * @param bool $fromMaster Whether to query the master or replica DB
* @return array Array of Blocks
* @since 1.22
*/
if ( $fromMaster ) {
$db = wfGetDB( DB_MASTER );
} else {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
}
$conds = $db->makeList( $conds, LIST_OR );
if ( !$isAnon ) {
return true;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow(
'category',
[ 'cat_id', 'cat_title', 'cat_pages', 'cat_subcats', 'cat_files' ],
*/
public function getMembers( $limit = false, $offset = '' ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds = [ 'cl_to' => $this->getName(), 'cl_from = page_id' ];
$options = [ 'ORDER BY' => 'cl_sortkey' ];
/** @var string "AND" or "OR" */
protected $mode;
- /** @var IDatabase Read-DB slave */
+ /** @var IDatabase Read-DB replica DB */
protected $dbr;
/**
* @return array Array of page_ids (those given to seed() that match the conditions)
*/
public function run() {
- $this->dbr = wfGetDB( DB_SLAVE );
+ $this->dbr = wfGetDB( DB_REPLICA );
while ( count( $this->next ) > 0 ) {
$this->scanNextLayer();
}
}
function doCategoryQuery() {
- $dbr = wfGetDB( DB_SLAVE, 'category' );
+ $dbr = wfGetDB( DB_REPLICA, 'category' );
$this->nextPage = [
'page' => null,
* - password: DB password
* - type: DB type
*
- * - load: Ratio of DB_SLAVE load, must be >=0, the sum of all loads must be >0.
+ * - load: Ratio of DB_REPLICA load, must be >=0, the sum of all loads must be >0.
* If this is zero for any given server, no normal query traffic will be
* sent to it. It will be excluded from lag checks in maintenance scripts.
* The only way it can receive traffic is if groupLoads is used.
* - DBO_COMPRESS -- uses internal compression in database connections,
* if available
*
- * - max lag: (optional) Maximum replication lag before a slave will taken out of rotation
+ * - max lag: (optional) Maximum replication lag before a replica DB goes out of rotation
* - is static: (optional) Set to true if the dataset is static and no replication is used.
* - cliMode: (optional) Connection handles will not assume that requests are short-lived
* nor that INSERT..SELECT can be rewritten into a buffered SELECT and INSERT.
* perhaps in some command-line scripts).
*
* The first server listed in this array (with key 0) will be the master. The
- * rest of the servers will be slaves. To prevent writes to your slaves due to
+ * rest of the servers will be replica DBs. To prevent writes to your replica DBs due to
* accidental misconfiguration or MediaWiki bugs, set read_only=1 on all your
- * slaves in my.cnf. You can set read_only mode at runtime using:
+ * replica DBs in my.cnf. You can set read_only mode at runtime using:
*
* @code
* SET @@read_only=1;
* @endcode
*
- * Since the effect of writing to a slave is so damaging and difficult to clean
+ * Since the effect of writing to a replica DB is so damaging and difficult to clean
* up, we at Wikimedia set read_only=1 in my.cnf on all our DB servers, even
* our masters, and then set read_only=0 on masters at runtime.
*/
'class' => 'SqlBagOStuff',
'args' => [ [ 'slaveOnly' => false ] ]
],
- 'loggroup' => 'SQLBagOStuff'
+ 'loggroup' => 'SQLBagOStuff',
+ 'reportDupes' => false
],
'apc' => [ 'class' => 'APCBagOStuff', 'reportDupes' => false ],
$wgSquidMaxage = 18000;
/**
- * Cache timeout for the CDN when DB slave lag is high
+ * Cache timeout for the CDN when DB replica DB lag is high
* @see $wgSquidMaxage
* @since 1.27
*/
* If set, any SquidPurge call on a URL or URLs will send a second purge no less than
* this many seconds later via the job queue. This requires delayed job support.
* This should be safely higher than the 'max lag' value in $wgLBFactoryConf, so that
- * slave lag does not cause page to be stuck in stales states in CDN.
+ * replica DB lag does not cause page to be stuck in stales states in CDN.
*
* This also fixes race conditions in two-tiered CDN setups (e.g. cdn2 => cdn1 => MediaWiki).
* If a purge for a URL reaches cdn2 before cdn1 and a request reaches cdn2 for that URL,
$wgJobBackoffThrottling = [];
/**
- * Make job runners commit changes for slave-lag prone jobs one job at a time.
- * This is useful if there are many job workers that race on slave lag checks.
+ * Make job runners commit changes for replica DB-lag prone jobs one job at a time.
+ * This is useful if there are many job workers that race on replica DB lag checks.
* If set, jobs taking this many seconds of DB write time have serialized commits.
*
* Note that affected jobs may have worse lock contention. Also, if they affect
$wgAPIMaxUncachedDiffs = 1;
/**
- * Maximum amount of DB lag on a majority of DB slaves to tolerate
+ * Maximum amount of DB lag on a majority of DB replica DBs to tolerate
* before forcing bots to retry any write requests via API errors.
* This should be lower than the 'max lag' value in $wgLBFactoryConf.
*/
* Valid database indexes
* Operation-based indexes
*/
-define( 'DB_SLAVE', -1 ); # Read from the slave (or only server)
+define( 'DB_REPLICA', -1 ); # Read from a replica (or only server)
define( 'DB_MASTER', -2 ); # Write to master (or only server)
/**@}*/
# Obsolete aliases
+define( 'DB_SLAVE', -1 );
define( 'DB_READ', -1 );
define( 'DB_WRITE', -2 );
* @return bool|stdClass
*/
protected function getLastDelete() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$data = $dbr->selectRow(
[ 'logging', 'user' ],
[
* Check if the site is in read-only mode and return the message if so
*
* This checks wfConfiguredReadOnlyReason() and the main load balancer
- * for slave lag. This may result in DB_SLAVE connection being made.
+ * for replica DB lag. This may result in DB connection being made.
*
* @return string|bool String when in read-only mode; false otherwise
*/
* Get a Database object.
*
* @param int $db Index of the connection to get. May be DB_MASTER for the
- * master (for write queries), DB_SLAVE for potentially lagged read
+ * master (for write queries), DB_REPLICA for potentially lagged read
* queries, or an integer >= 0 for a particular server.
*
* @param string|string[] $groups Query groups. An array of group names that this query
*
* @param string|bool $wiki The wiki ID, or false for the current wiki
*
- * Note: multiple calls to wfGetDB(DB_SLAVE) during the course of one request
+ * Note: multiple calls to wfGetDB(DB_REPLICA) during the course of one request
* will always return the same object, unless the underlying connection or load
* balancer is manually destroyed.
*
}
/**
- * Waits for the slaves to catch up to the master position
+ * Waits for the replica DBs to catch up to the master position
*
* Use this when updating very large numbers of rows, as in maintenance scripts,
- * to avoid causing too much lag. Of course, this is a no-op if there are no slaves.
+ * to avoid causing too much lag. Of course, this is a no-op if there are no replica DBs.
*
* By default this waits on the main DB cluster of the current wiki.
* If $cluster is set to "*" it will wait on all DB clusters, including
if ( isset( self::$blobCache[$this->mOldId] ) ) {
$obj = self::$blobCache[$this->mOldId];
} else {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow(
'text',
[ 'old_flags', 'old_text' ],
* @return string|bool
*/
function getText() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow( 'cur', [ 'cur_text' ], [ 'cur_id' => $this->mCurId ] );
if ( !$row ) {
return false;
* @return array Array to be passed to Database::buildLike() or false on error
*/
public static function makeLikeArray( $filterEntry, $protocol = 'http://' ) {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
$target = $protocol . $filterEntry;
$bits = wfParseUrl( $target );
return null;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Up to the value of $wgShowRollbackEditCount revisions are counted
$res = $dbr->select(
$request->response()->setCookie( 'UseCDNCache', 'false', $expires, $options );
}
- // Avoid letting a few seconds of slave lag cause a month of stale data. This logic is
+ // Avoid letting a few seconds of replica DB lag cause a month of stale data. This logic is
// also intimately related to the value of $wgCdnReboundPurgeDelay.
- if ( $factory->laggedSlaveUsed() ) {
+ if ( $factory->laggedReplicaUsed() ) {
$maxAge = $config->get( 'CdnMaxageLagged' );
$context->getOutput()->lowerCdnMaxage( $maxAge );
$request->response()->header( "X-Database-Lagged: true" );
*/
class MergeHistory {
- /** @const int Maximum number of revisions that can be merged at once (avoid too much slave lag) */
+ /** @const int Maximum number of revisions that can be merged at once */
const REVISION_LIMIT = 5000;
/** @var Title Page from which history will be merged */
$lb->setArray( $arr );
# Fetch existence plus the hiddencat property
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$fields = array_merge(
LinkCache::getSelectFields(),
[ 'page_namespace', 'page_title', 'pp_value' ]
}
/**
- * Show a warning about slave lag
+ * Show a warning about replica DB lag
*
* If the lag is higher than $wgSlaveLagCritical seconds,
* then the warning is a bit more obvious. If the lag is
}
if ( $queryIDs ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->select(
'page_props',
[
}
if ( $queryIDs != [] ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->select(
'page_props',
[
* @return bool
*/
private function checkIfSent() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$sent = $dbr->selectField(
'updatelog', '1', [ 'ul_key' => $this->key ], __METHOD__ );
return $sent !== false;
*/
private function getOrCreatePingbackId() {
if ( !$this->id ) {
- $id = wfGetDB( DB_SLAVE )->selectField(
+ $id = wfGetDB( DB_REPLICA )->selectField(
'updatelog', 'ul_value', [ 'ul_key' => 'PingBack' ] );
if ( $id == false ) {
$t = Title::newFromText( $search, $ns );
$prefix = $t ? $t->getDBkey() : '';
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( 'page',
[ 'page_id', 'page_namespace', 'page_title' ],
[
} else {
// Use a join to get the latest revision
$conds[] = 'rev_id=page_latest';
- $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
return self::loadFromConds( $db, $conds, $flags );
}
}
} else {
// Use a join to get the latest revision
$conds[] = 'rev_id = page_latest';
- $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
return self::loadFromConds( $db, $conds, $flags );
}
}
* Given a set of conditions, fetch a revision
*
* This method is used then a revision ID is qualified and
- * will incorporate some basic slave/master fallback logic
+ * will incorporate some basic replica DB/master fallback logic
*
* @param array $conditions
* @param int $flags (optional)
* @return Revision|null
*/
private static function newFromConds( $conditions, $flags = 0 ) {
- $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
$rev = self::loadFromConds( $db, $conditions, $flags );
// Make sure new pending/committed revision are visibile later on
*/
public static function fetchRevision( LinkTarget $title ) {
$row = self::fetchFromConds(
- wfGetDB( DB_SLAVE ),
+ wfGetDB( DB_REPLICA ),
[
'rev_id=page_latest',
'page_namespace' => $title->getNamespace(),
}
// rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
if ( $this->mId !== null ) {
- $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_SLAVE, [], $this->mWiki );
+ $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_REPLICA, [], $this->mWiki );
$row = $dbr->selectRow(
[ 'page', 'revision' ],
self::selectPageFields(),
* @return RecentChange|null
*/
public function getRecentChange( $flags = 0 ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
list( $dbType, ) = DBAccessObjectUtils::getDBOptions( $flags );
}
if ( !$row ) {
- // Text data is immutable; check slaves first.
- $dbr = wfGetDB( DB_SLAVE );
+ // Text data is immutable; check replica DBs first.
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow( 'text',
[ 'old_text', 'old_flags' ],
[ 'old_id' => $textId ],
__METHOD__ );
}
- // Fallback to the master in case of slave lag. Also use FOR UPDATE if it was
+ // Fallback to the master in case of replica DB lag. Also use FOR UPDATE if it was
// used to fetch this revision to avoid missing the row due to REPEATABLE-READ.
$forUpdate = ( $this->mQueryFlags & self::READ_LOCKING == self::READ_LOCKING );
if ( !$row && ( $forUpdate || wfGetLB()->getServerCount() > 1 ) ) {
wfDebugLog( 'Revision', "No blob for text row '$textId' (revision {$this->getId()})." );
}
- # No negative caching -- negative hits on text rows may be due to corrupted slave servers
+ # No negative caching -- negative hits on text rows may be due to corrupted replica DB servers
if ( $wgRevisionCacheExpiry && $text !== false ) {
$processCache->set( $key, $text );
$cache->set( $key, $text, $wgRevisionCacheExpiry );
static function getTimestampFromId( $title, $id, $flags = 0 ) {
$db = ( $flags & self::READ_LATEST )
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
// Casting fix for databases that can't take '' for rev_id
if ( $id == '' ) {
$id = 0;
}
$this->mRefreshMutableFields = false;
- $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_SLAVE, [], $this->mWiki );
+ $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_REPLICA, [], $this->mWiki );
$row = $dbr->selectRow(
[ 'revision', 'user' ],
[ 'rev_deleted', 'user_name' ],
*/
public function reset() {
if ( !$this->res ) {
- $this->res = $this->doQuery( wfGetDB( DB_SLAVE ) );
+ $this->res = $this->doQuery( wfGetDB( DB_REPLICA ) );
} else {
$this->res->rewind();
}
'LinkCache' => function( MediaWikiServices $services ) {
return new LinkCache(
- $services->getTitleFormatter()
+ $services->getTitleFormatter(),
+ ObjectCache::getMainWANInstance()
);
},
# Update schema
$u = new SiteStatsUpdate( 0, 0, 0 );
$u->doUpdate();
- self::$row = self::doLoad( wfGetDB( DB_SLAVE ) );
+ self::$row = self::doLoad( wfGetDB( DB_REPLICA ) );
}
self::$loaded = true;
static function loadAndLazyInit() {
global $wgMiserMode;
- wfDebug( __METHOD__ . ": reading site_stats from slave\n" );
- $row = self::doLoad( wfGetDB( DB_SLAVE ) );
+ wfDebug( __METHOD__ . ": reading site_stats from replica DB\n" );
+ $row = self::doLoad( wfGetDB( DB_REPLICA ) );
if ( !self::isSane( $row ) ) {
// Might have just been initialized during this request? Underflow?
- wfDebug( __METHOD__ . ": site_stats damaged or missing on slave\n" );
+ wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB\n" );
$row = self::doLoad( wfGetDB( DB_MASTER ) );
}
// clean schema with mwdumper.
wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
- SiteStatsInit::doAllAndCommit( wfGetDB( DB_SLAVE ) );
+ SiteStatsInit::doAllAndCommit( wfGetDB( DB_REPLICA ) );
$row = self::doLoad( wfGetDB( DB_MASTER ) );
}
wfMemcKey( 'SiteStats', 'groupcounts', $group ),
$cache::TTL_HOUR,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $group ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$setOpts += Database::getCacheSetOptions( $dbr );
*/
static function pagesInNs( $ns ) {
if ( !isset( self::$pageCount[$ns] ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
self::$pageCount[$ns] = (int)$dbr->selectField(
'page',
'COUNT(*)',
} elseif ( $database ) {
$this->db = wfGetDB( DB_MASTER );
} else {
- $this->db = wfGetDB( DB_SLAVE, 'vslow' );
+ $this->db = wfGetDB( DB_REPLICA, 'vslow' );
}
}
* @return Title|null The new object, or null on an error
*/
public static function newFromID( $id, $flags = 0 ) {
- $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
$row = $db->selectRow(
'page',
self::getSelectFields(),
if ( !count( $ids ) ) {
return [];
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'page',
* @return Title|null An object representing the article, or null if no such article was found
*/
public static function nameOf( $id ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$s = $dbr->selectRow(
'page',
* @param string $action Action that permission needs to be checked for
* @param User $user User to check
* @param string $rigor One of (quick,full,secure)
- * - quick : does cheap permission checks from slaves (usable for GUI creation)
- * - full : does cheap and expensive checks possibly from a slave
+ * - quick : does cheap permission checks from replica DBs (usable for GUI creation)
+ * - full : does cheap and expensive checks possibly from a replica DB
* - secure : does cheap and expensive checks, using the master as needed
* @param array $ignoreErrors Array of Strings Set this to a list of message keys
* whose corresponding errors may be ignored.
* @param string $action Action that permission needs to be checked for
* @param User $user User to check
* @param string $rigor One of (quick,full,secure)
- * - quick : does cheap permission checks from slaves (usable for GUI creation)
- * - full : does cheap and expensive checks possibly from a slave
+ * - quick : does cheap permission checks from replica DBs (usable for GUI creation)
+ * - full : does cheap and expensive checks possibly from a replica DB
* - secure : does cheap and expensive checks, using the master as needed
* @param bool $short Set this to true to stop after the first permission error.
* @return array Array of arrays of the arguments to wfMessage to explain permissions problems.
}
if ( $this->mTitleProtection === null ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'protected_titles',
[
return [ $this->mHasCascadingRestrictions, $pagerestrictions ];
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $this->getNamespace() == NS_FILE ) {
$tables = [ 'imagelinks', 'page_restrictions' ];
* restrictions from page table (pre 1.10)
*/
public function loadRestrictionsFromRows( $rows, $oldFashionedRestrictions = null ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$restrictionTypes = $this->getRestrictionTypes();
*/
public function loadRestrictions( $oldFashionedRestrictions = null ) {
if ( !$this->mRestrictionsLoaded ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $this->exists() ) {
$res = $dbr->select(
'page_restrictions',
return [];
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds['page_namespace'] = $this->getNamespace();
$conds[] = 'page_title ' . $dbr->buildLike( $this->getDBkey() . '/', $dbr->anyString() );
$options = [];
if ( $this->getNamespace() < 0 ) {
$n = 0;
} else {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$n = $dbr->selectField( 'archive', 'COUNT(*)',
[ 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ],
if ( $this->getNamespace() < 0 ) {
return false;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$deleted = (bool)$dbr->selectField( 'archive', '1',
[ 'ar_namespace' => $this->getNamespace(), 'ar_title' => $this->getDBkey() ],
__METHOD__
if ( count( $options ) > 0 ) {
$db = wfGetDB( DB_MASTER );
} else {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
}
$res = $db->select(
return [];
}
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
$blNamespace = "{$prefix}_namespace";
$blTitle = "{$prefix}_title";
return [];
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
[ 'page', 'pagelinks' ],
[ 'pl_namespace', 'pl_title' ],
return $data;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'categorylinks',
* @return int|bool Old revision ID, or false if none exists
*/
public function getPreviousRevisionID( $revId, $flags = 0 ) {
- $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
$revId = $db->selectField( 'revision', 'rev_id',
[
'rev_page' => $this->getArticleID( $flags ),
* @return int|bool Next revision ID, or false if none exists
*/
public function getNextRevisionID( $revId, $flags = 0 ) {
- $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
$revId = $db->selectField( 'revision', 'rev_id',
[
'rev_page' => $this->getArticleID( $flags ),
public function getFirstRevision( $flags = 0 ) {
$pageId = $this->getArticleID( $flags );
if ( $pageId ) {
- $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ $db = ( $flags & self::GAID_FOR_UPDATE ) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_REPLICA );
$row = $db->selectRow( 'revision', Revision::selectFields(),
[ 'rev_page' => $pageId ],
__METHOD__,
* @return bool
*/
public function isNewPage() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
return (bool)$dbr->selectField( 'page', 'page_is_new', $this->pageCond(), __METHOD__ );
}
}
if ( $this->mIsBigDeletion === null ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$revCount = $dbr->selectRowCount(
'revision',
}
if ( $this->mEstimateRevisions === null ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$this->mEstimateRevisions = $dbr->estimateRowCount( 'revision', '*',
[ 'rev_page' => $this->getArticleID() ], __METHOD__ );
}
if ( !$old || !$new ) {
return 0; // nothing to compare
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds = [
'rev_page' => $this->getArticleID(),
'rev_timestamp > ' . $dbr->addQuotes( $dbr->timestamp( $old->getTimestamp() ) ),
}
return $authors;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( 'revision', 'DISTINCT rev_user_text',
[
'rev_page' => $this->getArticleID(),
$conds + [ 'page_touched < ' . $dbw->addQuotes( $dbTimestamp ) ],
$fname
);
+ MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $this );
}
),
DeferredUpdates::PRESEND
*/
public function getTouched( $db = null ) {
if ( $db === null ) {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
}
$touched = $db->selectField( 'page', 'page_touched', $this->pageCond(), __METHOD__ );
return $touched;
public function getRedirectsHere( $ns = null ) {
$redirs = [];
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$where = [
'rd_namespace' => $this->getNamespace(),
'rd_title' => $this->getDBkey(),
* @throws MWException
*/
private function getConnection() {
- return $this->loadBalancer->getConnection( DB_SLAVE, [ 'watchlist' ] );
+ return $this->loadBalancer->getConnection( DB_REPLICA, [ 'watchlist' ] );
}
/**
}
/**
- * @param int $slaveOrMaster DB_MASTER or DB_SLAVE
+ * @param int $dbIndex DB_MASTER or DB_REPLICA
*
* @return DatabaseBase
* @throws MWException
*/
- private function getConnection( $slaveOrMaster ) {
- return $this->loadBalancer->getConnection( $slaveOrMaster, [ 'watchlist' ] );
+ private function getConnection( $dbIndex ) {
+ return $this->loadBalancer->getConnection( $dbIndex, [ 'watchlist' ] );
}
/**
* @return int
*/
public function countWatchedItems( User $user ) {
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$return = (int)$dbr->selectField(
'watchlist',
'COUNT(*)',
* @return int
*/
public function countWatchers( LinkTarget $target ) {
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$return = (int)$dbr->selectField(
'watchlist',
'COUNT(*)',
* @throws MWException
*/
public function countVisitingWatchers( LinkTarget $target, $threshold ) {
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$visitingWatchers = (int)$dbr->selectField(
'watchlist',
'COUNT(*)',
public function countWatchersMultiple( array $targets, array $options = [] ) {
$dbOptions = [ 'GROUP BY' => [ 'wl_namespace', 'wl_title' ] ];
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
if ( array_key_exists( 'minimumWatchers', $options ) ) {
$dbOptions['HAVING'] = 'COUNT(*) >= ' . (int)$options['minimumWatchers'];
array $targetsWithVisitThresholds,
$minimumWatchers = null
) {
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$conds = $this->getVisitingWatchersCondition( $dbr, $targetsWithVisitThresholds );
return false;
}
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$row = $dbr->selectRow(
'watchlist',
'wl_notificationtimestamp',
"wl_title {$options['sort']}"
];
}
- $db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_SLAVE );
+ $db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_REPLICA );
$res = $db->select(
'watchlist',
return $timestamps;
}
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$lb = new LinkBatch( $targetsToLoad );
$res = $dbr->select(
$queryOptions['LIMIT'] = $unreadLimit;
}
- $dbr = $this->getConnection( DB_SLAVE );
+ $dbr = $this->getConnection( DB_REPLICA );
$rowCount = $dbr->selectRowCount(
'watchlist',
'1',
return new FakeResultWrapper( [] );
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $direction === self::DIR_PREV ) {
list( $dirs, $oper ) = [ "ASC", ">=" ];
$title = $page->getTitle();
$id = $title->getArticleID();
- $dbr = wfGetDB( DB_SLAVE );
- $dbrWatchlist = wfGetDB( DB_SLAVE, 'watchlist' );
+ $dbr = wfGetDB( DB_REPLICA );
+ $dbrWatchlist = wfGetDB( DB_REPLICA, 'watchlist' );
$setOpts += Database::getCacheSetOptions( $dbr, $dbrWatchlist );
}
/**
- * Gets a default slave database connection object
+ * Gets a default replica DB connection object
* @return DatabaseBase
*/
protected function getDB() {
if ( !isset( $this->mSlaveDB ) ) {
- $this->mSlaveDB = wfGetDB( DB_SLAVE, 'api' );
+ $this->mSlaveDB = wfGetDB( DB_REPLICA, 'api' );
}
return $this->mSlaveDB;
* @param array $params
* @param bool|string $load Whether load the object's state from the database:
* - false: don't load (if the pageid is given, it will still be loaded)
- * - 'fromdb': load from a slave database
+ * - 'fromdb': load from a replica DB
* - 'fromdbmaster': load from the master database
* @return WikiPage
*/
}
}
- // If a majority of slaves are too lagged then disallow writes
- $slaveCount = wfGetLB()->getServerCount() - 1;
- if ( $numLagged >= ceil( $slaveCount / 2 ) ) {
+ // If a majority of replica DBs are too lagged then disallow writes
+ $replicaCount = wfGetLB()->getServerCount() - 1;
+ if ( $numLagged >= ceil( $replicaCount / 2 ) ) {
$laggedServers = implode( ', ', $laggedServers );
wfDebugLog(
'api-readonly',
$this->fld_patrolled = isset( $prop['patrolled'] );
$this->fld_tags = isset( $prop['tags'] );
- // Most of this code will use the 'contributions' group DB, which can map to slaves
+ // Most of this code will use the 'contributions' group DB, which can map to replica DBs
// with extra user based indexes or partioning by user. The additional metadata
- // queries should use a regular slave since the lookup pattern is not all by user.
- $dbSecondary = $this->getDB(); // any random slave
+ // queries should use a regular replica DB since the lookup pattern is not all by user.
+ $dbSecondary = $this->getDB(); // any random replica DB
// TODO: if the query is going only against the revision table, should this be done?
- $this->selectNamedDB( 'contributions', DB_SLAVE, 'contributions' );
+ $this->selectNamedDB( 'contributions', DB_REPLICA, 'contributions' );
$this->idMode = false;
if ( isset( $this->params['userprefix'] ) ) {
* @return void
*/
private function run( $resultPageSet = null ) {
- $this->selectNamedDB( 'watchlist', DB_SLAVE, 'watchlist' );
+ $this->selectNamedDB( 'watchlist', DB_REPLICA, 'watchlist' );
$params = $this->extractRequestParams();
* @return string|null TS_MW timestamp or null
*/
private static function lastEditTime( User $user ) {
- $time = wfGetDB( DB_SLAVE )->selectField(
+ $time = wfGetDB( DB_REPLICA )->selectField(
'recentchanges',
'MAX(rc_timestamp)',
[ 'rc_user_text' => $user->getName() ],
}
protected static function validateLogId( $logid ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->selectField( 'logging', 'log_id', [ 'log_id' => $logid ],
__METHOD__ );
return (bool)$result;
: $warning['file'];
$warnings[$warning['warning']] = $localFile->getName();
}
+
+ if ( isset( $warnings['no-change'] ) ) {
+ /** @var File $file */
+ $file = $warnings['no-change'];
+ unset( $warnings['no-change'] );
+
+ $warnings['nochange'] = [
+ 'timestamp' => wfTimestamp( TS_ISO_8601, $file->getTimestamp() )
+ ];
+ }
+
+ if ( isset( $warnings['duplicate-version'] ) ) {
+ $dupes = [];
+ /** @var File $dupe */
+ foreach ( $warnings['duplicate-version'] as $dupe ) {
+ $dupes[] = [
+ 'timestamp' => wfTimestamp( TS_ISO_8601, $dupe->getTimestamp() )
+ ];
+ }
+ unset( $warnings['duplicate-version'] );
+
+ ApiResult::setIndexedTagName( $dupes, 'ver' );
+ $warnings['duplicateversions'] = $dupes;
+ }
}
return $warnings;
"apihelp-options-example-change": "לשנות את ההעדפות <kbd>skin</kbd> ו־<kbd>hideminor</kbd>.",
"apihelp-options-example-complex": "לאתחל את כל ההעדפות ואז להגדיר את <kbd>skin</kbd> ואת <kbd>nickname</kbd>.",
"apihelp-paraminfo-description": "קבלת מידע על יחידות של API.",
- "apihelp-paraminfo-param-modules": "רשימה של שמות יחידות (ערכים של הפרמטרים <var>action</var> ו־<var>format</var>, או <kbd>main</kbd>). אפשר להגדיר תת־יחידות עם <kbd>+</kbd>.",
+ "apihelp-paraminfo-param-modules": "רשימה של שמות יחידות (ערכים של הפרמטרים <var>action</var> ו־<var>format</var>, או <kbd>main</kbd>). אפשר להגדיר תת־יחידות עם <kbd>+</kbd>, או כל התת־מודולים עם <kbd dir=\"ltr\">+*</kbd>, או כל התת־מודולים באופן רקורסיבי עם <kbd dir=\"ltr\">+**</kbd>.",
"apihelp-paraminfo-param-helpformat": "תסדיר מחרוזות העזרה.",
"apihelp-paraminfo-param-querymodules": "רשימת שמות יחידות query (ערך של הפרמטר <var>prop</var>, <var>meta</var> או <var>list</var>). יש להשתמש ב־<kbd>$1modules=query+foo</kbd> במקום <kbd>$1querymodules=foo</kbd>.",
"apihelp-paraminfo-param-mainmodule": "קבלת מידע עם היחידה הראשית (העליונה). יש להשתמש ב־<kbd>$1modules=main</kbd> במקום זה.",
"apihelp-paraminfo-param-pagesetmodule": "קבלת מידע גם על יחידת pageset (שמספק את titles= וידידיו).",
"apihelp-paraminfo-param-formatmodules": "רשימת שמות תסדירים (ערכים של הפרמטר <var>format</var>). יש להשתמש ב־<var>$1modules</var> במקום זה.",
"apihelp-paraminfo-example-1": "הצגת מידע עבור <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, ו־<kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd>.",
+ "apihelp-paraminfo-example-2": "הצגת מידע עבור כל התת־מודולים של <kbd>[[Special:ApiHelp/query|action=query]]</kbd>.",
"apihelp-parse-description": "מפענח את התוכן ומחזיר פלט מפענח.\n\nר' את יחידת ה־prop השיונות של <kbd>[[Special:ApiHelp/query|action=query]]</kbd> כדי לקבל מידע על הגרסה הנוכחית של הדף.\n\nיש מספר דרכים לציין טקסט לפענוח:\n# ציון דף או גרסה באמצעות <var>$1page</var>, <var>$1pageid</var>, או <var>$1oldid</var>.\n# ציון התוכן במפורש, באמצעות <var>$1text</var>, <var>$1title</var>, ו־<var>$1contentmodel</var>.\n# ציון רק של התקציר לפענוח. ל־<var>$1prop</var> צריך לתת ערך ריק.",
"apihelp-parse-param-title": "שם הדף שהטקסט שייך אליו. אם זה מושמט, יש לציין את <var>$1contentmodel</var>, ו־[[API]] ישמש ככותרת.",
"apihelp-parse-param-text": "הטקסט לפענוח. יש להשתמש ב־<var>$1title</var> או ב־<var>$1contentmodel</var>.",
"api-help-param-deprecated": "Застарілий.",
"api-help-param-required": "Цей параметр є обов'язковим.",
"api-help-datatypes-header": "Типи даних",
- "api-help-datatypes": "Ð\94еÑ\8fкÑ\96 Ñ\82ипи паÑ\80амеÑ\82Ñ\80Ñ\96в Ñ\83 запиÑ\82аÑ\85 API поÑ\82Ñ\80ебÑ\83Ñ\8eÑ\82Ñ\8c Ñ\88иÑ\80Ñ\88ого поÑ\8fÑ\81неннÑ\8f:\n;boolean\n:Ð\9bогÑ\96Ñ\87нÑ\96 паÑ\80амеÑ\82Ñ\80и пÑ\80аÑ\86Ñ\8eÑ\8eÑ\82Ñ\8c Ñ\8fк галоÑ\87ки HTML: Ñ\8fкÑ\89о паÑ\80амеÑ\82Ñ\80 вказано, не залежно вÑ\96д знаÑ\87еннÑ\8f, вÑ\96н вважаÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ñ\96Ñ\81Ñ\82инним. Щоб знаÑ\87еннÑ\8f бÑ\83ло Ñ\85ибним, пÑ\80опÑ\83Ñ\81Ñ\82Ñ\96Ñ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 зовÑ\81Ñ\96м.\n;timestamp\n:ЧаÑ\81овÑ\96 мÑ\96Ñ\82ки можÑ\83Ñ\82Ñ\8c бÑ\83Ñ\82и вказанÑ\96 Ñ\83 кÑ\96лÑ\8cкоÑ\85 Ñ\84оÑ\80маÑ\82аÑ\85. РекомендÑ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ñ\87аÑ\81 Ñ\96 даÑ\82а в ISO 8601. УÑ\81Ñ\96 знаÑ\87еннÑ\8f Ñ\87аÑ\81Ñ\83 в UTC, бÑ\83дÑ\8c-Ñ\8fкÑ\96 Ñ\87аÑ\81овÑ\96 поÑ\8fÑ\81и Ñ\96гноÑ\80Ñ\83Ñ\8eÑ\82Ñ\8cÑ\81Ñ\8f.\n:* Ð\94аÑ\82а Ñ\96 Ñ\87аÑ\81 ISO 8601, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (пÑ\83нкÑ\82Ñ\83аÑ\86Ñ\96Ñ\8f Ñ\96 <kbd>Z</kbd> необов'Ñ\8fзоквÑ\96)\n:* Ð\94аÑ\82а Ñ\96 Ñ\87аÑ\81 ISO 8601 з (Ñ\96гноÑ\80ованими) Ñ\87аÑ\81Ñ\82ками Ñ\81екÑ\83нди, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (деÑ\84Ñ\96Ñ\81и, двокÑ\80апки Ñ\82а <kbd>Z</kbd> необов'Ñ\8fзковÑ\96)\n:* ФоÑ\80маÑ\82 MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Ð\97агалÑ\8cний Ñ\87иÑ\81ловий Ñ\84оÑ\80маÑ\82, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (необов'Ñ\8fзковий Ñ\87аÑ\81овий поÑ\8fÑ\81 <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd> або <kbd>-<var>##</var></kbd> Ñ\96гноÑ\80Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f)\n:* ФоÑ\80маÑ\82 EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 RFC 2822 (Ñ\87аÑ\81овий поÑ\8fÑ\81 може бÑ\83Ñ\82и опÑ\83Ñ\89ений), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 RFC 850 (Ñ\87аÑ\81овий поÑ\8fÑ\81 може бÑ\83Ñ\82и опÑ\83Ñ\89ений), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 C ctime, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* СекÑ\83нди вÑ\96д 1970-01-01T00:00:00Z Ñ\83 виглÑ\8fдÑ\96 Ñ\86Ñ\96лого Ñ\87иÑ\81ла вÑ\96д 1 до 13 Ñ\86иÑ\84Ñ\80 (без <kbd>0</kbd>)\n:* Ð Ñ\8fдок <kbd>now</kbd>",
+ "api-help-datatypes": "Ð\92Ñ\85Ñ\96днÑ\96 данÑ\96 Ñ\83 MediaWiki маÑ\8eÑ\82Ñ\8c бÑ\83Ñ\82и в NFC-ноÑ\80малÑ\96зованомÑ\83 UTF-8. MediaWiki може Ñ\81пÑ\80обÑ\83ваÑ\82и конвеÑ\80Ñ\82Ñ\83ваÑ\82и вÑ\85Ñ\96днÑ\96 данÑ\96 Ñ\96нÑ\88ого виглÑ\8fдÑ\83, але вÑ\96д Ñ\86Ñ\8cого можÑ\83Ñ\82Ñ\8c поÑ\81Ñ\82Ñ\80аждаÑ\82и деÑ\8fкÑ\96 опеÑ\80аÑ\86Ñ\96Ñ\97 (Ñ\8fк [[Special:ApiHelp/edit|Ñ\80едагÑ\83ваннÑ\8f]] з пеÑ\80евÑ\96Ñ\80коÑ\8e MD5).\n\nÐ\94еÑ\8fкÑ\96 Ñ\82ипи паÑ\80амеÑ\82Ñ\80Ñ\96в Ñ\83 запиÑ\82аÑ\85 API поÑ\82Ñ\80ебÑ\83Ñ\8eÑ\82Ñ\8c Ñ\88иÑ\80Ñ\88ого поÑ\8fÑ\81неннÑ\8f:\n;boolean\n:Ð\9bогÑ\96Ñ\87нÑ\96 паÑ\80амеÑ\82Ñ\80и пÑ\80аÑ\86Ñ\8eÑ\8eÑ\82Ñ\8c Ñ\8fк галоÑ\87ки HTML: Ñ\8fкÑ\89о паÑ\80амеÑ\82Ñ\80 вказано, не залежно вÑ\96д знаÑ\87еннÑ\8f, вÑ\96н вважаÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ñ\96Ñ\81Ñ\82инним. Щоб знаÑ\87еннÑ\8f бÑ\83ло Ñ\85ибним, пÑ\80опÑ\83Ñ\81Ñ\82Ñ\96Ñ\82Ñ\8c паÑ\80амеÑ\82Ñ\80 зовÑ\81Ñ\96м.\n;timestamp\n:ЧаÑ\81овÑ\96 мÑ\96Ñ\82ки можÑ\83Ñ\82Ñ\8c бÑ\83Ñ\82и вказанÑ\96 Ñ\83 кÑ\96лÑ\8cкоÑ\85 Ñ\84оÑ\80маÑ\82аÑ\85. РекомендÑ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ñ\87аÑ\81 Ñ\96 даÑ\82а в ISO 8601. УÑ\81Ñ\96 знаÑ\87еннÑ\8f Ñ\87аÑ\81Ñ\83 в UTC, бÑ\83дÑ\8c-Ñ\8fкÑ\96 Ñ\87аÑ\81овÑ\96 поÑ\8fÑ\81и Ñ\96гноÑ\80Ñ\83Ñ\8eÑ\82Ñ\8cÑ\81Ñ\8f.\n:* Ð\94аÑ\82а Ñ\96 Ñ\87аÑ\81 ISO 8601, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (пÑ\83нкÑ\82Ñ\83аÑ\86Ñ\96Ñ\8f Ñ\96 <kbd>Z</kbd> необов'Ñ\8fзоквÑ\96)\n:* Ð\94аÑ\82а Ñ\96 Ñ\87аÑ\81 ISO 8601 з (Ñ\96гноÑ\80ованими) Ñ\87аÑ\81Ñ\82ками Ñ\81екÑ\83нди, <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (деÑ\84Ñ\96Ñ\81и, двокÑ\80апки Ñ\82а <kbd>Z</kbd> необов'Ñ\8fзковÑ\96)\n:* ФоÑ\80маÑ\82 MediaWiki, <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Ð\97агалÑ\8cний Ñ\87иÑ\81ловий Ñ\84оÑ\80маÑ\82, <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (необов'Ñ\8fзковий Ñ\87аÑ\81овий поÑ\8fÑ\81 <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd> або <kbd>-<var>##</var></kbd> Ñ\96гноÑ\80Ñ\83Ñ\94Ñ\82Ñ\8cÑ\81Ñ\8f)\n:* ФоÑ\80маÑ\82 EXIF, <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 RFC 2822 (Ñ\87аÑ\81овий поÑ\8fÑ\81 може бÑ\83Ñ\82и опÑ\83Ñ\89ений), <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 RFC 850 (Ñ\87аÑ\81овий поÑ\8fÑ\81 може бÑ\83Ñ\82и опÑ\83Ñ\89ений), <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* ФоÑ\80маÑ\82 C ctime, <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* СекÑ\83нди вÑ\96д 1970-01-01T00:00:00Z Ñ\83 виглÑ\8fдÑ\96 Ñ\86Ñ\96лого Ñ\87иÑ\81ла вÑ\96д 1 до 13 Ñ\86иÑ\84Ñ\80 (без <kbd>0</kbd>)\n:* Ð Ñ\8fдок <kbd>now</kbd>\n;алÑ\8cÑ\82еÑ\80наÑ\82ивний Ñ\80оздÑ\96лÑ\8cник багаÑ\82Ñ\8cоÑ\85 знаÑ\87енÑ\8c\n:Ð\9fаÑ\80амеÑ\82Ñ\80и, Ñ\89о пÑ\80иймаÑ\8eÑ\82Ñ\8c багаÑ\82о знаÑ\87енÑ\8c, зазвиÑ\87ай подаÑ\8eÑ\82Ñ\8cÑ\81Ñ\8f зÑ\96 знаÑ\87еннÑ\8fми, Ñ\80оздÑ\96леними веÑ\80Ñ\82икалÑ\8cноÑ\8e Ñ\80иÑ\81коÑ\8e, напÑ\80иклад, <kbd>param=value1|value2</kbd> або <kbd>param=value1%7Cvalue2</kbd>. ЯкÑ\89о знаÑ\87еннÑ\8f повинне мÑ\96Ñ\81Ñ\82иÑ\82и веÑ\80Ñ\82икалÑ\8cнÑ\83 Ñ\80иÑ\81кÑ\83, викоÑ\80иÑ\81Ñ\82овÑ\83йÑ\82е Ñ\8fк Ñ\80оздÑ\96лÑ\8cник U+001F (Ñ\80оздÑ\96лÑ\8cник одиниÑ\86Ñ\8c) ''Ñ\82а'' поÑ\81Ñ\82авÑ\82е U+001F пеÑ\80ед знаÑ\87еннÑ\8fм, напÑ\80иклад, <kbd>param=%1Fvalue1%1Fvalue2</kbd>.",
"api-help-param-type-limit": "Тип: ціле число або <kbd>max</kbd>",
"api-help-param-type-integer": "Тип: {{PLURAL:$1|1=ціле число|2=список цілих чисел}}",
"api-help-param-type-boolean": "Тип: логічний ([[Special:ApiHelp/main#main/datatypes|деталі]])",
"api-help-param-type-timestamp": "Тип: {{PLURAL:$1|1=часова мітка|2=список часових міток}} ([[Special:ApiHelp/main#main/datatypes|дозволені формати]])",
"api-help-param-type-user": "Тип: {{PLURAL:$1|1=ім'я користувача|2=список імен користувачів}}",
- "api-help-param-list": "{{PLURAL:$1|1=Одне з наступних значень|2=Значення (розділені через <kbd>{{!}}</kbd>)}}: $2",
+ "api-help-param-list": "{{PLURAL:$1|1=Одне з наступних значень|2=Значення (розділені через <kbd>{{!}}</kbd> або [[Special:ApiHelp/main#main/datatypes|альтернативу]])}}: $2",
"api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Повинно бути пустим|Може бути пустим або $2}}",
"api-help-param-limit": "Дозволено не більше $1.",
"api-help-param-limit2": "Дозволено не більше $1 ($2 для ботів).",
"api-help-param-integer-max": "{{PLURAL:$1|1=Значення має бути|2=Значення мають бути}} не більше $3.",
"api-help-param-integer-minmax": "{{PLURAL:$1|1=Значення має бути|2=Значення мають бути}} між $2 і $3.",
"api-help-param-upload": "Повинно бути надіслано у формі надсилання файлу використовуючи multipart/form-data.",
- "api-help-param-multi-separate": "Розділіть значення з допомогою <kbd>|</kbd>.",
+ "api-help-param-multi-separate": "Розділіть значення з допомогою <kbd>|</kbd> або [[Special:ApiHelp/main#main/datatypes|альтернативу]].",
"api-help-param-multi-max": "Максимальна кількість значень — {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} для ботів).",
"api-help-param-default": "За замовчуванням: $1",
"api-help-param-default-empty": "За замовчуванням: <span class=\"apihelp-empty\">(пусто)</span>",
$username = $user->getName();
- // Try the local user from the slave DB
+ // Try the local user from the replica DB
$localId = User::idFromName( $username );
$flags = User::READ_NORMAL;
return AuthenticationResponse::newAbstain();
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow(
'user',
[
return false;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow(
'user',
[ 'user_newpassword', 'user_newpass_time' ],
}
/**
- * Get the slave connection to the database
+ * Get the replica DB connection to the database
* When non existing, will initialize the connection.
* @return DatabaseBase
*/
protected function getDB() {
if ( !isset( $this->db ) ) {
- $this->db = wfGetDB( DB_SLAVE );
+ $this->db = wfGetDB( DB_REPLICA );
}
return $this->db;
return;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$table = [ 'user', 'user_properties' ];
$fields = [ 'user_name', 'up_value' ];
$conds = [ 'user_name' => $usersToCheck ];
*/
class HTMLFileCache extends FileCacheBase {
/**
- * Construct an ObjectFileCache from a Title and an action
+ * Construct an HTMLFileCache object from a Title and an action
+ *
+ * @deprecated since 1.24, instantiate this class directly
* @param Title|string $title Title object or prefixed DB key string
* @param string $action
* @throws MWException
* @return HTMLFileCache
- *
- * @deprecated Since 1.24, instantiate this class directly
*/
public static function newFromTitle( $title, $action ) {
return new self( $title, $action );
}
// This is similar to LinkHolderArray::replaceInternal
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$table = 'page';
$fields = array_merge(
LinkCache::getSelectFields(),
* @ingroup Cache
*/
class LinkCache {
- /**
- * @var HashBagOStuff
- */
+ /** @var HashBagOStuff */
private $mGoodLinks;
- /**
- * @var HashBagOStuff
- */
+ /** @var HashBagOStuff */
private $mBadLinks;
+ /** @var WANObjectCache */
+ private $wanCache;
+
+ /** @var bool */
private $mForUpdate = false;
- /**
- * @var TitleFormatter
- */
+ /** @var TitleFormatter */
private $titleFormatter;
/**
*/
const MAX_SIZE = 10000;
- public function __construct( TitleFormatter $titleFormatter ) {
+ public function __construct( TitleFormatter $titleFormatter, WANObjectCache $cache ) {
$this->mGoodLinks = new HashBagOStuff( [ 'maxKeys' => self::MAX_SIZE ] );
$this->mBadLinks = new HashBagOStuff( [ 'maxKeys' => self::MAX_SIZE ] );
+ $this->wanCache = $cache;
$this->titleFormatter = $titleFormatter;
}
return 0;
}
- // Some fields heavily used for linking...
- $db = $this->mForUpdate ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
+ // Cache template/file pages as they are less often viewed but heavily used
+ if ( $this->mForUpdate ) {
+ $row = $this->fetchPageRow( wfGetDB( DB_MASTER ), $nt );
+ } elseif ( $this->isCacheable( $nt ) ) {
+ // These pages are often transcluded heavily, so cache them
+ $cache = $this->wanCache;
+ $row = $cache->getWithSetCallback(
+ $cache->makeKey( 'page', $nt->getNamespace(), sha1( $nt->getDBkey() ) ),
+ $cache::TTL_DAY,
+ function ( $curValue, &$ttl, array &$setOpts ) use ( $cache, $nt ) {
+ $dbr = wfGetDB( DB_REPLICA );
+ $setOpts += Database::getCacheSetOptions( $dbr );
- $row = $db->selectRow( 'page', self::getSelectFields(),
- [ 'page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey() ],
- __METHOD__
- );
+ $row = $this->fetchPageRow( $dbr, $nt );
+ $mtime = $row ? wfTimestamp( TS_UNIX, $row->page_touched ) : false;
+ $ttl = $cache->adaptiveTTL( $mtime, $ttl );
- if ( $row !== false ) {
+ return $row;
+ }
+ );
+ } else {
+ $row = $this->fetchPageRow( wfGetDB( DB_REPLICA ), $nt );
+ }
+
+ if ( $row ) {
$this->addGoodLinkObjFromRow( $nt, $row );
$id = intval( $row->page_id );
} else {
return $id;
}
+ private function isCacheable( LinkTarget $title ) {
+ return ( $title->inNamespace( NS_TEMPLATE ) || $title->inNamespace( NS_FILE ) );
+ }
+
+ private function fetchPageRow( IDatabase $db, LinkTarget $nt ) {
+ $fields = self::getSelectFields();
+ if ( $this->isCacheable( $nt ) ) {
+ $fields[] = 'page_touched';
+ }
+
+ return $db->selectRow(
+ 'page',
+ $fields,
+ [ 'page_namespace' => $nt->getNamespace(), 'page_title' => $nt->getDBkey() ],
+ __METHOD__
+ );
+ }
+
+ /**
+ * Purge the link cache for a title
+ *
+ * @param LinkTarget $title
+ * @since 1.28
+ */
+ public function invalidateTitle( LinkTarget $title ) {
+ if ( $this->isCacheable( $title ) ) {
+ $cache = ObjectCache::getMainWANInstance();
+ $cache->delete(
+ $cache->makeKey( 'page', $title->getNamespace(), sha1( $title->getDBkey() ) )
+ );
+ }
+ }
+
/**
* Clears cache
*/
$cache->set( $cacheKey, $blob,
// Add part of a day to TTL to avoid all modules expiring at once
$cache::TTL_WEEK + mt_rand( 0, $cache::TTL_DAY ),
- Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) )
+ Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) )
);
return $blob;
}
public function updateMessage( $key ) {
$moduleNames = $this->getResourceLoader()->getModulesByMessage( $key );
foreach ( $moduleNames as $moduleName ) {
- // Uses a holdoff to account for database slave lag (for MessageCache)
+ // Uses a holdoff to account for database replica DB lag (for MessageCache)
$this->wanCache->touchCheckKey( $this->wanCache->makeKey( __CLASS__, $moduleName ) );
}
}
$where[] = 'global cache is expired';
$staleCache = $cache;
} elseif ( $hashVolatile ) {
- # DB results are slave lag prone until the holdoff TTL passes.
+ # DB results are replica DB lag prone until the holdoff TTL passes.
# By then, updates should be reflected in loadFromDBWithLock().
# One thread renerates the cache while others use old values.
$where[] = 'global cache is expired/volatile';
function loadFromDB( $code, $mode = null ) {
global $wgMaxMsgCacheEntrySize, $wgLanguageCode, $wgAdaptiveMessageCache;
- $dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_SLAVE );
+ $dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_REPLICA );
$cache = [];
}
// Mark this cache as definitely "latest" (non-volatile) so
- // load() calls do try to refresh the cache with slave data
+ // load() calls do try to refresh the cache with replica DB data
$this->mCache[$code]['LATEST'] = time();
// Update caches if the lock was acquired
+++ /dev/null
-<?php
-/**
- * Object cache in the file system.
- *
- * 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
- *
- * @file
- * @ingroup Cache
- */
-
-/**
- * Object cache in the file system.
- *
- * @ingroup Cache
- */
-class ObjectFileCache extends FileCacheBase {
- /**
- * Construct an ObjectFileCache from a key and a type
- * @param string $key
- * @param string $type
- * @return ObjectFileCache
- */
- public static function newFromKey( $key, $type ) {
- $cache = new self();
-
- $cache->mKey = (string)$key;
- $cache->mType = (string)$type;
-
- return $cache;
- }
-
- /**
- * Get the base file cache directory
- * @return string
- */
- protected function cacheDirectory() {
- return $this->baseCacheDirectory() . '/object';
- }
-}
// Lookup basic info for users not yet loaded...
if ( count( $usersToQuery ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$table = [ 'user' ];
$conds = [ 'user_id' => $usersToQuery ];
$fields = [ 'user_name', 'user_real_name', 'user_registration', 'user_id' ];
if ( $this->writesDone && $this->dbw ) {
$db = $this->dbw; // see the changes in finishWrite()
} else {
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
}
$value = $db->selectField(
/**
* T109700 - Default bot flag to true when there is no corresponding RC entry
* This means all changes caused by parser functions & Lua on reparse are marked as bot
- * Also in the case no RC entry could be found due to slave lag
+ * Also in the case no RC entry could be found due to replica DB lag
*/
$bot = 1;
$lastRevId = 0;
public static function newFromConds(
$conds,
$fname = __METHOD__,
- $dbType = DB_SLAVE
+ $dbType = DB_REPLICA
) {
$db = wfGetDB( $dbType );
$row = $db->selectRow( 'recentchanges', self::selectFields(), $conds, $fname );
$this->mAttribs['rc_ip'] = '';
}
+ # Strict mode fixups (not-NULL fields)
+ foreach ( [ 'minor', 'bot', 'new', 'patrolled', 'deleted' ] as $field ) {
+ $this->mAttribs["rc_$field"] = (int)$this->mAttribs["rc_$field"];
+ }
+ # ...more fixups (NULL fields)
+ foreach ( [ 'old_len', 'new_len' ] as $field ) {
+ $this->mAttribs["rc_$field"] = isset( $this->mAttribs["rc_$field"] )
+ ? (int)$this->mAttribs["rc_$field"]
+ : null;
+ }
+
# If our database is strict about IP addresses, use NULL instead of an empty string
if ( $dbw->strictIPs() && $this->mAttribs['rc_ip'] == '' ) {
unset( $this->mAttribs['rc_ip'] );
'rc_comment' => $logComment,
'rc_this_oldid' => $revId,
'rc_last_oldid' => 0,
- 'rc_bot' => $user->isAllowed( 'bot' ) ? $wgRequest->getBool( 'bot', true ) : 0,
+ 'rc_bot' => $user->isAllowed( 'bot' ) ? (int)$wgRequest->getBool( 'bot', true ) : 0,
'rc_ip' => self::checkIPAddress( $ip ),
'rc_patrolled' => $markPatrolled ? 1 : 0,
'rc_new' => 0, # obsolete
// Might as well look for rcids and so on.
if ( !$rc_id ) {
- // Info might be out of date, somewhat fractionally, on slave.
+ // Info might be out of date, somewhat fractionally, on replica DB.
// LogEntry/LogPage and WikiPage match rev/log/rc timestamps,
// so use that relation to avoid full table scans.
if ( $log_id ) {
);
}
} elseif ( !$log_id && !$rev_id ) {
- // Info might be out of date, somewhat fractionally, on slave.
+ // Info might be out of date, somewhat fractionally, on replica DB.
$log_id = $dbw->selectField(
'recentchanges',
'rc_logid',
$tagsToAdd = array_diff( $tagsToAdd, $tagsToRemove );
// Update the summary row.
- // $prevTags can be out of date on slaves, especially when addTags is called consecutively,
+ // $prevTags can be out of date on replica DBs, especially when addTags is called consecutively,
// causing loss of tags added recently in tag_summary table.
$prevTags = $dbw->selectField( 'tag_summary', 'ts_tags', $tsConds, __METHOD__ );
$prevTags = $prevTags ? $prevTags : '';
throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' );
}
- $fields['ts_tags'] = wfGetDB( DB_SLAVE )->buildGroupConcatField(
+ $fields['ts_tags'] = wfGetDB( DB_REPLICA )->buildGroupConcatField(
',', 'change_tag', 'ct_tag', $join_cond
);
wfMemcKey( 'active-tags' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) {
- $setOpts += Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
+ $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
// Ask extensions which tags they consider active
$extensionActive = [];
wfMemcKey( 'valid-tags-db' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$setOpts += Database::getCacheSetOptions( $dbr );
wfMemcKey( 'valid-tags-hook' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) {
- $setOpts += Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
+ $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
$tags = [];
Hooks::run( 'ListDefinedTags', [ &$tags ] );
wfMemcKey( 'change-tag-statistics' ),
WANObjectCache::TTL_MINUTE * 5,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) {
- $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+ $dbr = wfGetDB( DB_REPLICA, 'vslow' );
$setOpts += Database::getCacheSetOptions( $dbr );
* have it / want it.
*/
public function getAutoDeleteReason( Title $title, &$hasHistory ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Get the last revision
$rev = Revision::newFromTitle( $title );
* Get an appropriate DB index and options for a query
*
* @param integer $bitfield
- * @return array (DB_MASTER/DB_SLAVE, SELECT options array)
+ * @return array (DB_MASTER/DB_REPLICA, SELECT options array)
*/
public static function getDBOptions( $bitfield ) {
$index = self::hasFlags( $bitfield, IDBAccessObject::READ_LATEST )
? DB_MASTER
- : DB_SLAVE;
+ : DB_REPLICA;
$options = [];
if ( self::hasFlags( $bitfield, IDBAccessObject::READ_EXCLUSIVE ) ) {
* though certain objects may assume READ_LATEST for common use case or legacy reasons.
*
* There are four types of reads:
- * - READ_NORMAL : Potentially cached read of data (e.g. from a slave or stale replica)
+ * - READ_NORMAL : Potentially cached read of data (e.g. from a replica DB or stale replica)
* - READ_LATEST : Up-to-date read as of transaction start (e.g. from master or a quorum read)
* - READ_LOCKING : Up-to-date read as of now, that locks (shared) the records
* - READ_EXCLUSIVE : Up-to-date read as of now, that locks (exclusive) the records
* All record locks persist for the duration of the transaction.
*
* A special constant READ_LATEST_IMMUTABLE can be used for fetching append-only data. Such
- * data is either (a) on a slave and up-to-date or (b) not yet there, but on the master/quorum.
- * Because the data is append-only, it can never be stale on a slave if present.
+ * data is either (a) on a replica DB and up-to-date or (b) not yet there, but on the master/quorum.
+ * Because the data is append-only, it can never be stale on a replica DB if present.
*
* Callers should use READ_NORMAL (or pass in no flags) unless the read determines a write.
* In theory, such cases may require READ_LOCKING, though to avoid contention, READ_LATEST is
*/
interface IDBAccessObject {
/** Constants for object loading bitfield flags (higher => higher QoS) */
- /** @var integer Read from a slave/non-quorum */
+ /** @var integer Read from a replica DB/non-quorum */
const READ_NORMAL = 0;
/** @var integer Read from the master/quorum */
const READ_LATEST = 1;
/** @var integer Read from the master/quorum and lock out other writers and locking readers */
const READ_EXCLUSIVE = 7; // READ_LOCKING (3) and "FOR UPDATE" (4)
- /** @var integer Read from a slave/non-quorum immutable data, using the master/quorum on miss */
+ /** @var integer Read from a replica DB or without a quorum, using the master/quorum on miss */
const READ_LATEST_IMMUTABLE = 8;
// Convenience constant for tracking how data was loaded (higher => higher QoS)
*/
public function getApproximateLagStatus() {
return [
- 'lag' => $this->getLBInfo( 'slave' ) ? $this->getLag() : 0,
+ 'lag' => $this->getLBInfo( 'replica' ) ? $this->getLag() : 0,
'since' => microtime( true )
];
}
* @param bool|string $wiki Wiki ID, or false for the current wiki
* @return LoadBalancer
*/
- abstract public function &getExternalLB( $cluster, $wiki = false );
+ abstract public function getExternalLB( $cluster, $wiki = false );
/**
* Execute a function for each tracked load balancer
* - commitMasterChanges()
* - rollbackMasterChanges()
* - commitAll()
+ *
* This allows for custom transaction rounds from any outer transaction scope.
*
* @param string $fname
if ( $this->trxRoundId !== false ) {
throw new DBTransactionError(
null,
- "Transaction round '{$this->trxRoundId}' already started."
+ "$fname: transaction round '{$this->trxRoundId}' already started."
);
}
$this->trxRoundId = $fname;
* @throws Exception
*/
public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
+ if ( $this->trxRoundId !== false && $this->trxRoundId !== $fname ) {
+ throw new DBTransactionError(
+ null,
+ "$fname: transaction round '{$this->trxRoundId}' still running."
+ );
+ }
// Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
$this->forEachLBCallMethod( 'finalizeMasterChanges' );
$this->trxRoundId = false;
/**
* Detemine if any lagged replica DB connection was used
- * @since 1.27
* @return bool
+ * @since 1.28
*/
- public function laggedSlaveUsed() {
+ public function laggedReplicaUsed() {
$ret = false;
$this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) {
- $ret = $ret || $lb->laggedSlaveUsed();
+ $ret = $ret || $lb->laggedReplicaUsed();
} );
return $ret;
}
+ /**
+ * @return bool
+ * @since 1.27
+ * @deprecated Since 1.28; use laggedReplicaUsed()
+ */
+ public function laggedSlaveUsed() {
+ return $this->laggedReplicaUsed();
+ }
+
/**
* Determine if any master connection has pending/written changes from this request
* @return bool
* This will commit and wait unless $ticket indicates it is unsafe to do so
*
* @param string $fname Caller name (e.g. __METHOD__)
- * @param mixed $ticket Result of getOuterTransactionScopeTicket()
+ * @param mixed $ticket Result of getEmptyTransactionTicket()
* @param array $opts Options to waitForReplication()
* @throws DBReplicationWaitError
* @since 1.28
return;
}
- $this->commitMasterChanges( $fname );
+ // The transaction owner and any caller with the empty transaction ticket can commit
+ // so that getEmptyTransactionTicket() callers don't risk seeing DBTransactionError.
+ if ( $this->trxRoundId !== false && $fname !== $this->trxRoundId ) {
+ $this->trxLogger->info( "$fname: committing on behalf of {$this->trxRoundId}." );
+ $fnameEffective = $this->trxRoundId;
+ } else {
+ $fnameEffective = $fname;
+ }
+
+ $this->commitMasterChanges( $fnameEffective );
$this->waitForReplication( $opts );
+ // If a nested caller committed on behalf of $fname, start another empty $fname
+ // transaction, leaving the caller with the same empty transaction state as before.
+ if ( $fnameEffective !== $fname ) {
+ $this->beginMasterChanges( $fnameEffective );
+ }
}
/**
throw new DBAccessError;
}
- public function &getExternalLB( $cluster, $wiki = false ) {
+ public function getExternalLB( $cluster, $wiki = false ) {
throw new DBAccessError;
}
* @param bool|string $wiki Wiki ID, or false for the current wiki
* @return LoadBalancer
*/
- public function &getExternalLB( $cluster, $wiki = false ) {
+ public function getExternalLB( $cluster, $wiki = false ) {
if ( !isset( $this->extLBs[$cluster] ) ) {
$this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
$this->extLBs[$cluster]->parentInfo( [ 'id' => "ext-$cluster" ] );
}
$master = false;
} else {
- $serverInfo['slave'] = true;
+ $serverInfo['replica'] = true;
}
if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
$serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
if ( $i == 0 ) {
$server['master'] = true;
} else {
- $server['slave'] = true;
+ $server['replica'] = true;
}
$server += [ 'flags' => DBO_DEFAULT ];
}
* @param bool|string $wiki
* @return array
*/
- public function &getExternalLB( $cluster, $wiki = false ) {
+ public function getExternalLB( $cluster, $wiki = false ) {
if ( !isset( $this->extLBs[$cluster] ) ) {
$this->extLBs[$cluster] = $this->newExternalLB( $cluster, $wiki );
$this->extLBs[$cluster]->parentInfo( [ 'id' => "ext-$cluster" ] );
* @param bool|string $wiki Wiki ID, or false for the current wiki
* @return LoadBalancerSingle
*/
- public function &getExternalLB( $cluster, $wiki = false ) {
+ public function getExternalLB( $cluster, $wiki = false ) {
return $this->lb;
}
/** @var integer Warn when this many connection are held */
const CONN_HELD_WARN_THRESHOLD = 10;
/** @var integer Default 'max lag' when unspecified */
- const MAX_LAG = 10;
+ const MAX_LAG_DEFAULT = 10;
/** @var integer Max time to wait for a replica DB to catch up (e.g. ChronologyProtector) */
const POS_WAIT_TIMEOUT = 10;
/** @var integer Seconds to cache master server read-only status */
* - servers : Required. Array of server info structures.
* - loadMonitor : Name of a class used to fetch server lag and load.
* - readOnlyReason : Reason the master DB is read-only if so [optional]
+ * - waitTimeout : Maximum time to wait for replicas for consistency [optional]
* - srvCache : BagOStuff object [optional]
* - wanCache : WANObjectCache object [optional]
* @throws MWException
throw new MWException( __CLASS__ . ': missing servers parameter' );
}
$this->mServers = $params['servers'];
- $this->mWaitTimeout = self::POS_WAIT_TIMEOUT;
+ $this->mWaitTimeout = isset( $params['waitTimeout'] )
+ ? $params['waitTimeout']
+ : self::POS_WAIT_TIMEOUT;
$this->mReadIndex = -1;
$this->mWriteIndex = -1;
* @param int $maxLag Restrict the maximum allowed lag to this many seconds
* @return bool|int|string
*/
- private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = self::MAX_LAG ) {
+ private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
$lags = $this->getLagTimes( $wiki );
# Unset excessively lagged servers
foreach ( $lags as $i => $lag ) {
if ( $i != 0 ) {
- $maxServerLag = $maxLag;
- if ( isset( $this->mServers[$i]['max lag'] ) ) {
- $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
- }
+ # How much lag this server nominally is allowed to have
+ $maxServerLag = isset( $this->mServers[$i]['max lag'] )
+ ? $this->mServers[$i]['max lag']
+ : self::MAX_LAG_DEFAULT; // default
+ # Constrain that futher by $maxLag argument
+ $maxServerLag = min( $maxServerLag, $maxLag );
$host = $this->getServerName( $i );
- if ( $lag === false ) {
+ if ( $lag === false && !is_infinite( $maxServerLag ) ) {
wfDebugLog( 'replication', "Server $host (#$i) is not replicating?" );
unset( $loads[$i] );
} elseif ( $lag > $maxServerLag ) {
/**
* Set the master wait position
- * If a DB_SLAVE connection has been opened already, waits
+ * If a DB_REPLICA connection has been opened already, waits
* Otherwise sets a variable telling it to wait if such a connection is opened
* @param DBMasterPos $pos
*/
}
# Operation-based index
- if ( $i == DB_SLAVE ) {
+ if ( $i == DB_REPLICA ) {
$this->mLastError = 'Unknown error'; // reset error string
# Try the general server pool if $groups are unavailable.
$i = in_array( false, $groups, true )
/**
* This can happen in code like:
* foreach ( $dbs as $db ) {
- * $conn = $lb->getConnection( DB_SLAVE, [], $db );
+ * $conn = $lb->getConnection( DB_REPLICA, [], $db );
* ...
* $lb->reuseConnection( $conn );
* }
$this->getLazyConnectionRef( DB_MASTER, [], $db->getWikiID() )
);
$db->setTransactionProfiler( $this->trxProfiler );
- if ( $this->trxRoundId !== false ) {
- $this->applyTransactionRoundFlags( $db );
- }
if ( $server['serverIndex'] === $this->getWriterIndex() ) {
+ if ( $this->trxRoundId !== false ) {
+ $this->applyTransactionRoundFlags( $db );
+ }
foreach ( $this->trxRecurringCallbacks as $name => $callback ) {
$db->setTransactionListener( $name, $callback );
}
return $fnames;
}
- /**
- * @param mixed $value
- * @return mixed
- */
- public function waitTimeout( $value = null ) {
- return wfSetVar( $this->mWaitTimeout, $value );
- }
-
/**
* @note This method will trigger a DB connection if not yet done
- *
* @param string|bool $wiki Wiki ID, or false for the current wiki
* @return bool Whether the generic connection for reads is highly "lagged"
*/
- public function getLaggedSlaveMode( $wiki = false ) {
+ public function getLaggedReplicaMode( $wiki = false ) {
// No-op if there is only one DB (also avoids recursion)
if ( !$this->laggedReplicaMode && $this->getServerCount() > 1 ) {
try {
// See if laggedReplicaMode gets set
- $conn = $this->getConnection( DB_SLAVE, false, $wiki );
+ $conn = $this->getConnection( DB_REPLICA, false, $wiki );
$this->reuseConnection( $conn );
} catch ( DBConnectionError $e ) {
// Avoid expensive re-connect attempts and failures
return $this->laggedReplicaMode;
}
+ /**
+ * @param bool $wiki
+ * @return bool
+ * @deprecated 1.28; use getLaggedReplicaMode()
+ */
+ public function getLaggedSlaveMode( $wiki = false ) {
+ return $this->getLaggedReplicaMode( $wiki );
+ }
+
/**
* @note This method will never cause a new DB connection
* @return bool Whether any generic connection used for reads was highly "lagged"
+ * @since 1.28
+ */
+ public function laggedReplicaUsed() {
+ return $this->laggedReplicaMode;
+ }
+
+ /**
+ * @return bool
* @since 1.27
+ * @deprecated Since 1.28; use laggedReplicaUsed()
*/
public function laggedSlaveUsed() {
- return $this->laggedReplicaMode;
+ return $this->laggedReplicaUsed();
}
/**
public function getReadOnlyReason( $wiki = false, DatabaseBase $conn = null ) {
if ( $this->readOnlyReason !== false ) {
return $this->readOnlyReason;
- } elseif ( $this->getLaggedSlaveMode( $wiki ) ) {
+ } elseif ( $this->getLaggedReplicaMode( $wiki ) ) {
if ( $this->allReplicasDownMode ) {
return 'The database has been automatically locked ' .
'until the replica database servers become available';
* @since 1.27
*/
public function safeWaitForMasterPos( IDatabase $conn, $pos = false, $timeout = 10 ) {
- if ( $this->getServerCount() == 1 || !$conn->getLBInfo( 'slave' ) ) {
+ if ( $this->getServerCount() == 1 || !$conn->getLBInfo( 'replica' ) ) {
return true; // server is not a replica DB
}
* In web request mode, deferred updates can be run at the end of the request, either before or
* after the HTTP response has been sent. In either case, they run after the DB commit step. If
* an update runs after the response is sent, it will not block clients. If sent before, it will
- * run synchronously. If such an update works via queueing, it will be more likely to complete by
- * the time the client makes their next request after this one.
+ * run synchronously. These two modes are defined via PRESEND and POSTSEND constants, the latter
+ * being the default for addUpdate() and addCallableUpdate().
+ *
+ * Updates that work through this system will be more likely to complete by the time the client
+ * makes their next request after this one than with the JobQueue system.
*
* In CLI mode, updates run immediately if no DB writes are pending. Otherwise, they run when:
* - a) Any waitForReplication() call if no writes are pending on any DB
* - c) EnqueueableDataUpdate tasks may enqueue on commit of Maintenance::getDB( DB_MASTER )
* - d) At the completion of Maintenance::execute()
*
- * When updates are deferred, they use a FIFO queue (one for pre-send and one for post-send).
+ * When updates are deferred, they go into one two FIFO "top-queues" (one for pre-send and one
+ * for post-send). Updates enqueued *during* doUpdate() of a "top" update go into the "sub-queue"
+ * for that update. After that method finishes, the sub-queue is run until drained. This continues
+ * for each top-queue job until the entire top queue is drained. This happens for the pre-send
+ * top-queue, and later on, the post-send top-queue, in execute().
*
* @since 1.19
*/
private static function runUpdate( DeferrableUpdate $update, LBFactory $lbFactory, $stage ) {
$guiError = null;
try {
- $lbFactory->beginMasterChanges( __METHOD__ );
+ $fnameTrxOwner = get_class( $update ) . '::doUpdate';
+ $lbFactory->beginMasterChanges( $fnameTrxOwner );
$update->doUpdate();
- $lbFactory->commitMasterChanges( __METHOD__ );
+ $lbFactory->commitMasterChanges( $fnameTrxOwner );
} catch ( Exception $e ) {
// Reporting GUI exceptions does not work post-send
if ( $e instanceof ErrorPageError && $stage === self::PRESEND ) {
*/
public static function cacheUpdate( $dbw ) {
global $wgActiveUserDays;
- $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+ $dbr = wfGetDB( DB_REPLICA, 'vslow' );
# Get non-bot users than did some recent action other than making accounts.
# If account creation is included, the number gets inflated ~20+ fold on enwiki.
$activeUsers = $dbr->selectField(
*/
public function deletedLink( $id ) {
if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow( 'archive', '*',
[ 'ar_rev_id' => $id ],
__METHOD__ );
RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 )
) {
// Look for an unpatrolled change corresponding to this diff
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
$change = RecentChange::newFromConds(
[
'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ),
}
/**
- * Add style sheets and supporting JS for diff display.
+ * Add style sheets for diff display.
*/
public function showDiffStyle() {
- $this->getOutput()->addModuleStyles( 'mediawiki.action.history.diff' );
+ $this->getOutput()->addModuleStyles( 'mediawiki.diff.styles' );
}
/**
}
// Load tags information for both revisions
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $this->mOldid !== false ) {
$this->mOldTags = $dbr->selectField(
'tag_summary',
}
/**
- * Get a slave database connection for the specified cluster
+ * Get a replica DB connection for the specified cluster
*
* @param string $cluster Cluster name
* @return IDatabase
wfDebug( "writable external store\n" );
}
- $db = $lb->getConnection( DB_SLAVE, [], $wiki );
+ $db = $lb->getConnection( DB_REPLICA, [], $wiki );
$db->clearFlag( DBO_TRX ); // sanity
return $db;
}
/**
- * Helper function for self::batchFetchBlobs for merging master/slave results
+ * Helper function for self::batchFetchBlobs for merging master/replica DB results
* @param array &$ret Current self::batchFetchBlobs return value
* @param array &$ids Map from blob_id to requested itemIDs
* @param mixed $res DB result from Database::select
* @return array Translated paths in same order
*/
public function getBackendPaths( array $paths, $latest = true ) {
- $db = $this->getDB( $latest ? DB_MASTER : DB_SLAVE );
+ $db = $this->getDB( $latest ? DB_MASTER : DB_REPLICA );
// @TODO: batching
$resolved = [];
* @return IDatabase
*/
function getSlaveDB() {
- return wfGetDB( DB_SLAVE, [], $this->wiki );
+ return wfGetDB( DB_REPLICA, [], $this->wiki );
}
/**
}
/**
- * Get a connection to the slave DB
+ * Get a connection to the replica DB
* @return DatabaseBase
*/
function getSlaveDB() {
- return wfGetDB( DB_SLAVE );
+ return wfGetDB( DB_REPLICA );
}
/**
}
/**
- * Get a callback to get a DB handle given an index (DB_SLAVE/DB_MASTER)
+ * Get a callback to get a DB handle given an index (DB_REPLICA/DB_MASTER)
* @return Closure
*/
protected function getDBFactory() {
if ( !$this->title || $this->title->getNamespace() == NS_FILE ) {
$this->dataLoaded = true; // set it here, to have also true on miss
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow(
'filearchive',
self::selectFields(),
// Update article count statistics (T42009)
// The normal counting logic in WikiPage->doEditUpdates() is designed for
// one-revision-at-a-time editing, not bulk imports. In this situation it
- // suffers from issues of slave lag. We let WikiPage handle the total page
+ // suffers from issues of replica DB lag. We let WikiPage handle the total page
// and revision count, and we implement our own custom logic for the
// article (content page) count.
$page = WikiPage::factory( $title );
"config-mysql-myisam": "MyISAM",
"config-mysql-myisam-dep": "<strong>Warnung:</strong> Es wurde MyISAM als Speichersubsystem für das Datenbanksystem MySQL ausgewählt. Aus folgenden Gründen wird es nicht für den Einsatz mit MediaWiki empfohlen:\n* Es unterstützt aufgrund von Tabellensperrungen kaum die nebenläufige Ausführung von Aktionen.\n* Es ist anfälliger für Datenprobleme.\n* Es wird von MediaWiki nicht immer adäquat unterstützt.\n\nSofern die vorhandene MySQL-Installation das Speichersubsystem InnoDB unterstützt, wird deren Verwendung eindringlich empfohlen.\nSofern sie es nicht unterstützt, sollte nunmehr eine entsprechende Aktualisierung in Erwägung gezogen werden.",
"config-mysql-only-myisam-dep": "<strong>Warnung:</strong> MyISAM ist das einzige verfügbare Speichersubsystem für das Datenbanksystem MySQL auf diesem Server. Es wird nicht für die Verwendung mit MediaWiki empfohlen, da es\n* aufgrund von Tabellensperrungen kaum die nebenläufige Ausführung von Aktionen unterstützt,\n* anfälliger für Datenprobleme ist und\n* von MediaWiki nicht immer adäquat unterstützt wird.\n\nDeine MySQL-Installation unterstützt nicht das Speichersubsystem InnoDB. Eine Aktualisierung wird nunmehr empfohlen.",
- "config-mysql-engine-help": "'''InnoDB''' ist fast immer die bessere Wahl, da es gleichzeitige Zugriffe gut unterstützt.\n\n'''MyISAM''' ist in Einzelnutzerumgebungen sowie bei schreibgeschützten Wikis schneller.\nBei MyISAM-Datenbanken treten tendenziell häufiger Fehler auf als bei InnoDB-Datenbanken.",
+ "config-mysql-engine-help": "<strong>InnoDB</strong> als Speichersubsystem für das Datenbanksystem MySQL ist fast immer die bessere Wahl, da es gleichzeitige Zugriffe gut unterstützt.\n\n<strong>MyISAM</strong> als Speichersubsystem für das Datenbanksystem MySQL ist hingegen in Einzelnutzerumgebungen oder bei schreibgeschützten Wikis schneller.\nDatenbanken, die MyISAM verwenden, sind indes tendenziell fehleranfälliger als solche, die InnoDB verwenden.",
"config-mysql-charset": "Datenbankzeichensatz:",
"config-mysql-binary": "binär",
"config-mysql-utf8": "UTF-8",
* and tree storage backends (SQL, CDB, and plain PHP arrays).
*
* All information is loaded on creation when called by $this->fetch( $prefix ).
- * All work is done on slave, because this should *never* change (except during
+ * All work is done on replica DB, because this should *never* change (except during
* schema updates etc, which aren't wiki-related)
*
* @since 1.28
$this->objectCache->makeKey( 'interwiki', $prefix ),
$this->objectCacheExpiry,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $prefix ) {
- $dbr = wfGetDB( DB_SLAVE ); // TODO: inject LoadBalancer
+ $dbr = wfGetDB( DB_REPLICA ); // TODO: inject LoadBalancer
$setOpts += Database::getCacheSetOptions( $dbr );
* @return array[] Interwiki rows
*/
private function getAllPrefixesDB( $local ) {
- $db = wfGetDB( DB_SLAVE ); // TODO: inject DB LoadBalancer
+ $db = wfGetDB( DB_REPLICA ); // TODO: inject DB LoadBalancer
$where = [];
}
/**
- * Wait for any slaves or backup servers to catch up.
+ * Wait for any replica DBs or backup servers to catch up.
*
* This does nothing for certain queue classes.
*
}
// Build the full list of job rows to insert
$rows = array_merge( $rowList, array_values( $rowSet ) );
- // Insert the job rows in chunks to avoid slave lag...
+ // Insert the job rows in chunks to avoid replica DB lag...
foreach ( array_chunk( $rows, 50 ) as $rowBatch ) {
$dbw->insert( 'job', $rowBatch, $method );
}
*/
protected function getSlaveDB() {
try {
- return $this->getDB( DB_SLAVE );
+ return $this->getDB( DB_REPLICA );
} catch ( DBConnectionError $e ) {
throw new JobQueueConnectionError( "DBConnectionError:" . $e->getMessage() );
}
}
/**
- * @param int $index (DB_SLAVE/DB_MASTER)
+ * @param int $index (DB_REPLICA/DB_MASTER)
* @return DBConnRef
*/
protected function getDB( $index ) {
}
/**
- * Wait for any slaves or backup queue servers to catch up.
+ * Wait for any replica DBs or backup queue servers to catch up.
*
* This does nothing for certain queue classes.
*
use MediaWiki\MediaWikiServices;
use MediaWiki\Logger\LoggerFactory;
+use Liuggio\StatsdClient\Factory\StatsdDataFactory;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
protected $logger;
const MAX_ALLOWED_LAG = 3; // abort if more than this much DB lag is present
- const LAG_CHECK_PERIOD = 1.0; // check slave lag this many seconds
+ const LAG_CHECK_PERIOD = 1.0; // check replica DB lag this many seconds
const ERROR_BACKOFF_TTL = 1; // seconds to back off a queue due to errors
/**
$response['reached'] = 'read-only';
return $response;
}
+
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
// Bail out if there is too much DB lag.
// This check should not block as we want to try other wiki queues.
- list( , $maxLag ) = wfGetLB( wfWikiID() )->getMaxLag();
+ list( , $maxLag ) = $lbFactory->getMainLB( wfWikiID() )->getMaxLag();
if ( $maxLag >= self::MAX_ALLOWED_LAG ) {
- $response['reached'] = 'slave-lag-limit';
+ $response['reached'] = 'replica-lag-limit';
return $response;
}
// Flush any pending DB writes for sanity
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
$lbFactory->commitAll( __METHOD__ );
- // Catch huge single updates that lead to slave lag
+ // Catch huge single updates that lead to replica DB lag
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
$trxProfiler->setExpectations( $wgTrxProfilerLimits['JobRunner'], __METHOD__ );
$wait = 'wait'; // block to read backoffs the first time
$group = JobQueueGroup::singleton();
- $stats = RequestContext::getMain()->getStats();
+ $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
$jobsPopped = 0;
$timeMsTotal = 0;
$startTime = microtime( true ); // time since jobs started running
- $lastCheckTime = 1; // timestamp of last slave check
+ $lastCheckTime = 1; // timestamp of last replica DB check
do {
// Sync the persistent backoffs with concurrent runners
$backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait );
} else {
$job = $group->pop( $type ); // job from a single queue
}
+ $lbFactory->commitMasterChanges( __METHOD__ ); // flush any JobQueueDB writes
if ( $job ) { // found a job
++$jobsPopped;
$backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait );
}
- $lbFactory->commitMasterChanges( __METHOD__ ); // flush any JobQueueDB writes
- $info = $this->executeJob( $job, $stats, $popTime );
+ $info = $this->executeJob( $job, $lbFactory, $stats, $popTime );
if ( $info['status'] !== false || !$job->allowRetries() ) {
$group->ack( $job ); // succeeded or job cannot be retried
$lbFactory->commitMasterChanges( __METHOD__ ); // flush any JobQueueDB writes
break;
}
- // Don't let any of the main DB slaves get backed up.
+ // Don't let any of the main DB replica DBs get backed up.
// This only waits for so long before exiting and letting
// other wikis in the farm (on different masters) get a chance.
$timePassed = microtime( true ) - $lastCheckTime;
'timeout' => self::MAX_ALLOWED_LAG
] );
} catch ( DBReplicationWaitError $e ) {
- $response['reached'] = 'slave-lag-limit';
+ $response['reached'] = 'replica-lag-limit';
break;
}
$lastCheckTime = microtime( true );
}
- // Don't let any queue slaves/backups fall behind
+ // Don't let any queue replica DBs/backups fall behind
if ( $jobsPopped > 0 && ( $jobsPopped % 100 ) == 0 ) {
$group->waitForBackups();
}
/**
* @param Job $job
- * @param BufferingStatsdDataFactory $stats
+ * @param LBFactory $lbFactory
+ * @param StatsdDataFactory $stats
* @param float $popTime
* @return array Map of status/error/timeMs
*/
- private function executeJob( Job $job, $stats, $popTime ) {
+ private function executeJob( Job $job, LBFactory $lbFactory, $stats, $popTime ) {
$jType = $job->getType();
$msg = $job->toString() . " STARTING";
$this->logger->debug( $msg );
$this->debugCallback( $msg );
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
// Run the job...
$rssStart = $this->getMaxRssKb();
$jobStartTime = microtime( true );
try {
+ $fnameTrxOwner = get_class( $job ) . '::run'; // give run() outer scope
+ $lbFactory->beginMasterChanges( $fnameTrxOwner );
$status = $job->run();
$error = $job->getLastError();
- $this->commitMasterChanges( $job );
-
+ $this->commitMasterChanges( $lbFactory, $job, $fnameTrxOwner );
+ // Run any deferred update tasks; doUpdates() manages transactions itself
DeferredUpdates::doUpdates();
- $this->commitMasterChanges( $job );
} catch ( Exception $e ) {
MWExceptionHandler::rollbackMasterChangesAndLog( $e );
$status = false;
// Commit all outstanding connections that are in a transaction
// to get a fresh repeatable read snapshot on every connection.
- // Note that jobs are still responsible for handling slave lag.
+ // Note that jobs are still responsible for handling replica DB lag.
$lbFactory->flushReplicaSnapshots( __METHOD__ );
// Clear out title cache data from prior snapshots
- LinkCache::singleton()->clear();
+ MediaWikiServices::getInstance()->getLinkCache()->clear();
$timeMs = intval( ( microtime( true ) - $jobStartTime ) * 1000 );
$rssEnd = $this->getMaxRssKb();
/**
* Issue a commit on all masters who are currently in a transaction and have
* made changes to the database. It also supports sometimes waiting for the
- * local wiki's slaves to catch up. See the documentation for
+ * local wiki's replica DBs to catch up. See the documentation for
* $wgJobSerialCommitThreshold for more.
*
+ * @param LBFactory $lbFactory
* @param Job $job
+ * @param string $fnameTrxOwner
* @throws DBError
*/
- private function commitMasterChanges( Job $job ) {
+ private function commitMasterChanges( LBFactory $lbFactory, Job $job, $fnameTrxOwner ) {
global $wgJobSerialCommitThreshold;
- $lb = wfGetLB( wfWikiID() );
+ $lb = $lbFactory->getMainLB( wfWikiID() );
if ( $wgJobSerialCommitThreshold !== false && $lb->getServerCount() > 1 ) {
// Generally, there is one master connection to the local DB
$dbwSerial = $lb->getAnyOpenConnection( $lb->getWriterIndex() );
$dbwSerial = false;
}
} else {
- // There are no slaves or writes are all to foreign DB (we don't handle that)
+ // There are no replica DBs or writes are all to foreign DB (we don't handle that)
$dbwSerial = false;
}
if ( !$dbwSerial ) {
- wfGetLBFactory()->commitMasterChanges( __METHOD__ );
+ $lbFactory->commitMasterChanges( $fnameTrxOwner );
return;
}
// This will trigger a rollback in the main loop
throw new DBError( $dbwSerial, "Timed out waiting on commit queue." );
}
- // Wait for the slave DBs to catch up
+ // Wait for the replica DBs to catch up
$pos = $lb->getMasterPos();
if ( $pos ) {
$lb->waitForAll( $pos );
}
// Actually commit the DB master changes
- wfGetLBFactory()->commitMasterChanges( __METHOD__ );
+ $lbFactory->commitMasterChanges( $fnameTrxOwner );
// Release the lock
$dbwSerial->unlock( 'jobrunner-serial-commit', __METHOD__ );
return false;
}
- $dbr = wfGetDB( DB_SLAVE, [ 'recentchanges' ] );
- // Wait till the slave is caught up so that jobs for this page see each others' changes
+ $dbr = wfGetDB( DB_REPLICA, [ 'recentchanges' ] );
+ // Wait till the replica DB is caught up so that jobs for this page see each others' changes
if ( !wfGetLB()->safeWaitForMasterPos( $dbr ) ) {
- $this->setLastError( "Timed out while waiting for slave to catch up" );
+ $this->setLastError( "Timed out while waiting for replica DB to catch up" );
return false;
}
// Clear any stale REPEATABLE-READ snapshot
$update = new LinksDeletionUpdate( $page, $pageId, $timestamp );
$update->setTransactionTicket( $factory->getEmptyTransactionTicket( __METHOD__ ) );
- DataUpdate::runUpdates( [ $update ] );
+ $update->doUpdate();
return true;
}
);
if ( $rcIds ) {
$dbw->delete( 'recentchanges', [ 'rc_id' => $rcIds ], __METHOD__ );
- // There might be more, so try waiting for slaves
+ // There might be more, so try waiting for replica DBs
try {
$factory->commitAndWaitForReplication(
__METHOD__, $ticket, [ 'timeout' => 3 ]
const PARSE_THRESHOLD_SEC = 1.0;
/** @var integer Lag safety margin when comparing root job times to last-refresh times */
const CLOCK_FUDGE = 10;
- /** @var integer How many seconds to wait for slaves to catch up */
+ /** @var integer How many seconds to wait for replica DBs to catch up */
const LAG_WAIT_TIMEOUT = 15;
function __construct( Title $title, array $params ) {
// 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 slaves to catch up to the master.
+ // 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'] ) ) {
$skewedTimestamp = $this->params['rootJobTimestamp'];
if ( $opportunistic ) {
- // Neither clock skew nor DB snapshot/slave lag matter much for such
+ // Neither clock skew nor DB snapshot/replica DB lag matter much for such
// updates; focus on reusing the (often recently updated) cache
} else {
// For transclusion updates, the template changes must be reflected
}
}
- DataUpdate::runUpdates( $updates );
+ foreach ( $updates as $update ) {
+ $update->doUpdate();
+ }
InfoAction::invalidateCache( $title );
* @param array $params Parameters for HashBagOStuff
*/
function __construct( BagOStuff $backend, $params = [] ) {
+ unset( $params['reportDupes'] ); // useless here
+
parent::__construct( $params );
$this->backend = $backend;
/**
* A cache class that directs writes to one set of servers and reads to
- * another. This assumes that the servers used for reads are setup to slave
+ * another. This assumes that the servers used for reads are setup to replica DB
* those that writes go to. This can easily be used with redis for example.
*
* In the WAN scenario (e.g. multi-datacenter case), this is useful when
* - writeFactory : ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
* This object will be used for writes (e.g. the master DB).
* - readFactory : ObjectFactory::getObjectFromSpec array yeilding BagOStuff.
- * This object will be used for reads (e.g. a slave DB).
+ * This object will be used for reads (e.g. a replica DB).
*
* @param array $params
* @throws InvalidArgumentException
__METHOD__ . ': the "readFactory" parameter is required' );
}
+ $opts = [ 'reportDupes' => false ]; // redundant
$this->writeStore = ( $params['writeFactory'] instanceof BagOStuff )
? $params['writeFactory']
- : ObjectFactory::getObjectFromSpec( $params['writeFactory'] );
+ : ObjectFactory::getObjectFromSpec( $opts + $params['writeFactory'] );
$this->readStore = ( $params['readFactory'] instanceof BagOStuff )
? $params['readFactory']
- : ObjectFactory::getObjectFromSpec( $params['readFactory'] );
+ : ObjectFactory::getObjectFromSpec( $opts + $params['readFactory'] );
$this->attrMap = $this->mergeFlagMaps( [ $this->readStore, $this->writeStore ] );
}
/** Default time-since-expiry on a miss that makes a key "hot" */
const LOCK_TSE = 1;
+ /** Never consider performing "popularity" refreshes until a key reaches this age */
+ const AGE_NEW = 60;
+ /** The time length of the "popularity" refresh window for hot keys */
+ const HOT_TTR = 900;
+ /** Hits/second for a refresh to be expected within the "popularity" window */
+ const HIT_RATE_HIGH = 1;
+ /** Seconds to ramp up to the "popularity" refresh chance after a key is no longer new */
+ const RAMPUP_TTL = 30;
+
/** Idiom for getWithSetCallback() callbacks to avoid calling set() */
const TTL_UNCACHEABLE = -1;
/** Idiom for getWithSetCallback() callbacks to 'lockTSE' logic */
*
* Example usage:
* @code
- * $dbr = wfGetDB( DB_SLAVE );
+ * $dbr = wfGetDB( DB_REPLICA );
* $setOpts = Database::getCacheSetOptions( $dbr );
* // Fetch the row from the DB
* $row = $dbr->selectRow( ... );
* @param integer $ttl Seconds to live. Special values are:
* - WANObjectCache::TTL_INDEFINITE: Cache forever
* @param array $opts Options map:
- * - lag : Seconds of slave lag. Typically, this is either the slave lag
- * before the data was read or, if applicable, the slave lag before
+ * - lag : Seconds of replica DB lag. Typically, this is either the replica DB lag
+ * before the data was read or, if applicable, the replica DB lag before
* the snapshot-isolated transaction the data was read from started.
* Default: 0 seconds
* - since : UNIX timestamp of the data in $value. Typically, this is either
* Keys using it via get(), getMulti(), or getWithSetCallback() will
* be invalidated. It is treated as being HOLDOFF_TTL seconds in the future
* by those methods to avoid race conditions where dependent keys get updated
- * with stale values (e.g. from a DB slave).
+ * with stale values (e.g. from a DB replica DB).
*
* This is typically useful for keys with hardcoded names or in some cases
* dynamically generated names where a low number of combinations exist.
* $cache::TTL_MINUTE,
* // Function that derives the new key value
* function ( $oldValue, &$ttl, array &$setOpts ) {
- * $dbr = wfGetDB( DB_SLAVE );
- * // Account for any snapshot/slave lag
+ * $dbr = wfGetDB( DB_REPLICA );
+ * // Account for any snapshot/replica DB lag
* $setOpts += Database::getCacheSetOptions( $dbr );
*
* return $dbr->selectRow( ... );
* $cache::TTL_DAY,
* // Function that derives the new key value
* function ( $oldValue, &$ttl, array &$setOpts ) {
- * $dbr = wfGetDB( DB_SLAVE );
- * // Account for any snapshot/slave lag
+ * $dbr = wfGetDB( DB_REPLICA );
+ * // Account for any snapshot/replica DB lag
* $setOpts += Database::getCacheSetOptions( $dbr );
*
* return CatConfig::newFromRow( $dbr->selectRow( ... ) );
* // Function that derives the new key value
* function ( $oldValue, &$ttl, array &$setOpts ) {
* // Determine new value from the DB
- * $dbr = wfGetDB( DB_SLAVE );
- * // Account for any snapshot/slave lag
+ * $dbr = wfGetDB( DB_REPLICA );
+ * // Account for any snapshot/replica DB lag
* $setOpts += Database::getCacheSetOptions( $dbr );
*
* return CatState::newFromResults( $dbr->select( ... ) );
* 10,
* // Function that derives the new key value
* function ( $oldValue, &$ttl, array &$setOpts ) {
- * $dbr = wfGetDB( DB_SLAVE );
- * // Account for any snapshot/slave lag
+ * $dbr = wfGetDB( DB_REPLICA );
+ * // Account for any snapshot/replica DB lag
* $setOpts += Database::getCacheSetOptions( $dbr );
*
* // Start off with the last cached list
* - checkKeys: List of "check" keys. The key at $key will be seen as invalid when either
* touchCheckKey() or resetCheckKey() is called on any of these keys.
* Default: [].
- * - lowTTL: Consider pre-emptive updates when the current TTL (seconds) of the key is less
- * than this. It becomes more likely over time, becoming certain once the key is expired.
- * Default: WANObjectCache::LOW_TTL.
* - lockTSE: If the key is tombstoned or expired (by checkKeys) less than this many seconds
* ago, then try to have a single thread handle cache regeneration at any given time.
* Other threads will try to use stale values if possible. If, on miss, the time since
* - pcTTL: Process cache the value in this PHP instance for this many seconds. This avoids
* network I/O when a key is read several times. This will not cache when the callback
* returns false, however. Note that any purges will not be seen while process cached;
- * since the callback should use slave DBs and they may be lagged or have snapshot
+ * since the callback should use replica DBs and they may be lagged or have snapshot
* isolation anyway, this should not typically matter.
* Default: WANObjectCache::TTL_UNCACHEABLE.
* - version: Integer version number. This allows for callers to make breaking changes to
* versions are stored alongside older versions concurrently. Avoid storing class objects
* however, as this reduces compatibility (due to serialization).
* Default: null.
+ * - hotTTR: Expected time-till-refresh for keys that average ~1 hit/second.
+ * This should be greater than "ageNew". Keys with higher hit rates will regenerate
+ * more often. This is useful when a popular key is changed but the cache purge was
+ * delayed or lost. Seldom used keys are rarely affected by this setting, unless an
+ * extremely low "hotTTR" value is passed in.
+ * Default: WANObjectCache::HOT_TTR.
+ * - lowTTL: Consider pre-emptive updates when the current TTL (seconds) of the key is less
+ * than this. It becomes more likely over time, becoming certain once the key is expired.
+ * Default: WANObjectCache::LOW_TTL.
+ * - ageNew: Consider popularity refreshes only once a key reaches this age in seconds.
+ * Default: WANObjectCache::AGE_NEW.
* @return mixed Value found or written to the key
* @note Callable type hints are not used to avoid class-autoloading
*/
$lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
$checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : [];
$busyValue = isset( $opts['busyValue'] ) ? $opts['busyValue'] : null;
+ $popWindow = isset( $opts['hotTTR'] ) ? $opts['hotTTR'] : self::HOT_TTR;
+ $ageNew = isset( $opts['ageNew'] ) ? $opts['ageNew'] : self::AGE_NEW;
$minTime = isset( $opts['minTime'] ) ? $opts['minTime'] : 0.0;
$versioned = isset( $opts['version'] );
if ( $value !== false
&& $curTTL > 0
&& $this->isValid( $value, $versioned, $asOf, $minTime )
- && !$this->worthRefresh( $curTTL, $lowTTL )
+ && !$this->worthRefreshExpiring( $curTTL, $lowTTL )
+ && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow )
) {
return $value;
}
* @param float $lowTTL Consider a refresh when $curTTL is less than this
* @return bool
*/
- protected function worthRefresh( $curTTL, $lowTTL ) {
+ protected function worthRefreshExpiring( $curTTL, $lowTTL ) {
if ( $curTTL >= $lowTTL ) {
return false;
} elseif ( $curTTL <= 0 ) {
return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
}
+ /**
+ * Check if a key is due for randomized regeneration due to its popularity
+ *
+ * This is used so that popular keys can preemptively refresh themselves for higher
+ * consistency (especially in the case of purge loss/delay). Unpopular keys can remain
+ * in cache with their high nominal TTL. This means popular keys keep good consistency,
+ * whether the data changes frequently or not, and long-tail keys get to stay in cache
+ * and get hits too. Similar to worthRefreshExpiring(), randomization is used.
+ *
+ * @param float $asOf UNIX timestamp of the value
+ * @param integer $ageNew Age of key when this might recommend refreshing (seconds)
+ * @param integer $timeTillRefresh Age of key when it should be refreshed if popular (seconds)
+ * @return bool
+ */
+ protected function worthRefreshPopular( $asOf, $ageNew, $timeTillRefresh ) {
+ $age = microtime( true ) - $asOf;
+ $timeOld = $age - $ageNew;
+ if ( $timeOld <= 0 ) {
+ return false;
+ }
+
+ // Lifecycle is: new, ramp-up refresh chance, full refresh chance
+ $refreshWindowSec = max( $timeTillRefresh - $ageNew - self::RAMPUP_TTL / 2, 1 );
+ // P(refresh) * (# hits in $refreshWindowSec) = (expected # of refreshes)
+ // P(refresh) * ($refreshWindowSec * $popularHitsPerSec) = 1
+ // P(refresh) = 1/($refreshWindowSec * $popularHitsPerSec)
+ $chance = 1 / ( self::HIT_RATE_HIGH * $refreshWindowSec );
+
+ // Ramp up $chance from 0 to its nominal value over RAMPUP_TTL seconds to avoid stampedes
+ $chance *= ( $timeOld <= self::RAMPUP_TTL ) ? $timeOld / self::RAMPUP_TTL : 1;
+
+ return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
+ }
+
/**
* Check whether $value is appropriately versioned and not older than $minTime (if set)
*
*
* @param int $newId Id of the log entry.
* @param string $to One of: rcandudp (default), rc, udp
- * @return RecentChange|null
*/
public function publish( $newId, $to = 'rcandudp' ) {
- $log = new LogPage( $this->getType() );
- if ( $log->isRestricted() ) {
- return null;
- }
-
- $rc = $this->getRecentChange( $newId );
-
- if ( $to === 'rc' || $to === 'rcandudp' ) {
- $rc->save( 'pleasedontudp' );
- }
-
- if ( $to === 'udp' || $to === 'rcandudp' ) {
- $rc->notifyRCFeeds();
- }
-
- // Log the autopatrol if the log entry is patrollable
- if ( $this->getIsPatrollable() &&
- $rc->getAttribute( 'rc_patrolled' ) === 1 ) {
- PatrolLog::record( $rc, true, $this->getPerformer() );
- }
-
- // Add change tags to the log entry and (if applicable) the associated revision
- $tags = $this->getTags();
- if ( !is_null( $tags ) ) {
- $rcId = $rc->getAttribute( 'rc_id' );
- $revId = $this->getAssociatedRevId(); // Use null if $revId is 0
- ChangeTags::addTags( $tags, $rcId, $revId > 0 ? $revId : null, $newId );
- }
-
- return $rc;
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $newId, $to ) {
+ $log = new LogPage( $this->getType() );
+ if ( !$log->isRestricted() ) {
+ $rc = $this->getRecentChange( $newId );
+
+ if ( $to === 'rc' || $to === 'rcandudp' ) {
+ $rc->save( 'pleasedontudp' );
+ }
+
+ if ( $to === 'udp' || $to === 'rcandudp' ) {
+ $rc->notifyRCFeeds();
+ }
+
+ // Log the autopatrol if the log entry is patrollable
+ if ( $this->getIsPatrollable() &&
+ $rc->getAttribute( 'rc_patrolled' ) === 1
+ ) {
+ PatrolLog::record( $rc, true, $this->getPerformer() );
+ }
+
+ // Add change tags to the log entry and (if applicable) the associated revision
+ $tags = $this->getTags();
+ if ( !is_null( $tags ) ) {
+ $rcId = $rc->getAttribute( 'rc_id' );
+ $revId = $this->getAssociatedRevId(); // Use null if $revId is 0
+ ChangeTags::addTags( $tags, $rcId, $revId > 0 ? $revId : null, $newId );
+ }
+ }
+ },
+ DeferredUpdates::POSTSEND,
+ wfGetDB( DB_MASTER )
+ );
}
public function getType() {
$this->getDateCond( $year, $month );
$this->mTagFilter = $tagFilter;
- $this->mDb = wfGetDB( DB_SLAVE, 'logpager' );
+ $this->mDb = wfGetDB( DB_REPLICA, 'logpager' );
}
public function getDefaultQuery() {
* Purpose: Ephemeral global storage.
* Stored centrally within the primary data-center.
* Changes are applied there first and replicated to other DCs (best-effort).
- * To retrieve the latest value (e.g. not from a slave), use BagOStuff::READ_LATEST.
+ * To retrieve the latest value (e.g. not from a replica DB), use BagOStuff::READ_LATEST.
* This store may be subject to LRU style evictions.
*
* - ObjectCache::getInstance( $cacheType )
try {
if ( $this->getMasterLinkStatus( $conn ) === 'down' ) {
// If the master cannot be reached, fail-over to the next server.
- // If masters are in data-center A, and slaves in data-center B,
+ // If masters are in data-center A, and replica DBs in data-center B,
// this helps avoid the case were fail-over happens in A but not
// to the corresponding server in B (e.g. read/write mismatch).
continue;
}
/**
- * Check the master link status of a Redis server that is configured as a slave.
+ * Check the master link status of a Redis server that is configured as a replica DB.
* @param RedisConnRef $conn
* @return string|null Master link status (either 'up' or 'down'), or null
- * if the server is not a slave.
+ * if the server is not a replica DB.
*/
protected function getMasterLinkStatus( RedisConnRef $conn ) {
$info = $conn->info();
/** @var string */
protected $tableName = 'objectcache';
/** @var bool */
- protected $slaveOnly = false;
+ protected $replicaOnly = false;
/** @var int */
protected $syncTimeout = 3;
* required to hold the largest shard index. Data will be
* distributed across all tables by key hash. This is for
* MySQL bugs 61735 and 61736.
- * - slaveOnly: Whether to only use slave DBs and avoid triggering
+ * - slaveOnly: Whether to only use replica DBs and avoid triggering
* garbage collection logic of expired items. This only
* makes sense if the primary DB is used and only if get()
* calls will be used. This is used by ReplicatedBagOStuff.
- * - syncTimeout: Max seconds to wait for slaves to catch up for WRITE_SYNC.
+ * - syncTimeout: Max seconds to wait for replica DBs to catch up for WRITE_SYNC.
*
* @param array $params
*/
if ( isset( $params['syncTimeout'] ) ) {
$this->syncTimeout = $params['syncTimeout'];
}
- $this->slaveOnly = !empty( $params['slaveOnly'] );
+ $this->replicaOnly = !empty( $params['slaveOnly'] );
}
protected function getSeparateMainLB() {
$db = DatabaseBase::factory( $type, $info );
$db->clearFlag( DBO_TRX );
} else {
- $index = $this->slaveOnly ? DB_SLAVE : DB_MASTER;
+ $index = $this->replicaOnly ? DB_REPLICA : DB_MASTER;
if ( $this->getSeparateMainLB() ) {
$db = $this->getSeparateMainLB()->getConnection( $index );
$db->clearFlag( DBO_TRX ); // auto-commit mode
}
protected function garbageCollect() {
- if ( !$this->purgePeriod || $this->slaveOnly ) {
+ if ( !$this->purgePeriod || $this->replicaOnly ) {
// Disabled
return;
}
?: MediaWikiServices::getInstance()->getDBLoadBalancer();
if ( $lb->getServerCount() <= 1 ) {
- return true; // no slaves
+ return true; // no replica DBs
}
- // Main LB is used; wait for any slaves to catch up
+ // Main LB is used; wait for any replica DBs to catch up
$masterPos = $lb->getMasterPos();
$loop = new WaitConditionLoop(
return false;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$oldestRevisionTimestamp = $dbr->selectField(
'revision',
'MIN( rev_timestamp )',
if ( !$rc ) {
// Don't cache: This can be hit if the page gets accessed very fast after
- // its creation / latest upload or in case we have high slave lag. In case
+ // its creation / latest upload or in case we have high replica DB lag. In case
// the revision is too old, we will already return above.
return false;
}
// This, as a side-effect, also makes sure that the following query isn't being run for
// pages with a larger history, unless the user has the 'bigdelete' right
// (and is about to delete this page).
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$revisions = $edits = (int)$dbr->selectField(
'revision',
'COUNT(rev_page)',
* @return ResultWrapper
*/
protected function queryImageLinks( $target, $limit ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
return $dbr->select(
[ 'imagelinks', 'page' ],
*/
use \MediaWiki\Logger\LoggerFactory;
+use \MediaWiki\MediaWikiServices;
/**
* Class representing a MediaWiki article and history.
*
* @param int $id Article ID to load
* @param string|int $from One of the following values:
- * - "fromdb" or WikiPage::READ_NORMAL to select from a slave database
+ * - "fromdb" or WikiPage::READ_NORMAL to select from a replica DB
* - "fromdbmaster" or WikiPage::READ_LATEST to select from the master database
*
* @return WikiPage|null
}
$from = self::convertSelectType( $from );
- $db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_REPLICA );
$row = $db->selectRow(
'page', self::selectFields(), [ 'page_id' => $id ], __METHOD__ );
if ( !$row ) {
* @since 1.20
* @param object $row Database row containing at least fields returned by selectFields().
* @param string|int $from Source of $data:
- * - "fromdb" or WikiPage::READ_NORMAL: from a slave DB
+ * - "fromdb" or WikiPage::READ_NORMAL: from a replica DB
* - "fromdbmaster" or WikiPage::READ_LATEST: from the master DB
* - "forupdate" or WikiPage::READ_LOCKING: from the master DB using SELECT FOR UPDATE
* @return WikiPage
*
* @param object|string|int $from One of the following:
* - A DB query result object.
- * - "fromdb" or WikiPage::READ_NORMAL to get from a slave DB.
+ * - "fromdb" or WikiPage::READ_NORMAL to get from a replica DB.
* - "fromdbmaster" or WikiPage::READ_LATEST to get from the master DB.
* - "forupdate" or WikiPage::READ_LOCKING to get from the master DB
* using SELECT FOR UPDATE.
$data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
if ( !$data
- && $index == DB_SLAVE
+ && $index == DB_REPLICA
&& wfGetLB()->getServerCount() > 1
&& wfGetLB()->hasOrMadeRecentMasterChanges()
) {
$data = $this->pageDataFromTitle( wfGetDB( $index ), $this->mTitle, $opts );
}
} else {
- // No idea from where the caller got this data, assume slave database.
+ // No idea from where the caller got this data, assume replica DB.
$data = $from;
$from = self::READ_NORMAL;
}
* @since 1.20
* @param object|bool $data DB row containing fields returned by selectFields() or false
* @param string|int $from One of the following:
- * - "fromdb" or WikiPage::READ_NORMAL if the data comes from a slave DB
+ * - "fromdb" or WikiPage::READ_NORMAL if the data comes from a replica DB
* - "fromdbmaster" or WikiPage::READ_LATEST if the data comes from the master DB
* - "forupdate" or WikiPage::READ_LOCKING if the data comes from
* the master DB using SELECT FOR UPDATE
*/
public function getOldestRevision() {
- // Try using the slave database first, then try the master
+ // Try using the replica DB first, then try the master
$continue = 2;
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
$revSelectFields = Revision::selectFields();
$row = null;
$flags = Revision::READ_LOCKING;
} elseif ( $this->mDataLoadedFrom == self::READ_LATEST ) {
// Bug T93976: if page_latest was loaded from the master, fetch the
- // revision from there as well, as it may not exist yet on a slave DB.
+ // revision from there as well, as it may not exist yet on a replica DB.
// Also, this keeps the queries in the same REPEATABLE-READ snapshot.
$flags = Revision::READ_LATEST;
} else {
// links.
$hasLinks = (bool)count( $editInfo->output->getLinks() );
} else {
- $hasLinks = (bool)wfGetDB( DB_SLAVE )->selectField( 'pagelinks', 1,
+ $hasLinks = (bool)wfGetDB( DB_REPLICA )->selectField( 'pagelinks', 1,
[ 'pl_from' => $this->getId() ], __METHOD__ );
}
}
}
// Query the redirect table
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow( 'redirect',
[ 'rd_namespace', 'rd_title', 'rd_fragment', 'rd_interwiki' ],
[ 'rd_from' => $this->getId() ],
public function getContributors() {
// @todo FIXME: This is expensive; cache this info somewhere.
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $dbr->implicitGroupby() ) {
$realNameField = 'user_real_name';
$baseRevId = null;
if ( $edittime && $sectionId !== 'new' ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$rev = Revision::loadFromTimestamp( $dbr, $this->mTitle, $edittime );
// Try the master if this thread may have just added it.
// This could be abstracted into a Revision method, but we don't want
// We get here if vary-revision is set. This means that this page references
// itself (such as via self-transclusion). In this case, we need to make sure
// that any such self-references refer to the newly-saved revision, and not
- // to the previous one, which could otherwise happen due to slave lag.
+ // to the previous one, which could otherwise happen due to replica DB lag.
$oldCallback = $edit->popts->getCurrentRevisionCallback();
$edit->popts->setCurrentRevisionCallback(
function ( Title $title, $parser = false ) use ( $revision, &$oldCallback ) {
$title->purgeSquid();
$title->deleteTitleProtection();
+ MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
+
if ( $title->getNamespace() == NS_CATEGORY ) {
// Load the Category object, which will schedule a job to create
- // the category table row if necessary. Checking a slave is ok
+ // the category table row if necessary. Checking a replica DB is ok
// here, in the worst case it'll run an unnecessary recount job on
// a category that probably doesn't have many members.
Category::newFromTitle( $title )->getID();
$title->touchLinks();
$title->purgeSquid();
+ MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
+
// File cache
HTMLFileCache::clearFileCache( $title );
InfoAction::invalidateCache( $title );
// Invalidate the caches of all pages which redirect here
DeferredUpdates::addUpdate( new HTMLCacheUpdate( $title, 'redirect' ) );
+ MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title );
+
// Purge CDN for this page only
$title->purgeSquid();
// Clear file cache for this page only
return TitleArray::newFromResult( new FakeResultWrapper( [] ) );
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( 'categorylinks',
[ 'cl_to AS page_title, ' . NS_CATEGORY . ' AS page_namespace' ],
// Have to do that since DatabaseBase::fieldNamesWithAlias treats numeric indexes
return [];
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( [ 'categorylinks', 'page_props', 'page' ],
[ 'cl_to' ],
[ 'cl_from' => $id, 'pp_page=page_id', 'pp_propname' => 'hiddencat',
}
$this->mIsBackwards = ( $this->mRequest->getVal( 'dir' ) == 'prev' );
- # Let the subclass set the DB here; otherwise use a slave DB for the current wiki
- $this->mDb = $this->mDb ?: wfGetDB( DB_SLAVE );
+ # Let the subclass set the DB here; otherwise use a replica DB for the current wiki
+ $this->mDb = $this->mDb ?: wfGetDB( DB_REPLICA );
$index = $this->getIndexField(); // column to sort on
$extraSort = $this->getExtraSortFields(); // extra columns to sort on for query planning
$output = $this->parent->getOutput();
$linkRenderer = $this->parent->getLinkRenderer();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
# Sort by namespace
ksort( $this->internals );
if ( !$linkBatch->isEmpty() ) {
// construct query
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$fields = array_merge(
LinkCache::getSelectFields(),
[ 'page_namespace', 'page_title' ]
$pageId = $title->getArticleID();
$revId = $title->getLatestRevID();
- $rev = Revision::newKnownCurrent( wfGetDB( DB_SLAVE ), $pageId, $revId );
+ $rev = Revision::newKnownCurrent( wfGetDB( DB_REPLICA ), $pageId, $revId );
if ( $rev ) {
$rev->setTitle( $title );
}
*/
public function fetchScaryTemplateMaybeFromCache( $url ) {
global $wgTranscludeCacheExpiry;
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$tsCond = $dbr->timestamp( time() - $wgTranscludeCacheExpiry );
$obj = $dbr->selectRow( 'transcache', [ 'tc_time', 'tc_contents' ],
[ 'tc_url' => $url, "tc_time >= " . $dbr->addQuotes( $tsCond ) ] );
// Or else Database*::select() will explode, plus it's cheaper!
return;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$skin = $context->getSkin();
$lang = $context->getLanguage();
$good = $fileCache->isCacheGood( wfTimestamp( TS_MW, time() - $maxage ) );
if ( !$good ) {
try { // RL always hits the DB on file cache miss...
- wfGetDB( DB_SLAVE );
+ wfGetDB( DB_REPLICA );
} catch ( DBConnectionError $e ) { // ...check if we need to fallback to cache
$good = $fileCache->isCacheGood(); // cache existence check
}
// Try in-object cache first
if ( !isset( $this->fileDeps[$vary] ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$deps = $dbr->selectField( 'module_deps',
'md_deps',
[
$rl = $context->getResourceLoader();
$moduleNames = self::getStartupModules();
- $query = [
- 'modules' => ResourceLoader::makePackedModulesString( $moduleNames ),
- 'only' => 'scripts',
- 'lang' => $context->getLanguage(),
- 'skin' => $context->getSkin(),
- 'debug' => $context->getDebug() ? 'true' : 'false',
- 'version' => $rl->getCombinedVersion( $context, $moduleNames ),
- ];
- // Ensure uniform query order
- ksort( $query );
- return wfAppendQuery( wfScript( 'load' ), $query );
+ $derivative = new DerivativeResourceLoaderContext( $context );
+ $derivative->setModules( $moduleNames );
+ $derivative->setOnly( 'scripts' );
+ $derivative->setVersion(
+ $rl->getCombinedVersion( $context, $moduleNames )
+ );
+
+ return $rl->createLoaderURL( 'local', $derivative );
}
/**
/**
* Get the Database object used in getTitleInfo().
*
- * Defaults to the local slave DB. Subclasses may want to override this to return a foreign
+ * Defaults to the local replica DB. Subclasses may want to override this to return a foreign
* database object, or null if getTitleInfo() shouldn't access the database.
*
* NOTE: This ONLY works for getTitleInfo() and isKnownEmpty(), NOT FOR ANYTHING ELSE.
* @return IDatabase|null
*/
protected function getDB() {
- return wfGetDB( DB_SLAVE );
+ return wfGetDB( DB_REPLICA );
}
/**
}
public static function suggestTarget( $target, array $ids ) {
- $result = wfGetDB( DB_SLAVE )->select( 'logging',
+ $result = wfGetDB( DB_REPLICA )->select( 'logging',
'log_type',
[ 'log_id' => $ids ],
__METHOD__,
* @return bool|mixed
*/
public static function checkRevisionExistence( $title, $revid ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$exists = $dbr->selectField( 'revision', '1',
[ 'rev_id' => $revid ], __METHOD__ );
if ( $db ) {
$this->db = $db;
} else {
- $this->db = wfGetDB( DB_SLAVE );
+ $this->db = wfGetDB( DB_REPLICA );
}
}
} elseif ( $configType !== null ) {
$class = $configType;
} else {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$class = $dbr->getSearchEngine();
}
if ( is_null( self::$mMinSearchLength ) ) {
$sql = "SHOW GLOBAL VARIABLES LIKE 'ft\\_min\\_word\\_len'";
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->query( $sql, __METHOD__ );
$row = $result->fetchObject();
$result->free();
protected function loadSites() {
$this->sites = new SiteList();
- $dbr = $this->dbLoadBalancer->getConnection( DB_SLAVE );
+ $dbr = $this->dbLoadBalancer->getConnection( DB_REPLICA );
$res = $dbr->select(
'sites',
$s = '';
}
- if ( wfGetLB()->getLaggedSlaveMode() ) {
+ if ( wfGetLB()->getLaggedReplicaMode() ) {
$s .= ' <strong>' . $this->msg( 'laggedslavemode' )->parse() . '</strong>';
}
* @return IDatabase
*/
protected function getDB() {
- return wfGetDB( DB_SLAVE );
+ return wfGetDB( DB_REPLICA );
}
/**
* @return IDatabase
*/
function getRecacheDB() {
- return wfGetDB( DB_SLAVE, [ $this->getName(), 'QueryPage::recache', 'vslow' ] );
+ return wfGetDB( DB_REPLICA, [ $this->getName(), 'QueryPage::recache', 'vslow' ] );
}
/**
* @since 1.18
*/
public function fetchFromCache( $limit, $offset = false ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$options = [];
if ( $limit !== false ) {
$options['LIMIT'] = intval( $limit );
public function getCachedTimestamp() {
if ( is_null( $this->cachedTimestamp ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$fname = get_class( $this ) . '::getCachedTimestamp';
$this->cachedTimestamp = $dbr->selectField( 'querycache_info', 'qci_timestamp',
[ 'qci_type' => $this->getName() ], $fname );
// Mention the level of cache staleness...
$cacheText = '';
- $dbr = wfGetDB( DB_SLAVE, 'recentchanges' );
+ $dbr = wfGetDB( DB_REPLICA, 'recentchanges' );
$rcMax = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', '', __METHOD__ );
if ( $rcMax ) {
$cTime = $dbr->selectField( 'querycache_info',
list( $namespace, $fromKey, $from ) = $fromList;
list( , $toKey, $to ) = $toList;
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$filterConds = [ 'page_namespace' => $namespace ];
if ( $hideredirects ) {
$filterConds['page_is_redirect'] = 0;
case Block::TYPE_IP:
case Block::TYPE_RANGE:
list( $start, $end ) = IP::parseRange( $target );
- $conds[] = wfGetDB( DB_SLAVE )->makeList(
+ $conds[] = wfGetDB( DB_REPLICA )->makeList(
[
'ipb_address' => $target,
Block::getRangeCond( $start, $end )
} else {
$linkRenderer = $this->getLinkRenderer();
- $dbr = BotPassword::getDB( DB_SLAVE );
+ $dbr = BotPassword::getDB( DB_REPLICA );
$res = $dbr->select(
'bot_passwords',
[ 'bp_app_id' ],
}
public function getQueryInfo() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
return [
'tables' => [
if ( !$pager->getNumRows() ) {
$out->addWikiMsg( 'nocontribs', $target );
} else {
- # Show a message about slave lag, if applicable
+ # Show a message about replica DB lag, if applicable
$lag = wfGetLB()->safeGetLag( $pager->getDatabase() );
if ( $lag > 0 ) {
$out->showLagWarning( $lag );
return;
}
- # Show a message about slave lag, if applicable
+ # Show a message about replica DB lag, if applicable
$lag = wfGetLB()->safeGetLag( $pager->getDatabase() );
if ( $lag > 0 ) {
$out->showLagWarning( $lag );
function reallyGetQueryInfo( $namespace = null, $title = null ) {
$limitToTitle = !( $namespace === null && $title === null );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$retval = [
'tables' => [
'ra' => 'redirect',
// get a little more detail about each individual entry quickly
// using the filter of reallyGetQueryInfo.
if ( $result && !isset( $result->nsb ) ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$qi = $this->reallyGetQueryInfo(
$result->namespace,
$result->title
/* Ok, let's get to it... */
if ( $history == WikiExporter::CURRENT ) {
$lb = false;
- $db = wfGetDB( DB_SLAVE );
+ $db = wfGetDB( DB_REPLICA );
$buffer = WikiExporter::BUFFER;
} else {
// Use an unbuffered query; histories may be very long!
$lb = wfGetLBFactory()->newMainLB();
- $db = $lb->getConnection( DB_SLAVE );
+ $db = $lb->getConnection( DB_REPLICA );
$buffer = WikiExporter::STREAM;
// This might take a while... :D
$name = $title->getDBkey();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
[ 'page', 'categorylinks' ],
[ 'page_namespace', 'page_title' ],
$maxPages = $this->getConfig()->get( 'ExportPagelistLimit' );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'page',
[ 'page_namespace', 'page_title' ],
* @return array
*/
private function getLinks( $inputPages, $pageSet, $table, $fields, $join ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
foreach ( $inputPages as $page ) {
$title = Title::newFromText( $page );
*/
static function mungeQuery( $query, $prot ) {
$field = 'el_index';
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $query === '*' && $prot !== '' ) {
// Allow queries like 'ftp://*' to find all ftp links
}
public function getQueryInfo() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// strip everything past first wildcard, so that
// index-based-only lookup would be done
list( $this->mungedQuery, $clause ) = self::mungeQuery( $this->mQuery, $this->mProt );
* Special:BrokenRedirects also rely on this.
*/
public function getQueryInfo() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$fakeTitle = $dbr->buildConcat( [
'img_media_type',
$dbr->addQuotes( ';' ),
( $oldTalk->exists()
|| ( $oldTitleTalkSubpages && $canMoveSubpage ) );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $this->getConfig()->get( 'FixDoubleRedirects' ) ) {
$hasRedirects = $dbr->selectField( 'redirect', '1',
[
$opts['OFFSET'] = $offset;
}
- $res = wfGetDB( DB_SLAVE )->select(
+ $res = wfGetDB( DB_REPLICA )->select(
'page_props',
'pp_propname',
'',
# ## @todo FIXME: Should complain if $fromNs != $namespace
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds = [
'page_namespace' => $namespace,
]
];
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$minClTime = $this->getTimestampOffset( $rand );
if ( $minClTime ) {
$qi['conds'][] = 'cl_timestamp ' . $op . ' ' .
* @throws MWException If category has no entries.
*/
protected function getMinAndMaxForCat( Title $category ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->selectRow(
'categorylinks',
[
* @return array Info for the title selected.
*/
private function selectRandomPageFromDB( $rand, $offset, $up, $fname = __METHOD__ ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$query = $this->getQueryInfo( $rand, $offset, $up );
$res = $dbr->select(
}
private function selectRandomPageFromDB( $randstr, $fname = __METHOD__ ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$query = $this->getQueryInfo( $randstr );
$res = $dbr->select(
public function __construct() {
parent::__construct( 'Randomrootpage' );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$this->extra[] = 'page_title NOT ' . $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() );
}
}
protected function getDB() {
- return wfGetDB( DB_SLAVE, 'recentchanges' );
+ return wfGetDB( DB_REPLICA, 'recentchanges' );
}
public function outputFeedLinks() {
* expects only one result set so we use UNION instead.
*/
- $dbr = wfGetDB( DB_SLAVE, 'recentchangeslinked' );
+ $dbr = wfGetDB( DB_REPLICA, 'recentchangeslinked' );
$id = $title->getArticleID();
$ns = $title->getNamespace();
$dbkey = $title->getDBkey();
'log_user_text',
];
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Gets the nested SQL statement which
// returns timestamp of the log with the given log ID
// continuing with this, as the user is just going to end up getting sent
// somewhere else. Additionally, if we keep going here, we end up
// populating the memcache of tag data (see ChangeTags::listDefinedTags)
- // with out-of-date data from the slave, because the slave hasn't caught
+ // with out-of-date data from the replica DB, because the replica DB hasn't caught
// up to the fact that a new tag has been created as part of an implicit,
// as yet uncommitted transaction on master.
if ( $out->getRedirect() !== '' ) {
* @return ResultWrapper
*/
public static function listAllPages() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
return self::listPages( $dbr, '' );
}
* @return ResultWrapper
*/
public static function listPagesByPrefix( $prefix ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$title = Title::newFromText( $prefix );
if ( $title ) {
* @return ResultWrapper
*/
function listRevisions() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$tables = [ 'archive' ];
return null;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
return $dbr->select(
'filearchive',
ArchivedFile::selectFields(),
* @return Revision|null
*/
function getRevision( $timestamp ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$fields = [
'ar_rev_id',
* @return Revision|null Null when there is no previous revision
*/
function getPreviousRevision( $timestamp ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Check the previous deleted revision...
$row = $dbr->selectRow( 'archive',
}
// New-style: keyed to the text storage backend.
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$text = $dbr->selectRow( 'text',
[ 'old_text', 'old_flags' ],
[ 'old_id' => $row->ar_text_id ],
* @return string|null
*/
function getLastRevisionText() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$row = $dbr->selectRow( 'archive',
[ 'ar_text', 'ar_flags', 'ar_text_id' ],
[ 'ar_namespace' => $this->title->getNamespace(),
* @return bool
*/
function isDeleted() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$n = $dbr->selectField( 'archive', 'COUNT(ar_title)',
[ 'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey() ],
$minor = $rev->isMinor() ? ChangesList::flag( 'minor' ) : '';
- $tags = wfGetDB( DB_SLAVE )->selectField(
+ $tags = wfGetDB( DB_REPLICA )->selectField(
'tag_summary',
'ts_tags',
[ 'ts_rev_id' => $rev->getId() ],
}
if ( $warning == 'exists' ) {
$msg = "\t<li>" . self::getExistsWarning( $args ) . "</li>\n";
+ } elseif ( $warning == 'no-change' ) {
+ $file = $args;
+ $filename = $file->getTitle()->getPrefixedText();
+ $msg = "\t<li>" . wfMessage( 'fileexists-no-change', $filename )->parse() . "</li>\n";
+ } elseif ( $warning == 'duplicate-version' ) {
+ $file = $args[0];
+ $count = count( $args );
+ $filename = $file->getTitle()->getPrefixedText();
+ $message = wfMessage( 'fileexists-duplicate-version' )
+ ->params( $filename )
+ ->numParams( $count );
+ $msg = "\t<li>" . $message->parse() . "</li>\n";
} elseif ( $warning == 'was-deleted' ) {
# If the file existed before and was deleted, warn the user of this
$ltitle = SpecialPage::getTitleFor( 'Log' );
* @return string
*/
public static function softwareInformation() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Put the software in an array of form 'name' => 'version'. All messages should
// be loaded here, so feel free to use wfMessage in the 'name'. Raw HTML or
* @return IDatabase
*/
protected function getDB() {
- return wfGetDB( DB_SLAVE, 'watchlist' );
+ return wfGetDB( DB_REPLICA, 'watchlist' );
}
/**
$user = $this->getUser();
$output = $this->getOutput();
- # Show a message about slave lag, if applicable
+ # Show a message about replica DB lag, if applicable
$lag = wfGetLB()->safeGetLag( $dbr );
if ( $lag > 0 ) {
$output->showLagWarning( $lag );
*/
function showIndirectLinks( $level, $target, $limit, $from = 0, $back = 0 ) {
$out = $this->getOutput();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$hidelinks = $this->opts->getValue( 'hidelinks' );
$hideredirs = $this->opts->getValue( 'hideredirs' );
'join_conds' => [ 'langlinks' => [ 'LEFT JOIN', 'll_from = page_id' ] ]
];
if ( $this->prefix ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$query['conds'][] = 'page_title ' . $dbr->buildLike( $this->prefix, $dbr->anyString() );
}
public static function getCustomisedStatuses( $messageNames, $langcode = 'en', $foreign = false ) {
// FIXME: This function should be moved to Language:: or something.
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select( 'page',
[ 'page_namespace', 'page_title' ],
[ 'page_namespace' => [ NS_MEDIAWIKI, NS_MEDIAWIKI_TALK ] ],
$month = isset( $options['month'] ) ? $options['month'] : false;
$this->getDateCond( $year, $month );
- // Most of this code will use the 'contributions' group DB, which can map to slaves
+ // Most of this code will use the 'contributions' group DB, which can map to replica DBs
// with extra user based indexes or partioning by user. The additional metadata
- // queries should use a regular slave since the lookup pattern is not all by user.
- $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random slave
- $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
+ // queries should use a regular replica DB since the lookup pattern is not all by user.
+ $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random replica DB
+ $this->mDb = wfGetDB( DB_REPLICA, 'contributions' );
}
function getDefaultQuery() {
}
$this->target = $target;
$this->namespace = $namespace;
- $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
+ $this->mDb = wfGetDB( DB_REPLICA, 'contributions' );
}
function getDefaultQuery() {
$nt = Title::newFromText( $this->mSearch );
if ( $nt ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$this->mQueryConds[] = 'LOWER(img_name)' .
$dbr->buildLike( $dbr->anyString(),
strtolower( $nt->getDBkey() ), $dbr->anyString() );
if ( $this->mSearch !== '' ) {
$nt = Title::newFromText( $this->mSearch );
if ( $nt ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds[] = 'LOWER(' . $prefix . '_name)' .
$dbr->buildLike( $dbr->anyString(),
strtolower( $nt->getDBkey() ), $dbr->anyString() );
}
unset( $field );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $dbr->implicitGroupby() ) {
$options = [ 'GROUP BY' => 'img_name' ];
} else {
$this->title = $source;
$this->articleID = $source->getArticleID();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$maxtimestamp = $dbr->selectField(
'revision',
'MIN(rev_timestamp)',
$likeVal = $opts->getValue( 'like' );
if ( !$this->getConfig()->get( 'MiserMode' ) && $likeVal !== '' ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$likeObj = Title::newFromText( $likeVal );
if ( $likeObj instanceof Title ) {
$like = $dbr->buildLike(
* @return array
*/
function getQueryInfo() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$conds = [];
// Don't show hidden names
}
// Lookup groups for all the users
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$groupRes = $dbr->select(
'user_groups',
[ 'ug_user', 'ug_group' ],
$warnings['empty-file'] = true;
}
+ $hash = $this->getTempFileSha1Base36();
$exists = self::getExistsWarning( $localFile );
if ( $exists !== false ) {
$warnings['exists'] = $exists;
+
+ // check if file is an exact duplicate of current file version
+ if ( $hash === $localFile->getSha1() ) {
+ $warnings['no-change'] = $localFile;
+ }
+
+ // check if file is an exact duplicate of older versions of this file
+ $history = $localFile->getHistory();
+ foreach ( $history as $oldFile ) {
+ if ( $hash === $oldFile->getSha1() ) {
+ $warnings['duplicate-version'][] = $oldFile;
+ }
+ }
}
if ( $localFile->wasDeleted() && !$localFile->exists() ) {
}
// Check dupes against existing files
- $hash = $this->getTempFileSha1Base36();
$dupes = RepoGroup::singleton()->findBySha1( $hash );
$title = $this->getTitle();
// Remove all matches against self
* Helper function: do the actual database query to fetch file metadata.
*
* @param string $key
- * @param int $readFromDB Constant (default: DB_SLAVE)
+ * @param int $readFromDB Constant (default: DB_REPLICA)
* @return bool
*/
- protected function fetchFileMetadata( $key, $readFromDB = DB_SLAVE ) {
+ protected function fetchFileMetadata( $key, $readFromDB = DB_REPLICA ) {
// populate $fileMetadata[$key]
$dbr = null;
if ( $readFromDB === DB_MASTER ) {
/**
* Get a database connection for the bot passwords database
- * @param int $db Index of the connection to get, e.g. DB_MASTER or DB_SLAVE.
+ * @param int $db Index of the connection to get, e.g. DB_MASTER or DB_REPLICA.
* @return DatabaseBase
*/
public static function getDB( $db ) {
}
$audience = $this->checkAudience( $audience );
- $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
$options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
? [ 'LOCK IN SHARE MODE' ]
: [];
}
$audience = $this->checkAudience( $audience );
- $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_SLAVE );
+ $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
$options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
? [ 'LOCK IN SHARE MODE' ]
: [];
* @throws MWException On unexpected database errors
*/
protected function getUsersByEmail( $email ) {
- $res = wfGetDB( DB_SLAVE )->select(
+ $res = wfGetDB( DB_REPLICA )->select(
'user',
User::selectFields(),
[ 'user_email' => $email ],
$this->getCacheKey( $cache ),
$cache::TTL_HOUR,
function ( $oldValue, &$ttl, array &$setOpts ) use ( $cache ) {
- $setOpts += Database::getCacheSetOptions( wfGetDB( DB_SLAVE ) );
+ $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
wfDebug( "User: cache miss for user {$this->mId}\n" );
$this->loadFromDatabase( self::READ_NORMAL );
public static function newFromConfirmationCode( $code, $flags = 0 ) {
$db = ( $flags & self::READ_LATEST ) == self::READ_LATEST
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
$id = $db->selectField(
'user',
$conds[] = 'ug_user > ' . (int)$after;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$ids = $dbr->selectFieldValues(
'user_groups',
'ug_user',
if ( is_null( $this->mGroups ) ) {
$db = ( $this->queryFlagsUsed & self::READ_LATEST )
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
$res = $db->select( 'user_groups',
[ 'ug_group' ],
[ 'ug_user' => $this->mId ],
/**
* Get blocking information
- * @param bool $bFromSlave Whether to check the slave database first.
- * To improve performance, non-critical checks are done against slaves.
+ * @param bool $bFromSlave Whether to check the replica DB first.
+ * To improve performance, non-critical checks are done against replica DBs.
* Check when actually saving should be done against master.
*/
private function getBlockedStatus( $bFromSlave = true ) {
/**
* Check if user is blocked
*
- * @param bool $bFromSlave Whether to check the slave database instead of
+ * @param bool $bFromSlave Whether to check the replica DB instead of
* the master. Hacked from false due to horrible probs on site.
* @return bool True if blocked, false otherwise
*/
/**
* Get the block affecting the user, or null if the user is not blocked
*
- * @param bool $bFromSlave Whether to check the slave database instead of the master
+ * @param bool $bFromSlave Whether to check the replica DB instead of the master
* @return Block|null
*/
public function getBlock( $bFromSlave = true ) {
* Check if user is blocked from editing a particular article
*
* @param Title $title Title to check
- * @param bool $bFromSlave Whether to check the slave database instead of the master
+ * @param bool $bFromSlave Whether to check the replica DB instead of the master
* @return bool
*/
public function isBlockedFrom( $title, $bFromSlave = false ) {
return [];
}
$utp = $this->getTalkPage();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Get the "last viewed rev" timestamp from the oldest message notification
$timestamp = $dbr->selectField( 'user_newtalk',
'MIN(user_last_timestamp)',
* @return bool True if the user has new messages
*/
protected function checkNewtalk( $field, $id ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$ok = $dbr->selectField( 'user_newtalk', $field, [ $field => $id ], __METHOD__ );
if ( is_null( $this->mFormerGroups ) ) {
$db = ( $this->queryFlagsUsed & self::READ_LATEST )
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
$res = $db->select( 'user_former_groups',
[ 'ufg_group' ],
[ 'ufg_user' => $this->mId ],
if ( $this->mEditCount === null ) {
/* Populate the count, if it has not been populated yet */
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// check if the user_editcount field has been initialized
$count = $dbr->selectField(
'user', 'user_editcount',
// Only update the timestamp if the page is being watched.
// The query to find out if it is watched is cached both in memcached and per-invocation,
- // and when it does have to be executed, it can be on a slave
+ // and when it does have to be executed, it can be on a replica DB
// If this is the user's newtalk page, we always update the timestamp
$force = '';
if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
// Get a new user_touched that is higher than the old one.
// This will be used for a CAS check as a last-resort safety
- // check against race conditions and slave lag.
+ // check against race conditions and replica DB lag.
$newTouched = $this->newTouchedTimestamp();
$dbw = wfGetDB( DB_MASTER );
// Maybe the problem was a missed cache update; clear it to be safe
$this->clearSharedCache( 'refresh' );
// User was changed in the meantime or loaded with stale data
- $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
+ $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'replica';
throw new MWException(
"CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
" the version of the user to be saved is older than the current version."
$db = ( ( $flags & self::READ_LATEST ) == self::READ_LATEST )
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
$options = ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING )
? [ 'LOCK IN SHARE MODE' ]
if ( $this->getId() == 0 ) {
return false; // anons
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$time = $dbr->selectField( 'revision', 'rev_timestamp',
[ 'rev_user' => $this->getId() ],
__METHOD__,
// Lazy initialization check...
if ( $dbw->affectedRows() == 0 ) {
// Now here's a goddamn hack...
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $dbr !== $dbw ) {
- // If we actually have a slave server, the count is
+ // If we actually have a replica DB server, the count is
// at least one behind because the current transaction
// has not been committed and replicated.
$this->mEditCount = $this->initEditCount( 1 );
} else {
- // But if DB_SLAVE is selecting the master, then the
+ // But if DB_REPLICA is selecting the master, then the
// count we just read includes the revision that was
// just added in the working transaction.
$this->mEditCount = $this->initEditCount();
} else {
if ( $this->mEditCount === null ) {
$this->getEditCount();
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$this->mEditCount += ( $dbr !== $dbw ) ? 1 : 0;
} else {
$this->mEditCount++;
* @return int Number of edits
*/
protected function initEditCount( $add = 0 ) {
- // Pull from a slave to be less cruel to servers
+ // Pull from a replica DB to be less cruel to servers
// Accuracy isn't the point anyway here
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$count = (int)$dbr->selectField(
'revision',
'COUNT(rev_user)',
// Load from database
$dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
? wfGetDB( DB_MASTER )
- : wfGetDB( DB_SLAVE );
+ : wfGetDB( DB_REPLICA );
$res = $dbr->select(
'user_properties',
* Get a new instance of this user that was loaded from the master via a locking read
*
* Use this instead of the main context User when updating that user. This avoids races
- * where that user was loaded from a slave or even the master but without proper locks.
+ * where that user was loaded from a replica DB or even the master but without proper locks.
*
* @return User|null Returns null if the user was not found in the DB
* @since 1.27
// Database::select() doesn't like empty arrays
return new ArrayIterator( [] );
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'user',
User::selectFields(),
// Database::select() doesn't like empty arrays
return new ArrayIterator( [] );
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$res = $dbr->select(
'user',
User::selectFields(),
public static function search( $audience, $search, $limit, $offset = 0 ) {
$user = User::newFromName( $search );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$prefix = $user ? $user->getName() : '';
$tables = [ 'user' ];
$cond = [ 'user_name ' . $dbr->buildLike( $prefix, $dbr->anyString() ) ];
* method of batch updating rows in a database. To use create a class
* implementing the RowUpdateGenerator interface and configure the
* BatchRowIterator and BatchRowWriter for access to the correct table.
- * The components will handle reading, writing, and waiting for slaves
+ * The components will handle reading, writing, and waiting for replica DBs
* while the generator implementation handles generating update arrays
* for singular rows.
*
"علاء",
"Hhaboh162002",
"بدارين",
- "باسم"
+ "باسم",
+ "Moud hosny"
]
},
"tog-underline": "سطر تحت الوصلات:",
"filerevert-submit": "استرجع",
"filerevert-success": "'''[[Media:$1|$1]]''' تم استرجاعها [$4 للنسخة بتاريخ $3، $2].",
"filerevert-badversion": "لا توجد نسخة محلية سابقة لهذا الملف بالتاريخ المعطى.",
+ "filerevert-identical": "الإصدار الحالي من الملف بالفعل مطابق للإصدار المحدد.",
"filedelete": "احذف $1",
"filedelete-legend": "احذف الملف",
"filedelete-intro": "أنت على وشك حذف الملف '''[[Media:$1|$1]]''' مع كل تاريخه.",
"file-thumbnail-no": "El ficheru entama con <strong>$1</strong>.\nPaez ser una imaxe de tamañu menguáu ''(miniatura)''.\nSi tienes esta imaxe a resolución completa xúbila; si non, por favor camuda'l nome del ficheru.",
"fileexists-forbidden": "Yá esiste un ficheru con esti nome, y nun se pue renomar.\nSi tovía asina quies xubir el ficheru, por favor vuelvi atrás y usa otru nome.\n[[File:$1|thumb|center|$1]]",
"fileexists-shared-forbidden": "Yá esiste un ficheru con esti nome nel direutoriu de ficheros compartíos.\nSi tovía asina quies xubir el ficheru, por favor vuelvi atrás y usa otru nome.\n[[File:$1|thumb|center|$1]]",
+ "fileexists-no-change": "La carga ye un duplicáu exautu de la versión actual de <strong>[[:$1]]</strong>.",
"file-exists-duplicate": "Esti ficheru ye un duplicáu {{PLURAL:$1|del siguiente ficheru|de los siguientes ficheros}}:",
"file-deleted-duplicate": "Yá se desanició enantes un ficheru idénticu a esti ([[:$1]]).\nDeberíes revisar el historial de desaniciu del ficheru enantes de xubilu otra vuelta.",
"file-deleted-duplicate-notitle": "Un ficheru idénticu a esti desanicióse anteriormente, y suprimióse'l títulu. Tendría de pidir a dalguién que pueda ver los datos del ficheru desaniciáu que revise la situación enantes de volver a xubilu.",
"filerevert-submit": "Вярнуць",
"filerevert-success": "'''[[Media:$1|$1]]''' быў вернуты да [вэрсіі $4 ад $3, $2].",
"filerevert-badversion": "Не існуе папярэдняй лякальнай вэрсіі гэтага файла з пазначанай датай.",
+ "filerevert-identical": "Цяперашняя вэрсія файлу ўжо ідэнтычная абранай.",
"filedelete": "Выдаліць $1",
"filedelete-legend": "Выдаліць файл",
"filedelete-intro": "Вы выдаляеце файл '''[[Media:$1|$1]]''' з усёй яго гісторыяй.",
"mw-widgets-dateinput-placeholder-month": "ГГГГ-ММ",
"mw-widgets-titleinput-description-new-page": "старонка яшчэ не існуе",
"mw-widgets-titleinput-description-redirect": "перанакіраваньне на $1",
+ "sessionmanager-tie": "Немагчыма выкарыстаць адначасова некалькі тыпаў аўтэнтыфікацыі: $1.",
"sessionprovider-generic": "$1 сэсіі",
"randomrootpage": "Выпадковая карэнная старонка",
"log-action-filter-block": "Тып блякаваньня:",
"content-model-json": "JSON",
"content-json-empty-object": "Objecte buit",
"content-json-empty-array": "Matriu buida",
+ "deprecated-self-close-category": "Pàgines que usen etiquetes HTML autotancades no vàlides",
"duplicate-args-warning": "<strong>Avís:</strong> [[:$1]] crida [[:$2]] amb més d'un valor pel paràmetre «$3». Només s'utilitzarà el darrer valor proporcionat.",
"duplicate-args-category": "Pàgines amb arguments duplicats en utilització de plantilles",
"duplicate-args-category-desc": "La pàgina conté crides a plantilles que fan servir duplicats d'arguments, com ara <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> o <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"filerevert-submit": "Vrátit zpět",
"filerevert-success": "Soubor '''[[Media:$1|$1]]''' byl vrácen zpět na [$4 verzi z $3 $2].",
"filerevert-badversion": "Není dostupná předchozí verze tohoto souboru s odpovídající časovou značkou.",
+ "filerevert-identical": "Aktuální verze souboru se již od vybrané verze neliší.",
"filedelete": "Smazání souboru $1",
"filedelete-legend": "Smazat soubor",
"filedelete-intro": "Chystáte se smazat soubor '''[[Media:$1|$1]]''' i s celou historií.",
"nextn-title": "{{PLURAL:$1|Folgendes Ergebnis|Folgende $1 Ergebnisse}}",
"shown-title": "Zeige $1 {{PLURAL:$1|Ergebnis|Ergebnisse}} pro Seite",
"viewprevnext": "Zeige ($1 {{int:pipe-separator}} $2) ($3)",
- "searchmenu-exists": "<strong>Es gibt eine Seite, die den Namen „[[:$1]]“ hat.</strong> {{PLURAL:$2|0=|Weitere Suchergebnisse anzeigen.}}",
+ "searchmenu-exists": "<strong>Es gibt eine Seite, die den Namen „[[:$1]]“ hat.</strong> {{PLURAL:$2|0=|Weitere Suchergebnisse:}}",
"searchmenu-new": "<strong>Erstelle die Seite „[[:$1]]“ in diesem Wiki.</strong> {{PLURAL:$2|0=|Siehe auch die über deine Suche gefundene Seite.|Siehe auch die gefundenen Suchergebnisse.}}",
"searchprofile-articles": "Inhaltsseiten",
"searchprofile-images": "Multimedia",
"file-thumbnail-no": "Der Dateiname beginnt mit <strong>$1</strong>. Dies deutet auf ein Bild verringerter Größe ''(Minitatur)'' hin.\nBitte prüfe, ob du das Bild in voller Auflösung vorliegen hast und lade dieses unter dem Originalnamen hoch.",
"fileexists-forbidden": "Unter diesem Namen existiert bereits eine Datei und sie kann nicht überschrieben werden. Bitte gehe zurück und lade die Datei unter einem anderen Namen hoch. [[File:$1|thumb|center|$1]]",
"fileexists-shared-forbidden": "Unter diesem Namen existiert bereits eine Datei im zentralen Medienarchiv.\nWenn du diese Datei trotzdem hochladen möchtest, gehe bitte zurück und ändere den Namen.\n[[File:$1|thumb|center|$1]]",
+ "fileexists-no-change": "Die hochgeladene Datei ist ein exaktes Duplikat der aktuellen Version von <strong>[[:$1]]</strong>.",
+ "fileexists-duplicate-version": "Die hochgeladene Datei ist ein exaktes Duplikat {{PLURAL:$2|einer älteren Version|von älteren Versionen}} von <strong>[[:$1]]</strong>.",
"file-exists-duplicate": "Diese Datei ist ein Duplikat der folgenden {{PLURAL:$1|Datei|$1 Dateien}}:",
"file-deleted-duplicate": "Eine mit dieser identische Datei ([[:$1]]) wurde früher gelöscht. Sieh das Lösch-Logbuch ein, bevor du sie hochlädst.",
"file-deleted-duplicate-notitle": "Eine identische Datei wurde kürzlich gelöscht und der Titel wurde unterdrückt.\nDu solltest jemanden fragen, der die Möglichkeit hat, die unterdrückten Dateidaten anzusehen, um die Situation vor dem erneuten Hochladen zu überprüfen.",
"mergehistory-box": "revizyonê pelanî yew bike:",
"mergehistory-from": "Pela çımey:",
"mergehistory-into": "Pela destinasyonî",
- "mergehistory-list": "tarixê vurnayîşî ke eşkeno yew bi.",
+ "mergehistory-list": "Tarixê vurnayışiyo yewbiyaye",
"mergehistory-merge": "[[:$1]] qey ney revizyonê cêrini [[:$2]] şıma ekeni piyawani. Benatê wexto muwaqqet de piyayanayişê rezizyonan de tuşa radyo bıxebitne.",
"mergehistory-go": "Yew bıyaye vurriyayışa bıasne",
"mergehistory-submit": "revizyonî yew bike",
"mergelog": "Qeydé zew kerdışi",
"revertmerge": "Abırnê",
"mergelogpagetext": "Cêr de yew liste esta ke mocnena ra, raya tewr peyêne kamci pela tarixi be a bine ra şanawa pê.",
- "history-title": "Tarixê çım ra viyarnayışë \"$1\"",
+ "history-title": "Tarixê çımraviyarnayışê \"$1\"",
"difference-title": "Pela \"$1\" ferqê çım ra viyarnayışan",
"difference-title-multipage": "Ferkê pelan dê \"$1\" u \"$2\"",
"difference-multipage": "(Ferqê pelan)",
"rcshowhidepatr-show": "Bımocne",
"rcshowhidepatr-hide": "Bınımne",
"rcshowhidemine": "vurnayışanê mı $1",
- "rcshowhidemine-show": "Bımocne",
+ "rcshowhidemine-show": "Bımosne",
"rcshowhidemine-hide": "Bınımne",
"rcshowhidecategorization": "kategorizasyonê pele $1",
"rcshowhidecategorization-show": "Bımocne",
"protectedpages-unknown-performer": "Karbero nêzanaye",
"protectedtitles": "Sernameyê pawıteyi",
"protectedtitlesempty": "pê ney parametreyan sernuşteyê pawite çinê",
- "protectedtitles-submit": "Sernaman bımocne",
+ "protectedtitles-submit": "Sernameyan bımocne",
"listusers": "Listeyê Karberan",
"listusers-editsonly": "Teyna karberan bimucne ke ey nuştê",
"listusers-creationsort": "goreyê wextê vıraştışi rêz ker",
"cant-move-user-page": "desturê şıma çino, şıma pelanê karberani bıkırışi (bê pelê cerıni).",
"cant-move-to-user-page": "desturê şıma çino, şıma yew peli bıkırışi pelê yew karberi.",
"newtitle": "Sernameyo newe:",
- "move-watch": "Peler seyr ke",
+ "move-watch": "Na pele seyr ke",
"movepagebtn": "Pele bere",
"pagemovedsub": "Berdışi kerd temam",
"movepage-moved": "'''\"$1\" berd \"$2\"'''",
"tooltip-ca-nstab-main": "Pela zerreki bıvêne",
"tooltip-ca-nstab-user": "Pela karberi bıvêne",
"tooltip-ca-nstab-media": "Pela medya bıvêne",
- "tooltip-ca-nstab-special": "Na pelaya xas a, şıma nêşenê sero vurnayış bıkerê",
+ "tooltip-ca-nstab-special": "Na yew pela xasa, şıma nêşenê sero vurnayış bıkerê",
"tooltip-ca-nstab-project": "Pela proceyi bıvêne",
"tooltip-ca-nstab-image": "Pera dosyayer bıvin",
"tooltip-ca-nstab-mediawiki": "Mesacê sistemi bımocne",
"pageinfo-header-edits": "Veréna timar kerdışi",
"pageinfo-header-restrictions": "Sıtarkerdışê pele",
"pageinfo-header-properties": "Xısusiyetê pele",
- "pageinfo-display-title": "Sernuştey bımocne",
+ "pageinfo-display-title": "Sernuşteyo ke mosneyêno",
"pageinfo-default-sort": "Hesıbyaye mırfeyo kılm",
"pageinfo-length": "Derdeya pela (bayti heta)",
"pageinfo-article-id": "Kamiya pele",
"exif-pixelydimension": "Berzeya resimi",
"exif-usercomment": "Mışewreyê karberi",
"exif-relatedsoundfile": "Derhekê dosya yê vengi",
- "exif-datetimeoriginal": "Zeman u tarixê data varaziyayişi",
- "exif-datetimedigitized": "Zeman u tarixê dicital kerdişi",
+ "exif-datetimeoriginal": "Demê afernayışê dayeyo sıfteyıni",
+ "exif-datetimedigitized": "Zeman û tarixê dicitalkerdışi",
"exif-subsectime": "ZemanTarix saniyeyibini",
"exif-subsectimeoriginal": "ZemanTarixOricinal saniyeyibini",
"exif-subsectimedigitized": "ZemanTarixDicital saniyeyibini",
"version": "Versiyon",
"version-extensions": "Ekstensiyonî ke ronaye",
"version-skins": "Bar kerde bejni",
- "version-specialpages": "Pelanê xasiyan",
+ "version-specialpages": "Pelê xısusiyi",
"version-parserhooks": "Çengelê Parserî",
"version-variables": "Vurnayeyî",
"version-antispam": "Spam vındarnayış",
"specialpages-note-top": "Kıtabek",
"specialpages-note": "* Pelê xasê normali.\n* <span class=\"mw-specialpagerestricted\">Pelê xasê nımıtey.</span>",
"specialpages-group-maintenance": "Raporê pawıtışi",
- "specialpages-group-other": "Pelê xasiyê bini",
+ "specialpages-group-other": "Pelê xısusiyê bini",
"specialpages-group-login": "Dekew / hesab vıraz",
"specialpages-group-changes": "Vurnayışê peyêni û qeydi",
"specialpages-group-media": "Raporê medya û barkerdışi",
"tagline": "{{SITENAME}}बाट",
"help": "सहायता",
"search": "खोज",
+ "search-ignored-headings": " #<!-- leave this line exactly as it is --> <pre>\n# Headings that will be ignored by search.\n# Changes to this take effect as soon as the page with the heading is indexed.\n# You can force page reindexing by doing a null edit.\n# The syntax is as follows:\n# * Everything from a \"#\" character to the end of the line is a comment.\n# * Every non-blank line is the exact title to ignore, case and everything.\nReferences\nExternal links\nSee also\n #</pre> <!-- leave this line exactly as it is -->",
"searchbutton": "खोज",
"go": "जाने",
"searcharticle": "जाओ",
"import-logentry-upload-detail": "$1 {{PLURAL:$1|संशोधन|संशोधनहरू}} आयात भयो",
"tooltip-pt-userpage": "{{GENDER:|तमरो प्रयोगकर्ता}} पान्नो",
"tooltip-pt-anonuserpage": "तमी जो IP ठेगानाको रुपमी सम्पादन गद्दै छौ , त्यैको प्रयोगकर्ता पानो निम्न छ :",
- "tooltip-pt-mytalk": "{{GENDER:|तमरà¥\8b}} à¤\95à¥\81रडà¥\80à¤\95ानà¥\80 पानà¥\8dनà¥\8b",
+ "tooltip-pt-mytalk": "{{GENDER:|तमरो}} कुरडीकानी पानो",
"tooltip-pt-preferences": "{{GENDER:|तमरी}} अभिरुचि",
"tooltip-pt-watchlist": "पृष्ठहरूको सूची जैका फेरबदलहरुलाई तमले पहरा गरिराखेका छौ ।",
"tooltip-pt-mycontris": "{{GENDER:|तमरा}} योगदानअनऐ सूची",
"passwordreset-emailelement": "Nòm utèint: \n$1\n.\nCêva 'd ingrès pruvişôria: \n$2",
"passwordreset-emailsentemail": "Se cl’indirés ed pôsta eletrônica ché l’è unî a la tó utèinsa, alōra a gnirà spidî ‘na lètra per per turnêr a impustêr la cêva ‘d ingrès.",
"changeemail": "Mudéfica o tó via l'indirés ed pôsta eletrônica",
- "changeemail-header": "Câmbia l'indirés ed la pôsta eletrônica 'd la tó inscrisiòun.",
+ "changeemail-header": "Finés cól fòj ché per cambiêr al tó indirés ed pôsta eletrônica, 'S an 't vō mia avèir nisûn indirés coleghê a la tó utèinsa lêsa vōd al spâsi per l'indirés nōv quând té spidés al fòj.",
"changeemail-no-info": "Per andêr dèinter diretamèint a cla pàgina ché 't gh'ê da fêr l'ingrès.",
"changeemail-oldemail": "L'indirés ed la pôsta eletrànica 'd adès.",
"changeemail-newemail": "Nōv indirés ed pàsta eletrônica:",
"sig_tip": "Fîrma cun la dâta e l'ōra",
"hr_tip": "Rîga spiâna (drōva cun giudési)",
"summary": "Ogèt:",
- "subject": "Argumèint (tétol):",
+ "subject": "Argumèint:",
"minoredit": "Còsta l'é 'na mudéfica céca",
"watchthis": "Tîn adrē a cla pàgina ché",
"savearticle": "Sêlva la pàgina",
"missingsummary": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda cun al mutîv vōd.",
"selfredirect": "<strong>Ateinti:</strong>t'é drē fêr un rinvéi a l'istèsa pàgina. Ét prés avèir şbaliê sgnêr al pôst dal rinvéi o t'é drē mudifichêr la pàgina şbaliêda. S'ét fê cléch incòra in sém a \"{{int:savearticle}}\", al rinvéi al gnirà fât in tót' al manēri.",
"missingcommenttext": "Scréver un cumèint ché sòta.",
- "missingcommentheader": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv/al tétol de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda sèinsa tétol.",
+ "missingcommentheader": "<strong>Atensiòun:<strong> an n'é mìa stê precişê l'argumèint de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda sèinsa.",
"summary-preview": "Guêrda préma sûnt:",
- "subject-preview": "Guêrda préma argumèint/tétol:",
+ "subject-preview": "Guêrda préma l'argumèint:",
"previewerrortext": "A gh'é stê 'n erōr mèinter a s'é serchê ed guardêr al lavōr préma 'd salvêrel.",
"blockedtitle": "Utèint bluchê",
"blockedtext": " '''Al tō nòm utèint o indirés IP l'é stê bluchê.'''\n\nAl blôch l'é stê fât da $1. Al mutîv dal blôch l'é còst: ''$2''.\n\n*Inési dal blôch: $8\n*Scadèinsa dal blôch: $6\n*Intervâl ed blôch: $7\n\nS' ét vō, l'é pusébil mètres in cuntât cun $1 o 'n êter [[{{MediaWiki:Grouppage-sysop}}|aministradōr]] per discóter dal blôch.\n\nGuêrda che la funsiòun 'Scrév a l'utèint' an n'é mìa in ôvra s' an n'é mìa stê registrtê un indirés ed pôsta eletrônica vâlid int al tō [[Special:Preferences| preferèinsi]] o se sté funsiòun l'é stêda bluchêda. L'indirés IP 'd adèsa l'é $3, al nóme ID dal blôch l'é #$5. T'é perghê ed precişêr tót j elemèint ed préma per ògni dmânda de spiegasiòun",
"accmailtext": "'Na cêva 'd ingrés l'è stêda fâta a chêş per [[User talk:$1|$1]] e l'è stêda spidîda a $2. Cla cêva 'd ingrès ché la pōl èser cambiêda int la pàgina per ''[[Special:ChangePassword|cambiêr la cêva 'd ingrès]]'' subét dôp avèir fât l'ingrès.",
"newarticle": "(Nōv)",
"newarticletext": "Al colegamèint apèina fât al cumbîna cun 'na pàgina ch' an n'é mìa incòra stêda fâta. S'ét vō fêr la pàgina adès, l'é asê cumincêr a scréver al tèst int la caşèla ché sòt (per vedèr infurmasiòun pió precîşi guêrda la [$1 pàgina 'd ajót]). Se al colegamèint l'é stê avêrt per erōr, l'é asê clichêr al pulsânt \"Indrē\" dal tó navigadōr.",
- "anontalkpagetext": "----'' Còsta l'è la pàgina 'd discusiòun ed 'n utèint sèinsa nòm, ch' an n' à mìa incòra fât 'n' utèinsa o in tót al manēri an n'è mìa drē druvêrla. Per arcgnòsrel l'è dòunca necesâri druvê al só indirés IP. J indirés IP a pōlen èser spartî cun êter utèint. Se t'è un utèint sèinsa nòm e 't pèins che i cumèint in cla pàgina ché an riguêrden mìa tè, [[Special:CreateAccount|fa 'n' utèinsa nōva]] o [[Special:UserLogin|vîn dèinter cun còla ch' ét gh'ê bèle]] per schivşêr, in futûr, 'd èser cunfûş cun 'd j êter utèint sèinsa nòm.''",
+ "anontalkpagetext": "----\n<em>Còsta l'è la pàgina 'd discusiòun ed 'n utèint sèinsa nòm, ch' an n' à mìa incòra fât 'n' utèinsa o in tót al manēri an n'è mìa drē druvêrla.</em> Per arcgnòsrel l'è dòunca necesâri druvê al nóme dal só indirés IP. J indirés IP a pōlen èser spartî cun êter utèint. Se t'é un utèint sèinsa nòm e 't pèins che i cumèint in cla pàgina ché an riguêrden mìa té, [[Special:CreateAccount|fa 'n' utèinsa nōva]] o [[Special:UserLogin|vîn dèinter cun còla ch' ét gh'ê bèle]] per schivşêr, in futûr, 'd èser cunfûş cun 'd j êter utèint sèinsa nòm.",
"noarticletext": "In cól mumèint ché la pàgina serchêda l'é vōda. L'é pusébil [[Special:Search/{{PAGENAME}}|serchêr sté tétol]] int al j êtri pàgini dal sît, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchêr int i regéster coleghê] opór [{{fullurl:{{FULLPAGENAME}}|action=edit}} mudifichêr la pàgina adèsa]</span>.",
"noarticletext-nopermission": "In cól mumèint ché la pàgina serchêda l'é vōda. L'é pusébil [[Special:Search/{{PAGENAME}}|serchêr sté tétol]] int al j êtri pàgini dal sît o<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} serchêr int i regéster coleghê] <span>, mó an 't gh'ê mìa al permès ed fêr cla pàgina ché.",
"missing-revision": "La revişiòun #$1 'd la pagina \"{{FULLPAGENAME}}\" l' an gh'è mìa. Còst, ed sôlit, a sucēd mèint'r as va drē a 'n colegamèint a 'na pàgina scanşlêda, in 'na stòria, di lavōr fât, mìa arnuvêda. I particulêr a 's pōlen catêr int al [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} regéster dal scanşladûri].",
"previewnote": "'''Να θυμάστε ότι αυτή είναι μόνο μια προεπισκόπηση.'''\nΟι αλλαγές σας δεν έχουν ακόμη αποθηκευτεί!",
"continue-editing": "Μεταβείτε στην περιοχή επεξεργασίας",
"previewconflict": "Αυτή η προεπισκόπηση απεικονίζει το κείμενο στην επάνω περιοχή επεξεργασίας κειμένου, όπως θα εμφανιστεί εάν επιλέξετε να το αποθηκεύσετε.",
- "session_fail_preview": "'''Συγγνώμη! Δεν μπορούσαμε να διεκπεραιώσουμε την επεξεργασία σας λόγω απώλειας των δεδομένων της συνεδρίας.\nΠαρακαλώ προσπαθήστε ξανά. Αν δεν δουλεύει ξανά, δοκιμάστε να αποσυνδεθείτε και να συνδεθείτε πάλι.'''",
+ "session_fail_preview": "'''Συγγνώμη! Δεν μπορούσαμε να διεκπεραιώσουμε την επεξεργασία σας λόγω απώλειας των δεδομένων της συνεδρίας.\nΠαρακαλώ προσπαθήστε ξανά. Αν δεν δουλεύει ξανά, δοκιμάστε να [[Special:UserLogout|αποσυνδεθείτε]] και να συνδεθείτε πάλι.'''",
"session_fail_preview_html": "'''Λυπούμαστε! Δεν μπορέσαμε να διεκπεραιώσουμε την επεξεργασία σας λόγω απώλειας των δεδομένων της συνεδρίας.'''\n\n''Επειδή το {{SITENAME}} επιτρέπει την εισαγωγή ακατέργαστου HTML, η προεπισκόπηση είναι κρυμμένη ως προφύλαξη ενάντια σε επιθέσεις με Javascript.''\n\n'''Αν αυτή είναι μια έγκυρη προσπάθεια επεξεργασίας, παρακαλώ προσπαθήστε ξανά. Αν πάλι δε δουλεύει, δοκιμάστε να αποσυνδεθείτε και να συνδεθείτε πάλι.'''",
"token_suffix_mismatch": "'''Η επεξεργασία σας απορρίφθηκε γιατί το πρόγραμμα-πελάτη σας κατακρεούργησε τους χαρακτήρες στίξης στο κουπόνι επεξεργασίας. Η επεξεργασία απορρίφθηκε για να αποφευχθεί η παραφθορά του κειμένου της σελίδας.\nΑυτό μερικές φορές συμβαίνει όταν χρησιμοποιείται ένας ανώνυμος διακομιστής μεσολάβησης διαθέσιμος μέσω του παγκόσμιου ιστού με σφάλματα.'''",
"edit_form_incomplete": "'''Ορισμένα τμήματα της φόρμας επεξεργασίας δεν έφθασαν στο διακομιστή. Ελέγξτε ότι οι αλλαγές σας είναι άθικτες και προσπαθήστε ξανά.'''",
"uploadstash-summary": "Η σελίδα παρέχει πρόσβαση σε αρχεία που είναι επιφορτωμένα (ή στη διαδικασία της επιφόρτωσης) αλλά δεν έχει ακόμη δημοσιευθεί για το wiki. Αυτά τα αρχεία δεν είναι ορατά σε οποιονδήποτε, αλλά στο χρήστη που τα επιφόρτωσε.",
"uploadstash-clear": "Καθαρά διατηρημένα αρχεία",
"uploadstash-nofiles": "Δεν έχετε κρυμμένα αρχεία.",
- "uploadstash-badtoken": "Î\95κÏ\84ÎλεÏ\83η Ï\84ηÏ\82 εν λÏ\8cγÏ\89 ενÎÏ\81γειαÏ\82 ήÏ\84αν ανεÏ\80ιÏ\84Ï\85Ï\87ήÏ\82, ίÏ\83Ï\89Ï\82 εÏ\80ειδή Ï\84α διαÏ\80ιÏ\83Ï\84εÏ\85Ï\84ήÏ\81ιά εÏ\80εξεÏ\81γαÏ\83ίαÏ\82 Ï\83αÏ\82 ÎÏ\87οÏ\85ν λήξει. Î\94οκίμαστε ξανά.",
- "uploadstash-errclear": "Î\97 εκκαθάÏ\81ιÏ\83η Ï\84Ï\89ν αÏ\81Ï\87είÏ\89ν ήÏ\84αν ανεÏ\80ιÏ\84Ï\85Ï\87ήÏ\82.",
+ "uploadstash-badtoken": "Î\95κÏ\84ÎλεÏ\83η Ï\84ηÏ\82 εν λÏ\8cγÏ\89 ενÎÏ\81γειαÏ\82 αÏ\80ÎÏ\84Ï\85Ï\87ε, ίÏ\83Ï\89Ï\82 εÏ\80ειδή Ï\84α διαÏ\80ιÏ\83Ï\84εÏ\85Ï\84ήÏ\81ιά εÏ\80εξεÏ\81γαÏ\83ίαÏ\82 Ï\83αÏ\82 ÎÏ\87οÏ\85ν λήξει. ΠαÏ\81ακαλοÏ\8dμε δοκιμάστε ξανά.",
+ "uploadstash-errclear": "Î\97 εκκαθάÏ\81ιÏ\83η Ï\84Ï\89ν αÏ\81Ï\87είÏ\89ν αÏ\80ÎÏ\84Ï\85Ï\87ε.",
"uploadstash-refresh": "Ανανεώσετε τη λίστα των αρχείων",
"invalid-chunk-offset": "Άκυρο κομμάτι όφσετ",
"img-auth-accessdenied": "Δεν επετράπη η πρόσβαση",
"delete-toobig": "Αυτή η σελίδα έχει μεγάλο ιστορικό τροποποιήσεων, πάνω από $1 {{PLURAL:$1|τροποποίηση|τροποποιήσεις}}.\nΗ διαγραφή τέτοιων σελίδων έχει περιοριστεί για την αποφυγή τυχαίας αναστάτωσης του {{SITENAME}}.",
"delete-warning-toobig": "Αυτή η σελίδα έχει μεγάλο ιστορικό τροποποιήσεων, πάνω από $1 {{PLURAL:$1|τροποποίηση|τροποποιήσεις}}.\nΗ διαγραφή της μπορεί να αναστατώσει τη λειτουργία της βάσης δεδομένων του {{SITENAME}}. Συνιστούμε μεγάλη προσοχή.",
"deleteprotected": "Δεν μπορείτε να διαγράψετε αυτή τη σελίδα επειδή είναι προστατευόμενη.",
- "deleting-backlinks-warning": "\"'Προσοχή:\"' [[Special:WhatLinksHere/{{FULLPAGENAME}}|Άλλες σελίδες]] συνδέουν ή ενσωματώνουν τη σελίδα που πρόκειται να διαγράψετε.",
+ "deleting-backlinks-warning": "<strong>Προσοχή:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Άλλες σελίδες]] συνδέουν ή ενσωματώνουν τη σελίδα που πρόκειται να διαγράψετε.",
"rollback": "Επαναφορά επεξεργασιών",
"rollbacklink": "αναστροφή",
"rollbacklinkcount": "Επαναφορά $1 {{PLURAL:$1|επεξεργασίας|επεξεργασιών}}",
"undeletedrevisions": "{{PLURAL:$1|τροποποίηση|τροποποιήσεις}} αποκαταστάθηκαν",
"undeletedrevisions-files": "$1 {{PLURAL:$1|αναθεώρηση|αναθεωρήσεις}} και $2 {{PLURAL:$2|αρχείο|αρχεία}} επαναφέρθηκαν",
"undeletedfiles": "$1 {{PLURAL:$1|αρχείο|αρχεία}} επαναφέρθηκαν",
- "cannotundelete": "Î\97 αναίÏ\81εÏ\83η διαγÏ\81αÏ\86ήÏ\82 αÏ\80ÎÏ\84Ï\85Ï\87ε: $1",
+ "cannotundelete": "Î\9cεÏ\81ικÎÏ\82 ή Ï\8cλεÏ\82 οι αναιÏ\81ÎÏ\83ειÏ\82 διαγÏ\81αÏ\86ήÏ\82 αÏ\80ÎÏ\84Ï\85Ï\87αν: $1",
"undeletedpage": "'''Η $1 έχει επαναφερθεί'''\n\nΣυμβουλευτείτε το [[Special:Log/delete|αρχείο καταγραφής διαγραφών]] για ένα μητρώο των πρόσφατων διαγραφών και επαναφορών.",
"undelete-header": "Δείτε [[Special:Log/delete|το αρχείο καταγραφής διαγραφών]] για πρόσφατα διαγεγραμμένες σελίδες.",
"undelete-search-title": "Αναζήτηση διαγεγραμμένων σελίδων",
"sp-contributions-newbies-sub": "Για νέους λογαριασμούς",
"sp-contributions-newbies-title": "Συνεισφορές χρηστών για νέους λογαριασμούς",
"sp-contributions-blocklog": "αρχείο καταγραφών φραγών",
- "sp-contributions-suppresslog": "διαγεγραμμένες συνεισφορές χρήστη",
+ "sp-contributions-suppresslog": "διαγεγραμμένες συνεισφορές {{GENDER:$1|χρήστη|χρήστριας}}",
"sp-contributions-deleted": "διαγεγραμμένες συνεισφορές χρήστη",
"sp-contributions-uploads": "ανεβάσματα αρχείων",
"sp-contributions-logs": "καταγραφές",
"watchlistedit-raw-done": "Η λίστα παρακολούθησής σας ενημερώθηκε.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 σελίδα|$1 σελίδες}} προστέθηκαν:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 σελίδα|$1 σελίδες}} αφαιρέθηκαν:",
- "watchlistedit-clear-title": "Î\95κκαθαÏ\81ιÏ\83μÎνη λίÏ\83Ï\84α παρακολούθησης",
+ "watchlistedit-clear-title": "Î\95κκαθάÏ\81ιÏ\83η λίÏ\83Ï\84αÏ\82 παρακολούθησης",
"watchlistedit-clear-legend": "Εκκαθάριση λίστας παρακολούθησης",
"watchlistedit-clear-explain": "Όλοι οι τίτλοι θα αφαιρεθούν από τη λίστα παρακολούθησής σας",
"watchlistedit-clear-titles": "Τίτλοι:",
"version-libraries-license": "Άδεια χρήσης",
"version-libraries-description": "Περιγραφή",
"version-libraries-authors": "Δημιουργοί",
- "redirect": "Ανακατεύθυνση κατά αρχείο, χρήστη, σελίδα ή αναγνωριστικό αναθεώρησης",
+ "redirect": "Ανακατεύθυνση κατά αρχείο, χρήστη, σελίδα, αναγνωριστικό αναθεώρησης ή αρχείο καταγραφής ID",
"redirect-submit": "Μετάβαση",
"redirect-lookup": "Αναζήτηση:",
"redirect-value": "Τιμή:",
"tags-delete-submit": "Μη αναστρέψιμη διαγραφή αυτής της ετικέτας",
"tags-delete-not-found": "Η ετικέτα «$1» δεν υπάρχει.",
"tags-delete-too-many-uses": "Η ετικέτα «$1» εφαρμόζεται σε πάνω από {{PLURAL:$2|μία αναθεώρηση|$2 αναθεωρήσεις}}, που σημαίνει ότι δεν μπορεί να διαγραφεί.",
- "tags-delete-warnings-after-delete": "Η ετικέτα «$1» διαγράφηκε με επιτυχία, αλλά {{PLURAL:$2|προέκυψε η ακόλουθη προειδοποίηση|προέκυψαν οι ακόλουθες προειδοποιήσεις}}:",
+ "tags-delete-warnings-after-delete": "Η ετικέτα «$1» διαγράφηκε, αλλά {{PLURAL:$2|προέκυψε η ακόλουθη προειδοποίηση|προέκυψαν οι ακόλουθες προειδοποιήσεις}}:",
"tags-delete-no-permission": "Δεν έχετε άδεια να διαχειριστείτε ετικέτες αλλαγής.",
"tags-activate-title": "Ενεργοποίηση ετικέτας",
"tags-activate-question": "Πρόκειται να ενεργοποιήσετε την ετικέτα «$1».",
"tags-edit-reason": "Αιτία:",
"tags-edit-revision-submit": "Εφαρμογή αλλαγών σε {{PLURAL:$1|αυτή την αναθεώρηση|$1 αναθεωρήσεις}}",
"tags-edit-logentry-submit": "Εφαρμογή αλλαγών σε {{PLURAL:$1|αυτήν την καταχώρηση|$1 καταχωρήσεις}} του αρχείου καταγραφής",
- "tags-edit-success": "Οι αλλαγές εφαρμόστηκαν με επιτυχία.",
+ "tags-edit-success": "Οι αλλαγές εφαρμόστηκαν.",
"tags-edit-failure": "Οι αλλαγές δεν ήταν δυνατόν να εφαρμοστούν:\n$1",
"tags-edit-nooldid-title": "Μη έγκυρη αναθεώρηση προορισμού",
"tags-edit-none-selected": "Παρακαλώ επιλέξτε τουλάχιστον μία ετικέτα για να προσθέσετε ή να αφαιρέσετε.",
"yourpasswordagain": "Retype password:",
"createacct-yourpasswordagain": "Confirm password",
"createacct-yourpasswordagain-ph": "Enter password again",
- "remembermypassword": "Remember my login on this browser (for a maximum of $1 {{PLURAL:$1|day|days}})",
"userlogin-remembermypassword": "Keep me logged in",
"userlogin-signwithsecure": "Use secure connection",
"cannotloginnow-title": "Cannot log in now",
"file-thumbnail-no": "The filename begins with <strong>$1</strong>.\nIt seems to be an image of reduced size <em>(thumbnail)</em>.\nIf you have this image in full resolution upload this one, otherwise change the filename please.",
"fileexists-forbidden": "A file with this name already exists, and cannot be overwritten.\nIf you still want to upload your file, please go back and use a new name.\n[[File:$1|thumb|center|$1]]",
"fileexists-shared-forbidden": "A file with this name exists already in the shared file repository.\nIf you still want to upload your file, please go back and use a new name.\n[[File:$1|thumb|center|$1]]",
+ "fileexists-no-change": "The upload is an exact duplicate of the current version of <strong>[[:$1]]</strong>.",
+ "fileexists-duplicate-version": "The upload is an exact duplicate of {{PLURAL:$2|an older version|older versions}} of <strong>[[:$1]]</strong>.",
"file-exists-duplicate": "This file is a duplicate of the following {{PLURAL:$1|file|files}}:",
"file-deleted-duplicate": "A file identical to this file ([[:$1]]) has previously been deleted.\nYou should check that file's deletion history before proceeding to re-upload it.",
"file-deleted-duplicate-notitle": "A file identical to this file has previously been deleted, and the title has been suppressed.\nYou should ask someone with the ability to view suppressed file data to review the situation before proceeding to re-upload it.",
"action-import": "importar páginas desde otro wiki",
"action-importupload": "importar páginas mediante la carga de un archivo",
"action-patrol": "marcar ediciones de otros como verificadas",
- "action-autopatrol": "tener tus ediciones marcadas como verificadas",
+ "action-autopatrol": "marcar como verificadas tus propias ediciones",
"action-unwatchedpages": "ver la lista de páginas no vigiladas",
"action-mergehistory": "fusionar el historial de esta página",
"action-userrights": "modificar todos los permisos de usuario",
"logentry-delete-revision": "$1 {{GENDER:$2|modificó}} la visibilidad de {{PLURAL:$5|una revisión |$5 revisiones}} en la página $3: $4",
"logentry-delete-event-legacy": "$1 ha {{GENDER:$2|cambiado}} la visibilidad de eventos del registro en $3",
"logentry-delete-revision-legacy": "$1 ha {{GENDER:$2|cambiado}} la visibilidad de las revisiones en la página $3",
- "logentry-suppress-delete": "$1 {{GENDER:$2|borró}} la página $3",
+ "logentry-suppress-delete": "$1 {{GENDER:$2|suprimió}} la página $3",
"logentry-suppress-event": "$1 {{GENDER:$2|modificó}} secretamente la visibilidad de {{PLURAL:$5|un evento|$5 eventos}} del registro en $3: $4",
"logentry-suppress-revision": "$1 {{GENDER:$2|modificó}} secretamente la visibilidad de {{PLURAL:$5|una edición|$5 ediciones}} en la página $3: $4",
"logentry-suppress-event-legacy": "$1 {{GENDER:$2|modificó}} secretamente la visibilidad de los eventos del registro en $3",
"createacct-another-realname-tip": "Benetako izena hautazkoa da.\nEmatea erabakitzen baduzu hori erabiliko da lanaren atribuzioa egiterako garaian.",
"pt-login": "Saioa hasi",
"pt-login-button": "Saioa hasi",
+ "pt-login-continue-button": "Konexioa jarraitu",
"pt-createaccount": "Sortu kontua",
"pt-userlogout": "Saioa itxi",
"php-mail-error-unknown": "PHPren mail() funtzioan arazo ezezagun bat egon da.",
"resetpass_submit": "Pasahitza definitu eta saioa hasi",
"changepassword-success": "Zure pasahitza aldatu da!",
"changepassword-throttled": "Saioa hasteko saiakera gehiegi egin berri dituzu.\nBerriro saiatu aurretik $1 itxoin, mesedez.",
+ "botpasswords": "Bot pasahitzak",
+ "botpasswords-disabled": "Bot pasahitzak desgaituak daude.",
"botpasswords-label-appid": "Bot izena:",
"botpasswords-label-create": "Sortu",
"botpasswords-label-update": "Eguneratu",
"userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" lankidea ez dago erregistatuta. Mesedez, konprobatu orri hau editatu/sortu nahi duzun.",
"userpage-userdoesnotexist-view": "\"$1\" erabiltzaile-kontua ez dago erregistraturik.",
"blocked-notice-logextract": "Erabiltzaile hau blokeatuta dago une honetan.\nAzken blokeoaren erregistroa ageri da behean, erreferentzia gisa:",
- "clearyourcache": "'''Oharra:''' Gorde ondoren, zure nabigatzailearen katxea ekidin beharko duzu aldaketak ikusteko.\n* '''Firefox / Safari:''' ''Shift'' tekla sakatu birkargatzeko momentuan, edo ''Ctrl-Shift-R'' edo ''Crtl-F5'' sakatu (''⌘-R''' Mac batean)\n* '''Google Chrome:''' ''Ctrl-Shift-R'' sakatu (''⌘-Shift-R'' Mac batean)\n* '''Internet Explorer:''' ''Ctrl'' tekla sakatu birkargatzeko momentuan, edo ''Ctrl-F5'' sakatu\n* '''Opera''' erabiltzaileek ''Tresnak → Hobespenak'' atalera joan eta katxea garbitzeko aukera hautatu",
+ "clearyourcache": "<strong>Oharra:</strong> Gorde ondoren, zure nabigatzailearen katxea ekidin beharko duzu aldaketak ikusteko.\n* <strong>Firefox / Safari:</strong> <em>Shift</em> tekla sakatu birkargatzeko momentuan, edo <em>Ctrl-Shift-R</em> edo <em>Crtl-F5</em> sakatu (<em>⌘-R</em> Mac batean)\n* <strong>Google Chrome:</strong> <em>Ctrl-Shift-R </em> sakatu (<em>⌘-Shift-R</em> Mac batean)\n* <strong>Internet Explorer:</strong> <em>Ctrl</em> tekla sakatu birkargatzeko momentuan, edo <em>Ctrl-F5</em> sakatu\n* <strong>Opera</strong> erabiltzaileek <em>Tresnak → Hobespenak</em> atalera joan eta katxea garbitzeko aukera hautatu",
"usercssyoucanpreview": "'''Laguntza:''' Zure CSS berria gorde aurretik probatzeko \"{{int:showpreview}}\" botoia erabili.",
"userjsyoucanpreview": "'''Laguntza:''' Zure JS berria gorde aurretik probatzeko \"{{int:showpreview}}\" botoia erabili.",
"usercsspreview": "'''Ez ahaztu zure CSS kodea aurreikusten zabiltzala.'''\n'''Oraindik gorde gabe dago!'''",
"previewnote": "'''Gogoratu hau aurrikuspen bat dela.'''\nZure aldaketak ez dira oraindik gorde!",
"continue-editing": "Edizio-eremura joan",
"previewconflict": "Aurreikuspenak aldaketen koadroan idatzitako testua erakusten du, gorde ondoren agertuko den bezala.",
- "session_fail_preview": "'''Sentitzen dugu! Ezin izan da zure aldaketa prozesatu, saioko datu batzuen galera dela-eta. Mesedez, saiatu berriz. Arazoak jarraitzen badu, saiatu saioa amaitu eta berriz hasten.'''",
+ "session_fail_preview": "'''Sentitzen dugu! Ezin izan da zure aldaketa prozesatu, saioko datu batzuen galera dela-eta. Mesedez, saiatu berriz. Arazoak jarraitzen badu, saiatu [[Special:UserLogout|saioa amaitu]] eta berriz hasten.'''",
"session_fail_preview_html": "'''Sentitzen dugu! Ezin izan dugu zure aldaketa burutu, saio datu galera bat medio.'''\n\n''Wiki honek HTML kodea onartzen duenez, aurreikuspena ezgaituta dago JavaScript erasoak saihestu asmoz.''\n\n'''Aldaketa saiakera hau zuzena baldin bada, saiatu berriro mesedez. Arazoak jarraitzen badu, saiatu saioa itxi eta berriz hasten.'''",
"token_suffix_mismatch": "'''Zure aldaketa ezeztatua izan da zure bezeroak puntuazio-karaktereak itxuragabetu dituelako.\nAldaketa ezeztatua izan da testuaren galtzea galarazteko.\nHau batzuetan gertatzen da buggyan oinarritutako web proxy zerbitzua erabiltzean.'''",
"edit_form_incomplete": "'''Aldaketa formularioaren atal batzuk ez dira iritsi zerbitzarira; bi aldiz ziurtatu zure aldaketak osorik daudela eta berriro saiatu.'''",
"undeletedrevisions": "{{PLURAL:$1|Berrikuspen 1 leheneratu da|$1 berrikuspen leheneratu dira}}",
"undeletedrevisions-files": "{{PLURAL:$1|berrikuspen|berrikuspen}} eta {{PLURAL:$2|fitxategi|fitxategi}} leheneratu dira",
"undeletedfiles": "{{PLURAL:$1|fitxategi|fitxategi}} leheneratu dira",
- "cannotundelete": "Ezabatutako birgaitzean akatsa: $1",
+ "cannotundelete": "Ezabatutako birgaitze betean edo hainbatetan akatsa: $1",
"undeletedpage": "'''«$1» leheneratu da'''\n\nAzken ezabatze eta leheneratzeak ikusteko, jo ezazu [[Special:Log/delete|ezabaketa erregistrora]].",
"undelete-header": "Berriki ezabatutako orriak ikusteko, jo ezazu [[Special:Log/delete|ezabaketa erregistrora]].",
"undelete-search-title": "Ezabatutako orrialdeak bilatu",
"sp-contributions-newbies-sub": "Hasiberrientzako",
"sp-contributions-newbies-title": "Lankideen ekarpenak lankide berrietn",
"sp-contributions-blocklog": "Blokeaketa erregistroa",
- "sp-contributions-suppresslog": "lankide-ekarpen ezabatuak",
+ "sp-contributions-suppresslog": "{{GENDER:$1|(r)en}} lankide-ekarpen ezabatuak",
"sp-contributions-deleted": "lankide-ekarpen ezabatuak",
"sp-contributions-uploads": "igoerak",
"sp-contributions-logs": "erregistroak",
"zip-file-open-error": "Une erreur s'est produite lors de l'ouverture du fichier ZIP pour contrôle.",
"zip-wrong-format": "Le fichier spécifié n'est pas une archive ZIP.",
"zip-bad": "Le fichier est une archive ZIP corrompue ou illisible.\nIl ne peut pas être correctement vérifié pour la sécurité.",
- "zip-unsupported": "Le fichier est une archive ZIP qui utilise des caractéristiques non supportées par MediaWiki. \nSa sécurité ne peut pas être correctement vérifiée.",
+ "zip-unsupported": "Le fichier est une archive ZIP qui utilise des caractéristiques non prises en charge par MediaWiki.\nSa sécurité ne peut pas être correctement vérifiée.",
"uploadstash": "Cache d’import",
"uploadstash-summary": "Cette page donne accès aux fichiers qui sont importés (ou en cours d’importation), mais ne sont pas encore publiés dans le wiki. Ces fichiers ne sont pas encore visibles, sauf pour l’utilisateur qui les a importés.",
"uploadstash-clear": "Effacer les fichiers en cache d'import",
"javascripttest-pagetext-unknownaction": "Action « $1 » inconnue.",
"javascripttest-qunit-intro": "Voir [$1 la documentation de test] sur mediawiki.org.",
"tooltip-pt-userpage": "{{GENDER:|Votre}} page utilisateur",
- "tooltip-pt-anonuserpage": "La page utilisateur de l'IP avec laquelle vous contribuez",
+ "tooltip-pt-anonuserpage": "La page utilisateur avec l'adresse IP de laquelle vous contribuez",
"tooltip-pt-mytalk": "{{GENDER:|Votre}} page de discussion",
"tooltip-pt-anontalk": "La page de discussion pour les contributions depuis cette adresse IP",
"tooltip-pt-preferences": "{{GENDER:|Vos}} préférences",
- "tooltip-pt-watchlist": "La liste des pages dont vous suivez les modifications",
+ "tooltip-pt-watchlist": "Une liste des pages dont vous suivez les modifications",
"tooltip-pt-mycontris": "La liste de {{GENDER:|vos}} contributions",
"tooltip-pt-anoncontribs": "Une liste des modifications effectuées depuis cette adresse IP",
"tooltip-pt-login": "Il est recommandé de vous identifier ; ce n'est cependant pas obligatoire.",
"tooltip-n-recentchanges": "Liste des modifications récentes sur le wiki",
"tooltip-n-randompage": "Afficher une page au hasard",
"tooltip-n-help": "Aide",
- "tooltip-t-whatlinkshere": "Liste des pages liées à celle-ci",
- "tooltip-t-recentchangeslinked": "Liste des modifications récentes des pages liées à celle-ci",
+ "tooltip-t-whatlinkshere": "Liste des pages liées qui pointent sur celle-ci",
+ "tooltip-t-recentchangeslinked": "Liste des modifications récentes des pages appelées par celle-ci",
"tooltip-feed-rss": "Flux RSS pour cette page",
"tooltip-feed-atom": "Flux Atom pour cette page",
"tooltip-t-contributions": "Voir la liste des contributions de {{GENDER:$1|cet utilisateur|cette utilisatrice}}",
"tooltip-ca-nstab-template": "Voir le modèle",
"tooltip-ca-nstab-help": "Voir la page d'aide",
"tooltip-ca-nstab-category": "Voir la page de la catégorie",
- "tooltip-minoredit": "Marquer mes modifications comme mineures",
+ "tooltip-minoredit": "Marquer ceci comme modification mineure",
"tooltip-save": "Enregistrer vos modifications",
"tooltip-publish": "Publier vos modifications",
"tooltip-preview": "Merci de prévisualiser vos modifications avant de les publier",
- "tooltip-diff": "Affiche les modifications que vous avez apportées au texte",
- "tooltip-compareselectedversions": "Afficher les différences entre deux versions de cette page",
+ "tooltip-diff": "Afficher les modifications que vous avez apportées au texte",
+ "tooltip-compareselectedversions": "Afficher les différences entre les deux versions selectionnées de cette page",
"tooltip-watch": "Ajouter cette page à votre liste de suivi",
"tooltip-watchlistedit-normal-submit": "Enlever les titres",
"tooltip-watchlistedit-raw-submit": "Mise à jour de la liste de suivi",
"tooltip-recreate": "Recréer la page même si celle-ci a été effacée",
"tooltip-upload": "Démarrer l'import",
- "tooltip-rollback": "« Révoquer » annule en un clic la ou les modification(s) de cette page par son dernier contributeur.",
+ "tooltip-rollback": "« Révoquer » annule en un clic la ou les modification(s) de cette page réalisées par son dernier contributeur",
"tooltip-undo": "« Annuler » rétablit la modification précédente et ouvre la fenêtre de modification en mode prévisualisation. Il est possible d’ajouter une raison dans le résumé.",
"tooltip-preferences-save": "Sauvegarder les préférences",
"tooltip-summary": "Entrez un bref résumé",
"htmlform-title-not-exists": "$1 n’existe pas",
"htmlform-user-not-exists": "<strong>$1</strong> n’existe pas.",
"htmlform-user-not-valid": "<strong>$1</strong> n’est pas un nom d’utilisateur valide.",
- "sqlite-has-fts": "$1 avec recherche en texte intégral supportée",
- "sqlite-no-fts": "$1 sans recherche en texte intégral supportée",
+ "sqlite-has-fts": "$1 avec recherche en texte intégral prise en charge",
+ "sqlite-no-fts": "$1 sans recherche en texte intégral prise en charge",
"logentry-delete-delete": "$1 {{GENDER:$2|a supprimé}} la page $3",
"logentry-delete-restore": "$1 {{GENDER:$2|a restauré}} la page $3",
"logentry-delete-event": "$1 {{GENDER:$2|a modifié}} la visibilité {{PLURAL:$5|d'un événement du journal|de $5 événements du journal}} sur $3: $4",
"filerevert-submit": "Reverter",
"filerevert-success": "Reverteuse \"'''[[Media:$1|$1]]'''\" á [$4 versión do $2 ás $3].",
"filerevert-badversion": "Non existe unha versión local anterior deste ficheiro coa data e hora indicadas.",
+ "filerevert-identical": "A versión actual do ficheiro é igual á seleccionada.",
"filedelete": "Borrar \"$1\"",
"filedelete-legend": "Eliminar un ficheiro",
"filedelete-intro": "Está a piques de eliminar o ficheiro \"'''[[Media:$1|$1]]'''\" xunto con todo o seu historial.",
"filerevert-submit": "שחזור",
"filerevert-success": "<strong>[[Media:$1|$1]]</strong> שוחזר ל[$4 גרסה מ־$3, $2].",
"filerevert-badversion": "אין גרסה מקומית קודמת של הקובץ שהועלתה בתאריך המבוקש.",
+ "filerevert-identical": "הגרסה הנוכחית של הקובץ כבר זהה לגרסה שנבחרה.",
"filedelete": "מחיקת $1",
"filedelete-legend": "מחיקת קובץ",
"filedelete-intro": "אתם עומדים למחוק את הקובץ <strong>[[Media:$1|$1]]</strong> יחד עם כל היסטוריית הגרסאות שלו.",
"filerevert-submit": "Ripristina",
"filerevert-success": "'''Il file [[Media:$1|$1]]''' è stato ripristinato alla [$4 versione del $2, $3].",
"filerevert-badversion": "Non esistono versioni locali precedenti del file con il timestamp richiesto.",
+ "filerevert-identical": "La versione attuale del file è già identica a quella selezionata.",
"filedelete": "Cancella $1",
"filedelete-legend": "Cancella il file",
"filedelete-intro": "Stai per cancellare il file '''[[Media:$1|$1]]''' con tutta la sua cronologia.",
"viewyourtext": "Sampéyan bisa ndeleng lan nyalin sumbering <strong>besutaning sampéyan</strong> ing kaca iki.",
"protectedinterface": "Kaca iki isiné tèks antarmuka sing dienggo software lan wis dikunci kanggo menghindari kasalahan.",
"editinginterface": "'''Pènget:''' Panjenengan nyunting kaca sing dianggo nyedyakaké tèks antarmuka kanggo piranti alus.\nPangowahan kaca iki bakal awèh pangaruh marang tampilan antarmuka panganggo kanggoné panganggo liya.\nKanggo terjemahan, mangga nganggo [https://translatewiki.net/wiki/Main_Page?setlang=en translatewiki.net], proyèk lokalisasi MediaWiki.",
- "translateinterface": "Kanggo nambah utawa ngowah pertalan kanggo kabèh wiki, mangga anggoa [https://translatewiki.net/ translatewiki.net] minangka proyèk palokaling MediaWiki.",
+ "translateinterface": "Saperlu nambah utawa ngowah pertalan tumrap kabèh wiki, mangga anggoa [https://translatewiki.net/ translatewiki.net] minangka proyèk panglokaling MediaWiki.",
"cascadeprotected": "Kaca iki wis direksa saka panyuntingan amerga disertakaké ing {{PLURAL:$1|kaca|kaca-kaca}} ngisor iki sing wis direksa mawa opsi \"runtun\" diaktifaké:\n$2",
"namespaceprotected": "Panjenengan ora kagungan idin kanggo nyunting kaca ing bilik nama '''$1'''.",
"customcssprotected": "Sampéyan ora dililakaké nyunting kaca CSS iki amarga kaisi pangaturan pribadi saka panganggo liya.",
"cannotchangeemail": "Alamat layang èlèktronik akun ora bisa diganti nèng wiki iki.",
"emaildisabled": "Situs iki ora bisa ngirim layang èlèktronik.",
"accountcreated": "Akun wis kagawé",
- "accountcreatedtext": "Akun panganggo kanggo [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|wicara]]) wis digawé.",
+ "accountcreatedtext": "Akun panganggo [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|rembug]]) wis digawé.",
"createaccount-title": "Gawé rékening kanggo {{SITENAME}}",
"createaccount-text": "Ana wong sing nggawé sawijining akun utawa rékening kanggo alamat e-mail panjenengan ing {{SITENAME}} ($4) mawa jeneng \"$2\" lan tembung sandi \"$3\". Panjenengan disaranaké kanggo mlebu log lan ngganti tembung sandi panjenengan saiki.\n\nPanjenengan bisa nglirwakaké pesen iki yèn akun utawa rékening iki digawé déné sawijining kaluputan.",
"login-throttled": "Panjenengan wis kakèhan njajal mlebu log.\nTulung nunggu dhisik $1 sadurungé njajal manèh.",
"page_last": "pungkasan",
"histlegend": "Kanggo mbandhingaké: tandhani kothak radhio révisi-révisi sing arep dibandhingaké lan pencèt ''Enter'' utawa tombol sing ana ing ngisor.<br />\nLegéndha: <strong>({{int:cur}})</strong> = béda karo révisi pungkasan, <strong>({{int:last}})</strong> = béda karo révisi sadurungé, <strong>{{int:minoreditletter}}</strong> = besutan cilik.",
"history-fieldset-title": "Luru sujarah",
- "history-show-deleted": "Namung sing dibusak",
- "histfirst": "suwé dhéwé",
+ "history-show-deleted": "Mligi sing dibusak",
+ "histfirst": "lawas dhéwé",
"histlast": "anyar dhéwé",
"historysize": "($1 {{PLURAL:$1|bét|bét}})",
"historyempty": "(suwung)",
"searchmenu-exists": "'''Ana kaca kanthi jeneng \"[[$1]]\" ing wiki iki'''",
"searchmenu-new": "<strong>Gawéa kaca \"[[:$1]]\" nyang wiki iki!</strong> {{PLURAL:$2|0=|Uga delenga kaca sing katemu sarana panggolèking sampéyan.|Uga delenga kasiling panggolèk.}}",
"searchprofile-articles": "Kaca isi",
- "searchprofile-images": "Sarwamadya",
+ "searchprofile-images": "Multimédhia",
"searchprofile-everything": "Samubarang",
"searchprofile-advanced": "Lungidan",
"searchprofile-articles-tooltip": "Golèkan ing $1",
"yourvariant": "Werna basa isi:",
"prefs-help-variant": "Varian utawa ortograpi sing Sampéyan pilih kanggo nampilaké kaca kontèn saka wiki iki.",
"yournick": "Asma sesinglon/samaran (kagem tapak asta):",
- "prefs-help-signature": "Komentar ing kaca wicara kudu ditapak astani nganggo \"<nowiki>~~~~</nowiki>\" sing bakal dikonvèrsi dadi tapak asta panjenengan lan tanggal wektu.",
+ "prefs-help-signature": "Tanggapan ing kaca parembugan kudu ditandhatangani mawa \"<nowiki>~~~~</nowiki>\", sing bakal salin dadi tandha tangan lan cap wektumu.",
"badsig": "Tapak astanipun klèntu; cèk rambu HTML.",
"badsiglength": "Tapak asta panjenengan kedawan.\nAja luwih saka {{PLURAL:$1|karakter|karakter}}.",
"yourgender": "Kepiyé sampéyan medhar priangganing sampéyan?",
"grant-delete": "Busak kaca, owahan, lan isian cathetan",
"newuserlogpage": "Log naraguna anyar",
"newuserlogpagetext": "Ing ngisor iki kapacak log pandaftaran panganggo anyar.",
- "rightslog": "Log pangowahan hak aksès",
+ "rightslog": "Log hak panganggo",
"rightslogtext": "Ing ngisor iki kapacak log pangowahan marang hak-hak panganggo.",
"action-read": "maca kaca iki",
"action-edit": "besut kaca iki",
"action-createpage": "nggawé kaca-kaca",
- "action-createtalk": "gawé kaca wicara anyar",
+ "action-createtalk": "gawé kaca parembugan iki",
"action-createaccount": "gawé akun panganggo iki",
"action-minoredit": "tandhani iki minangka besutan cilik",
"action-move": "alihna kaca iki",
"statistics-header-hooks": "Statistik liya",
"statistics-articles": "Kaca-kaca isi",
"statistics-pages": "Gunggung kaca",
- "statistics-pages-desc": "Kabèh kaca ing wiki iki, klebu kaca wicara, pangalihan, lan liya-liyané.",
+ "statistics-pages-desc": "Kabèh kaca ing wiki iki, kalebu kaca parembugan, alihan, lsp.",
"statistics-files": "Berkas sing diunggahaké",
"statistics-edits": "Gunggung suntingan wiwit {{SITENAME}} diwiwiti",
"statistics-edits-average": "Rata-rata suntingan saben kaca",
"usercreated": "{{GENDER:$3|Digawé}} $1 wanci $2",
"newpages": "Kaca anyar",
"newpages-username": "Asma panganggo:",
- "ancientpages": "Kaca-kaca langkung sepuh",
+ "ancientpages": "Kaca paling lawas",
"move": "Pindhahen",
"movethispage": "Lih kaca iki",
"unusedimagestext": "Berkas-berkas sing kapacak iki ana nanging ora dienggo ing kaca apa waé.\nTulung digatèkaké yèn situs wèb liyané mbok-menawa bisa nyambung ing sawijining berkas sacara langsung mawa URL langsung, lan berkas-berkas kaya mengkéné iku mbok-menawa ana ing daftar iki senadyan ora dienggo aktif manèh.",
"categories": "Kategori",
"categoriespagetext": "{{PLURAL:$1|kategori ing ngisor iki ngandhut|kategori ing ngisor iki ngandhut}} kaca utawa media.\n[[Special:UnusedCategories|Kategori sing ora dianggo]] ora ditampilaké ing kéné.\nDeleng uga [[Special:WantedCategories|kategori sing diperlokaké]].",
"categoriesfrom": "Tampilaké kategori-kategori diwiwiti saka:",
- "deletedcontributions": "Sumbanganing panganggo sing dibusak",
+ "deletedcontributions": "Sumbangan panganggo sing dibusak",
"deletedcontributions-title": "Sumbanganing panganggo sing dibusak",
"sp-deletedcontributions-contribs": "sumbangan",
"linksearch": "Golèkan pranala njaba",
"rollbacklinkcount-morethan": "balèkaké luwih saka $1 {{PLURAL:$1|suntingan|suntingan}}",
"rollbackfailed": "Pambalèkan gagal dilakoni",
"cantrollback": "Ora bisa mbalèkaké suntingan; panganggo pungkasan iku siji-sijiné penulis artikel iki.",
- "alreadyrolled": "Ora bisa mbalèkaké suntingan pungkasan [[:$1]] déning [[User:$2|$2]] ([[User talk:$2|Wicara]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); wong liya wis nyunting utawa mbalèkaké kaca artikel iku.\n\nSuntingan pungkasan dilakoni déning [[User:$3|$3]] ([[User talk:$3|Wicara]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+ "alreadyrolled": "Ora bisa mulihaké besutan pungkasan [[:$1]] déning [[User:$2|$2]] ([[User talk:$2|rembug]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); ana wong liya sing wis mbesut utawa mulihaké kaca iki.\n\nBesutan pungkasan kaca iku garapané [[User:$3|$3]] ([[User talk:$3|rembug]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "Ringkesan suntingan yaiku: <em>$1</em>.",
"revertpage": "Besutan sing dibalèkaké [[Special:Contributions/$2|$2]] ([[User talk:$2|rembugan]]) bab owahan pungkasan déning [[User:$1|$1]]",
"revertpage-nouser": "Suntingan déning panganggo sing didhelikake, dibalèkaké nèng benahan pungkasan déning [[User:$1|$1]]",
"tooltip-namespace_association": "Centhang kothak iki kanggo nglebokaké uga bilik jeneng gumenan utawa subyèk sing kakait karo bilik jeneng kapilih",
"blanknamespace": "(Pokok)",
"contributions": "Sumbangan {{GENDER:$1|panganggo}}",
- "contributions-title": "Sumbanganing panganggo $1",
+ "contributions-title": "Sumbangan panganggo $1",
"mycontris": "Sumbangan",
"anoncontribs": "Sumbangan",
"contribsub2": "Kanggo {{GENDER:$3|$1}} ($2)",
"sp-contributions-deleted": "sumbanganing panganggo sing dibusak",
"sp-contributions-uploads": "unggahan",
"sp-contributions-logs": "log",
- "sp-contributions-talk": "wicara",
+ "sp-contributions-talk": "rembug",
"sp-contributions-userrights": "pengaturan hak panganggo",
"sp-contributions-blocked-notice": "Panganggo iki lagi diblokir.\nÈntri log blokiran pungkasan sumadhiya nèng ngisor kanggo rujukan:",
"sp-contributions-blocked-notice-anon": "Alamat IP iki lagi diblokir.\nÈntri log blokiran pungkasan sumadhiya nèng ngisor kanggo rujukan:",
"sp-contributions-search": "Golèk sumbangan",
"sp-contributions-username": "Alamat IP utawa jeneng panganggo:",
- "sp-contributions-toponly": "Tuduhaké was suntingan saka benahan pungkasan",
+ "sp-contributions-toponly": "Tuduhaké besutan mligi rèvisi anyar",
+ "sp-contributions-newonly": "Tuduhaké besutan mligi kaca gawéan",
"sp-contributions-submit": "Golèk",
"whatlinkshere": "Sing nggayut mréné",
"whatlinkshere-title": "Kaca mawa pranala nggayut \"$1\"",
"right-managechangetags": "[[Special:Tags|ტეგების]] შექმნა და (დე)აქტივაცია",
"right-applychangetags": "[[Special:Tags|tags]] მიღება თქვენ ცვლილებებთან ერთად",
"right-changetags": "თვითნებური [[Special:Tags|tags]] დამატება ან წაშლა ცალკეულ ცვლილებებსა და ჟურნალის ჩანაწერებში",
+ "right-deletechangetags": "მონაცემთა ბაზიდან [[Special:Tags|ტეგების]] წაშლა",
"grant-generic": "\"$1\" უფლებები",
"grant-group-page-interaction": "კავშირი გვერდებთან",
"grant-group-file-interaction": "კავშირი მედია-ფაილებთან",
"action-managechangetags": "ტეგების შექმნა და (დე)აქტივაცია",
"action-applychangetags": "ტეგების მიღება თქვენ ცვლილებებთან ერთად",
"action-changetags": "თავისუფალი ტეგების დამატება და წაშლა ცალკეულ ცვლილებებსა და ჟურნალების ჩანაწერებში",
+ "action-deletechangetags": "მონაცემთა ბაზიდან ტეგების წაშლა",
+ "action-purge": "ამ გვერდის წაშლა",
"nchanges": "$1 ცვლილება",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ბოლო ვიზიტის შემდეგ}}",
"enhancedrc-history": "ისტორია",
"upload-http-error": "მოხდა HTTP შეცდომა: $1",
"upload-copy-upload-invalid-domain": "ამ დომენში ატვირთვების კოპირება არ არის ხელმისაწვდომი.",
"upload-foreign-cant-upload": "ეს ვიკი არ არის დაკონფიგურირებული იმისათვის, რომ ატვირთოს ფაილების უცხო ფაილთა საწყობში.",
+ "upload-dialog-disabled": "ფაილის ატვირთვა ამ დიალოგური ფანჯრით გათიშულია ამ ვიკიზე.",
"upload-dialog-title": "ფაილის ატვირთვა",
"upload-dialog-button-cancel": "გაუქმება",
"upload-dialog-button-done": "შესრულდა",
"uploadstash-badtoken": "მითითებული მოქმედება ვერ შესრულდა. შესაძლოა, რედაქტირების უფლებამოსილების მოქმედების ვადა ამოიწურა. გთხოვთ, სცადეთ თავიდან.",
"uploadstash-errclear": "ფაილების გასუფთავება ვერ მოხერხდა.",
"uploadstash-refresh": "ფაილების სიის განახლება",
+ "uploadstash-thumbnail": "მინიატურის ნახვა",
"invalid-chunk-offset": "არასწორი საწყისი წერტილი",
"img-auth-accessdenied": "მოქმედება აკრძალულია",
"img-auth-nopathinfo": "დაკარგულია PATH_INFO.\nთქვენი სერვერი არ არის მომართული ამ ინფორმაციის გადასაცემად.\nშესაძლოა, ის მუშაობს CGI-ის ბაზაზე და არ გააჩნია img_auth მხარდაჭერა.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization იხილეთ სურათის ავტორიზაცია.]",
"filerevert-submit": "გაუქმება",
"filerevert-success": "'''[[Media:$1|$1]]''' დაუბრუნდა ვერსიას [$4 $3, $2]-დან.",
"filerevert-badversion": "არ არსებობს ფაილის წინა ლოკალური ვერსია მოთხოვნილი თარიღითა და დროით",
+ "filerevert-identical": "ფაილის ამჟამინდელი ვერსია უკვე არის შერჩეულის იდენტური.",
"filedelete": "$1 წაშლა",
"filedelete-legend": "ფაილის წაშლა",
"filedelete-intro": "თქვენ შლით <strong>[[Media:$1|$1]]-ს</strong> მისი ისტორიით.",
"trackingcategories-msg": "კატეგორიის მიდევნება",
"trackingcategories-name": "შეტყობინების სახელი",
"trackingcategories-desc": "კატეგორიაში ჩართვის კრიტერიუმები",
+ "restricted-displaytitle-ignored": "გვერდები დაიგნორებული სათაურებით",
"noindex-category-desc": "გვერდი არ არის ინდექსირებული საძიებო სამუშაოებით, რადგან მასზე არის „ჯადოსნური სიტყვა“ <code><nowiki>__NOINDEX__</nowiki></code> და ის იმყოფება სახელთა სივრცეში, სადაც დასაშვებია ეს დროშა.",
"index-category-desc": "გვერდზე არის „ჯადოსნური სიტყვა“ <code><nowiki>__INDEX__</nowiki></code> (და გვერდი იმყოფება სახელთა სივრცეში, სადაც დაშვებულია ეს დროშა). ამიტომ იგი ინდექსირებულია საძიებო სამუშაოებით იმ შემთხვევებში, როცა ეს ჩვეულებრივ არ ხდება.",
"post-expand-template-inclusion-category-desc": "გვერდის ზომა უფრო გაიზრდება <code>$wgMaxArticleSize</code> ყველა თარგის ჩვენების შემდეგ, ამიტომ ზოგიერთი მათგანი არ იყო ნაჩვენები მთლიანად.",
"watchnologin": "რეგისტრაცია ვერ შესრულდა",
"addwatch": "კონტროლის სიაში დამატება",
"addedwatchtext": "„[[:$1]]“ და მისი განხილვის გვერდი დაემატა თქვენს [[Special:Watchlist|კონტროლის სიას]].",
+ "addedwatchtext-talk": "„[[:$1]]“ და მასთან დაკავშირებული გვერდი დაემატა თქვენს [[Special:Watchlist|კონტროლის სიას]].",
"addedwatchtext-short": "გვერდი „$1“ დაემატა თქვენი კონტროლის სიას.",
"removewatch": "კონტროლის სიიდან წაშლა",
"removedwatchtext": "„[[:$1]]“ და მისი განხილვის გვერდი ამოღებულია თქვენი [[Special:Watchlist|კონტროლის სიიდან]].",
+ "removedwatchtext-talk": "„[[:$1]]“ და მასთან დაკავშირებული გვერდი ამოღებულია თქვენი [[Special:Watchlist|კონტროლის სიიდან]].",
"removedwatchtext-short": "გვერდი „$1“ წაიშალა თქვენი კონტროლის სიიდან.",
"watch": "კონტროლი",
"watchthispage": "ამ გვერდის კონტროლი",
"rollbacklinkcount": "$1 {{PLURAL:$1|ცვლილების|ცვლილების}} გაუქმება",
"rollbacklinkcount-morethan": "$1-ზე მეტი {{PLURAL:$1|ცვლილების|ცვლილების}} გაუქმება",
"rollbackfailed": "შეცდომა გაუქმებისას",
+ "rollback-missingparam": "აკლია საჭირო პარამეტრები.",
"cantrollback": "შეუძლებელია უწინდელი რედაქციის აღდგენა; ის, ვინც უკანასკნელი ცვლილებები შეიტანა, ამ სტატიის ერთადერთი ავტორია.",
"alreadyrolled": "შეუძლებელია ბოლო ცვლილების გაუქმება [[:$1]], გაკეებული [[User:$2|$2]] ([[User talk:$2|განხილვა]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\nვიღაცა სხვამ უკვე შეასწორა ან გაააუქმა ეს გვერდი.\n\nბოლო ცვლილებები შეიტანა [[User:$3|$3]] ([[User talk:$3|განხილვა]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
"editcomment": "რედაქტირება განმარტებული იყო როგორც: <em>$1</em>.",
"changecontentmodel-success-text": "[[:$1]]-ის კონტენტის ტიპი შეიცვალა.",
"changecontentmodel-cannot-convert": "[[:$1]]-ის შინაარსის $2-ის ტიპზე კონვერტაცია შეუძლებელია.",
"changecontentmodel-nodirectediting": "$1 შინაარსის მოდელს არ აქვს პირდაპირი რედაქტირების მხარდაჭერა",
+ "changecontentmodel-emptymodels-title": "შინაარსის მოდელები არ არის ხელმისაწვდომი",
+ "changecontentmodel-emptymodels-text": "შინაარსი [[:$1]]-ზე არ კონვერტირდება არცერთ ტიპზე.",
"log-name-contentmodel": "შინაარსის მოდელის შეცვლის ჟურნალი",
"log-description-contentmodel": "გვერდის შინაარსის მოდელთან დაკავშირებული მოვლენები",
"logentry-contentmodel-new": "$1-მ {{GENDER:$2|შექმნა}} გვერდი $3, არა-სტანდარტული მოდელით \"$5\"",
"undeletehistorynoadmin": "ეს სტატია წაშლილია. წაშლის მიზეზი ნაჩვენებია მოკლე ანოტაციაში ქვემოთ, იმ მომხმარებელთა დეტალებთან ერთად ვინც რედაქტირება გაუკეთა ამ გვერდს წაშლის წინ. იმ წაშლილი ტექსტების აქტუალური ვერსიები მიღწევადია მხოლოდ ადმინისტრატორებისათვის.",
"undelete-revision": "$1-ის წაშლილი ვერსია ($5, $4-ის მდგომარეობით), შენახული მომხმარებლის $3 მიერ:",
"undeleterevision-missing": "არასწორი ან არარსებული ვერსია. სავარაუდოდ ქვენ გადახვედით არასწორ ბმულზე, ან იგი წაიშალა არქივიდან.",
+ "undeleterevision-duplicate-revid": "{{PLURAL:$1|ერთი ცვლილება|$1 ცვლილება}} ვერ აღდგა, რადგან {{PLURAL:$1|მისი|მათი}} <code>rev_id</code> უკვე გამოიყენებოდა.",
"undelete-nodiff": "წინა ცვლილება ვერ ვიპოვეთ.",
"undeletebtn": "აღდგენა",
"undeletelink": "ნახვა/აღდგენა",
"invalidateemail": "ელ-ფოსტის დადასტურების გაუქმება",
"notificationemail_subject_changed": "{{SITENAME}} რეგისტრირებული იმეილის მისამართები შეიცვალა",
"notificationemail_subject_removed": "{{SITENAME}} რეგისტრირებული იმეილის მისამართები წაიშალა",
+ "notificationemail_body_changed": "ვიღაცამ, სავარაუდოდ თქვენ, IP მისამართიდან $1,\n{{SITENAME}}ში შეცვალა „$2“ ანგარიშის იმეილის მისამართი „$3“-ზე.\n\nთუ ეს თქვენ არ იყავით, გთხოვთ დაუკავშირდით საიტის ადმინისტრატორს სასწრაფოდ.",
+ "notificationemail_body_removed": "ვიღაცამ, სავარაუდოდ თქვენ, IP მისამართიდან $1,\n{{SITENAME}}ში წაშალა ანგარიშის „$2“ იმეილის მისამართი.\n\nთუ ეს თქვენ არ იყავით, გთხოვთ დაუკავშირდით საიტის ადმინისტრატორს სასწრაფოდ.",
"scarytranscludedisabled": "[«Interwiki transcluding» გათიშულია]",
"scarytranscludefailed": "[$1-თან დაკავშირების შეცდომა]",
"scarytranscludefailed-httpstatus": "[ვერ მოხერხდა თარგის ჩატვირთვა $1-თვის: HTTP $2]",
"confirm-unwatch-button": "დიახ",
"confirm-unwatch-top": "მოვხსნა ეს გვერდი თქვენი კონტროლის სიიდან?",
"confirm-rollback-button": "კარგი",
+ "confirm-rollback-top": "დავაბრუნოთ რედაქტირებები ამ გვერდზე?",
"semicolon-separator": "; ",
"comma-separator": ", ",
"colon-separator": ": ",
"timezone-local": "ლოკალური",
"duplicate-defaultsort": "'''ყურადღება.'''სორტირების გასაღებს «$2»-ს გააჭრის წინა გასაღებს «$1»-ს.",
"duplicate-displaytitle": "<strong>ყურადღება:</strong> დისპლეის სათაური \"$2\" განსაზღვრავს ადრე გაცემულ დისპლეის სათაურს \"$1\".",
+ "restricted-displaytitle": "<strong>Warning:</strong> სათაური „$1“ იგნორირებულ იქნა, რადგან ის არ ემთხვევა გვერდის ნამდვილ სათაურს.",
"invalid-indicator-name": "<strong>შეცდომა:</strong> გვერდის სტატუსის ინდიკატორი <code>name</code> ატრიბუტი არ უნდა იყოს ცარიელი.",
"version": "ვერსია",
"version-extensions": "დაყენებული გაფართოებები",
"tags-delete-not-found": "აღნიშვნა „$1“ არ არსებობს.",
"tags-delete-too-many-uses": "ტეგი \"$1\" მიღებულია $2 ვერსიებთან, რაც იმას ნიშნავს, რომ იგი არ შეიძლება იყოს წაშლილი",
"tags-delete-warnings-after-delete": "ტეგი „$1“ წაიშალა, თუმცა აღმოჩენილია შემდეგი {{PLURAL:$2|შეტყობინება|შეტყობინებები}}:",
+ "tags-delete-no-permission": "თქვენ არ გაქვთ შეცვლილი ტეგების წაშლის უფლება.",
"tags-activate-title": "ტეგის გააქტიურება",
"tags-activate-question": "თქვენ ცდილობთ დასათაურების გააქტიურებას „$1“.",
"tags-activate-reason": "მიზეზი:",
"feedback-useragent": "მომხმარებლის აგენტი:",
"searchsuggest-search": "ძიება",
"searchsuggest-containing": "შეიცავს...",
+ "api-error-autoblocked": "თქვენი IP მისამართი ავტომატურად დაიბლოკა, რადგან ის გამოიყენა დაბლოკილმა მომხმარებელმა.",
"api-error-badaccess-groups": "თქვენ არ გაქვთ ამ ვიკიში ფაილების ატვირთვის უფლება.",
"api-error-badtoken": "შიდა შეცდომა: ცუდი ტოკენი.",
+ "api-error-blocked": "თქვენთვის რედაქტირება დაბლოკილია.",
"api-error-copyuploaddisabled": "ამ სერვერზე URL-მისამართის საშუალებით ატვირთვა გამორთულია.",
"api-error-duplicate": "საიტზე უკვე {{PLURAL:$1|არსებობს სხვა ფაილი|არსებობს სხვა ფაილები}} ანალოგიური შინაარსით.",
"api-error-duplicate-archive": "საიტზე ადრე {{PLURAL:$1|უკვე იყო ფაილი}} ანალოგიური შინაარსით, მაგრამ {{PLURAL:$1|ის წაიშალა|ისინი წაიშალა}}.",
"api-error-unknownerror": "უცნობი შეცდომა: „$1“.",
"api-error-uploaddisabled": "ატვირთვის მექანიზმი ამ ვიკიზე გამორთულია",
"api-error-verification-error": "ეს ფაილი ან რაიმე შეცდომას შეიცავს, ან არ აქვს სახელის გაფართოება.",
+ "api-error-was-deleted": "ფაილი ამ სახელწოდებით ადრე აიტვირთა და შემდეგ წაიშალა.",
"duration-seconds": "$1 {{PLURAL:$1|წამი|წამი}}",
"duration-minutes": "$1 {{PLURAL:$1|წუთი|წუთი}}",
"duration-hours": "$1 {{PLURAL:$1|საათი|საათი}}",
"sessionprovider-nocookies": "შესაძლოა ქუქები გათიშულია. გთხოვთ ჩართეთ და სცადეთ განმეორებით.",
"randomrootpage": "შემთხვევითი ძირეული გვერდი",
"log-action-filter-block": "ბლოკირების ტიპი:",
+ "log-action-filter-contentmodel": "შეინაარსის მოდელის მოდერაციის ტიპი:",
"log-action-filter-delete": "წაშლის ტიპი:",
"log-action-filter-import": "იმპორტის ტიპი:",
"log-action-filter-managetags": "ტეგის ცვლილების ტიპი:",
"log-action-filter-patrol": "შემოწმების ტიპი:",
"log-action-filter-protect": "დაცვის ტიპი:",
"log-action-filter-rights": "უფლების შეცვლის ტიპი:",
+ "log-action-filter-suppress": "დამალვის ტიპი:",
"log-action-filter-upload": "ატვირთვის ტიპი:",
"log-action-filter-all": "ყველა",
"log-action-filter-block-block": "დაბლოკვა",
"log-action-filter-block-reblock": "ბლოკირების შეცვლა",
"log-action-filter-block-unblock": "განბლოკვა",
+ "log-action-filter-contentmodel-change": "შინაარსის მოდელის შეცვლა",
+ "log-action-filter-contentmodel-new": "გვერდის შექმნა არასტანდარტული შინაარსის მოდელით",
+ "log-action-filter-delete-delete": "გვერდის წაშლა",
+ "log-action-filter-delete-restore": "გვერდის აღდგენა",
+ "log-action-filter-delete-event": "ჯურნალის ჩანაწერის წაშლა",
+ "log-action-filter-delete-revision": "ვერსიის წაშლა",
+ "log-action-filter-import-interwiki": "Transwiki-ს იმპორტი",
+ "log-action-filter-import-upload": "XML ატვირთვიდან იმპორტი",
+ "log-action-filter-managetags-create": "ტეგის შექმნა",
+ "log-action-filter-managetags-delete": "ტეგის წაშლა",
+ "log-action-filter-managetags-activate": "ტეგის აქტივაცია",
+ "log-action-filter-managetags-deactivate": "ტეგის დეაქტივაცია",
+ "log-action-filter-move-move": "გადატანა გადამისამართებების გადაწერის გარეშე",
+ "log-action-filter-move-move_redir": "გადატანა გადამისამართებების გადაწერით",
+ "log-action-filter-newusers-create": "შექმნა ანონიმური მომხმარებლის მიერ",
"log-action-filter-newusers-create2": "დარეგისტრირებული მომხმარებლის შექმნა",
"log-action-filter-newusers-autocreate": "ავტომატური შექმნა",
"log-action-filter-newusers-byemail": "პაროლით შექმნა, რომელიც გამოიგზავნა იმეილით",
+ "log-action-filter-patrol-patrol": "ხელით შემოწმება",
"log-action-filter-patrol-autopatrol": "ავტომატური შემოწმება",
"log-action-filter-protect-protect": "დაცვა",
+ "log-action-filter-protect-modify": "დაცვის შეცვლა",
"log-action-filter-protect-unprotect": "დაცვის მოხსნა",
"log-action-filter-protect-move_prot": "დაცვა გადატანისაგან",
+ "log-action-filter-rights-rights": "ხელით შეცვლა",
"log-action-filter-rights-autopromote": "ავტომატური შეცვლა",
+ "log-action-filter-suppress-event": "ჟურნალის დამალვა",
+ "log-action-filter-suppress-revision": "ცვლილების დამალვა",
+ "log-action-filter-suppress-delete": "გვერდის დამალვა",
+ "log-action-filter-suppress-block": "მომხმარებლის დამალვა ბლოკით",
+ "log-action-filter-suppress-reblock": "მომხმარებლის დამალვა ხელახლა ბლოკირებით",
"log-action-filter-upload-upload": "ახალი ატვირთვა",
"log-action-filter-upload-overwrite": "ხელახლა ატვირთვა",
+ "authmanager-authn-not-in-progress": "აუტენტიფიკაცია არ მიმდინარეობს ან სესიის მონაცემი დაიკარგა. გთხოვთ დაიწყეთ თავიდან.",
+ "authmanager-authn-no-primary": "მოწოდებული მონაცემები ვერ იქნა აუტენტიფიცირებული.",
+ "authmanager-authn-no-local-user": "მოწოდებული მონაცემები არ უკავშირდება არცერთ მომხმარებელს ამ ვიკიზე.",
+ "authmanager-create-disabled": "ანგარიშის შექმნა გათიშულია.",
+ "authmanager-create-from-login": "ანგარიშის შესაქმნელად, გთხოვთ შეავსეთ ქვემოთ მოცემული ველები.",
+ "authmanager-create-not-in-progress": "ანგარიშის შექმა არ მიმდინარეობს ან სესიის მონაცემი დაიკარგა. გთხოვთ დაიწყეთ თავიდან.",
+ "authmanager-create-no-primary": "მოწოდებული მონაცემები არ გამოდგა ანგარიშის შესაქმნელად.",
+ "authmanager-link-no-primary": "მოწოდებული მონაცემები არ გამოდგა ანგარიშის დასაკავშირებლად.",
+ "authmanager-link-not-in-progress": "ანგარიშის დაკავშირება არ მიმდინარეობს ან სესიის მონაცემი დაიკარგა. გთხოვთ დაიწყეთ თავიდან.",
"authmanager-authplugin-setpass-failed-title": "პაროლის ცვლილება ვერ განხორციელდა",
+ "authmanager-authplugin-setpass-failed-message": "აუთენთიფიკაციის პლაგინმა უარყო პაროლის ცვლილება.",
+ "authmanager-authplugin-create-fail": "აუთენთიფიკაციის პლაგინმა უარყო ანგარიშის შექმნა.",
+ "authmanager-authplugin-setpass-denied": "აუთენთიფიკაციის პლაგინი არ იძლევა პაროლების გამოცვლის უფლებას.",
+ "authmanager-authplugin-setpass-bad-domain": "არასწორი დომეინი.",
+ "authmanager-autocreate-noperm": "ავტომატური ანგარიშის შექმნა არ არის ნებადართული.",
+ "authmanager-autocreate-exception": "ავტომატური ანგარიშის შექმნა დროებით გათიშულია ადრინდელი ხარვეზების გამო.",
+ "authmanager-userdoesnotexist": "მომხმარებლის ანგარიში „$1“ არ არის რეგისტრირებული",
+ "authmanager-username-help": "მომხმარებლის სახელი აუთენთიფიკაციისთვის.",
+ "authmanager-password-help": "პაროლი აუთენთიფიკაციისთვის.",
+ "authmanager-domain-help": "დომეინი გარე აუთენთიფიკაციისთვის.",
+ "authmanager-retype-help": "დასადასტურებლად კვლავ შეიყვანეთ პაროლი.",
"authmanager-email-label": "ელ. ფოსტა",
"authmanager-email-help": "ელ. ფოსტის მისამართი",
"authmanager-realname-label": "ნამდვილი სახელი",
"authmanager-realname-help": "მომხმარებლის ნამდვილი სახელი",
+ "authmanager-provider-password": "პაროლზე დაფუძნებული აუთენთიფიკაცია",
+ "authmanager-provider-password-domain": "პაროლზე და დომეინზე დაფუძნებული აუთენთიფიკაცია",
+ "authmanager-provider-temporarypassword": "დროებითი პაროლი",
+ "authprovider-confirmlink-request-label": "ანგარიშები, რომლებიც დაკავშირებული უნდა იყოს",
+ "authprovider-confirmlink-success-line": "$1: დაუკავშირდა წარმატებით.",
+ "authprovider-confirmlink-failed": "ანგარიშის დაკავშირება არ შესრულდა სრულად: $1",
+ "authprovider-confirmlink-ok-help": "გააგრძელე დაკავშირების ჩავარდნის შეტყობინებების ჩვენების შემდეგ.",
"authprovider-resetpass-skip-label": "გამოტოვება",
"authprovider-resetpass-skip-help": "გამოტოვეთ პაროლის შეცვლის პროცესი.",
+ "authform-nosession-login": "ავტორიზაციამ წარმატებით ჩაიარა, თუმცა თქვენი ბრაუზერი ვერ ახერხებს მის „დამახსოვრებას“.\n\n$1",
+ "authform-nosession-signup": "ანგარიში შეიქმნა, თუმცა თქვენი ბრაუზერი ვერ ახერხებს მის „დამახსოვრებას“.\n\n$1",
+ "authform-newtoken": "არ არის ტოკენი. $1",
+ "authform-notoken": "არ არის ტოკენი",
+ "authform-wrongtoken": "არასწორი ტოკენი",
"specialpage-securitylevel-not-allowed-title": "არ არის ნებადართული",
- "credentialsform-account": "ანგარიშის სახელი:"
+ "specialpage-securitylevel-not-allowed": "უკაცრავად, თქვე არ შეგიძლიათ ამ გვერდის გამოყენება, რადგან თქვენი იდენთიფიკაცია არ არის დადასტურებული.",
+ "authpage-cannot-login": "შეუძლებელია ავტორიზაციის დაწყება.",
+ "authpage-cannot-login-continue": "შეუძლებელია ავტორიზაციის გაგრძელება. სავარაუდოდ, თქვენი სესიის დრო ამოიწურა.",
+ "authpage-cannot-create": "შეუძლებელია ანგარიშის შექმნის დაწყება.",
+ "authpage-cannot-create-continue": "შეუძლებელია ანგარიშის შექმნის გაგრძელება. სავარაუდოდ, თქვენი სესიის დრო ამოიწურა.",
+ "authpage-cannot-link": "შეუძლებელია ანგარიშის დაკავშირების დაწყება.",
+ "authpage-cannot-link-continue": "შეუძლებელია ანგარიშის დაკავშირების გაგრძელება. სავარაუდოდ, თქვენი სესიის დრო ამოიწურა.",
+ "cannotauth-not-allowed-title": "ნებართვა უარყოფილია",
+ "cannotauth-not-allowed": "თქვენ არ გაქვთ ამ გვერდის გამოყენების უფლება",
+ "changecredentials": "მონაცემების შეცვლა",
+ "changecredentials-submit": "მონაცემების შეცვლა",
+ "changecredentials-invalidsubpage": "$1 არ არის ვალიდური მონაცემის ტიპი.",
+ "changecredentials-success": "თქვენი მონაცემები შეიცვალა.",
+ "removecredentials": "მონაცემების წაშლა",
+ "removecredentials-submit": "მონაცემების წაშლა",
+ "removecredentials-invalidsubpage": "$1 არ არის ვალიდური მონაცემის ტიპი.",
+ "removecredentials-success": "თქვენი მონაცემები წაიშალა.",
+ "credentialsform-provider": "მონაცემის ტიპი:",
+ "credentialsform-account": "ანგარიშის სახელი:",
+ "cannotlink-no-provider-title": "არ არის დაკავშირებული ანგარიშები",
+ "cannotlink-no-provider": "არ არის დაკავშირებული ანგარიშები.",
+ "linkaccounts": "ანგარიშების დაკავშირება",
+ "linkaccounts-success-text": "ანგარიში დაკავშირებულია.",
+ "linkaccounts-submit": "ანგარიშების დაკავშირება",
+ "unlinkaccounts": "ანგარიშებისთვის დაკავშირების მოშორება",
+ "unlinkaccounts-success": "ანგარიშს მოეხსნა დაკავშირება.",
+ "userjsispublic": "შენიშვნა: ჯავასკრიპტის ქვეგვერდები არ უნდა შეიცავდეს პირადულ მონაცემებს, რადგან მას სხვა მომხმარებლებიც ხედავენ.",
+ "usercssispublic": "შენიშვნა: CSS ქვეგვერდები არ უნდა შეიცავდეს პირადულ მონაცემებს, რადგან მას სხვა მომხმარებლებიც ხედავენ."
}
"createacct-reason-ph": "Неге басқа тіркегі жасамақшысыз",
"createacct-submit": "Тіркелгіңізді жасаңыз",
"createacct-another-submit": "Тіркелгі жасау",
+ "createacct-continue-submit": "Тіркелуді жалғастыру",
"createacct-benefit-heading": "{{SITENAME}} сіздермен жасалады.",
"createacct-benefit-body1": "{{PLURAL:$1|өңдеме|өңдеме}}",
"createacct-benefit-body2": "{{PLURAL:$1|бет|бет}}",
"minoredit": "Haec est recensio minor",
"watchthis": "Hanc paginam observare",
"savearticle": "Hanc redactionem servare",
+ "savechanges": "Mutationes divulgare",
"publishpage": "Hanc paginam divulgare",
"publishchanges": "Hanc recensionem divulgare",
"preview": "Praevidere",
"specialpages-group-changes": "Rezent Ännerungen a Lëschten",
"specialpages-group-media": "Medie-Rapporten an eropgeluede Fichieren",
"specialpages-group-users": "Benotzer a Rechter",
- "specialpages-group-highuse": "Dacks benotzte Säiten",
+ "specialpages-group-highuse": "Dacks benotzt Säiten",
"specialpages-group-pages": "Lëschte vu Säiten",
"specialpages-group-pagetools": "Handwierksgeschir fir Säiten",
"specialpages-group-wiki": "Daten an Handwierksgeschir",
"subject-preview": "Anteprimma do soggetto:",
"previewerrortext": "Gh'è stæto un errô mentre se çercava de mostrâ l'anteprimma.",
"blockedtitle": "L'utente o l'é bloccòu",
- "blockedtext": "''''O to nomme utente ò adresso IP o l'è stæto bloccòu.'''\n\nO blòcco o l'è stæto fæto da $1. A raxon dæta a l'è ''$2''.\n\n* Iniçio do blocco: $8\n* Fin do blocco: $6\n* Utente blocou: $7\n\nL'è poscibbile contattâ $1 o un âtro [[{{MediaWiki:Grouppage-sysop}}|amministratô]] pe discûtte inscio blòcco.\nNo ti poeu doeuviâ o comando \"Manda un'e-mail a st'ûtente\" se no ti g'hæ 'n adresso e-mail registròu inte to [[Special:Preferences|preferençe]] e se no t'ê stæto bloccòu ascì.\nO to adresso IP o l'è $3, e o to blòcco ID o l'è #$5.\nPe piaxei, pe domandâ informaçioin, speçifficali tutti doî.",
+ "blockedtext": "''''O to nomme utente ò adresso IP o l'è stæto bloccòu.'''\n\nO blòcco o l'è stæto fæto da $1. A raxon dæta a l'è ''$2''.\n\n* Prinçippio do blocco: $8\n* Fin do blocco: $6\n* Utente blocou: $7\n\nL'è poscibbile contattâ $1 ò un atro [[{{MediaWiki:Grouppage-sysop}}|amministratô]] pe discûtte inscio blòcco.\nNo ti poeu doeuviâ o comando \"Manda un'e-mail a st'utente\" se no ti g'hæ 'n adreçço e-mail registròu inte to [[Special:Preferences|preferençe]] e se no t'ê stæto bloccòu ascì.\nO to adreçço IP o l'è $3, e o to blòcco ID o l'è #$5.\nPe piaxei, pe domandâ de informaçioin, speçifficali tutti doî.",
"autoblockedtext": "O teu addresso IP o l'è stæto bloccòu outomaticamente perché o l'ea za usòu da 'n âtro utente, bloccòu da $1.\nA raxon dæta a l'è stæta:\n\n:''$2''\n\n* Prinsippio do blòcco: $8\n* Fin do blòcco: $6\n\nTi peu contattâ $1 ò un âtro\n[[{{MediaWiki:Grouppage-sysop}}|amministratô]] pe discutte o blòcco.\n\nDanni a mente a che no ti pêu ûsâ o comando \"manda 'na e-mail a sto utente\" se non ti g'hæ 'n addresso de posta elettronega registròu in te têu [[Special:Preferences|preferense]] e se ti no t'ê stæto bloccòu ascì.\n\nO to adresso IP o l'è $3, e o to blòcco ID o l'è #$5. Pe piaxei, pe domandâ informaçioin, speçifficali tutti doî.",
"blockednoreason": "nisciun-a motivaçion dæta",
"whitelistedittext": "Pe modificâ e paggine l'è necessaio $1.",
"defemailsubject": "Messaggio da {{SITENAME}} da l'utente \"$1\"",
"usermaildisabled": "e-mail utente disabilitâ",
"usermaildisabledtext": "No l'è poscibbile inviâ de e-mail a di atri utenti insce questo wiki",
- "noemailtitle": "Nisciun adreççoo e-mail",
+ "noemailtitle": "Nisciun adreçço e-mail",
"noemailtext": "Questo utente o no l'ha indicou un adreçço e-mail vallido.",
"nowikiemailtext": "Questo utente o l'ha scerto de no riçeive messaggi de posta elettronica da-i atri utenti.",
"emailnotarget": "Nomme utente do destinataio inexistente o non vallido.",
"emailto": "A:",
"emailsubject": "Sogetto:",
"emailmessage": "Messaggio:",
- "emailsend": "Spèdi",
- "emailccme": "Mandame unn-a copia do messagio co unn-a lettìa elettronega.",
+ "emailsend": "Spedisci",
+ "emailccme": "Mandime una copia do messaggio a-o mæ adreçço.",
"emailccsubject": "Coppia do messaggio inviou a $1: $2",
"emailsent": "E-mail spedïa",
"emailsenttext": "A teu e-mail a l'è stæta spedïa.",
"export-templates": "Inciodi i template",
"export-pagelinks": "Includdi paggine colegæ scin a 'na profonditæ de:",
"export-manual": "Azonzi paggine manoalmente:",
- "allmessages": "Messaggi do scistemma",
+ "allmessages": "Messaggi do scistema",
"allmessagesname": "Nomme",
"allmessagesdefault": "Testo predefinio",
"allmessagescurrent": "Testo corrente",
"minoredit": "အရေးမကြီးသော ပြင်ဆင်မှု ဖြစ်သည်",
"watchthis": "ဤစာမျက်နှာကို စောင့်ကြည့်ရန်",
"savearticle": "ဤစာမျက်နှာကို သိမ်းရန်",
+ "savechanges": "ပြောင်းလဲမှုများကို သိမ်းရန်",
"publishpage": "စာမျက်နှာကို လွှင့်တင်ရန်",
"publishchanges": "ပြောင်းလဲမှုများကို လွှင့်တင်ရန်",
"preview": "နမူနာ",
"faqpage": "Project:धैरै सोधिएका प्रश्नहरु",
"actions": "कार्यहरु",
"namespaces": "नेमस्पेस",
- "variants": "बहà¥\81रà¥\81पहरà¥\81",
+ "variants": "बहà¥\81रà¥\81पहरà¥\82",
"navigation-heading": "नेविगेशन मेनू",
"errorpagetitle": "त्रुटि",
"returnto": "$1 मा फर्कनुहोस् ।",
"image_tip": "इम्बेडेड(जडान गरिएको) फाइल",
"media_sample": "उदाहरण.ogg",
"media_tip": "फाइल लिङ्क",
- "sig_tip": "तपाà¤\88à¤\81को समयछाप सहितको दस्तखत",
+ "sig_tip": "तपाà¤\88à¤\82को समयछाप सहितको दस्तखत",
"hr_tip": "क्षितिजिय रेखा (कम प्रयोग गर्नुहोस्)",
"summary": "सारांश:",
"subject": "विषय/शीर्षक:",
"showpreview": "पूर्वालोकन देखाउनुहोस्",
"showdiff": "परिवर्तन देखाउनुहोस्",
"blankarticle": "<strong>चेतावनी:</strong> तपाईं एउटा खालि पृष्ठको निर्माण गर्दै हुनुहुन्छ।\nयदि तपाईं \"{{int:savearticle}}\" लाई पुनः थिच्नुहुन्छ भने पृष्ठ बिना कुनै सामग्री नै निर्मित गरिनेछ।",
- "anoneditwarning": "<strong>à¤\9aà¥\87तावनà¥\80:</strong> तपाà¤\88à¤\81लà¥\87 पà¥\8dरवà¥\87श à¤\97रà¥\8dनà¥\81 à¤à¤\8fà¤\95à¥\8b à¤\9bà¥\88न । तपाà¤\88à¤\81à¤\95à¥\8b à¤\86à¤\87पि ठà¥\87à¤\97ाना पà¥\83षà¥\8dठसमà¥\8dपादन à¤\87तिहासमा दरà¥\8dता à¤\97रिनà¥\87 à¤\9b र यà¥\8b सबà¥\88लà¥\87 हà¥\87रà¥\8dन सà¤\95à¥\8dà¤\9bन । यदि तपाà¤\88à¤\82 <strong>[$1 लà¤\97à¤\88न]</strong> वा <strong>[$2 नयाà¤\81 à¤\96ाता बनाà¤\89नà¥\87] à¤\97रà¥\8dनà¥\81à¤à¤¯à¥\8b à¤à¤¨à¥\87 तपाà¤\88à¤\82दà¥\8dवारा à¤\97रिà¤\8fà¤\95à¥\8b समà¥\8dपादन तपाà¤\88à¤\82à¤\95à¥\8b पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dतानाममा à¤\9cà¥\8bडिनà¥\87à¤\9b।",
+ "anoneditwarning": "<strong>à¤\9aà¥\87तावनà¥\80:</strong> तपाà¤\88à¤\82लà¥\87 पà¥\8dरवà¥\87श à¤\97रà¥\8dनà¥\81 à¤à¤\8fà¤\95à¥\8b à¤\9bà¥\88न । तपाà¤\88à¤\82à¤\95à¥\8b à¤\86à¤\87पि ठà¥\87à¤\97ाना पà¥\83षà¥\8dठसमà¥\8dपादन à¤\87तिहासमा दरà¥\8dता à¤\97रिनà¥\87 à¤\9b र यà¥\8b सबà¥\88लà¥\87 हà¥\87रà¥\8dन सà¤\95à¥\8dà¤\9bनà¥\8d । यदि तपाà¤\88à¤\82 <strong>[$1 लà¤\97à¤\88न]</strong> वा <strong>[$2 नयाà¤\81 à¤\96ाता बनाà¤\89नà¥\87] à¤\97रà¥\8dनà¥\81à¤à¤¯à¥\8b à¤à¤¨à¥\87 तपाà¤\88à¤\82दà¥\8dवारा à¤\97रिà¤\8fà¤\95à¥\8b समà¥\8dपादन तपाà¤\88à¤\82à¤\95à¥\8b पà¥\8dरयà¥\8bà¤\97à¤\95रà¥\8dतानाममा à¤\9cà¥\8bडिनà¥\87à¤\9b ।",
"anonpreviewwarning": "''तपाईंले प्रवेश गर्नु भएको छैन। संग्रह (Save) गरेको खण्डमा पृष्ठको इतिहासमा तपाईंको IP ठेगाना अंकित गरिनेछ।''",
"missingsummary": "'''यादगर्नुहोस् :''' तपाईंले सम्पादन सारांश दिनुभएको छैन ।\nयदि तपाईंले \"{{int:savearticle}}\" थिच्नुभयो भने , सारांश बिना नै संग्रहित गरिने छ ।",
"selfredirect": "<strong>चेतावनी:</strong> तपाईं यस पृष्ठलाई आफुमा पुनः निर्देशित गर्दै हुनुहुन्छ।\nहुनसक्छ तपाईं अनुप्रेषितको लागि गलत लक्ष्य निर्दिष्ट गर्दै हुनुहुन्छ, वा गलत पृष्ठको सम्पादन गर्दै हुनुहुन्छ।\nतपाईं पुनः एकपटक \"{{int:savearticle}}\" क्लिक गर्नुहुन्छ, पुनः निर्देशित त्यसै पनि बनाइनेछ।",
"diff-multi-manyusers": "($2 {{PLURAL:$2|भन्दा अधिक प्रयोगकर्ता|भन्दा अधिक प्रयोगकर्ताहरू}}द्वारा {{PLURAL:$1|एउटा मध्यवर्ती संशोधन|$1 मध्यवर्ती संशोधनहरू}} नदेखाइएको)",
"difference-missing-revision": "यस अन्तर {{PLURAL:$2|को एक अवतरण|को $2 अवतरण}} ($1) {{PLURAL:$2|भेटिएन|खोज्न सकिएन}}।\n\nयो सामान्य रूपमा एउटा हताइएको पृष्ठको अवतरणहरूमा अन्तर खोज्दा हुन्छ । अधिक जानकारी [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} हटाइएको लग]मा हेर्न सकिन्छ।",
"searchresults": "खोज नतिजाहरू",
- "searchresults-title": " \"$1\"à¤\95à¥\8b लाà¤\97ि à¤\96à¥\8bà¤\9c नतिà¤\9cाहरà¥\81",
+ "searchresults-title": " \"$1\"à¤\95à¥\8b लाà¤\97ि à¤\96à¥\8bà¤\9c नतिà¤\9cाहरà¥\82",
"titlematches": "पृष्ठ शिर्षक मिल्छ",
"textmatches": "पृष्ठ पाठ मिल्छ",
"notextmatches": "अक्षरस् पेज भेटिएन",
"next-page": "अर्को पृष्ठ",
"prevn-title": "पहिलेको $1 {{PLURAL:$1|नतिजा|नतिजाहरु}}",
"nextn-title": "यस पछिको $1 {{PLURAL:$1|नतिजा |नतिजाहरु}}",
- "shown-title": "दà¥\87à¤\96ाà¤\89नà¥\87 $1 {{PLURAL:$1|नतिà¤\9cा|नतिà¤\9cाहरà¥\81}} प्रति पृष्ठ",
+ "shown-title": "दà¥\87à¤\96ाà¤\89नà¥\87 $1 {{PLURAL:$1|नतिà¤\9cा|नतिà¤\9cाहरà¥\82}} प्रति पृष्ठ",
"viewprevnext": "हेर्नुहोस् ($1 {{int:pipe-separator}} $2) ($3)",
"searchmenu-exists": "''' \"[[:$1]]\" नाम गरेको पृष्ठ यो विकीमा रहेको छ'''",
"searchmenu-new": "<strong>\"[[:$1]]\" पृष्ठ यस विकिमा बनाउनुहोस्!</strong> {{PLURAL:$2|0=|तपाईंले खोज गरी भटिएको पृष्ठ पनि मिलान गर्नुहोस्।|तपाईंको खोज परिणाम पनि हेर्नुहोस।}}",
"showingresults": "देखाउँदै {{PLURAL:$1|'''१''' नतिजा|'''$1''' नतिजाहरू }} , #'''$2''' बाट सुरुहुने ।",
"showingresultsinrange": "देखाई रहेको छ{{PLURAL:$1|<strong>1</strong> result|<strong>$1</strong> परिणाम}} सम्म पहुँच #<strong>$2</strong> देखि #<strong>$3</strong> मा।",
"search-showingresults": "{{PLURAL:$4|<strong>$3</strong> मा बाट <strong>$1</strong> परिणाम|<strong>$3</strong> मा बाट परिणाम <strong>$1 - $2</strong>}}",
- "search-nonefound": "तपाà¤\88à¤\81को क्वेरीसँग मेल खाने नतिजाहरू भेटिएनन्",
+ "search-nonefound": "तपाà¤\88à¤\82को क्वेरीसँग मेल खाने नतिजाहरू भेटिएनन्",
"powersearch-legend": "उन्नत खोज",
"powersearch-ns": "नेमस्पेसेजहरूमा खोज्ने :",
"powersearch-togglelabel": "जाँच्ने :",
"recentchangeslinked-feed": "सम्बन्धित परिवर्तनहरू",
"recentchangeslinked-toolbox": "सम्बन्धित परिवर्तनहरू",
"recentchangeslinked-title": "\"$1\" सँग सम्बन्धित परिवर्तन",
- "recentchangeslinked-summary": "यो सूची निर्दिष्ट पृष्ठ (वा निर्दिष्ट श्रेणी)सित जोडिएका भर्खरै परिवर्तन भएका पृष्ठको हो। [[Special:Watchlist|तपाईँको निगरानी सूची]]का पृष्ठहरू <strong>गाढा अक्षरमा</strong> छन्।",
+ "recentchangeslinked-summary": "यो सूची निर्दिष्ट पृष्ठ (वा निर्दिष्ट श्रेणी)सित जोडिएका भर्खरै परिवर्तन भएका पृष्ठको हो । [[Special:Watchlist|तपाईंको निगरानी सूची]]का पृष्ठहरू <strong>गाढा अक्षरमा</strong> छन् ।",
"recentchangeslinked-page": "पृष्ठ नाम:",
"recentchangeslinked-to": "यसको सट्टा यो पृष्ठसँग जोडिएका पृष्ठहरूको परिवर्तन देखाउने",
"upload": "फाइल उर्ध्वभरण",
"filehist-dimensions": "आकारहरू",
"filehist-filesize": "फाइल आकार",
"filehist-comment": "टिप्पणी",
- "imagelinks": "फाà¤\87लà¤\95à¥\8b पà¥\8dरयà¥\8bà¤\97हरà¥\81",
+ "imagelinks": "फाà¤\87लà¤\95à¥\8b पà¥\8dरयà¥\8bà¤\97हरà¥\82",
"linkstoimage": "यस फाइलमा निम्न{{PLURAL:$1|पृष्ठ जोडिन्छ|$1 पृष्ठहरू जोडिन्छन्}}:",
"linkstoimage-more": "$1 भन्दा अधिक {{PLURAL:$1|पृष्ठ लिङ्क|पृष्ठ लिङ्कहरू}} यस फाइलसँग जोडिएको छ। \nनिम्नलिखित सूची फाइलसँग {{PLURAL:$1|पहिलो पृष्ठ लिङ्क|पहिलो $1 पृष्ठ लिङ्कहरू}} जोडिने देखाउँछ।\n[[Special:WhatLinksHere/$2|पूर्ण सूची]] पनि उपलब्ध छ।",
"nolinkstoimage": "यो फाईलसंग लिंकभएको कुनै पृष्ठ छैन.",
"duplicatesoffile": "निम्नलिखित {{PLURAL:$1|फाइलको प्रतिलिपि हो|$1 फाइलहरूको प्रतिलिपि हो}} ([[Special:FileDuplicateSearch/$2|अधिक जानकारीहरू]]):",
"sharedupload": "यो फाइल $1 को हो र अन्य परियोजनामा प्रयोग गरिएको हुनसक्छ।",
"sharedupload-desc-there": "यो फाइल $1 बाट हो र अन्य परियोजनाहरू द्वारा पनि प्रयोग गर्न सकिनेछ। अधिक जानकारीको लागि कृपया [$2 फाइल विवरण पृष्ठ] हेर्नुहोस।",
- "sharedupload-desc-here": "यà¥\8b फाà¤\87ल $1 बाà¤\9f हà¥\8b र à¤\85नà¥\8dय परियà¥\8bà¤\9cनाहरà¥\82 दà¥\8dवारा पनि पà¥\8dरयà¥\8bà¤\97 à¤\97रà¥\8dन सà¤\95िनà¥\8dà¤\9b। \nतà¥\8dयहाà¤\81 नà¥\87र यसà¤\95à¥\8b [$2 फ़ाà¤\87ल विवरण पà¥\83षà¥\8dठ]मा रहà¥\87à¤\95à¥\8b विवरण तल दिà¤\87à¤\8fà¤\95à¥\8b à¤\9b।",
+ "sharedupload-desc-here": "यो फाइल $1 बाट हो र अन्य परियोजनाहरू द्वारा पनि प्रयोग गर्न सकिन्छ। \nत्यहाँ नेर यसको [$2 फाइल विवरण पृष्ठ]मा रहेको विवरण तल दिइएको छ।",
"sharedupload-desc-edit": "यो फाइल $1 बाट हो र अन्य परियोजनाहरू द्वारा पनि प्रयोग गर्न सकिन्छ। \nशायद तपाईं [$2 त्यहाँ यसको फाइल विवरण पृष्ठ]लाई सम्पादित गर्न चाहनुहुन्छ।",
"sharedupload-desc-create": "यो फाइल $1 बाट हो र अन्य परियोजनाहरू द्वारा पनि प्रयोग गर्न सकिन्छ। \nशायद तपाईं [$2 त्यहाँ यसको फाइल विवरण पृष्ठ]लाई सम्पादित गर्न चाहनुहुन्छ।",
"filepage-nofile": "यस नामको फाइल छैन।",
"shared-repo-from": " $1 बाट",
"shared-repo": "एल साझा भण्डार",
"shared-repo-name-wikimediacommons": "विकिमीडिया कमन्स",
- "upload-disallowed-here": "तपाà¤\88à¤\81ले यो फाइल अधिलेखन गर्न सक्नुहुन्न ।",
+ "upload-disallowed-here": "तपाà¤\88à¤\82ले यो फाइल अधिलेखन गर्न सक्नुहुन्न ।",
"filerevert": "पूर्वस्थिति $1 मा फर्काउने",
"filerevert-legend": " फाइल पूर्वस्थितीमा फर्काउने",
"filerevert-intro": "तपाईं <strong>[[Media:$1|$1]]</strong>लाई [$4 $2 मा $3 बजेको अवतरण] लाई पूर्ववत गर्दै हुनुहुन्छ।",
"javascripttest": "JavaScript जाँच गरिदै",
"javascripttest-pagetext-unknownaction": "अज्ञात कारवाही \"$1\" ।",
"javascripttest-qunit-intro": "mediawiki.org मा [$1 जाँचको कागजात] हेर्नुहोस् ।",
- "tooltip-pt-userpage": "तपाईंको प्रयोगकर्ता पृष्ठ",
+ "tooltip-pt-userpage": "{{GENDER:| तपाईंको प्रयोगकर्ता}} पृष्ठ",
"tooltip-pt-anonuserpage": "तपाईँ जुन IP ठेगानाको रुपमा सम्पादन गर्दै हुनुहुन्छ , त्यसको प्रयोगकर्ता पृष्ठ निम्न छ :",
- "tooltip-pt-mytalk": "तपाईंको वार्ता पृष्ठ",
+ "tooltip-pt-mytalk": "{{GENDER:|तपाईंको}} वार्ता पृष्ठ",
"tooltip-pt-anontalk": "यो IP ठेगानाबाट गरिएका सम्पादनका बारेमा बार्तालाप",
- "tooltip-pt-preferences": "तपाईंका अभिरुचिहरू",
+ "tooltip-pt-preferences": "{{GENDER:|तपाईंका}} अभिरुचिहरू",
"tooltip-pt-watchlist": "पृष्ठहरूको सूची जसका परिवर्तनहरूलाई तपाईँले निगरानी गरिरहनु भएको छ",
- "tooltip-pt-mycontris": "तपाईंका योगदानहरूको सूची",
- "tooltip-pt-login": "तपाà¤\88à¤\81लाà¤\88 पà¥\8dरवà¥\87शगर्न सुझाव दिइन्छ ; तर यो जरुरी भने छैन",
+ "tooltip-pt-mycontris": "{{GENDER:|तपाईंका}} योगदानहरूको सूची",
+ "tooltip-pt-login": "तपाà¤\88à¤\82लाà¤\88 पà¥\8dरवà¥\87स गर्न सुझाव दिइन्छ ; तर यो जरुरी भने छैन",
"tooltip-pt-logout": "निर्गमन (लग आउट) गर्नुहोस्",
- "tooltip-pt-createaccount": "तपाईंलाई खाता बनाउन र लग इन गर्न हामि प्रोत्साहित गर्छौ; तथापि, यो अनिवार्य भने छैन।",
+ "tooltip-pt-createaccount": "तपाईंलाई खाता बनाउन र लग इन गर्न हामि प्रोत्साहित गर्छौ; तथापि, यो अनिवार्य भने छैन ।",
"tooltip-ca-talk": "सामग्री पृष्ठबारेमा छलफल",
"tooltip-ca-edit": "यो पृष्ठ सम्पादन गर्ने",
"tooltip-ca-addsection": "नयाँ खण्ड सुरु गर्नुहोस्",
"tooltip-ca-viewsource": "यो पृष्ठ सुरक्षित गरिएको छ। यसको श्रोत हेर्न सक्नुहुन्छ।",
- "tooltip-ca-history": "यस पà¥\83षà¥\8dठà¤\95à¥\8b पहिलà¥\87à¤\95ा पà¥\81नरावलà¥\8bà¤\95नहरà¥\81",
+ "tooltip-ca-history": "यस पà¥\83षà¥\8dठा पहिलà¥\87à¤\95ा पà¥\81नरावलà¥\8bà¤\95नहरà¥\82",
"tooltip-ca-protect": "यो पृष्ठलाई संरक्षित गर्नुहोस्",
"tooltip-ca-unprotect": "यस पृष्ठको सुरक्षा परिवर्तन गर्ने",
"tooltip-ca-delete": "यो पृष्ठ मेटाउनुहोस्",
"tooltip-ca-undelete": "मेटिएको भए पनि यो पृष्ठको सम्पादनहरू पुन:प्राप्त गर्नुहोस्",
"tooltip-ca-move": "यो पृष्ठलाई सार्नुहोस्",
- "tooltip-ca-watch": "यà¥\8b पà¥\83षà¥\8dठलाà¤\88 तपाà¤\88à¤\81को अवलोकनसूचीमा थप्नुहोस्",
+ "tooltip-ca-watch": "यà¥\8b पà¥\83षà¥\8dठलाà¤\88 तपाà¤\88à¤\82को अवलोकनसूचीमा थप्नुहोस्",
"tooltip-ca-unwatch": "यो पृष्ठलाई तपाईँको अवलोकनसूचीबाट हटाउनुहोस्",
"tooltip-search": "{{SITENAME}} मा खोज्नुहोस्",
"tooltip-search-go": "यदि यो नामको पृष्ठ रहेको छ भने त्यसमा जाने",
"tooltip-search-fulltext": "यो पाठको लागि पृष्ठहरू खोज्नुहोस्",
"tooltip-p-logo": "मुख्य पृष्ठ",
"tooltip-n-mainpage": "मुख्य पृष्ठमा जाने",
- "tooltip-n-mainpage-description": "मà¥\81à¤\96à¥\8dय पà¥\83षà¥\8dठमा à¤\9cानà¥\81हà¥\8bà¥\8dसà¥\8d",
- "tooltip-n-portal": "à¤\86यà¥\8bà¤\9cनाà¤\95ा बारà¥\87मा, तपाà¤\88à¤\81 के गर्न सक्नुहुन्छ, सामग्री कहाँ भेट्टाउने",
+ "tooltip-n-mainpage-description": "मुख्य पृष्ठमा जानुहोस्",
+ "tooltip-n-portal": "à¤\86यà¥\8bà¤\9cनाà¤\95ा बारà¥\87मा, तपाà¤\88à¤\82 के गर्न सक्नुहुन्छ, सामग्री कहाँ भेट्टाउने",
"tooltip-n-currentevents": "हालैको घटनाको बारेमा पृष्ठभूमि जानकारी पत्ता लगाउनुहोस्",
- "tooltip-n-recentchanges": "विà¤\95िमा à¤\97रिà¤\8fà¤\95ा हालà¥\88à¤\95ा परिवरà¥\8dतनहरà¥\81को सूची",
- "tooltip-n-randompage": "à¤\9cà¥\81न à¤\95à¥\81नà¥\88 पृष्ठ खोल्ने",
+ "tooltip-n-recentchanges": "विà¤\95िमा à¤\97रिà¤\8fà¤\95ा हालà¥\88à¤\95ा परिवरà¥\8dतनहरà¥\82को सूची",
+ "tooltip-n-randompage": "à¤\95à¥\81नà¥\88 à¤\8fà¤\95 पृष्ठ खोल्ने",
"tooltip-n-help": "पत्तालगाउनु पर्ने स्थान",
"tooltip-t-whatlinkshere": "यो सँग जोडिएका सबै विकि पृष्ठहरूको सूची",
"tooltip-t-recentchangeslinked": "यस पृष्ठमा जोडिएका पृष्ठहरूमा हालैको परिवर्तन",
"tooltip-ca-nstab-help": "सहायता पृष्ठ हेर्नुहोस्",
"tooltip-ca-nstab-category": "श्रेणी पृष्ठ हेर्ने",
"tooltip-minoredit": "यसलाई सामान्य सम्पादनको रुपमा चिनो लगाउने",
- "tooltip-save": "तपाà¤\88à¤\81लà¥\87 à¤\97रà¥\87à¤\95ा परिवरà¥\8dतनहरà¥\82 सà¤\82ग्रह गर्नुहोस्",
- "tooltip-preview": "तपाà¤\88à¤\81à¤\95à¥\8b परिवरà¥\8dतनà¤\95à¥\8b पà¥\82रà¥\8dवरà¥\82प , à¤\95à¥\83पया सà¤\82ग्रह गर्नु अघि यो प्रयोग गर्नुहोला !",
- "tooltip-diff": "तपाà¤\88à¤\81ले पाठमा के के परिवर्तन गर्नुभयो भनेर देखाउने",
+ "tooltip-save": "तपाà¤\88à¤\82à¤\95ा परिवरà¥\8dतनहरà¥\82 सà¤\99à¥\8dग्रह गर्नुहोस्",
+ "tooltip-preview": "तपाà¤\88à¤\82à¤\95à¥\8b परिवरà¥\8dतनà¤\95à¥\8b पà¥\82रà¥\8dवरà¥\82प , à¤\95à¥\83पया सà¤\99à¥\8dग्रह गर्नु अघि यो प्रयोग गर्नुहोला !",
+ "tooltip-diff": "तपाà¤\88à¤\82ले पाठमा के के परिवर्तन गर्नुभयो भनेर देखाउने",
"tooltip-compareselectedversions": "यस पृष्ठको छानिएका दुई पुनरावलोकन बीच फरक हेर्नुहोस्",
"tooltip-watch": "यो पृष्ठलाई तपाईँको अवलोकनसूचीमा थप्नुहोस्",
"tooltip-watchlistedit-normal-submit": "शीर्षकहरू हटाउने",
"widthheight": "$1 × $2",
"widthheightpage": "$1 × $2, $3 {{PLURAL:$3|पृष्ठ|पृष्ठहरू}}",
"file-info": "फाइल आकार: $1, MIME प्रकार: $2",
- "file-info-size": "$1 Ã\97 $2 पिà¤\95à¥\8dसà¥\87लहरà¥\81, फाइल आकार: $3, MIME प्रकार: $4",
+ "file-info-size": "$1 Ã\97 $2 पिà¤\95à¥\8dसà¥\87लहरà¥\82, फाइल आकार: $3, MIME प्रकार: $4",
"file-info-size-pages": "$1 × $2 पिक्सेलहरू, फाइल आकार: $3, MIME प्रकार: $4, $5 {{PLURAL:$5|पृष्ठ|पृष्ठहरू}}",
"file-nohires": "उच्च रिजोल्युशन अनुपलब्ध",
"svg-long-desc": "SVG फाइल,साधारण $1 × $2 पिक्सेलहरु, फाइल आकार: $3",
"svg-long-error": "अमान्य एसभिजी फाइल: $1",
"show-big-image": "मूल फाइल",
"show-big-image-preview": "यस पूर्व रुपको आकार: $1।",
- "show-big-image-other": "à¤\85रà¥\81 {{PLURAL:$2|resolution|रिà¤\9cà¥\8bलà¥\8dयà¥\81शनहरà¥\81}}: $1।",
+ "show-big-image-other": "à¤\85रà¥\81 {{PLURAL:$2|resolution|रिà¤\9cà¥\8bलà¥\8dयà¥\81शनहरà¥\82}}: $1।",
"show-big-image-size": "$1 × $2 पिक्सल",
"file-info-gif-looped": "चकृय गरिएको",
"file-info-gif-frames": "$1 {{PLURAL:$1|फ्रेम|फ्रेमहरु}}",
"yesterday-at": "हिजो $1मा",
"bad_image_list": "(* बाट शुरु हुने पंक्ति)को विषय सूची मात्र मान्य छ। पंक्तिको पहिलो लिङ्क नराम्रो फाइलसित लिङ्क हुनैपर्छ । एउटै पंक्तिमा कुनै पछिबाट हुने लिंकलाई अपवाद मानिनेछ अर्थात् जुन पृष्ठमा फाइल इन-लाइन हुनसक्छ।",
"metadata": "मेटाडेटा",
- "metadata-help": "यस फाà¤\87लमा à¤\85तिरिà¤\95à¥\8dत à¤\9cानà¤\95ारà¥\80हरà¥\81 à¤\9bनà¥\8d, यसलाà¤\88 बनाà¤\89न समà¥\8dà¤à¤µà¤¤à¤\83 डिà¤\9cिà¤\9fल à¤\95à¥\8dयामà¥\87रा à¤\85थवा सà¥\8dà¤\95à¥\8dयानर पà¥\8dरयà¥\8bà¤\97 à¤\97रिà¤\8fà¤\95à¥\8b हà¥\81नà¥\81परà¥\8dà¤\9b। यदि यस फाà¤\87ललाà¤\88 मà¥\82ल à¤\85वसà¥\8dथाबाà¤\9f परिवरà¥\8dतन à¤\97रिà¤\8fà¤\95à¥\8b हà¥\8b à¤à¤¨à¥\87à¤\82 यस फाइलले सम्पूर्ण विवरण प्रतिबिम्बित गर्न सक्नेछैन ।",
+ "metadata-help": "यस फाà¤\87लमा à¤\85तिरिà¤\95à¥\8dत à¤\9cानà¤\95ारà¥\80हरà¥\82 à¤\9bनà¥\8d, यसलाà¤\88 बनाà¤\89न समà¥\8dà¤à¤µà¤¤à¤\83 डिà¤\9cिà¤\9fल à¤\95à¥\8dयामà¥\87रा à¤\85थवा सà¥\8dà¤\95à¥\8dयानर पà¥\8dरयà¥\8bà¤\97 à¤\97रिà¤\8fà¤\95à¥\8b हà¥\81नà¥\81परà¥\8dà¤\9b । यदि यस फाà¤\87ललाà¤\88 मà¥\82ल à¤\85वसà¥\8dथाबाà¤\9f परिवरà¥\8dतन à¤\97रिà¤\8fà¤\95à¥\8b हà¥\8b à¤à¤¨à¥\87 यस फाइलले सम्पूर्ण विवरण प्रतिबिम्बित गर्न सक्नेछैन ।",
"metadata-expand": "लामो विबरण हेर्ने",
"metadata-collapse": "लामो विवरण लुकाउने",
- "metadata-fields": "Image metadata fields listed in this message will be included on image page display when the metadata table is collapsed.\nOthers will be hidden by default.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+ "metadata-fields": "मेटाडाटा तालिकालाई लघुरूप गरियो भने यस सन्देशमा सूचीबद्ध इएक्सआयएफ मेटाडाटा जानकारिहरू छवि प्रदर्शित हुने बेला सम्मिलित गरिने छ ।\nअन्य डिफल्ट रूपसँग लुकिरहने छ ।\n* make \n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
"exif-imagewidth": "चौडाइ",
"exif-imagelength": "उचाई",
"exif-bitspersample": "घटक प्रति बिट्स",
"Luan",
"Anderson Costa",
"LucyDiniz",
- "Tusca"
+ "Tusca",
+ "Cristofer Alves"
]
},
"tog-underline": "Sublinhar links:",
"userlogin-resetpassword-link": "Esqueceu sua senha?",
"userlogin-helplink2": "Ajuda com o login",
"userlogin-loggedin": "Você já está conectado como {{GENDER:$1|$1}}.\nUse o formulário abaixo para iniciar sessão como outro usuário.",
+ "userlogin-reauth": "Deve iniciar novamente a sessão para verificar se é {{GENDER:$1|$1}}.",
"userlogin-createanother": "Crie uma outra conta",
"createacct-emailrequired": "Endereço de e-mail",
"createacct-emailoptional": "Endereço de e-mail (opcional)",
"createacct-email-ph": "Confirme seu endereço de e-mail",
"createacct-another-email-ph": "Forneça o endereço de e-mail",
"createaccountmail": "Usar uma senha aleatória e temporária que será enviada ao endereço de e-mail especificado a seguir",
+ "createaccountmail-help": "Pode ser utilizado para criar uma conta para outra pessoa sem saber a senha.",
"createacct-realname": "Nome real (opcional)",
"createaccountreason": "Motivo:",
"createacct-reason": "Motivo",
"createacct-reason-ph": "Por que você está criando outra conta",
+ "createacct-reason-help": "Mensagem mostrada no registro de criação de conta",
"createacct-submit": "Crie sua conta",
"createacct-another-submit": "Criar conta",
+ "createacct-continue-submit": "Continuar criação de conta",
+ "createacct-another-continue-submit": "Continuar criação de conta",
"createacct-benefit-heading": "{{SITENAME}} é feita por pessoas como você.",
"createacct-benefit-body1": "{{PLURAL:$1|edição|edições}}",
"createacct-benefit-body2": "{{PLURAL:$1|página|páginas}}",
"nocookiesnew": "A conta do usuário foi criada, mas você não foi autenticado.\n{{SITENAME}} utiliza ''cookies'' para autenticar os usuários.\nVocê tem os ''cookies'' desativados no seu navegador.\nPor favor ative-os, depois autentique-se com o seu novo nome de usuário e a sua senha.",
"nocookieslogin": "Você tem os <i>cookies</i> desativados no seu navegador, e a {{SITENAME}} utiliza <i>cookies</i> para ligar os usuários às suas contas. Por favor os ative e tente novamente.",
"nocookiesfornew": "A conta de usuário não foi criada porque não foi possível confirmar a sua origem.\nCertifique-se de que tem os cookies ativados, recarregue esta página e tente novamente.",
+ "createacct-loginerror": "A conta foi criada com êxito, mas não pôde ser autenticado automaticamente. Por favor, faça o [[Special:UserLogin|início de sessão manualmente]].",
"noname": "Você não colocou um nome de usuário válido.",
"loginsuccesstitle": "Autenticado",
"loginsuccess": "'''Agora você está {{GENDER:autenticado|autenticada}} ao wiki {{SITENAME}} como \"$1\"'''.",
"botpasswords-label-delete": "Apagar",
"botpasswords-label-resetpassword": "Redefinir a sua senha",
"botpasswords-label-grants": "Permissões aplicáveis",
+ "botpasswords-help-grants": "Cada permissão da acesso à lista permissões de usuários que um usuário já tenha. Veja o [[Special:ListGrants|Lista de Permissões]] para mais informações.",
"botpasswords-label-restrictions": "Restrições de uso:",
"botpasswords-label-grants-column": "Concedido",
"botpasswords-bad-appid": "O nome de robô \"$1\" não é válido.",
"passwordreset-emailsentemail": "Se este é um endereço de e-mail registrado para a sua conta, em seguida, um e-mail de redefinição de senha será enviada.",
"passwordreset-emailsentusername": "Se houver um endereço de email associado a esta conta, ser-lhe-á enviada uma mensagem para redefinir a sua senha.",
"passwordreset-emailsent-capture2": "A redefinição da senha {{PLURAL:$1|do e-mail|dos e-mails}} foi enviada. {{PLURAL:$1|O nome de usuário e senha|A lista de nomes de usuário e senhas}} encontram-se a seguir.",
+ "passwordreset-emailerror-capture2": "O envio do e-mail {{GENDER:$2|usuário}} falhou: $1 Os {{PLURAL:$3|nome de usuário e senha|lista de nomes de usuários e senhas}} são mostrados abaixo.",
+ "passwordreset-nocaller": "Um interlocutor deve ser fornecido",
+ "passwordreset-nosuchcaller": "O interlocutor não existe: $1",
+ "passwordreset-ignored": "A redefinição da senha não foi realizada. Talvez o provedor não tenha sido configurado?",
+ "passwordreset-invalideamil": "Endereço de e-mail inválido",
+ "passwordreset-nodata": "Não foram fornecidos nome de usuário nem endereço de e-mail",
"changeemail": "Alterar ou remover endereço de email",
"changeemail-header": "Preencha este formulário para alterar seu endereço de e-mail. Se você gostaria de remover a associação de qualquer endereço de e-mail da sua conta, deixe o novo endereço de email em branco quando enviar o formulário.",
"changeemail-no-info": "Para acessar diretamente esta página você tem de estar autenticado.",
"minoredit": "Marcar como edição menor",
"watchthis": "Vigiar esta página",
"savearticle": "Salvar página",
+ "savechanges": "Salvar alterações",
"publishpage": "Publicar página",
"publishchanges": "Publicar alterações",
"preview": "Pré-visualização",
"accmailtext": "Uma senha gerada aleatoriamente para [[User talk:$1|$1]] foi enviada para $2.\n\nEla pode ser alterada na página ''[[Special:ChangePassword|de troca de senha]]'', após o início de sessão.",
"newarticle": "(Nova)",
"newarticletext": "Você seguiu um link para uma página que ainda não existe.\nPara criá-la, comece escrevendo na caixa abaixo (veja [$1 a página de ajuda] para mais informações).\nSe você chegou aqui por engano, clique no botão '''voltar''' do seu navegador.",
- "anontalkpagetext": "---- ''Esta é a página de discussão para um usuário anônimo que ainda não criou uma conta ou que não a usa, de forma que temos de utilizar o endereço de IP para identificá-lo(a). Tal endereço de IP pode ser compartilhado por vários usuários. Se você é um usuário anônimo e acha que comentários irrelevantes foram direcionados a você, por gentileza, [[Special:CreateAccount|crie uma conta]] ou [[Special:UserLogin|autentique-se]], a fim de evitar futuras confusões com outros usuários anônimos.''",
+ "anontalkpagetext": "---\n<em> Esta é a pagina de discussão para usuários anônimos que ainda não ciaram uma conta, ou para aqueles que a usa. </em>\nNós entretanto temos que usar o endereço numérico de IP para identifica-lo/a.\nEste endereço de IP pode ser compartilhado por vários usuários.\nse você é um usuário anônimo e sente que aquele comentário irrelevante foi direcionado à você, por favor [[Special:CreateAccount|Criar Conta]] ou [[Special:UserLogin|Logar]] para evitar futuras confusões com outros usuários anônimos.",
"noarticletext": "Não há conteúdo nesta página no momento.\nVocê pode [[Special:Search/{{PAGENAME}}|pesquisar pelo título desta página]] em outras páginas, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar por registros relacionados],\nou [{{fullurl:{{FULLPAGENAME}}|action=edit}} criar esta página]</span>.",
"noarticletext-nopermission": "No momento, não há conteúdo nesta página\nVocê pode [[Special:Search/{{PAGENAME}}|pesquisar pelo título desta página]] em outras páginas,\nou <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} buscar por registros relacionados] </span>. Note que, no entanto, você não tem permissão para criar esta página.",
"missing-revision": "A revisão #$1 da página denominada \"{{FULLPAGENAME}}\" não existe.\n\nIsto é geralmente causado por seguir um link de histórico desatualizado para uma página que foi eliminada.\nOs detalhes podem ser encontrados no [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} registro de eliminação].",
"userpage-userdoesnotexist": "A conta \"<nowiki>$1</nowiki>\" não se encontra registrada.\nVerifique se deseja mesmo criar/editar esta página.",
"userpage-userdoesnotexist-view": "A conta de usuário \"$1\" não está registrada.",
"blocked-notice-logextract": "Este usuário está atualmente bloqueado.\nO registro de bloqueio mais recente é fornecido abaixo, para referência:",
- "clearyourcache": "Nota:''' Depois de salvar, você terá de limpar o ''cache'' do seu navegador para ver as alterações.\n* '''Firefox / Safari:''' pressione ''Shift'' enquanto clica em ''Recarregar'', ou pressione ''Ctrl-F5'' ou ''Ctrl-R'' (''Command-R'' para Mac);\n* '''Google Chrome:''' pressione ''Ctrl-Shift-R'' (''Command-Shift-R'' em um Mac)\n* '''Internet Explorer:''' pressione ''Ctrl'' enquanto clica em ''Recarregar'' ou pressione ''Ctrl-F5'';\n* '''Opera:''' limpe o ''cache'' em ''Ferramentas → Preferências'' (''Tools → Preferences'')",
+ "clearyourcache": "<strong>Nota:</strong> Após salvar, você pode ter que limpar o \"cache\" do seu navegador para ver as alterações.\n*<strong>Firefox / Safari:</strong> Pressione <em>Shift</em> enquanto clica <em>Recarregar</em>, ou pressione <em>Ctrl-F5</em> ou <em>Ctrl-R</em> (<em>⌘-R</em> no Mac)\n*<strong>Google Chorme:</strong> Pressione <em>Ctrl-Shift-R</em> (<em>⌘-Shift-R</em> no Mac)\n* <strong>Internet Explorer:</strong> Pressione<em>Ctrl</em> enquanto clica <em>Recarregar</em>, ou Pressione <em>Ctrl-F5</em>\n* <strong>Opera:</strong> Vá para <em>Menu → Configurações</em> (<em>Opera → Preferencias</em> no Mac) e depois para <em>Privacidade e Segurança → Limpar dados de navegação → Imagens e arquivos em cache</em>.",
"usercssyoucanpreview": "'''Dica:''' Utilize o botão \"{{int:showpreview}}\" para testar seu novo CSS antes de salvar.",
"userjsyoucanpreview": "'''Dica:''' Utilize o botão \"{{int:showpreview}}\" para testar seu novo JavaScript antes de salvar.",
"usercsspreview": "'''Lembre-se de que você está apenas previsualizando o seu CSS particular.'''\n'''Ele ainda não foi salvo!'''",
"content-json-empty-object": "Objeto vazio",
"content-json-empty-array": "Array vazia",
"deprecated-self-close-category": "Páginas com etiquetas HTML de autofechamento não válidas",
+ "deprecated-self-close-category-desc": "A página contém tags HTML auto-fechadas inválidas, como <code><b/></code> ou <code><span/></code>. O comportamento destas mudará em breve para coincidam com as especificações do HTML5, pelo que seu uso no wikitext está obsoleto.",
"duplicate-args-warning": "<strong> Aviso: </strong> [[:$1]] está chamando [[:$2]] com mais de um valor para o parâmetro \"$3\". Será utilizado apenas o último valor fornecido.",
"duplicate-args-category": "Páginas com argumentos de predefinições duplicados",
"duplicate-args-category-desc": "A pagina contem modelos que usam argumentos duplicados, como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ou <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"grant-group-high-volume": "Realizar grande volume de atividades",
"grant-group-customization": "Personalização e preferências",
"grant-group-administration": "Realizar ações administrativas",
+ "grant-group-private-information": "acessar os dados privados sobre você",
"grant-group-other": "Atividade diversa",
"grant-blockusers": "Bloquear e desbloquear usuários",
"grant-createaccount": "Criar contas",
"grant-highvolume": "Edição de grandes volumes",
"grant-oversight": "Ocultar usuários e revisões suprimidas",
"grant-patrol": "Patrulhar as alterações nas páginas",
+ "grant-privateinfo": "acessar informações privadas",
"grant-protect": "Proteger e desproteger páginas",
"grant-rollback": "Reverter alterações nas páginas",
"grant-sendemail": "Enviar e-mail a outros usuários",
"rightslogtext": "Este é um registro de mudanças nos privilégios de usuários.",
"action-read": "ler esta página",
"action-edit": "editar esta página",
- "action-createpage": "criar páginas",
- "action-createtalk": "criar páginas de discussão",
+ "action-createpage": "criar esta páginas",
+ "action-createtalk": "criar esta páginas de discussão",
"action-createaccount": "criar esta conta de usuário",
"action-autocreateaccount": "Criar uma conta de usuário externa automaticamente",
"action-history": "Ver o histórico desta página",
"action-applychangetags": "aplicar etiquetas juntamente com suas alterações",
"action-changetags": "adicionar e remover etiquetas arbitrárias em revisões e ''logs'' individuais",
"action-deletechangetags": "deletar marcações da base de dados",
+ "action-purge": "purgar esta página",
"nchanges": "$1 {{PLURAL:$1|alteração|alterações}}",
"enhancedrc-since-last-visit": "$1 {{PLURAL:$1|desde a última visita}}",
"enhancedrc-history": "histórico",
"uploaded-event-handler-on-svg": "Não é permitido configurar atributos que manipulem eventos <code>$1=\"$2\"</code> em arquivos SVG.",
"uploaded-href-attribute-svg": "os atributos href nos ficheiros SVG só están autorizados a ligar a direccións http:// ou https://, atopado <code><$1 $2=\"$3\"></code>.",
"uploaded-href-unsafe-target-svg": "Encontrado href para dados não seguros: alvo URI <code><$1 $2=\"$3\"></code> no arquivo SVG carregado.",
+ "uploaded-animate-svg": "Encontrado a tag \"animate\" que pode estar mudando \"href\", usando o atributo \"from\" <code><$1 $2=\"$3\"></code> no arquivo SVG carregado.",
"uploadscriptednamespace": "Este aruivo SVG contém um espaço nominal probido \"$1\"",
"uploadinvalidxml": "O XML no arquivo enviado não pôde ser analisado.",
"uploadvirus": "O arquivo contém vírus!\nDetalhes: $1",
"2axterix2",
"Ата",
"Matěj Suchánek",
- "Chaduvari"
+ "Chaduvari",
+ "MarcoAurelio"
]
},
"sidebar": "{{notranslate}}",
"yourpasswordagain": "Since 1.22 no longer used in core, but may be used by some extensions. DEPRECATED",
"createacct-yourpasswordagain": "In create account form, label for field to re-enter password\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]\n{{Identical|Confirm password}}",
"createacct-yourpasswordagain-ph": "Placeholder text in create account form for re-enter password field.\n\nSee example: [{{canonicalurl:Special:UserLogin|type=signup}} Special:UserLogin?type=signup]",
- "remembermypassword": "Used as checkbox label on [[Special:ChangePassword]]. Parameters:\n* $1 - number of days\n{{Identical|Remember my login on this computer}}",
- "userlogin-remembermypassword": "The text for a check box in [[Special:UserLogin]].",
+ "userlogin-remembermypassword": "Used as checkbox label in [[Special:UserLogin]]. Parameters:\n* $1 - number of days the login session will be active if checked (Unused but used on-wiki)\n",
"userlogin-signwithsecure": "Text of link to HTTPS login form.\n\nSee example: [[Special:UserLogin]]",
"cannotloginnow-title": "Error page title shown when logging in is not possible.",
"cannotloginnow-text": "Error page text shown when logging in is not possible. Parameters:\n* $1 - Session type in use that makes it not possible to log in, from a message like {{msg-mw|sessionprovider-mediawiki-session-cookiesessionprovider}}.",
"file-thumbnail-no": "Error message at [[Special:Upload]]. Parameters:\n* $1 - String (e.g. \"180px-\")",
"fileexists-forbidden": "{{doc-important|''thumb'' and ''center'' are magic words. Leave it untranslated!}}\nParameters:\n* $1 - name of the existing file",
"fileexists-shared-forbidden": "{{doc-important|''thumb'' and ''center'' are magic words. Leave it untranslated!}}\nError message at [[Special:Upload]].\nParameters:\n* $1 - name of the existing file",
+ "fileexists-no-change": "Used in [[Special:Upload]] to warn when the upload is an exact duplicate of the current version of the file.\nParameters:\n* $1 - name of the existing file",
+ "fileexists-duplicate-version": "Used in [[Special:Upload]] to warn when the upload is an exact duplicate of (an) older version(s) of the file\nParameters:\n* $1 - name of the existing file\n* $2 - Amount of matching older versions (PLURAL support)",
"file-exists-duplicate": "Used as warning in [[Special:Upload]].\nThis message is followed by the gallery of the duplicate files.\n\nParameters:\n* $1 - number of duplicate files",
"file-deleted-duplicate": "Used in [[Special:Upload]. Parameters:\n* $1 - page title of the file\n\nSee also:\n* {{msg-mw|file-deleted-duplicate-notitle}}",
"file-deleted-duplicate-notitle": "Used in [[Special:Upload]] when the title of the deleted duplicate is not available.\n\nSee also:\n* {{msg-mw|file-deleted-duplicate}}",
"logentry-delete-revision": "{{Logentry|[[Special:Log/delete]]}}\n{{Logentryparam}}\n* $5 - the number of affected revisions of the page $3",
"logentry-delete-event-legacy": "{{Logentry|[[Special:Log/delete]]}}",
"logentry-delete-revision-legacy": "{{Logentry|[[Special:Log/delete]]}}",
- "logentry-suppress-delete": "{{Logentry}}\n\n'Hid' is a possible alternative to 'suppressed' in this message.",
+ "logentry-suppress-delete": "{{Logentry}}\n\n'Hid' is a possible alternative to 'suppressed' in this message.\n\n'''This is not a normal deletion log entry''' and is used only when the page is removed even from administrators view (on WMF wikis this is called 'oversight' or 'suppression'.",
"logentry-suppress-event": "{{Logentry}}\n{{Logentryparam}}\n* $5 - count of affected log events",
"logentry-suppress-revision": "{{Logentry}}\n{{Logentryparam}}\n* $5 - the number of affected revisions of the page $3.",
"logentry-suppress-event-legacy": "{{Logentry}}",
"filerevert-submit": "Возвратить",
"filerevert-success": "'''[[Media:$1|$1]]''' был возвращён к [$4 версии от $3, $2].",
"filerevert-badversion": "Не существует предыдущей локальной версии этого файла с указанной меткой времени.",
+ "filerevert-identical": "Текущая версия файла уже идентична выбранной.",
"filedelete": "$1 — удаление",
"filedelete-legend": "Удалить файл",
"filedelete-intro": "Вы собираетесь удалить файл '''[[Media:$1|$1]]''' со всей его историей.",
"filerevert-submit": "Повернути",
"filerevert-success": "'''[[Media:$1|$1]]''' був повернутий до [$4 версії від $3, $2].",
"filerevert-badversion": "Немає локальної версії цього файлу з вказаною поміткою дати і часу.",
+ "filerevert-identical": "Поточна версія файлу вже ідентична обраній.",
"filedelete": "Вилучення $1",
"filedelete-legend": "Вилучити файл",
"filedelete-intro": "Ви збираєтесь вилучити '''[[Media:$1|$1]]''' і всю його історію.",
"filerevert-submit": "Lùi lại",
"filerevert-success": "'''[[Media:$1|$1]]''' đã được lùi về [$4 phiên bản lúc $3, $2].",
"filerevert-badversion": "Không tồn tại phiên bản trước đó của tập tin tại thời điểm trên.",
+ "filerevert-identical": "Phiên bản hiện tại của tập tin đã y hệt với phiên bản được chọn.",
"filedelete": "Xóa $1",
"filedelete-legend": "Xóa tập tin",
"filedelete-intro": "Bạn sắp xóa tập tin '''[[Media:$1|$1]]''' cùng với tất cả lịch sử của nó.",
"logentry-delete-revision": "$1{{GENDER:$2|更改}}页面$3的{{PLURAL:$5|$5个版本}}的可见性:$4",
"logentry-delete-event-legacy": "$1{{GENDER:$2|更改}}$3的日志事件的可见性",
"logentry-delete-revision-legacy": "$1{{GENDER:$2|更改}}页面$3的版本的可见性",
- "logentry-suppress-delete": "$1{{GENDER:$2|已隐藏}}页面$3",
+ "logentry-suppress-delete": "$1{{GENDER:$2|已屏蔽}}页面$3",
"logentry-suppress-event": "$1秘密地{{GENDER:$2|更改}}$3的{{PLURAL:$5|$5个日志事件}}的可见性:$4",
"logentry-suppress-revision": "$1秘密地{{GENDER:$2|更改}}页面$3的{{PLURAL:$5|$5个版本}}的可见性:$4",
"logentry-suppress-event-legacy": "$1秘密地{{GENDER:$2|更改}}$3的日志事件的可见性",
private $mDb = null;
/** @var float UNIX timestamp */
- private $lastSlaveWait = 0.0;
+ private $lastReplicationWait = 0.0;
/**
* Used when creating separate schema files.
* If not set, wfGetDB() will be used.
* This function has the same parameters as wfGetDB()
*
- * @param integer $db DB index (DB_SLAVE/DB_MASTER)
+ * @param integer $db DB index (DB_REPLICA/DB_MASTER)
* @param array $groups; default: empty array
* @param string|bool $wiki; default: current wiki
* @return IDatabase
}
/**
- * Commit the transcation on a DB handle and wait for slaves to catch up
+ * Commit the transcation on a DB handle and wait for replica DBs to catch up
*
* This method makes it clear that commit() is called from a maintenance script,
* which has outermost scope. This is safe, unlike $dbw->commit() called in other places.
*
* @param IDatabase $dbw
* @param string $fname Caller name
- * @return bool Whether the slave wait succeeded
+ * @return bool Whether the replica DB wait succeeded
* @since 1.27
*/
protected function commitTransaction( IDatabase $dbw, $fname ) {
$dbw->commit( $fname );
+ try {
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $lbFactory->waitForReplication(
+ [ 'timeout' => 30, 'ifWritesSince' => $this->lastReplicationWait ]
+ );
+ $this->lastReplicationWait = microtime( true );
- $ok = wfWaitForSlaves( $this->lastSlaveWait, false, '*', 30 );
- $this->lastSlaveWait = microtime( true );
-
- return $ok;
+ return true;
+ } catch ( DBReplicationWaitError $e ) {
+ return false;
+ }
}
/**
$dbr = $this->forcedDb;
if ( $this->forcedDb === null ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
}
$this->maxCount = $dbr->selectField( $table, "MAX($field)", '', __METHOD__ );
$this->startTime = microtime( true );
}
$this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( DB_SLAVE, 'dump' );
+ $db = $this->lb->getConnection( DB_REPLICA, 'dump' );
// Discourage the server from disconnecting us if it takes a long time
// to read out the big ol' batch query.
* @return bool|string Revision ID, or false if not found or error
*/
function getRevIdForTime( Title $title, $timestamp ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$id = $dbr->selectField(
[ 'revision', 'page' ],
public function execute() {
$this->output( "Fetching redirects...\n" );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$result = $dbr->select(
[ 'page' ],
[ 'page_namespace', 'page_title', 'page_latest' ],
public function execute() {
$start = '';
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$numImages = 0;
$numGood = 0;
}
function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$maxUserId = 0;
do {
$this->output( "Finding spam on " . count( $wgLocalDatabases ) . " wikis\n" );
$found = false;
foreach ( $wgLocalDatabases as $wikiID ) {
- $dbr = $this->getDB( DB_SLAVE, [], $wikiID );
+ $dbr = $this->getDB( DB_REPLICA, [], $wikiID );
$count = $dbr->selectField( 'externallinks', 'COUNT(*)',
[ 'el_index' . $dbr->buildLike( $like ) ], __METHOD__ );
} else {
// Clean up spam on this wiki
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$res = $dbr->select( 'externallinks', [ 'DISTINCT el_from' ],
[ 'el_index' . $dbr->buildLike( $like ) ], __METHOD__ );
$count = $dbr->numRows( $res );
* @throws MWException
*/
public function runTable( $params ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
if ( array_diff( array_keys( $params ),
[ 'table', 'conds', 'index', 'callback' ] )
protected function fileExists( $name ) {
// XXX: Doesn't actually check for file existence, just presence of image record.
// This is reasonable, since cleanupImages.php only iterates over the image table.
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$row = $dbr->selectRow( 'image', [ 'img_name' ], [ 'img_name' => $name ], __METHOD__ );
return $row !== false;
public function execute() {
global $wgLocalDatabases, $wgMemc;
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$res = $dbr->select( 'interwiki', [ 'iw_prefix' ], false );
$prefixes = [];
foreach ( $res as $row ) {
public function execute() {
$pages = $this->getOption( 'maxpages' );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$totalsec = 0.0;
$scanned = 0;
global $wgUser;
$this->output( "Checking existence of old default messages..." );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$res = $dbr->select( [ 'page', 'revision' ],
[ 'page_namespace', 'page_title' ],
[
}
public function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$result = $dbr->select( [ 'pagelinks', 'page' ],
[
'page_id',
// 2. The Connection, through the load balancer.
try {
- $this->db = $this->lb->getConnection( DB_SLAVE, 'dump' );
+ $this->db = $this->lb->getConnection( DB_REPLICA, 'dump' );
} catch ( Exception $e ) {
throw new MWException( __METHOD__
. " rotating DB failed to obtain new database (" . $e->getMessage() . ")" );
* @param bool $shared True to pass shared-dir settings to hash func
*/
function fetchUsed( $shared ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$image = $dbr->tableName( 'image' );
$imagelinks = $dbr->tableName( 'imagelinks' );
* @param bool $shared True to pass shared-dir settings to hash func
*/
function fetchLocal( $shared ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$result = $dbr->select( 'image',
[ 'img_name' ],
'',
* note that the text string itself is *not* followed by newline
*/
public function execute() {
- $db = $this->getDB( DB_SLAVE );
+ $db = $this->getDB( DB_REPLICA );
$stdin = $this->getStdin();
while ( !feof( $stdin ) ) {
$line = fgets( $stdin );
return true;
}
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$namespaces = [
NS_MEDIAWIKI => $dbr->buildLike( $dbr->anyString(), '.json' ),
NS_USER => $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString(), '.json' ),
$title = null;
}
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
// See also SpecialDoubleRedirects
$tables = [
$this->output( "Could not find registration for #$id NULL\n" );
}
}
- $this->output( "Waiting for slaves..." );
+ $this->output( "Waiting for replica DBs..." );
wfWaitForSlaves();
$this->output( " done.\n" );
} while ( $res->numRows() >= $this->mBatchSize );
public $timestamp;
/**
- * A database slave object
+ * A database replica DB object
*
* @var object
*/
$this->identifier = $this->getOption( 'identifier', wfWikiID() );
$this->compress = $this->getOption( 'compress', 'yes' ) !== 'no';
$this->skipRedirects = $this->getOption( 'skip-redirects', false ) !== false;
- $this->dbr = $this->getDB( DB_SLAVE );
+ $this->dbr = $this->getDB( DB_REPLICA );
$this->generateNamespaces();
$this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() );
$this->findex = fopen( "{$this->fspath}sitemap-index-{$this->identifier}.xml", 'wb' );
--- /dev/null
+<?php
+/**
+ * Reports the hostname of a replica DB server.
+ *
+ * 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
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script that reports the hostname of a replica DB server.
+ *
+ * @ingroup Maintenance
+ */
+class GetSlaveServer extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addOption( "group", "Query group to check specifically" );
+ $this->addDescription( 'Report the hostname of a replica DB server' );
+ }
+
+ public function execute() {
+ global $wgAllDBsAreLocalhost;
+ if ( $wgAllDBsAreLocalhost ) {
+ $host = 'localhost';
+ } elseif ( $this->hasOption( 'group' ) ) {
+ $db = $this->getDB( DB_REPLICA, $this->getOption( 'group' ) );
+ $host = $db->getServer();
+ } else {
+ $lb = wfGetLB();
+ $i = $lb->getReaderIndex();
+ $host = $lb->getServerName( $i );
+ }
+ $this->output( "$host\n" );
+ }
+}
+
+$maintClass = "GetSlaveServer";
+require_once RUN_MAINTENANCE_IF_MAIN;
<?php
-/**
- * Reports the hostname of a slave server.
- *
- * 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
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once __DIR__ . '/Maintenance.php';
-
-/**
- * Maintenance script that reports the hostname of a slave server.
- *
- * @ingroup Maintenance
- */
-class GetSlaveServer extends Maintenance {
- public function __construct() {
- parent::__construct();
- $this->addOption( "group", "Query group to check specifically" );
- $this->addDescription( 'Report the hostname of a slave server' );
- }
-
- public function execute() {
- global $wgAllDBsAreLocalhost;
- if ( $wgAllDBsAreLocalhost ) {
- $host = 'localhost';
- } elseif ( $this->hasOption( 'group' ) ) {
- $db = $this->getDB( DB_SLAVE, $this->getOption( 'group' ) );
- $host = $db->getServer();
- } else {
- $lb = wfGetLB();
- $i = $lb->getReaderIndex();
- $host = $lb->getServerName( $i );
- }
- $this->output( "$host\n" );
- }
-}
-
-$maintClass = "GetSlaveServer";
-require_once RUN_MAINTENANCE_IF_MAIN;
+// B/C alias
+require_once ( __DIR__ . '/getReplicaServer.php' );
if ( $doProtect ) {
# Protect the file
- echo "\nWaiting for slaves...\n";
- // Wait for slaves.
+ echo "\nWaiting for replica DBs...\n";
+ // Wait for replica DBs.
sleep( 2.0 ); # Why this sleep?
wfWaitForSlaves();
parent::__construct();
$this->addOption( 'quick', 'Force the update to be done in a single query' );
$this->addOption( 'background', 'Force replication-friendly mode; may be inefficient but
- avoids locking tables or lagging slaves with large updates;
- calculates counts on a slave if possible.
+ avoids locking tables or lagging replica DBs with large updates;
+ calculates counts on a replica DB if possible.
Background mode will be automatically used if multiple servers are listed
in the load balancer, usually indicating a replication environment.' );
if ( $backgroundMode ) {
$this->output( "Using replication-friendly background mode...\n" );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$chunkSize = 100;
$lastUser = $dbr->selectField( 'user', 'MAX(user_id)', '', __METHOD__ );
break;
}
- // print status and let slaves catch up
+ // print status and let replica DBs catch up
$this->output( sprintf(
"id %d done (up to %d), %5.3f%% \r", $lastId, $endId, $lastId / $endId * 100 ) );
wfWaitForSlaves();
* @return int
*/
protected function doLenUpdates( $table, $idCol, $prefix, $fields ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$dbw = $this->getDB( DB_MASTER );
$start = $dbw->selectField( $table, "MIN($idCol)", false, __METHOD__ );
$end = $dbw->selectField( $table, "MAX($idCol)", false, __METHOD__ );
}
// Validate the timestamps
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$this->startTimestamp = $dbr->timestamp( $this->getOption( 'starttime' ) );
$this->endTimestamp = $dbr->timestamp( $this->getOption( 'endtime' ) );
*/
protected function purgeFromLogType( $type ) {
$repo = RepoGroup::singleton()->getLocalRepo();
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
foreach ( self::$typeMappings[$type] as $logType => $logActions ) {
$this->verbose( "Scanning for {$logType}/" . implode( ',', $logActions ) . "\n" );
}
}
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$minTime = $dbr->timestamp( $this->getOption( 'starttime' ) );
$maxTime = $dbr->timestamp( $this->getOption( 'endtime' ) );
* @param int|bool $namespace
*/
private function purgeNamespace( $namespace = false ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$startId = 0;
if ( $namespace === false ) {
$conds = [];
$this->output( "Building content page file cache from page {$start}!\n" );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$overwrite = $this->getOption( 'overwrite', false );
$start = ( $start > 0 )
? $start
$this->init( $count, $table );
$this->output( "Processing $table...\n" );
- $result = $this->getDB( DB_SLAVE )->select( $table, '*', [], __METHOD__ );
+ $result = $this->getDB( DB_REPLICA )->select( $table, '*', [], __METHOD__ );
foreach ( $result as $row ) {
$update = call_user_func( $callback, $row, null );
public function execute() {
// Rebuild the text index
- if ( $this->getDB( DB_SLAVE )->getType() != 'postgres' ) {
+ if ( $this->getDB( DB_REPLICA )->getType() != 'postgres' ) {
$this->output( "** Rebuilding fulltext search index (if you abort "
. "this will break searching; run this script again to fix):\n" );
$rebuildText = $this->runChild( 'RebuildTextIndex', 'rebuildtextindex.php' );
$end = str_replace( ' ', '_', $this->getOption( 'end', '' ) ); // page on img_name
$count = 0;
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
do {
$conds = [ "img_name > {$dbr->addQuotes( $start )}" ];
if ( strlen( $end ) ) {
$end = null, $redirectsOnly = false, $oldRedirectsOnly = false
) {
$reportingInterval = 100;
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
if ( $start === null ) {
$start = 1;
) {
wfWaitForSlaves();
$this->output( "Deleting illegal entries from the links tables...\n" );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
do {
// Find the start of the next chunk. This is based only
// on existent page_ids.
*/
private function dfnCheckInterval( $start = null, $end = null, $batchSize = 100 ) {
$dbw = $this->getDB( DB_MASTER );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$linksTables = [ // table name => page_id field
'pagelinks' => 'pl_from',
}
public function execute() {
$this->commit = $this->hasOption( 'commit' );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$dbw = $this->getDB( DB_MASTER );
$lastId = 0;
do {
# Do an initial scan for inactive accounts and report the result
$this->output( "Checking for unused user accounts...\n" );
$del = [];
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$res = $dbr->select( 'user', [ 'user_id', 'user_name', 'user_touched' ], '', __METHOD__ );
if ( $this->hasOption( 'ignore-groups' ) ) {
$excludedGroups = explode( ',', $this->getOption( 'ignore-groups' ) );
* @return bool
*/
private function isInactiveAccount( $id, $master = false ) {
- $dbo = $this->getDB( $master ? DB_MASTER : DB_SLAVE );
+ $dbo = $this->getDB( $master ? DB_MASTER : DB_REPLICA );
$checks = [
'revision' => 'rev',
'archive' => 'ar',
wfCountDown( 5 );
}
+ // We list user by user_id from one of the replica DBs
// We list user by user_id from one of the slave database
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$where = [];
if ( $this->nullsOnly ) {
* @return array
*/
private function getRollbackTitles( $user ) {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$titles = [];
$results = $dbr->select(
[ 'page', 'revision' ],
<?php
/**
- * Run a database query in batches and wait for slaves. This is used on large
+ * Run a database query in batches and wait for replica DBs. This is used on large
* wikis to prevent replication lag from going through the roof when executing
* large write queries.
*
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script to run a database query in batches and wait for slaves.
+ * Maintenance script to run a database query in batches and wait for replica DBs.
*
* @ingroup Maintenance
*/
public function __construct() {
parent::__construct();
$this->addDescription(
- "Run a query repeatedly until it affects 0 rows, and wait for slaves in between.\n" .
+ "Run a query repeatedly until it affects 0 rows, and wait for replica DBs in between.\n" .
"NOTE: You need to set a LIMIT clause yourself." );
}
}
public function execute() {
- global $wgCommandLineMode;
-
if ( $this->hasOption( 'procs' ) ) {
$procs = intval( $this->getOption( 'procs' ) );
if ( $procs < 1 || $procs > 1000 ) {
$outputJSON = ( $this->getOption( 'result' ) === 'json' );
$wait = $this->hasOption( 'wait' );
- // Enable DBO_TRX for atomicity; JobRunner manages transactions
- // and works well in web server mode already (@TODO: this is a hack)
- $wgCommandLineMode = false;
-
$runner = new JobRunner( LoggerFactory::getInstance( 'runJobs' ) );
if ( !$outputJSON ) {
$runner->setDebugHandler( [ $this, 'debugInternal' ] );
sleep( 1 );
}
-
- $wgCommandLineMode = true;
}
/**
'ss_images' => 'Number of images',
];
- // Get cached stats from slave database
- $dbr = $this->getDB( DB_SLAVE );
+ // Get cached stats from a replica DB
+ $dbr = $this->getDB( DB_REPLICA );
$stats = $dbr->selectRow( 'site_stats', '*', '', __METHOD__ );
// Get maximum size for each column
parent::__construct();
$this->addDescription( 'Send SQL queries to a MediaWiki database. ' .
'Takes a file name containing SQL as argument or runs interactively.' );
- $this->addOption( 'query', 'Run a single query instead of running interactively', false, true );
+ $this->addOption( 'query',
+ 'Run a single query instead of running interactively', false, true );
$this->addOption( 'cluster', 'Use an external cluster by name', false, true );
- $this->addOption( 'wikidb', 'The database wiki ID to use if not the current one', false, true );
- $this->addOption( 'slave', 'Use a slave server (either "any" or by name)', false, true );
+ $this->addOption( 'wikidb',
+ 'The database wiki ID to use if not the current one', false, true );
+ $this->addOption( 'replicadb',
+ 'Replica DB server to use instead of the master DB (can be "any")', false, true );
}
public function execute() {
$lb = wfGetLB( $wiki );
}
// Figure out which server to use
- if ( $this->hasOption( 'slave' ) ) {
- $server = $this->getOption( 'slave' );
- if ( $server === 'any' ) {
- $index = DB_SLAVE;
- } else {
- $index = null;
- $serverCount = $lb->getServerCount();
- for ( $i = 0; $i < $serverCount; ++$i ) {
- if ( $lb->getServerName( $i ) === $server ) {
- $index = $i;
- break;
- }
- }
- if ( $index === null ) {
- $this->error( "No slave server configured with the name '$server'.", 1 );
+ $replicaDB = $this->getOption( 'replicadb', $this->getOption( 'slave', '' ) );
+ if ( $replicaDB === 'any' ) {
+ $index = DB_REPLICA;
+ } elseif ( $replicaDB != '' ) {
+ $index = null;
+ $serverCount = $lb->getServerCount();
+ for ( $i = 0; $i < $serverCount; ++$i ) {
+ if ( $lb->getServerName( $i ) === $replicaDB ) {
+ $index = $i;
+ break;
}
}
+ if ( $index === null ) {
+ $this->error( "No replica DB server configured with the name '$server'.", 1 );
+ }
} else {
$index = DB_MASTER;
}
// Get a DB handle (with this wiki's DB selected) from the appropriate load balancer
$db = $lb->getConnection( $index, [], $wiki );
- if ( $this->hasOption( 'slave' ) && $db->getLBInfo( 'master' ) !== null ) {
- $this->error( "The server selected ({$db->getServer()}) is not a slave.", 1 );
+ if ( $replicaDB != '' && $db->getLBInfo( 'master' ) !== null ) {
+ $this->error( "The server selected ({$db->getServer()}) is not a replica DB.", 1 );
}
if ( $this->hasArg( 0 ) ) {
];
function check( $fix = false, $xml = '' ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( $fix ) {
print "Checking, will fix errors if possible...\n";
} else {
return;
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$dbw = wfGetDB( DB_MASTER );
$dbr->ping();
$dbw->ping();
}
// Find text row again
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$oldId = $dbr->selectField( 'revision', 'rev_text_id', [ 'rev_id' => $id ], __METHOD__ );
if ( !$oldId ) {
echo "Missing revision row for rev_id $id\n";
) {
$loadStyle = self::LS_CHUNKED;
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$dbw = $this->getDB( DB_MASTER );
# Set up external storage
}
public function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$row = $dbr->selectRow(
[ 'text', 'revision' ],
[ 'old_flags', 'old_text' ],
}
function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$dbw = $this->getDB( DB_MASTER );
$dryRun = $this->getOption( 'dry-run' );
unset( $this->mapCache[$key] );
}
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$map = [];
$res = $dbr->select( 'revision',
[ 'rev_id', 'rev_text_id' ],
function moveToExternal( $cluster, $maxID, $minID = 1 ) {
$fname = 'moveToExternal';
$dbw = wfGetDB( DB_MASTER );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$count = $maxID - $minID + 1;
$blockSize = 1000;
protected function &getDB( $cluster, $groups = [], $wiki = false ) {
$lb = wfGetLBFactory()->getExternalLB( $cluster );
- return $lb->getConnection( DB_SLAVE );
+ return $lb->getConnection( DB_REPLICA );
}
public function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
if ( !$dbr->tableExists( 'blob_orphans' ) ) {
$this->error( "blob_orphans doesn't seem to exist, need to run trackBlobs.php first", true );
}
*/
use MediaWiki\Logger\LegacyLogger;
+use MediaWiki\MediaWikiServices;
$optionsWithArgs = RecompressTracked::getOptionsWithArgs();
require __DIR__ . '/../commandLine.inc';
public $numProcs = 1;
public $numBatches = 0;
public $pageBlobClass, $orphanBlobClass;
- public $slavePipes, $slaveProcs, $prevSlaveId;
+ public $replicaPipes, $replicaProcs, $prevReplicaId;
public $copyOnly = false;
public $isChild = false;
- public $slaveId = false;
+ public $replicaId = false;
public $noCount = false;
public $debugLog, $infoLog, $criticalLog;
public $store;
private static $optionsWithArgs = [
'procs',
- 'slave-id',
+ 'replica-id',
'debug-log',
'info-log',
'critical-log'
'procs' => 'numProcs',
'copy-only' => 'copyOnly',
'child' => 'isChild',
- 'slave-id' => 'slaveId',
+ 'replica-id' => 'replicaId',
'debug-log' => 'debugLog',
'info-log' => 'infoLog',
'critical-log' => 'criticalLog',
$this->store = new ExternalStoreDB;
if ( !$this->isChild ) {
$GLOBALS['wgDebugLogPrefix'] = "RCT M: ";
- } elseif ( $this->slaveId !== false ) {
- $GLOBALS['wgDebugLogPrefix'] = "RCT {$this->slaveId}: ";
+ } elseif ( $this->replicaId !== false ) {
+ $GLOBALS['wgDebugLogPrefix'] = "RCT {$this->replicaId}: ";
}
$this->pageBlobClass = function_exists( 'xdiff_string_bdiff' ) ?
'DiffHistoryBlob' : 'ConcatenatedGzipHistoryBlob';
function logToFile( $msg, $file ) {
$header = '[' . date( 'd\TH:i:s' ) . '] ' . wfHostname() . ' ' . posix_getpid();
- if ( $this->slaveId !== false ) {
- $header .= "({$this->slaveId})";
+ if ( $this->replicaId !== false ) {
+ $header .= "({$this->replicaId})";
}
$header .= ' ' . wfWikiID();
LegacyLogger::emit( sprintf( "%-50s %s\n", $header, $msg ), $file );
}
/**
- * Wait until the selected slave has caught up to the master.
- * This allows us to use the slave for things that were committed in a
+ * Wait until the selected replica DB has caught up to the master.
+ * This allows us to use the replica DB for things that were committed in a
* previous part of this batch process.
*/
function syncDBs() {
$dbw = wfGetDB( DB_MASTER );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$pos = $dbw->getMasterPos();
$dbr->masterPosWait( $pos, 100000 );
}
}
$this->syncDBs();
- $this->startSlaveProcs();
+ $this->startReplicaProcs();
$this->doAllPages();
$this->doAllOrphans();
- $this->killSlaveProcs();
+ $this->killReplicaProcs();
}
/**
* @return bool
*/
function checkTrackingTable() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
if ( !$dbr->tableExists( 'blob_tracking' ) ) {
$this->critical( "Error: blob_tracking table does not exist" );
* This necessary because text recompression is slow: loading, compressing and
* writing are all slow.
*/
- function startSlaveProcs() {
+ function startReplicaProcs() {
$cmd = 'php ' . wfEscapeShellArg( __FILE__ );
foreach ( self::$cmdLineOptionMap as $cmdOption => $classOption ) {
- if ( $cmdOption == 'slave-id' ) {
+ if ( $cmdOption == 'replica-id' ) {
continue;
} elseif ( in_array( $cmdOption, self::$optionsWithArgs ) && isset( $this->$classOption ) ) {
$cmd .= " --$cmdOption " . wfEscapeShellArg( $this->$classOption );
' --wiki ' . wfEscapeShellArg( wfWikiID() ) .
' ' . call_user_func_array( 'wfEscapeShellArg', $this->destClusters );
- $this->slavePipes = $this->slaveProcs = [];
+ $this->replicaPipes = $this->replicaProcs = [];
for ( $i = 0; $i < $this->numProcs; $i++ ) {
$pipes = [];
$spec = [
[ 'file', 'php://stderr', 'w' ]
];
MediaWiki\suppressWarnings();
- $proc = proc_open( "$cmd --slave-id $i", $spec, $pipes );
+ $proc = proc_open( "$cmd --replica-id $i", $spec, $pipes );
MediaWiki\restoreWarnings();
if ( !$proc ) {
- $this->critical( "Error opening slave process: $cmd" );
+ $this->critical( "Error opening replica DB process: $cmd" );
exit( 1 );
}
- $this->slaveProcs[$i] = $proc;
- $this->slavePipes[$i] = $pipes[0];
+ $this->replicaProcs[$i] = $proc;
+ $this->replicaPipes[$i] = $pipes[0];
}
- $this->prevSlaveId = -1;
+ $this->prevReplicaId = -1;
}
/**
* Gracefully terminate the child processes
*/
- function killSlaveProcs() {
- $this->info( "Waiting for slave processes to finish..." );
+ function killReplicaProcs() {
+ $this->info( "Waiting for replica DB processes to finish..." );
for ( $i = 0; $i < $this->numProcs; $i++ ) {
- $this->dispatchToSlave( $i, 'quit' );
+ $this->dispatchToReplica( $i, 'quit' );
}
for ( $i = 0; $i < $this->numProcs; $i++ ) {
- $status = proc_close( $this->slaveProcs[$i] );
+ $status = proc_close( $this->replicaProcs[$i] );
if ( $status ) {
$this->critical( "Warning: child #$i exited with status $status" );
}
}
/**
- * Dispatch a command to the next available slave.
- * This may block until a slave finishes its work and becomes available.
+ * Dispatch a command to the next available replica DB.
+ * This may block until a replica DB finishes its work and becomes available.
*/
function dispatch( /*...*/ ) {
$args = func_get_args();
- $pipes = $this->slavePipes;
+ $pipes = $this->replicaPipes;
$numPipes = stream_select( $x = [], $pipes, $y = [], 3600 );
if ( !$numPipes ) {
- $this->critical( "Error waiting to write to slaves. Aborting" );
+ $this->critical( "Error waiting to write to replica DBs. Aborting" );
exit( 1 );
}
for ( $i = 0; $i < $this->numProcs; $i++ ) {
- $slaveId = ( $i + $this->prevSlaveId + 1 ) % $this->numProcs;
- if ( isset( $pipes[$slaveId] ) ) {
- $this->prevSlaveId = $slaveId;
- $this->dispatchToSlave( $slaveId, $args );
+ $replicaId = ( $i + $this->prevReplicaId + 1 ) % $this->numProcs;
+ if ( isset( $pipes[$replicaId] ) ) {
+ $this->prevReplicaId = $replicaId;
+ $this->dispatchToReplica( $replicaId, $args );
return;
}
}
/**
- * Dispatch a command to a specified slave
- * @param int $slaveId
+ * Dispatch a command to a specified replica DB
+ * @param int $replicaId
* @param array|string $args
*/
- function dispatchToSlave( $slaveId, $args ) {
+ function dispatchToReplica( $replicaId, $args ) {
$args = (array)$args;
$cmd = implode( ' ', $args );
- fwrite( $this->slavePipes[$slaveId], "$cmd\n" );
+ fwrite( $this->replicaPipes[$replicaId], "$cmd\n" );
}
/**
* Move all tracked pages to the new clusters
*/
function doAllPages() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$i = 0;
$startId = 0;
if ( $this->noCount ) {
if ( $current == $end || $this->numBatches >= $this->reportingInterval ) {
$this->numBatches = 0;
$this->info( "$label: $current / $end" );
- wfWaitForSlaves();
+ MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->waitForReplication();
}
}
* Move all orphan text to the new clusters
*/
function doAllOrphans() {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$startId = 0;
$i = 0;
if ( $this->noCount ) {
case 'quit':
return;
}
- wfWaitForSlaves();
+ MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->waitForReplication();
}
}
} else {
$titleText = '[deleted]';
}
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Finish any incomplete transactions
if ( !$this->copyOnly ) {
$startId = 0;
$trx = new CgzCopyTransaction( $this, $this->pageBlobClass );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
while ( true ) {
$res = $dbr->select(
[ 'blob_tracking', 'text' ],
$this->debug( "$titleText: committing blob with " . $trx->getSize() . " items" );
$trx->commit();
$trx = new CgzCopyTransaction( $this, $this->pageBlobClass );
- wfWaitForSlaves();
+ $lbFactory->waitForReplication();
}
}
}
* @param array $conds
*/
function finishIncompleteMoves( $conds ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
$startId = 0;
$conds = array_merge( $conds, [
$startId = $row->bt_text_id;
$this->moveTextRow( $row->bt_text_id, $row->bt_new_url );
if ( $row->bt_text_id % 10 == 0 ) {
- wfWaitForSlaves();
+ $lbFactory->waitForReplication();
}
}
}
$trx = new CgzCopyTransaction( $this, $this->orphanBlobClass );
- $res = wfGetDB( DB_SLAVE )->select(
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ $res = wfGetDB( DB_REPLICA )->select(
[ 'text', 'blob_tracking' ],
[ 'old_id', 'old_text', 'old_flags' ],
[
$this->debug( "[orphan]: committing blob with " . $trx->getSize() . " rows" );
$trx->commit();
$trx = new CgzCopyTransaction( $this, $this->orphanBlobClass );
- wfWaitForSlaves();
+ $lbFactory->waitForReplication();
}
}
$this->debug( "[orphan]: committing blob with " . $trx->getSize() . " rows" );
/* Check to see if the target text_ids have been moved already.
*
- * We originally read from the slave, so this can happen when a single
+ * We originally read from the replica DB, so this can happen when a single
* text_id is shared between multiple pages. It's rare, but possible
* if a delete/move/undelete cycle splits up a null edit.
*
function resolveStubs() {
$fname = 'resolveStubs';
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$maxID = $dbr->selectField( 'text', 'MAX(old_id)', false, $fname );
$blockSize = 10000;
$numBlocks = intval( $maxID / $blockSize ) + 1;
$stub = unserialize( $stubText );
$flags = explode( ',', $flags );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$dbw = wfGetDB( DB_MASTER );
if ( strtolower( get_class( $stub ) ) !== 'historyblobstub' ) {
class StorageTypeStats extends Maintenance {
function execute() {
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$endId = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
if ( !$endId ) {
}
$type = isset( $options['type'] ) ? $options['type'] : 'ConcatenatedGzipHistoryBlob';
-$dbr = $this->getDB( DB_SLAVE );
+$dbr = $this->getDB( DB_REPLICA );
$res = $dbr->select(
[ 'page', 'revision', 'text' ],
'*',
function checkIntegrity() {
echo "Doing integrity check...\n";
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
// Scan for HistoryBlobStub objects in the text table (bug 20757)
function getTextClause() {
if ( !$this->textClause ) {
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$this->textClause = '';
foreach ( $this->clusters as $cluster ) {
if ( $this->textClause != '' ) {
*/
function trackRevisions() {
$dbw = wfGetDB( DB_MASTER );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$textClause = $this->getTextClause();
$startId = 0;
* archive table counts as orphan for our purposes.
*/
function trackOrphanText() {
- # Wait until the blob_tracking table is available in the slave
+ # Wait until the blob_tracking table is available in the replica DB
$dbw = wfGetDB( DB_MASTER );
- $dbr = wfGetDB( DB_SLAVE );
+ $dbr = wfGetDB( DB_REPLICA );
$pos = $dbw->getMasterPos();
$dbr->masterPosWait( $pos, 100000 );
echo "Searching for orphan blobs in $cluster...\n";
$lb = wfGetLBFactory()->getExternalLB( $cluster );
try {
- $extDB = $lb->getConnection( DB_SLAVE );
+ $extDB = $lb->getConnection( DB_REPLICA );
} catch ( DBConnectionError $e ) {
if ( strpos( $e->error, 'Unknown database' ) !== false ) {
echo "No database on $cluster\n";
class TidyUpBug37714 extends Maintenance {
public function execute() {
// Search for all log entries which are about changing the visability of other log entries.
- $result = $this->getDB( DB_SLAVE )->select(
+ $result = $this->getDB( DB_REPLICA )->select(
'logging',
[ 'log_id', 'log_params' ],
[
foreach ( $result as $row ) {
$ids = explode( ',', explode( "\n", $row->log_params )[0] );
- $result = $this->getDB( DB_SLAVE )->select( // Work out what log entries were changed here.
+ $result = $this->getDB( DB_REPLICA )->select( // Work out what log entries were changed here.
'logging',
'log_type',
[ 'log_id' => $ids ],
if ( $this->hasOption( 'use-master' ) ) {
$dbr = $this->getDB( DB_MASTER );
} else {
- $dbr = $this->getDB( DB_SLAVE, 'vslow' );
+ $dbr = $this->getDB( DB_REPLICA, 'vslow' );
}
$counter = new SiteStatsInit( $dbr );
$result = $counter->articles();
*/
class UpdateCollation extends Maintenance {
const BATCH_SIZE = 100; // Number of rows to process in one batch
- const SYNC_INTERVAL = 5; // Wait for slaves after this many batches
+ const SYNC_INTERVAL = 5; // Wait for replica DBs after this many batches
public $sizeHistogram = [];
global $wgCategoryCollation;
$dbw = $this->getDB( DB_MASTER );
- $dbr = $this->getDB( DB_SLAVE );
+ $dbr = $this->getDB( DB_REPLICA );
$force = $this->getOption( 'force' );
$dryRun = $this->getOption( 'dry-run' );
$verboseStats = $this->getOption( 'verbose-stats' );
$this->output( "$count done.\n" );
if ( !$dryRun && ++$batchCount % self::SYNC_INTERVAL == 0 ) {
- $this->output( "Waiting for slaves ... " );
+ $this->output( "Waiting for replica DBs ... " );
wfWaitForSlaves();
$this->output( "done\n" );
}
} while ( !wfGetLB()->pingAll() );
$this->output( "Reconnected\n\n" );
}
- # Wait for the slave to catch up
+ # Wait for the replica DB to catch up
wfWaitForSlaves();
} else {
$this->output( "cheap, skipped\n" );
$this->output( $minutes . 'm ' );
}
$this->output( sprintf( "%.2fs\n", $seconds ) );
- # Wait for the slave to catch up
+ # Wait for the replica DB to catch up
wfWaitForSlaves();
}
}
$ret = [];
$defaultOptions = User::getDefaultOptions();
- // We list user by user_id from one of the slave database
- $dbr = wfGetDB( DB_SLAVE );
+ // We list user by user_id from one of the replica DBs
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->select( 'user',
[ 'user_id' ],
[],
private function CHANGER() {
$this->warn();
- // We list user by user_id from one of the slave database
- $dbr = wfGetDB( DB_SLAVE );
+ // We list user by user_id from one of the replica DBs
+ $dbr = wfGetDB( DB_REPLICA );
$result = $dbr->select( 'user',
[ 'user_id' ],
[],
// must be loaded on the bottom
'position' => 'bottom',
],
+ 'mediawiki.diff.styles' => [
+ 'position' => 'top',
+ 'styles' => [
+ 'resources/src/mediawiki/mediawiki.diff.styles.css',
+ 'resources/src/mediawiki/mediawiki.diff.styles.print.css' => [
+ 'media' => 'print'
+ ],
+ ],
+ 'targets' => [ 'desktop', 'mobile' ],
+ ],
'mediawiki.feedback' => [
'scripts' => 'resources/src/mediawiki/mediawiki.feedback.js',
'styles' => 'resources/src/mediawiki/mediawiki.feedback.css',
'jquery.spinner',
'jquery.textSelection',
'mediawiki.api',
- 'mediawiki.action.history.diff',
+ 'mediawiki.diff.styles',
'mediawiki.util',
'mediawiki.jqueryMsg',
],
'position' => 'top',
'styles' => 'resources/src/mediawiki.action/mediawiki.action.history.styles.css',
],
+ // using this module is deprecated, for diff styles use mediawiki.diff.styles instead
'mediawiki.action.history.diff' => [
'position' => 'top',
'styles' => [
- 'resources/src/mediawiki.action/mediawiki.action.history.diff.css',
- 'resources/src/mediawiki.action/mediawiki.action.history.diff.print.css' => [
+ 'resources/src/mediawiki/mediawiki.diff.styles.css',
+ 'resources/src/mediawiki/mediawiki.diff.styles.print.css' => [
'media' => 'print'
],
],
+++ /dev/null
-/*!
- * Diff rendering
- */
-table.diff {
- border: none;
- border-spacing: 4px;
- margin: 0;
- width: 100%;
- /* Ensure that colums are of equal width */
- table-layout: fixed;
-}
-
-table.diff td {
- padding: 0.33em 0.5em;
-}
-
-table.diff td.diff-marker {
- /* Compensate padding for increased font-size */
- padding: 0.25em;
-}
-
-table.diff col.diff-marker {
- width: 2%;
-}
-
-table.diff col.diff-content {
- width: 48%;
-}
-
-table.diff td div {
- /* Force-wrap very long lines such as URLs or page-widening char strings */
- word-wrap: break-word;
-}
-
-td.diff-otitle,
-td.diff-ntitle {
- text-align: center;
-}
-
-td.diff-lineno {
- font-weight: bold;
-}
-
-td.diff-marker {
- text-align: right;
- font-weight: bold;
- font-size: 1.25em;
- line-height: 1.2;
-}
-
-td.diff-addedline,
-td.diff-deletedline,
-td.diff-context {
- font-size: 88%;
- line-height: 1.6;
- vertical-align: top;
- white-space: -moz-pre-wrap;
- white-space: pre-wrap;
- border-style: solid;
- border-width: 1px 1px 1px 4px;
- border-radius: 0.33em;
-}
-
-td.diff-addedline {
- border-color: #a3d3ff;
-}
-
-td.diff-deletedline {
- border-color: #ffe49c;
-}
-
-td.diff-context {
- background: #f9f9f9;
- border-color: #e6e6e6;
- color: #333;
-}
-
-.diffchange {
- font-weight: bold;
- text-decoration: none;
-}
-
-td.diff-addedline .diffchange,
-td.diff-deletedline .diffchange {
- border-radius: 0.33em;
- padding: 0.25em 0;
-}
-
-td.diff-addedline .diffchange {
- background: #d8ecff;
-}
-
-td.diff-deletedline .diffchange {
- background: #feeec8;
-}
-
-/* Correct user & content directionality when viewing a diff */
-.diff-currentversion-title,
-.diff {
- direction: ltr;
- unicode-bidi: embed;
-}
-
-/* @noflip */ .diff-contentalign-right td {
- direction: rtl;
- unicode-bidi: embed;
-}
-
-/* @noflip */ .diff-contentalign-left td {
- direction: ltr;
- unicode-bidi: embed;
-}
-
-.diff-multi,
-.diff-otitle,
-.diff-ntitle,
-.diff-lineno {
- direction: ltr !important;
- unicode-bidi: embed;
-}
+++ /dev/null
-/*!
- * Diff rendering
- */
-td.diff-context,
-td.diff-addedline .diffchange,
-td.diff-deletedline .diffchange {
- background-color: transparent;
-}
-
-td.diff-addedline .diffchange {
- text-decoration: underline;
-}
-
-td.diff-deletedline .diffchange {
- text-decoration: line-through;
-}
--- /dev/null
+/*!
+ * Diff rendering
+ */
+table.diff {
+ border: none;
+ border-spacing: 4px;
+ margin: 0;
+ width: 100%;
+ /* Ensure that colums are of equal width */
+ table-layout: fixed;
+}
+
+table.diff td {
+ padding: 0.33em 0.5em;
+}
+
+table.diff td.diff-marker {
+ /* Compensate padding for increased font-size */
+ padding: 0.25em;
+}
+
+table.diff col.diff-marker {
+ width: 2%;
+}
+
+table.diff col.diff-content {
+ width: 48%;
+}
+
+table.diff td div {
+ /* Force-wrap very long lines such as URLs or page-widening char strings */
+ word-wrap: break-word;
+}
+
+td.diff-otitle,
+td.diff-ntitle {
+ text-align: center;
+}
+
+td.diff-lineno {
+ font-weight: bold;
+}
+
+td.diff-marker {
+ text-align: right;
+ font-weight: bold;
+ font-size: 1.25em;
+ line-height: 1.2;
+}
+
+td.diff-addedline,
+td.diff-deletedline,
+td.diff-context {
+ font-size: 88%;
+ line-height: 1.6;
+ vertical-align: top;
+ white-space: -moz-pre-wrap;
+ white-space: pre-wrap;
+ border-style: solid;
+ border-width: 1px 1px 1px 4px;
+ border-radius: 0.33em;
+}
+
+td.diff-addedline {
+ border-color: #a3d3ff;
+}
+
+td.diff-deletedline {
+ border-color: #ffe49c;
+}
+
+td.diff-context {
+ background: #f9f9f9;
+ border-color: #e6e6e6;
+ color: #333;
+}
+
+.diffchange {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+td.diff-addedline .diffchange,
+td.diff-deletedline .diffchange {
+ border-radius: 0.33em;
+ padding: 0.25em 0;
+}
+
+td.diff-addedline .diffchange {
+ background: #d8ecff;
+}
+
+td.diff-deletedline .diffchange {
+ background: #feeec8;
+}
+
+/* Correct user & content directionality when viewing a diff */
+.diff-currentversion-title,
+.diff {
+ direction: ltr;
+ unicode-bidi: embed;
+}
+
+/* @noflip */ .diff-contentalign-right td {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+
+/* @noflip */ .diff-contentalign-left td {
+ direction: ltr;
+ unicode-bidi: embed;
+}
+
+.diff-multi,
+.diff-otitle,
+.diff-ntitle,
+.diff-lineno {
+ direction: ltr !important;
+ unicode-bidi: embed;
+}
--- /dev/null
+/*!
+ * Diff rendering
+ */
+td.diff-context,
+td.diff-addedline .diffchange,
+td.diff-deletedline .diffchange {
+ background-color: transparent;
+}
+
+td.diff-addedline .diffchange {
+ text-decoration: underline;
+}
+
+td.diff-deletedline .diffchange {
+ text-decoration: line-through;
+}
hexRnds[ i ] = byteToHex[ rnds[ i ] ];
}
- // Concatenation of two random integers with entrophy n and m
- // returns a string with entrophy n+m if those strings are independent
+ // Concatenation of two random integers with entropy n and m
+ // returns a string with entropy n+m if those strings are independent
return hexRnds.join( '' );
},
$wgDBserver, $dbw->getLBInfo( 'clusterMasterHost' ), 'cluster master set' );
$dbr = $lb->getConnection( DB_SLAVE );
- $this->assertTrue( $dbr->getLBInfo( 'slave' ), 'slave shows as slave' );
+ $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' );
$this->assertEquals(
$wgDBserver, $dbr->getLBInfo( 'clusterMasterHost' ), 'cluster master set' );
$this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
$dbr = $lb->getConnection( DB_SLAVE );
- $this->assertTrue( $dbr->getLBInfo( 'slave' ), 'slave shows as slave' );
+ $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' );
$factory->shutdown();
$lb->closeAll();
}
public function testGetLinkClasses() {
+ $wanCache = ObjectCache::getMainWANInstance();
$titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
- $linkCache = new LinkCache( $titleFormatter );
+ $linkCache = new LinkCache( $titleFormatter, $wanCache );
$foobarTitle = new TitleValue( NS_MAIN, 'FooBar' );
$redirectTitle = new TitleValue( NS_MAIN, 'Redirect' );
$userTitle = new TitleValue( NS_USER, 'Someuser' );