AbstractLockingProvider.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2016, ownCloud, Inc.
  5. *
  6. * @author Robin Appelman <robin@icewind.nl>
  7. *
  8. * @license AGPL-3.0
  9. *
  10. * This code is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License, version 3,
  12. * as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License, version 3,
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>
  21. *
  22. */
  23. namespace OC\Lock;
  24. use OCP\Lock\ILockingProvider;
  25. /**
  26. * Base locking provider that keeps track of locks acquired during the current request
  27. * to release any left over locks at the end of the request
  28. */
  29. abstract class AbstractLockingProvider implements ILockingProvider {
  30. /** @var int $ttl */
  31. protected $ttl; // how long until we clear stray locks in seconds
  32. protected $acquiredLocks = [
  33. 'shared' => [],
  34. 'exclusive' => []
  35. ];
  36. /**
  37. * Check if we've locally acquired a lock
  38. *
  39. * @param string $path
  40. * @param int $type
  41. * @return bool
  42. */
  43. protected function hasAcquiredLock(string $path, int $type): bool {
  44. if ($type === self::LOCK_SHARED) {
  45. return isset($this->acquiredLocks['shared'][$path]) && $this->acquiredLocks['shared'][$path] > 0;
  46. } else {
  47. return isset($this->acquiredLocks['exclusive'][$path]) && $this->acquiredLocks['exclusive'][$path] === true;
  48. }
  49. }
  50. /**
  51. * Mark a locally acquired lock
  52. *
  53. * @param string $path
  54. * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
  55. */
  56. protected function markAcquire(string $path, int $type) {
  57. if ($type === self::LOCK_SHARED) {
  58. if (!isset($this->acquiredLocks['shared'][$path])) {
  59. $this->acquiredLocks['shared'][$path] = 0;
  60. }
  61. $this->acquiredLocks['shared'][$path]++;
  62. } else {
  63. $this->acquiredLocks['exclusive'][$path] = true;
  64. }
  65. }
  66. /**
  67. * Mark a release of a locally acquired lock
  68. *
  69. * @param string $path
  70. * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE
  71. */
  72. protected function markRelease(string $path, int $type) {
  73. if ($type === self::LOCK_SHARED) {
  74. if (isset($this->acquiredLocks['shared'][$path]) and $this->acquiredLocks['shared'][$path] > 0) {
  75. $this->acquiredLocks['shared'][$path]--;
  76. if ($this->acquiredLocks['shared'][$path] === 0) {
  77. unset($this->acquiredLocks['shared'][$path]);
  78. }
  79. }
  80. } else if ($type === self::LOCK_EXCLUSIVE) {
  81. unset($this->acquiredLocks['exclusive'][$path]);
  82. }
  83. }
  84. /**
  85. * Change the type of an existing tracked lock
  86. *
  87. * @param string $path
  88. * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE
  89. */
  90. protected function markChange(string $path, int $targetType) {
  91. if ($targetType === self::LOCK_SHARED) {
  92. unset($this->acquiredLocks['exclusive'][$path]);
  93. if (!isset($this->acquiredLocks['shared'][$path])) {
  94. $this->acquiredLocks['shared'][$path] = 0;
  95. }
  96. $this->acquiredLocks['shared'][$path]++;
  97. } else if ($targetType === self::LOCK_EXCLUSIVE) {
  98. $this->acquiredLocks['exclusive'][$path] = true;
  99. $this->acquiredLocks['shared'][$path]--;
  100. }
  101. }
  102. /**
  103. * release all lock acquired by this instance which were marked using the mark* methods
  104. */
  105. public function releaseAll() {
  106. foreach ($this->acquiredLocks['shared'] as $path => $count) {
  107. for ($i = 0; $i < $count; $i++) {
  108. $this->releaseLock($path, self::LOCK_SHARED);
  109. }
  110. }
  111. foreach ($this->acquiredLocks['exclusive'] as $path => $hasLock) {
  112. $this->releaseLock($path, self::LOCK_EXCLUSIVE);
  113. }
  114. }
  115. protected function getOwnSharedLockCount(string $path) {
  116. return isset($this->acquiredLocks['shared'][$path]) ? $this->acquiredLocks['shared'][$path] : 0;
  117. }
  118. }