X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Flibs%2Flockmanager%2FQuorumLockManager.php;h=6478a61b1477f43c35ad15b3b697d1d37070f7b0;hb=54c93f1d384cd5accd2db2ebbb911e4d627c2980;hp=950b283670bf44d5b96d503fff5a81ddcafa781b;hpb=3ff807dd9a8e1e787b1290f610a5dff5739cd53c;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/lockmanager/QuorumLockManager.php b/includes/libs/lockmanager/QuorumLockManager.php index 950b283670..6478a61b14 100644 --- a/includes/libs/lockmanager/QuorumLockManager.php +++ b/includes/libs/lockmanager/QuorumLockManager.php @@ -38,7 +38,7 @@ abstract class QuorumLockManager extends LockManager { final protected function doLockByType( array $pathsByType ) { $status = StatusValue::newGood(); - $pathsToLock = []; // (bucket => type => paths) + $pathsByTypeByBucket = []; // (bucket => type => paths) // Get locks that need to be acquired (buckets => locks)... foreach ( $pathsByType as $type => $paths ) { foreach ( $paths as $path ) { @@ -46,23 +46,27 @@ abstract class QuorumLockManager extends LockManager { ++$this->locksHeld[$path][$type]; } else { $bucket = $this->getBucketFromPath( $path ); - $pathsToLock[$bucket][$type][] = $path; + $pathsByTypeByBucket[$bucket][$type][] = $path; } } } + // Acquire locks in each bucket in bucket order to reduce contention. Any blocking + // mutexes during the acquisition step will not involve circular waiting on buckets. + ksort( $pathsByTypeByBucket ); + $lockedPaths = []; // files locked in this attempt (type => paths) // Attempt to acquire these locks... - foreach ( $pathsToLock as $bucket => $pathsToLockByType ) { + foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) { // Try to acquire the locks for this bucket - $status->merge( $this->doLockingRequestBucket( $bucket, $pathsToLockByType ) ); + $status->merge( $this->doLockingRequestBucket( $bucket, $bucketPathsByType ) ); if ( !$status->isOK() ) { $status->merge( $this->doUnlockByType( $lockedPaths ) ); return $status; } // Record these locks as active - foreach ( $pathsToLockByType as $type => $paths ) { + foreach ( $bucketPathsByType as $type => $paths ) { foreach ( $paths as $path ) { $this->locksHeld[$path][$type] = 1; // locked // Keep track of what locks were made in this attempt @@ -77,7 +81,7 @@ abstract class QuorumLockManager extends LockManager { protected function doUnlockByType( array $pathsByType ) { $status = StatusValue::newGood(); - $pathsToUnlock = []; // (bucket => type => paths) + $pathsByTypeByBucket = []; // (bucket => type => paths) foreach ( $pathsByType as $type => $paths ) { foreach ( $paths as $path ) { if ( !isset( $this->locksHeld[$path][$type] ) ) { @@ -88,7 +92,7 @@ abstract class QuorumLockManager extends LockManager { if ( $this->locksHeld[$path][$type] <= 0 ) { unset( $this->locksHeld[$path][$type] ); $bucket = $this->getBucketFromPath( $path ); - $pathsToUnlock[$bucket][$type][] = $path; + $pathsByTypeByBucket[$bucket][$type][] = $path; } if ( $this->locksHeld[$path] === [] ) { unset( $this->locksHeld[$path] ); // no SH or EX locks left for key @@ -99,8 +103,8 @@ abstract class QuorumLockManager extends LockManager { // Remove these specific locks if possible, or at least release // all locks once this process is currently not holding any locks. - foreach ( $pathsToUnlock as $bucket => $pathsToUnlockByType ) { - $status->merge( $this->doUnlockingRequestBucket( $bucket, $pathsToUnlockByType ) ); + foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) { + $status->merge( $this->doUnlockingRequestBucket( $bucket, $bucketPathsByType ) ); } if ( $this->locksHeld === [] ) { $status->merge( $this->releaseAllLocks() );