MediaWiki REL1_39
MySqlLockManager.php
Go to the documentation of this file.
1<?php
2
5
20 protected $lockTypeMap = [
21 self::LOCK_SH => self::LOCK_SH,
22 self::LOCK_UW => self::LOCK_SH,
23 self::LOCK_EX => self::LOCK_EX
24 ];
25
26 public function __construct( array $config ) {
27 parent::__construct( $config );
28
29 $this->session = substr( $this->session, 0, 31 ); // fit to field
30 }
31
32 protected function initConnection( $lockDb, IDatabase $db ) {
33 # Let this transaction see lock rows from other transactions
34 $db->query( "SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;", __METHOD__ );
35 # Do everything in a transaction as it all gets rolled back eventually
36 $db->startAtomic( __CLASS__ );
37 }
38
49 protected function doGetLocksOnServer( $lockSrv, array $paths, $type ) {
50 $status = StatusValue::newGood();
51
52 $db = $this->getConnection( $lockSrv ); // checked in isServerUp()
53
54 $keys = []; // list of hash keys for the paths
55 $data = []; // list of rows to insert
56 $checkEXKeys = []; // list of hash keys that this has no EX lock on
57 # Build up values for INSERT clause
58 foreach ( $paths as $path ) {
59 $key = $this->sha1Base36Absolute( $path );
60 $keys[] = $key;
61 $data[] = [ 'fls_key' => $key, 'fls_session' => $this->session ];
62 if ( !isset( $this->locksHeld[$path][self::LOCK_EX] ) ) {
63 $checkEXKeys[] = $key; // this has no EX lock on $key itself
64 }
65 }
66
67 # Block new writers (both EX and SH locks leave entries here)...
68 $db->insert( 'filelocks_shared', $data, __METHOD__, [ 'IGNORE' ] );
69 # Actually do the locking queries...
70 if ( $type == self::LOCK_SH ) { // reader locks
71 # Bail if there are any existing writers...
72 if ( count( $checkEXKeys ) ) {
73 $blocked = (bool)$db->selectField( 'filelocks_exclusive', '1',
74 [ 'fle_key' => $checkEXKeys ],
75 __METHOD__
76 );
77 } else {
78 $blocked = false;
79 }
80 # Other prospective writers that haven't yet updated filelocks_exclusive
81 # will recheck filelocks_shared after doing so and bail due to this entry.
82 } else { // writer locks
83 $encSession = $db->addQuotes( $this->session );
84 # Bail if there are any existing writers...
85 # This may detect readers, but the safe check for them is below.
86 # Note: if two writers come at the same time, both bail :)
87 $blocked = (bool)$db->selectField( 'filelocks_shared', '1',
88 [ 'fls_key' => $keys, "fls_session != $encSession" ],
89 __METHOD__
90 );
91 if ( !$blocked ) {
92 # Build up values for INSERT clause
93 $data = [];
94 foreach ( $keys as $key ) {
95 $data[] = [ 'fle_key' => $key ];
96 }
97 # Block new readers/writers...
98 $db->insert( 'filelocks_exclusive', $data, __METHOD__ );
99 # Bail if there are any existing readers...
100 $blocked = (bool)$db->selectField( 'filelocks_shared', '1',
101 [ 'fls_key' => $keys, "fls_session != $encSession" ],
102 __METHOD__
103 );
104 }
105 }
106
107 if ( $blocked ) {
108 $status->fatal( 'lockmanager-fail-conflict' );
109 }
110
111 return $status;
112 }
113
118 protected function releaseAllLocks() {
119 $status = StatusValue::newGood();
120
121 foreach ( $this->conns as $lockDb => $db ) {
122 if ( $db->trxLevel() ) { // in transaction
123 try {
124 $db->rollback( __METHOD__ ); // finish transaction and kill any rows
125 } catch ( DBError $e ) {
126 $status->fatal( 'lockmanager-fail-db-release', $lockDb );
127 }
128 }
129 }
130
131 return $status;
132 }
133}
Version of LockManager based on using named/row DB locks.
getConnection( $lockDb)
Get (or reuse) a connection to a lock DB.
string $session
Random 32-char hex number.
const LOCK_SH
Lock types; stronger locks have higher values.
sha1Base36Absolute( $path)
Get the base 36 SHA-1 of a string, padded to 31 digits.
MySQL version of DBLockManager that supports shared locks.
array $lockTypeMap
Mapping of lock types to the type actually used.
initConnection( $lockDb, IDatabase $db)
Do additional initialization for new lock DB connection.
__construct(array $config)
Construct a new instance from configuration.
doGetLocksOnServer( $lockSrv, array $paths, $type)
Get a connection to a lock DB and acquire locks on $paths.
Database error base class.
Definition DBError.php:31
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:39
query( $sql, $fname=__METHOD__, $flags=0)
Run an SQL query statement and return the result.
startAtomic( $fname=__METHOD__, $cancelable=self::ATOMIC_NOT_CANCELABLE)
Begin an atomic section of SQL statements.