AbstractLockingProvider.php 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-only
  7. */
  8. namespace OC\Lock;
  9. use OCP\Lock\ILockingProvider;
  10. /**
  11. * Base locking provider that keeps track of locks acquired during the current request
  12. * to release any leftover locks at the end of the request
  13. */
  14. abstract class AbstractLockingProvider implements ILockingProvider {
  15. protected array $acquiredLocks = [
  16. 'shared' => [],
  17. 'exclusive' => []
  18. ];
  19. /**
  20. *
  21. * @param int $ttl how long until we clear stray locks in seconds
  22. */
  23. public function __construct(
  24. protected int $ttl,
  25. ) {
  26. }
  27. /** @inheritDoc */
  28. protected function hasAcquiredLock(string $path, int $type): bool {
  29. if ($type === self::LOCK_SHARED) {
  30. return isset($this->acquiredLocks['shared'][$path]) && $this->acquiredLocks['shared'][$path] > 0;
  31. } else {
  32. return isset($this->acquiredLocks['exclusive'][$path]) && $this->acquiredLocks['exclusive'][$path] === true;
  33. }
  34. }
  35. /** @inheritDoc */
  36. protected function markAcquire(string $path, int $targetType): void {
  37. if ($targetType === self::LOCK_SHARED) {
  38. if (!isset($this->acquiredLocks['shared'][$path])) {
  39. $this->acquiredLocks['shared'][$path] = 0;
  40. }
  41. $this->acquiredLocks['shared'][$path]++;
  42. } else {
  43. $this->acquiredLocks['exclusive'][$path] = true;
  44. }
  45. }
  46. /** @inheritDoc */
  47. protected function markRelease(string $path, int $type): void {
  48. if ($type === self::LOCK_SHARED) {
  49. if (isset($this->acquiredLocks['shared'][$path]) and $this->acquiredLocks['shared'][$path] > 0) {
  50. $this->acquiredLocks['shared'][$path]--;
  51. if ($this->acquiredLocks['shared'][$path] === 0) {
  52. unset($this->acquiredLocks['shared'][$path]);
  53. }
  54. }
  55. } elseif ($type === self::LOCK_EXCLUSIVE) {
  56. unset($this->acquiredLocks['exclusive'][$path]);
  57. }
  58. }
  59. /** @inheritDoc */
  60. protected function markChange(string $path, int $targetType): void {
  61. if ($targetType === self::LOCK_SHARED) {
  62. unset($this->acquiredLocks['exclusive'][$path]);
  63. if (!isset($this->acquiredLocks['shared'][$path])) {
  64. $this->acquiredLocks['shared'][$path] = 0;
  65. }
  66. $this->acquiredLocks['shared'][$path]++;
  67. } elseif ($targetType === self::LOCK_EXCLUSIVE) {
  68. $this->acquiredLocks['exclusive'][$path] = true;
  69. $this->acquiredLocks['shared'][$path]--;
  70. }
  71. }
  72. /** @inheritDoc */
  73. public function releaseAll(): void {
  74. foreach ($this->acquiredLocks['shared'] as $path => $count) {
  75. for ($i = 0; $i < $count; $i++) {
  76. $this->releaseLock($path, self::LOCK_SHARED);
  77. }
  78. }
  79. foreach ($this->acquiredLocks['exclusive'] as $path => $hasLock) {
  80. $this->releaseLock($path, self::LOCK_EXCLUSIVE);
  81. }
  82. }
  83. protected function getOwnSharedLockCount(string $path): int {
  84. return $this->acquiredLocks['shared'][$path] ?? 0;
  85. }
  86. }