X-Git-Url: https://git.cyclocoop.org/%27.WWW_URL.%27admin/?a=blobdiff_plain;f=includes%2Flibs%2Flockmanager%2FQuorumLockManager.php;h=6478a61b1477f43c35ad15b3b697d1d37070f7b0;hb=c5afd254bd0147de752d72de40548842cf5afeed;hp=1d2e21aa0d70a3c99be8f71f8f8720426ce048cc;hpb=237d3271fd313ebe09858a5c442a91216a7b61cf;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/libs/lockmanager/QuorumLockManager.php b/includes/libs/lockmanager/QuorumLockManager.php index 1d2e21aa0d..6478a61b14 100644 --- a/includes/libs/lockmanager/QuorumLockManager.php +++ b/includes/libs/lockmanager/QuorumLockManager.php @@ -35,18 +35,10 @@ abstract class QuorumLockManager extends LockManager { /** @var array Map of degraded buckets */ protected $degradedBuckets = []; // (bucket index => UNIX timestamp) - final protected function doLock( array $paths, $type ) { - return $this->doLockByType( [ $type => $paths ] ); - } - - final protected function doUnlock( array $paths, $type ) { - return $this->doUnlockByType( [ $type => $paths ] ); - } - - protected function doLockByType( array $pathsByType ) { + 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 ) { @@ -54,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 @@ -85,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] ) ) { @@ -96,9 +92,9 @@ 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 ( !count( $this->locksHeld[$path] ) ) { + if ( $this->locksHeld[$path] === [] ) { unset( $this->locksHeld[$path] ); // no SH or EX locks left for key } } @@ -107,10 +103,10 @@ 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 ( !count( $this->locksHeld ) ) { + if ( $this->locksHeld === [] ) { $status->merge( $this->releaseAllLocks() ); $this->degradedBuckets = []; // safe to retry the normal quorum } @@ -278,4 +274,12 @@ abstract class QuorumLockManager extends LockManager { * @return StatusValue */ abstract protected function releaseAllLocks(); + + final protected function doLock( array $paths, $type ) { + throw new LogicException( __METHOD__ . ': proxy class does not need this method.' ); + } + + final protected function doUnlock( array $paths, $type ) { + throw new LogicException( __METHOD__ . ': proxy class does not need this method.' ); + } }