PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/includes/filerepo/backend/lockmanager/LockManager.php

https://bitbucket.org/brunodefraine/mediawiki
PHP | 182 lines | 64 code | 18 blank | 100 comment | 2 complexity | b5894992d085cfb98ca55c05a1c2798c MD5 | raw file
Possible License(s): GPL-2.0, Apache-2.0, LGPL-3.0
  1. <?php
  2. /**
  3. * @defgroup LockManager Lock management
  4. * @ingroup FileBackend
  5. */
  6. /**
  7. * @file
  8. * @ingroup LockManager
  9. * @author Aaron Schulz
  10. */
  11. /**
  12. * Class for handling resource locking.
  13. *
  14. * Locks on resource keys can either be shared or exclusive.
  15. *
  16. * Implementations must keep track of what is locked by this proccess
  17. * in-memory and support nested locking calls (using reference counting).
  18. * At least LOCK_UW and LOCK_EX must be implemented. LOCK_SH can be a no-op.
  19. * Locks should either be non-blocking or have low wait timeouts.
  20. *
  21. * Subclasses should avoid throwing exceptions at all costs.
  22. *
  23. * @ingroup LockManager
  24. * @since 1.19
  25. */
  26. abstract class LockManager {
  27. /** @var Array Mapping of lock types to the type actually used */
  28. protected $lockTypeMap = array(
  29. self::LOCK_SH => self::LOCK_SH,
  30. self::LOCK_UW => self::LOCK_EX, // subclasses may use self::LOCK_SH
  31. self::LOCK_EX => self::LOCK_EX
  32. );
  33. /** @var Array Map of (resource path => lock type => count) */
  34. protected $locksHeld = array();
  35. /* Lock types; stronger locks have higher values */
  36. const LOCK_SH = 1; // shared lock (for reads)
  37. const LOCK_UW = 2; // shared lock (for reads used to write elsewhere)
  38. const LOCK_EX = 3; // exclusive lock (for writes)
  39. /**
  40. * Construct a new instance from configuration
  41. *
  42. * @param $config Array
  43. */
  44. public function __construct( array $config ) {}
  45. /**
  46. * Lock the resources at the given abstract paths
  47. *
  48. * @param $paths Array List of resource names
  49. * @param $type integer LockManager::LOCK_* constant
  50. * @return Status
  51. */
  52. final public function lock( array $paths, $type = self::LOCK_EX ) {
  53. return $this->doLock( array_unique( $paths ), $this->lockTypeMap[$type] );
  54. }
  55. /**
  56. * Unlock the resources at the given abstract paths
  57. *
  58. * @param $paths Array List of storage paths
  59. * @param $type integer LockManager::LOCK_* constant
  60. * @return Status
  61. */
  62. final public function unlock( array $paths, $type = self::LOCK_EX ) {
  63. return $this->doUnlock( array_unique( $paths ), $this->lockTypeMap[$type] );
  64. }
  65. /**
  66. * Get the base 36 SHA-1 of a string, padded to 31 digits
  67. *
  68. * @param $path string
  69. * @return string
  70. */
  71. final protected static function sha1Base36( $path ) {
  72. return wfBaseConvert( sha1( $path ), 16, 36, 31 );
  73. }
  74. /**
  75. * Lock resources with the given keys and lock type
  76. *
  77. * @param $paths Array List of storage paths
  78. * @param $type integer LockManager::LOCK_* constant
  79. * @return string
  80. */
  81. abstract protected function doLock( array $paths, $type );
  82. /**
  83. * Unlock resources with the given keys and lock type
  84. *
  85. * @param $paths Array List of storage paths
  86. * @param $type integer LockManager::LOCK_* constant
  87. * @return string
  88. */
  89. abstract protected function doUnlock( array $paths, $type );
  90. }
  91. /**
  92. * Self releasing locks
  93. *
  94. * LockManager helper class to handle scoped locks, which
  95. * release when an object is destroyed or goes out of scope.
  96. *
  97. * @ingroup LockManager
  98. * @since 1.19
  99. */
  100. class ScopedLock {
  101. /** @var LockManager */
  102. protected $manager;
  103. /** @var Status */
  104. protected $status;
  105. /** @var Array List of resource paths*/
  106. protected $paths;
  107. protected $type; // integer lock type
  108. /**
  109. * @param $manager LockManager
  110. * @param $paths Array List of storage paths
  111. * @param $type integer LockManager::LOCK_* constant
  112. * @param $status Status
  113. */
  114. protected function __construct(
  115. LockManager $manager, array $paths, $type, Status $status
  116. ) {
  117. $this->manager = $manager;
  118. $this->paths = $paths;
  119. $this->status = $status;
  120. $this->type = $type;
  121. }
  122. protected function __clone() {}
  123. /**
  124. * Get a ScopedLock object representing a lock on resource paths.
  125. * Any locks are released once this object goes out of scope.
  126. * The status object is updated with any errors or warnings.
  127. *
  128. * @param $manager LockManager
  129. * @param $paths Array List of storage paths
  130. * @param $type integer LockManager::LOCK_* constant
  131. * @param $status Status
  132. * @return ScopedLock|null Returns null on failure
  133. */
  134. public static function factory(
  135. LockManager $manager, array $paths, $type, Status $status
  136. ) {
  137. $lockStatus = $manager->lock( $paths, $type );
  138. $status->merge( $lockStatus );
  139. if ( $lockStatus->isOK() ) {
  140. return new self( $manager, $paths, $type, $status );
  141. }
  142. return null;
  143. }
  144. function __destruct() {
  145. $wasOk = $this->status->isOK();
  146. $this->status->merge( $this->manager->unlock( $this->paths, $this->type ) );
  147. if ( $wasOk ) {
  148. // Make sure status is OK, despite any unlockFiles() fatals
  149. $this->status->setResult( true, $this->status->value );
  150. }
  151. }
  152. }
  153. /**
  154. * Simple version of LockManager that does nothing
  155. * @since 1.19
  156. */
  157. class NullLockManager extends LockManager {
  158. protected function doLock( array $paths, $type ) {
  159. return Status::newGood();
  160. }
  161. protected function doUnlock( array $paths, $type ) {
  162. return Status::newGood();
  163. }
  164. }