MediaWiki
REL1_22
|
00001 <?php 00039 class LSLockManager extends QuorumLockManager { 00041 protected $lockTypeMap = array( 00042 self::LOCK_SH => self::LOCK_SH, 00043 self::LOCK_UW => self::LOCK_SH, 00044 self::LOCK_EX => self::LOCK_EX 00045 ); 00046 00048 protected $lockServers; // (server name => server config array) 00049 00051 protected $conns = array(); 00052 00053 protected $connTimeout; // float number of seconds 00054 protected $session = ''; // random SHA-1 string 00055 00071 public function __construct( array $config ) { 00072 parent::__construct( $config ); 00073 00074 $this->lockServers = $config['lockServers']; 00075 // Sanitize srvsByBucket config to prevent PHP errors 00076 $this->srvsByBucket = array_filter( $config['srvsByBucket'], 'is_array' ); 00077 $this->srvsByBucket = array_values( $this->srvsByBucket ); // consecutive 00078 00079 if ( isset( $config['connTimeout'] ) ) { 00080 $this->connTimeout = $config['connTimeout']; 00081 } else { 00082 $this->connTimeout = 3; // use some sane amount 00083 } 00084 00085 $this->session = wfRandomString( 32 ); // 128 bits 00086 } 00087 00092 protected function getLocksOnServer( $lockSrv, array $paths, $type ) { 00093 $status = Status::newGood(); 00094 00095 // Send out the command and get the response... 00096 $type = ( $type == self::LOCK_SH ) ? 'SH' : 'EX'; 00097 $keys = array_unique( array_map( array( $this, 'sha1Base36Absolute' ), $paths ) ); 00098 $response = $this->sendCommand( $lockSrv, 'ACQUIRE', $type, $keys ); 00099 00100 if ( $response !== 'ACQUIRED' ) { 00101 foreach ( $paths as $path ) { 00102 $status->fatal( 'lockmanager-fail-acquirelock', $path ); 00103 } 00104 } 00105 00106 return $status; 00107 } 00108 00113 protected function freeLocksOnServer( $lockSrv, array $paths, $type ) { 00114 $status = Status::newGood(); 00115 00116 // Send out the command and get the response... 00117 $type = ( $type == self::LOCK_SH ) ? 'SH' : 'EX'; 00118 $keys = array_unique( array_map( array( $this, 'sha1Base36Absolute' ), $paths ) ); 00119 $response = $this->sendCommand( $lockSrv, 'RELEASE', $type, $keys ); 00120 00121 if ( $response !== 'RELEASED' ) { 00122 foreach ( $paths as $path ) { 00123 $status->fatal( 'lockmanager-fail-releaselock', $path ); 00124 } 00125 } 00126 00127 return $status; 00128 } 00129 00134 protected function releaseAllLocks() { 00135 $status = Status::newGood(); 00136 00137 foreach ( $this->conns as $lockSrv => $conn ) { 00138 $response = $this->sendCommand( $lockSrv, 'RELEASE_ALL', '', array() ); 00139 if ( $response !== 'RELEASED_ALL' ) { 00140 $status->fatal( 'lockmanager-fail-svr-release', $lockSrv ); 00141 } 00142 } 00143 00144 return $status; 00145 } 00146 00151 protected function isServerUp( $lockSrv ) { 00152 return (bool)$this->getConnection( $lockSrv ); 00153 } 00154 00164 protected function sendCommand( $lockSrv, $action, $type, $values ) { 00165 $conn = $this->getConnection( $lockSrv ); 00166 if ( !$conn ) { 00167 return false; // no connection 00168 } 00169 $authKey = $this->lockServers[$lockSrv]['authKey']; 00170 // Build of the command as a flat string... 00171 $values = implode( '|', $values ); 00172 $key = hash_hmac( 'sha1', "{$this->session}\n{$action}\n{$type}\n{$values}", $authKey ); 00173 // Send out the command... 00174 if ( fwrite( $conn, "{$this->session}:$key:$action:$type:$values\n" ) === false ) { 00175 return false; 00176 } 00177 // Get the response... 00178 $response = fgets( $conn ); 00179 if ( $response === false ) { 00180 return false; 00181 } 00182 return trim( $response ); 00183 } 00184 00191 protected function getConnection( $lockSrv ) { 00192 if ( !isset( $this->conns[$lockSrv] ) ) { 00193 $cfg = $this->lockServers[$lockSrv]; 00194 wfSuppressWarnings(); 00195 $errno = $errstr = ''; 00196 $conn = fsockopen( $cfg['host'], $cfg['port'], $errno, $errstr, $this->connTimeout ); 00197 wfRestoreWarnings(); 00198 if ( $conn === false ) { 00199 return null; 00200 } 00201 $sec = floor( $this->connTimeout ); 00202 $usec = floor( ( $this->connTimeout - floor( $this->connTimeout ) ) * 1e6 ); 00203 stream_set_timeout( $conn, $sec, $usec ); 00204 $this->conns[$lockSrv] = $conn; 00205 } 00206 return $this->conns[$lockSrv]; 00207 } 00208 00212 function __destruct() { 00213 $this->releaseAllLocks(); 00214 foreach ( $this->conns as $conn ) { 00215 fclose( $conn ); 00216 } 00217 } 00218 }