dba = $dba; $this->pid = isset($pid) ? $pid : getmypid(); } /** * (@inheritdoc) */ public function acquire($key, $timeout = 120, $ttl = Duration::FIVE_MINUTES) { $got_lock = false; $start = time(); do { $this->dba->lock('locks'); $lock = $this->dba->selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); if ($this->dba->isResult($lock)) { if ($lock['locked']) { // We want to lock something that was already locked by us? So we got the lock. if ($lock['pid'] == $this->pid) { $got_lock = true; } } if (!$lock['locked']) { $this->dba->update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]); $got_lock = true; } } else { $this->dba->insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]); $got_lock = true; $this->markAcquire($key); } $this->dba->unlock(); if (!$got_lock && ($timeout > 0)) { usleep(rand(100000, 2000000)); } } while (!$got_lock && ((time() - $start) < $timeout)); return $got_lock; } /** * (@inheritdoc) */ public function release($key, $override = false) { if ($override) { $where = ['name' => $key]; } else { $where = ['name' => $key, 'pid' => $this->pid]; } if ($this->dba->exists('locks', $where)) { $return = $this->dba->delete('locks', $where); } else { $return = false; } $this->markRelease($key); return $return; } /** * (@inheritdoc) */ public function releaseAll($override = false) { $success = parent::releaseAll($override); if ($override) { $where = ['1 = 1']; } else { $where = ['pid' => $this->pid]; } $return = $this->dba->delete('locks', $where); $this->acquiredLocks = []; return $return && $success; } /** * (@inheritdoc) */ public function isLocked($key) { $lock = $this->dba->selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]); if ($this->dba->isResult($lock)) { return $lock['locked'] !== false; } else { return false; } } /** * {@inheritDoc} */ public function getName() { return Type::DATABASE; } /** * {@inheritDoc} */ public function getLocks(string $prefix = '') { if (empty($prefix)) { $where = ['`expires` >= ?', DateTimeFormat::utcNow()]; } else { $where = ['`expires` >= ? AND `name` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix]; } $stmt = $this->dba->select('locks', ['name'], $where); $keys = []; while ($key = $this->dba->fetch($stmt)) { array_push($keys, $key['name']); } $this->dba->close($stmt); return $keys; } }