MediaWiki REL1_34
DBLockManager.php
Go to the documentation of this file.
1<?php
27
42abstract class DBLockManager extends QuorumLockManager {
44 protected $dbServers; // (DB name => server config array)
46 protected $statusCache;
47
48 protected $lockExpiry; // integer number of seconds
49 protected $safeDelay; // integer number of seconds
51 protected $conns = [];
52
73 public function __construct( array $config ) {
74 parent::__construct( $config );
75
76 $this->dbServers = $config['dbServers'];
77 // Sanitize srvsByBucket config to prevent PHP errors
78 $this->srvsByBucket = array_filter( $config['dbsByBucket'], 'is_array' );
79 $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive
80
81 if ( isset( $config['lockExpiry'] ) ) {
82 $this->lockExpiry = $config['lockExpiry'];
83 } else {
84 $met = ini_get( 'max_execution_time' );
85 $this->lockExpiry = $met ?: 60; // use some sane amount if 0
86 }
87 $this->safeDelay = ( $this->lockExpiry <= 0 )
88 ? 60 // pick a safe-ish number to match DB timeout default
89 : $this->lockExpiry; // cover worst case
90
91 // Tracks peers that couldn't be queried recently to avoid lengthy
92 // connection timeouts. This is useless if each bucket has one peer.
93 $this->statusCache = $config['srvCache'] ?? new HashBagOStuff();
94 }
95
102 protected function getLocksOnServer( $lockSrv, array $pathsByType ) {
103 $status = StatusValue::newGood();
104 foreach ( $pathsByType as $type => $paths ) {
105 $status->merge( $this->doGetLocksOnServer( $lockSrv, $paths, $type ) );
106 }
107
108 return $status;
109 }
110
111 abstract protected function doGetLocksOnServer( $lockSrv, array $paths, $type );
112
113 protected function freeLocksOnServer( $lockSrv, array $pathsByType ) {
114 return StatusValue::newGood();
115 }
116
122 protected function isServerUp( $lockSrv ) {
123 if ( !$this->cacheCheckFailures( $lockSrv ) ) {
124 return false; // recent failure to connect
125 }
126 try {
127 $this->getConnection( $lockSrv );
128 } catch ( DBError $e ) {
129 $this->cacheRecordFailure( $lockSrv );
130
131 return false; // failed to connect
132 }
133
134 return true;
135 }
136
145 protected function getConnection( $lockDb ) {
146 if ( !isset( $this->conns[$lockDb] ) ) {
147 if ( $this->dbServers[$lockDb] instanceof IDatabase ) {
148 // Direct injected connection hande for $lockDB
149 $db = $this->dbServers[$lockDb];
150 } elseif ( is_array( $this->dbServers[$lockDb] ) ) {
151 // Parameters to construct a new database connection
152 $config = $this->dbServers[$lockDb];
153 $config['flags'] = ( $config['flags'] ?? 0 );
154 $config['flags'] &= ~( IDatabase::DBO_TRX | IDatabase::DBO_DEFAULT );
155 $db = Database::factory( $config['type'], $config );
156 } else {
157 throw new UnexpectedValueException( "No server called '$lockDb'." );
158 }
159 # If the connection drops, try to avoid letting the DB rollback
160 # and release the locks before the file operations are finished.
161 # This won't handle the case of DB server restarts however.
162 $options = [];
163 if ( $this->lockExpiry > 0 ) {
164 $options['connTimeout'] = $this->lockExpiry;
165 }
166 $db->setSessionOptions( $options );
167 $this->initConnection( $lockDb, $db );
168
169 $this->conns[$lockDb] = $db;
170 }
171
172 return $this->conns[$lockDb];
173 }
174
182 protected function initConnection( $lockDb, IDatabase $db ) {
183 }
184
192 protected function cacheCheckFailures( $lockDb ) {
193 return ( $this->safeDelay > 0 )
194 ? !$this->statusCache->get( $this->getMissKey( $lockDb ) )
195 : true;
196 }
197
204 protected function cacheRecordFailure( $lockDb ) {
205 return ( $this->safeDelay > 0 )
206 ? $this->statusCache->set( $this->getMissKey( $lockDb ), 1, $this->safeDelay )
207 : true;
208 }
209
216 protected function getMissKey( $lockDb ) {
217 return 'dblockmanager:downservers:' . str_replace( ' ', '_', $lockDb );
218 }
219
223 function __destruct() {
224 $this->releaseAllLocks();
225 foreach ( $this->conns as $db ) {
226 $db->close();
227 }
228 }
229}
Class representing a cache/ephemeral data store.
Definition BagOStuff.php:63
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.
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.
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.
Definition DBError.php:30
Relational database abstraction object.
Definition Database.php:49
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:38