MediaWiki REL1_35
DBLockManager.php
Go to the documentation of this file.
1<?php
27
43abstract 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}
Class representing a cache/ephemeral data store.
Definition BagOStuff.php:71
Version of LockManager based on using named/row DB locks.
__destruct()
Make sure remaining locks get cleared for sanity.
isServerUp( $lockSrv)
cacheRecordFailure( $lockDb)
Log a lock request failure to the cache.
IDatabase[] $conns
Map Database connections (DB name => Database)
freeLocksOnServer( $lockSrv, array $pathsByType)
Get a connection to a lock server and release locks on $paths.Subclasses must effectively implement t...
getMissKey( $lockDb)
Get a cache key for recent query misses for a DB.
getConnection( $lockDb)
Get (or reuse) a connection to a lock DB.
initConnection( $lockDb, IDatabase $db)
Do additional initialization for new lock DB connection Stable to override.
getLocksOnServer( $lockSrv, array $pathsByType)
array[] IDatabase[] $dbServers
Map of (DB names => server config or IDatabase)
__construct(array $config)
Construct a new instance from configuration.
doGetLocksOnServer( $lockSrv, array $paths, $type)
cacheCheckFailures( $lockDb)
Checks if the DB has not recently had connection/query errors.
BagOStuff $statusCache
Simple store for keeping values in an associative array for the current process.
Version of LockManager that uses a quorum from peer servers for locks.
releaseAllLocks()
Release all locks that this session is holding.
Database error base class @newable Stable to extend.
Definition DBError.php:32
Relational database abstraction object.
Definition Database.php:50
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:38