AbstractLockingProvider.php 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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(protected int $ttl) {
  24. }
  25. /** @inheritDoc */
  26. protected function hasAcquiredLock(string $path, int $type): bool {
  27. if ($type === self::LOCK_SHARED) {
  28. return isset($this->acquiredLocks['shared'][$path]) && $this->acquiredLocks['shared'][$path] > 0;
  29. } else {
  30. return isset($this->acquiredLocks['exclusive'][$path]) && $this->acquiredLocks['exclusive'][$path] === true;
  31. }
  32. }
  33. /** @inheritDoc */
  34. protected function markAcquire(string $path, int $targetType): void {
  35. if ($targetType === self::LOCK_SHARED) {
  36. if (!isset($this->acquiredLocks['shared'][$path])) {
  37. $this->acquiredLocks['shared'][$path] = 0;
  38. }
  39. $this->acquiredLocks['shared'][$path]++;
  40. } else {
  41. $this->acquiredLocks['exclusive'][$path] = true;
  42. }
  43. }
  44. /** @inheritDoc */
  45. protected function markRelease(string $path, int $type): void {
  46. if ($type === self::LOCK_SHARED) {
  47. if (isset($this->acquiredLocks['shared'][$path]) and $this->acquiredLocks['shared'][$path] > 0) {
  48. $this->acquiredLocks['shared'][$path]--;
  49. if ($this->acquiredLocks['shared'][$path] === 0) {
  50. unset($this->acquiredLocks['shared'][$path]);
  51. }
  52. }
  53. } elseif ($type === self::LOCK_EXCLUSIVE) {
  54. unset($this->acquiredLocks['exclusive'][$path]);
  55. }
  56. }
  57. /** @inheritDoc */
  58. protected function markChange(string $path, int $targetType): void {
  59. if ($targetType === self::LOCK_SHARED) {
  60. unset($this->acquiredLocks['exclusive'][$path]);
  61. if (!isset($this->acquiredLocks['shared'][$path])) {
  62. $this->acquiredLocks['shared'][$path] = 0;
  63. }
  64. $this->acquiredLocks['shared'][$path]++;
  65. } elseif ($targetType === self::LOCK_EXCLUSIVE) {
  66. $this->acquiredLocks['exclusive'][$path] = true;
  67. $this->acquiredLocks['shared'][$path]--;
  68. }
  69. }
  70. /** @inheritDoc */
  71. public function releaseAll(): void {
  72. foreach ($this->acquiredLocks['shared'] as $path => $count) {
  73. for ($i = 0; $i < $count; $i++) {
  74. $this->releaseLock($path, self::LOCK_SHARED);
  75. }
  76. }
  77. foreach ($this->acquiredLocks['exclusive'] as $path => $hasLock) {
  78. $this->releaseLock($path, self::LOCK_EXCLUSIVE);
  79. }
  80. }
  81. protected function getOwnSharedLockCount(string $path): int {
  82. return $this->acquiredLocks['shared'][$path] ?? 0;
  83. }
  84. }