MediaWiki  master
DBLockManager.php
Go to the documentation of this file.
1 <?php
27 
43 abstract class DBLockManager extends QuorumLockManager {
45  protected $dbServers; // (DB name => server config array)
47  protected $statusCache;
48 
49  protected $lockExpiry; // integer number of seconds
50  protected $safeDelay; // integer number of seconds
52  protected $conns = [];
53 
75  public function __construct( array $config ) {
76  parent::__construct( $config );
77 
78  $this->dbServers = $config['dbServers'];
79  // Sanitize srvsByBucket config to prevent PHP errors
80  $this->srvsByBucket = array_filter( $config['dbsByBucket'], 'is_array' );
81  $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive
82 
83  if ( isset( $config['lockExpiry'] ) ) {
84  $this->lockExpiry = $config['lockExpiry'];
85  } else {
86  $met = ini_get( 'max_execution_time' );
87  $this->lockExpiry = $met ?: 60; // use some sane amount if 0
88  }
89  $this->safeDelay = ( $this->lockExpiry <= 0 )
90  ? 60 // pick a safe-ish number to match DB timeout default
91  : $this->lockExpiry; // cover worst case
92 
93  // Tracks peers that couldn't be queried recently to avoid lengthy
94  // connection timeouts. This is useless if each bucket has one peer.
95  $this->statusCache = $config['srvCache'] ?? new HashBagOStuff();
96  }
97 
105  protected function getLocksOnServer( $lockSrv, array $pathsByType ) {
106  $status = StatusValue::newGood();
107  foreach ( $pathsByType as $type => $paths ) {
108  $status->merge( $this->doGetLocksOnServer( $lockSrv, $paths, $type ) );
109  }
110 
111  return $status;
112  }
113 
114  abstract protected function doGetLocksOnServer( $lockSrv, array $paths, $type );
115 
120  protected function freeLocksOnServer( $lockSrv, array $pathsByType ) {
121  return StatusValue::newGood();
122  }
123 
129  protected function isServerUp( $lockSrv ) {
130  if ( !$this->cacheCheckFailures( $lockSrv ) ) {
131  return false; // recent failure to connect
132  }
133  try {
134  $this->getConnection( $lockSrv );
135  } catch ( DBError $e ) {
136  $this->cacheRecordFailure( $lockSrv );
137 
138  return false; // failed to connect
139  }
140 
141  return true;
142  }
143 
152  protected function getConnection( $lockDb ) {
153  if ( !isset( $this->conns[$lockDb] ) ) {
154  if ( $this->dbServers[$lockDb] instanceof IDatabase ) {
155  // Direct injected connection hande for $lockDB
156  $db = $this->dbServers[$lockDb];
157  } elseif ( is_array( $this->dbServers[$lockDb] ) ) {
158  // Parameters to construct a new database connection
159  $config = $this->dbServers[$lockDb];
160  $config['flags'] = ( $config['flags'] ?? 0 );
161  $config['flags'] &= ~( IDatabase::DBO_TRX | IDatabase::DBO_DEFAULT );
162  $db = Database::factory( $config['type'], $config );
163  } else {
164  throw new UnexpectedValueException( "No server called '$lockDb'." );
165  }
166  # If the connection drops, try to avoid letting the DB rollback
167  # and release the locks before the file operations are finished.
168  # This won't handle the case of DB server restarts however.
169  $options = [];
170  if ( $this->lockExpiry > 0 ) {
171  $options['connTimeout'] = $this->lockExpiry;
172  }
173  $db->setSessionOptions( $options );
174  $this->initConnection( $lockDb, $db );
175 
176  $this->conns[$lockDb] = $db;
177  }
178 
179  return $this->conns[$lockDb];
180  }
181 
190  protected function initConnection( $lockDb, IDatabase $db ) {
191  }
192 
200  protected function cacheCheckFailures( $lockDb ) {
201  return ( $this->safeDelay > 0 )
202  ? !$this->statusCache->get( $this->getMissKey( $lockDb ) )
203  : true;
204  }
205 
212  protected function cacheRecordFailure( $lockDb ) {
213  return ( $this->safeDelay > 0 )
214  ? $this->statusCache->set( $this->getMissKey( $lockDb ), 1, $this->safeDelay )
215  : true;
216  }
217 
224  protected function getMissKey( $lockDb ) {
225  return 'dblockmanager:downservers:' . str_replace( ' ', '_', $lockDb );
226  }
227 
231  public function __destruct() {
232  $this->releaseAllLocks();
233  foreach ( $this->conns as $db ) {
234  $db->close( __METHOD__ );
235  }
236  }
237 }
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:50
HashBagOStuff
Simple store for keeping values in an associative array for the current process.
Definition: HashBagOStuff.php:32
DBLockManager\isServerUp
isServerUp( $lockSrv)
Definition: DBLockManager.php:129
DBLockManager\cacheRecordFailure
cacheRecordFailure( $lockDb)
Log a lock request failure to the cache.
Definition: DBLockManager.php:212
DBLockManager\__construct
__construct(array $config)
Construct a new instance from configuration.
Definition: DBLockManager.php:75
DBLockManager\getLocksOnServer
getLocksOnServer( $lockSrv, array $pathsByType)
Definition: DBLockManager.php:105
BagOStuff
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:71
DBLockManager\$safeDelay
$safeDelay
Definition: DBLockManager.php:50
Wikimedia\Rdbms\DBError
Database error base class @newable Stable to extend.
Definition: DBError.php:32
DBO_TRX
const DBO_TRX
Definition: defines.php:12
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
DBLockManager\cacheCheckFailures
cacheCheckFailures( $lockDb)
Checks if the DB has not recently had connection/query errors.
Definition: DBLockManager.php:200
QuorumLockManager
Version of LockManager that uses a quorum from peer servers for locks.
Definition: QuorumLockManager.php:32
QuorumLockManager\releaseAllLocks
releaseAllLocks()
Release all locks that this session is holding.
DBLockManager\getMissKey
getMissKey( $lockDb)
Get a cache key for recent query misses for a DB.
Definition: DBLockManager.php:224
DBLockManager\doGetLocksOnServer
doGetLocksOnServer( $lockSrv, array $paths, $type)
DBLockManager\initConnection
initConnection( $lockDb, IDatabase $db)
Do additional initialization for new lock DB connection @stable to override.
Definition: DBLockManager.php:190
DBLockManager\$dbServers
array[] IDatabase[] $dbServers
Map of (DB names => server config or IDatabase)
Definition: DBLockManager.php:45
DBLockManager\$conns
IDatabase[] $conns
Map Database connections (DB name => Database)
Definition: DBLockManager.php:52
DBLockManager\__destruct
__destruct()
Make sure remaining locks get cleared for sanity.
Definition: DBLockManager.php:231
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
DBLockManager\$lockExpiry
$lockExpiry
Definition: DBLockManager.php:49
DBLockManager\$statusCache
BagOStuff $statusCache
Definition: DBLockManager.php:47
DBLockManager\getConnection
getConnection( $lockDb)
Get (or reuse) a connection to a lock DB.
Definition: DBLockManager.php:152
DBLockManager
Version of LockManager based on using named/row DB locks.
Definition: DBLockManager.php:43
DBO_DEFAULT
const DBO_DEFAULT
Definition: defines.php:13
DBLockManager\freeLocksOnServer
freeLocksOnServer( $lockSrv, array $pathsByType)
Get a connection to a lock server and release locks on $paths.Subclasses must effectively implement t...
Definition: DBLockManager.php:120
$type
$type
Definition: testCompression.php:52