DatabaseLock.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. <?php
  2. namespace Illuminate\Cache;
  3. use Illuminate\Database\Connection;
  4. use Illuminate\Database\QueryException;
  5. class DatabaseLock extends Lock
  6. {
  7. /**
  8. * The database connection instance.
  9. *
  10. * @var \Illuminate\Database\Connection
  11. */
  12. protected $connection;
  13. /**
  14. * The database table name.
  15. *
  16. * @var string
  17. */
  18. protected $table;
  19. /**
  20. * The prune probability odds.
  21. *
  22. * @var array
  23. */
  24. protected $lottery;
  25. /**
  26. * The default number of seconds that a lock should be held.
  27. *
  28. * @var int
  29. */
  30. protected $defaultTimeoutInSeconds;
  31. /**
  32. * Create a new lock instance.
  33. *
  34. * @param \Illuminate\Database\Connection $connection
  35. * @param string $table
  36. * @param string $name
  37. * @param int $seconds
  38. * @param string|null $owner
  39. * @param array $lottery
  40. * @return void
  41. */
  42. public function __construct(Connection $connection, $table, $name, $seconds, $owner = null, $lottery = [2, 100], $defaultTimeoutInSeconds = 86400)
  43. {
  44. parent::__construct($name, $seconds, $owner);
  45. $this->connection = $connection;
  46. $this->table = $table;
  47. $this->lottery = $lottery;
  48. $this->defaultTimeoutInSeconds = $defaultTimeoutInSeconds;
  49. }
  50. /**
  51. * Attempt to acquire the lock.
  52. *
  53. * @return bool
  54. */
  55. public function acquire()
  56. {
  57. try {
  58. $this->connection->table($this->table)->insert([
  59. 'key' => $this->name,
  60. 'owner' => $this->owner,
  61. 'expiration' => $this->expiresAt(),
  62. ]);
  63. $acquired = true;
  64. } catch (QueryException) {
  65. $updated = $this->connection->table($this->table)
  66. ->where('key', $this->name)
  67. ->where(function ($query) {
  68. return $query->where('owner', $this->owner)->orWhere('expiration', '<=', time());
  69. })->update([
  70. 'owner' => $this->owner,
  71. 'expiration' => $this->expiresAt(),
  72. ]);
  73. $acquired = $updated >= 1;
  74. }
  75. if (random_int(1, $this->lottery[1]) <= $this->lottery[0]) {
  76. $this->connection->table($this->table)->where('expiration', '<=', time())->delete();
  77. }
  78. return $acquired;
  79. }
  80. /**
  81. * Get the UNIX timestamp indicating when the lock should expire.
  82. *
  83. * @return int
  84. */
  85. protected function expiresAt()
  86. {
  87. $lockTimeout = $this->seconds > 0 ? $this->seconds : $this->defaultTimeoutInSeconds;
  88. return time() + $lockTimeout;
  89. }
  90. /**
  91. * Release the lock.
  92. *
  93. * @return bool
  94. */
  95. public function release()
  96. {
  97. if ($this->isOwnedByCurrentProcess()) {
  98. $this->connection->table($this->table)
  99. ->where('key', $this->name)
  100. ->where('owner', $this->owner)
  101. ->delete();
  102. return true;
  103. }
  104. return false;
  105. }
  106. /**
  107. * Releases this lock in disregard of ownership.
  108. *
  109. * @return void
  110. */
  111. public function forceRelease()
  112. {
  113. $this->connection->table($this->table)
  114. ->where('key', $this->name)
  115. ->delete();
  116. }
  117. /**
  118. * Returns the owner value written into the driver for this lock.
  119. *
  120. * @return string
  121. */
  122. protected function getCurrentOwner()
  123. {
  124. return optional($this->connection->table($this->table)->where('key', $this->name)->first())->owner;
  125. }
  126. /**
  127. * Get the name of the database connection being used to manage the lock.
  128. *
  129. * @return string
  130. */
  131. public function getConnectionName()
  132. {
  133. return $this->connection->getName();
  134. }
  135. }