Enforce lagged-slave read-only mode on the DB layer
authorAaron Schulz <aschulz@wikimedia.org>
Mon, 5 Oct 2015 05:15:33 +0000 (22:15 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Mon, 5 Oct 2015 05:41:19 +0000 (05:41 +0000)
* Most callers gracefully check wfReadOnly(),
  but fail in case they dont. This also catches
  foreign DBs which might slip through the cracks.
* Also remove useless wfDebug() call around
  mDoneWrites check as write queries show in
  the logs anyway.

Change-Id: I560ebd19c4eb2b3a040d4331702346440617cfaa

autoload.php
includes/db/Database.php
includes/db/DatabaseError.php
includes/db/loadbalancer/LoadBalancer.php

index 9c859b7..46f592a 100644 (file)
@@ -287,6 +287,7 @@ $wgAutoloadLocalClasses = array(
        'DBLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php',
        'DBMasterPos' => __DIR__ . '/includes/db/DatabaseUtility.php',
        'DBQueryError' => __DIR__ . '/includes/db/DatabaseError.php',
+       'DBReadOnlyError' => __DIR__ . '/includes/db/DatabaseError.php',
        'DBSiteStore' => __DIR__ . '/includes/site/DBSiteStore.php',
        'DBUnexpectedError' => __DIR__ . '/includes/db/DatabaseError.php',
        'DataUpdate' => __DIR__ . '/includes/deferred/DataUpdate.php',
index 05d1934..2c2d37f 100644 (file)
@@ -932,9 +932,9 @@ abstract class DatabaseBase implements IDatabase {
 
                $isWriteQuery = $this->isWriteQuery( $sql );
                if ( $isWriteQuery ) {
-                       if ( !$this->mDoneWrites ) {
-                               wfDebug( __METHOD__ . ': Writes done: ' .
-                                       DatabaseBase::generalizeSQL( $sql ) . "\n" );
+                       $reason = $this->getLBInfo( 'readOnlyReason' );
+                       if ( is_string( $reason ) ) {
+                               throw new DBReadOnlyError( $this, "Database is read-only: $reason" );
                        }
                        # Set a flag indicating that writes have been done
                        $this->mDoneWrites = microtime( true );
index 928de61..6453854 100644 (file)
@@ -451,3 +451,9 @@ This may indicate a bug in the software.',
  */
 class DBUnexpectedError extends DBError {
 }
+
+/**
+ * @ingroup Database
+ */
+class DBReadOnlyError extends DBError {
+}
index a0ef753..cd3b006 100644 (file)
@@ -546,6 +546,14 @@ class LoadBalancer {
                        $trxProf->recordConnection( $host, $dbname, $masterOnly );
                }
 
+               # Make master connections read only if in lagged slave mode
+               if ( $masterOnly && $this->getServerCount() > 1 && $this->getLaggedSlaveMode() ) {
+                       $conn->setLBInfo( 'readOnlyReason',
+                               'The database has been automatically locked ' .
+                               'while the slave database servers catch up to the master'
+                       );
+               }
+
                return $conn;
        }