31 $status = StatusValue::newGood();
33 $pathsByTypeByBucket = [];
35 foreach ( $pathsByType as $type => $paths ) {
36 foreach ( $paths as
$path ) {
37 if ( isset( $this->locksHeld[
$path][$type] ) ) {
38 ++$this->locksHeld[
$path][$type];
41 $pathsByTypeByBucket[$bucket][$type][] =
$path;
48 ksort( $pathsByTypeByBucket );
52 foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
55 if ( !$status->isOK() ) {
61 foreach ( $bucketPathsByType as $type => $paths ) {
62 foreach ( $paths as
$path ) {
63 $this->locksHeld[
$path][$type] = 1;
65 $lockedPaths[$type][] =
$path;
81 $status = StatusValue::newGood();
83 $pathsByTypeByBucket = [];
84 foreach ( $pathsByType as $type => $paths ) {
85 foreach ( $paths as
$path ) {
86 if ( !isset( $this->locksHeld[
$path][$type] ) ) {
87 $status->warning(
'lockmanager-notlocked',
$path );
89 --$this->locksHeld[
$path][$type];
91 if ( $this->locksHeld[
$path][$type] <= 0 ) {
92 unset( $this->locksHeld[
$path][$type] );
94 $pathsByTypeByBucket[$bucket][$type][] =
$path;
96 if ( $this->locksHeld[
$path] === [] ) {
97 unset( $this->locksHeld[
$path] );
105 foreach ( $pathsByTypeByBucket as $bucket => $bucketPathsByType ) {
108 if ( $this->locksHeld === [] ) {
110 $this->degradedBuckets = [];
127 function ( $lockSrv ) use ( $pathsByType ) {
143 function ( $lockSrv ) use ( $pathsByType ) {
158 $status = StatusValue::newGood();
161 $votesLeft = count( $this->srvsByBucket[$bucket] );
162 $quorum = floor( $votesLeft / 2 + 1 );
164 foreach ( $this->srvsByBucket[$bucket] as $lockSrv ) {
167 $status->warning(
'lockmanager-fail-svr-acquire', $lockSrv );
168 $this->degradedBuckets[$bucket] = time();
172 $status->merge( $callback( $lockSrv ) );
173 if ( !$status->isOK() ) {
177 if ( $yesVotes >= $quorum ) {
181 $votesNeeded = $quorum - $yesVotes;
182 if ( $votesNeeded > $votesLeft ) {
187 $status->setResult(
false );
200 $status = StatusValue::newGood();
203 $votesLeft = count( $this->srvsByBucket[$bucket] );
204 $quorum = floor( $votesLeft / 2 + 1 );
205 $isDegraded = isset( $this->degradedBuckets[$bucket] );
206 foreach ( $this->srvsByBucket[$bucket] as $lockSrv ) {
208 $status->warning(
'lockmanager-fail-svr-release', $lockSrv );
211 $status->merge( $callback( $lockSrv ) );
215 if ( $yesVotes >= $quorum && !$isDegraded ) {
222 $status->setResult( $yesVotes >= $quorum );
235 $prefix = substr( sha1(
$path ), 0, 2 );
236 return (
int)base_convert( $prefix, 16, 10 ) % count( $this->srvsByBucket );
278 final protected function doLock( array $paths, $type ) {
280 throw new LogicException( __METHOD__ .
': proxy class does not need this method.' );
284 final protected function doUnlock( array $paths, $type ) {
286 throw new LogicException( __METHOD__ .
': proxy class does not need this method.' );
290class_alias( QuorumLockManager::class,
'QuorumLockManager' );
Generic operation result class Has warning/error list, boolean status and arbitrary value.