DefaultBackend.php 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <?php
  2. /**
  3. * Lock backend shared methods.
  4. */
  5. abstract class Redis_Lock_DefaultBackend
  6. extends Redis_AbstractBackend
  7. implements Redis_Lock_BackendInterface
  8. {
  9. /**
  10. * Current page lock token identifier.
  11. *
  12. * @var string
  13. */
  14. protected $_lockId;
  15. /**
  16. * Existing locks for this page.
  17. *
  18. * @var array
  19. */
  20. protected $_locks = array();
  21. /**
  22. * Default implementation from actual Drupal core.
  23. *
  24. * @see Redis_Lock_BackendInterface::lockWait()
  25. */
  26. public function lockWait($name, $delay = 30) {
  27. // Pause the process for short periods between calling
  28. // lock_may_be_available(). This prevents hitting the database with constant
  29. // database queries while waiting, which could lead to performance issues.
  30. // However, if the wait period is too long, there is the potential for a
  31. // large number of processes to be blocked waiting for a lock, especially
  32. // if the item being rebuilt is commonly requested. To address both of these
  33. // concerns, begin waiting for 25ms, then add 25ms to the wait period each
  34. // time until it reaches 500ms. After this point polling will continue every
  35. // 500ms until $delay is reached.
  36. // $delay is passed in seconds, but we will be using usleep(), which takes
  37. // microseconds as a parameter. Multiply it by 1 million so that all
  38. // further numbers are equivalent.
  39. $delay = (int) $delay * 1000000;
  40. // Begin sleeping at 25ms.
  41. $sleep = 25000;
  42. while ($delay > 0) {
  43. // This function should only be called by a request that failed to get a
  44. // lock, so we sleep first to give the parallel request a chance to finish
  45. // and release the lock.
  46. usleep($sleep);
  47. // After each sleep, increase the value of $sleep until it reaches
  48. // 500ms, to reduce the potential for a lock stampede.
  49. $delay = $delay - $sleep;
  50. $sleep = min(500000, $sleep + 25000, $delay);
  51. if ($this->lockMayBeAvailable($name)) {
  52. // No longer need to wait.
  53. return FALSE;
  54. }
  55. }
  56. // The caller must still wait longer to get the lock.
  57. return TRUE;
  58. }
  59. /**
  60. * Default implementation from actual Drupal core.
  61. *
  62. * @see Redis_Lock_BackendInterface::getLockId()
  63. */
  64. public function getLockId() {
  65. if (!isset($this->_lockId)) {
  66. $this->_lockId = uniqid(mt_rand(), TRUE);
  67. // We only register a shutdown function if a lock is used.
  68. drupal_register_shutdown_function('lock_release_all', $this->_lockId);
  69. }
  70. return $this->_lockId;
  71. }
  72. /**
  73. * Generate a redis key name for the current lock name
  74. */
  75. public function getKey($name = null) {
  76. if (null === $name) {
  77. return parent::getKey('lock');
  78. } else {
  79. return parent::getKey(array('lock', $name));
  80. }
  81. }
  82. }