/** * @return bool|mixed */ public function acquire() { if ($this->sessionId) { throw new \Exception('Resources are acquired.'); } $result = true; // Start a session $session = $this->session->create('{"Name": "semaphor", "LockDelay":0, "TTL": "' . $this->ttl . 's"}')->json(); $this->sessionId = $session['ID']; $lockedResources = []; foreach ($this->resources as $resource) { if (false === $this->kv->put($this->getResourceKey($resource, $this->sessionId), '', ['acquire' => $this->sessionId])->json()) { $result = false; } else { $lockedResources[] = $resource; $semaphoreMetaDataValue = ['limit' => $resource->limit, 'sessions' => []]; // get actuall metadata $semaphorDataItems = $this->kv->get($this->getResourceKeyPrefix($resource), ['recurse' => true])->json(); foreach ($semaphorDataItems as $key => $item) { if ($item['Key'] == $this->getResourceKey($resource, $this->metaDataKey)) { $semaphoreMetaDataActual = $item; $semaphoreMetaDataActual['Value'] = json_decode(base64_decode($semaphoreMetaDataActual['Value']), true); unset($semaphorDataItems[$key]); break; } } // build new metadata if (isset($semaphoreMetaDataActual)) { foreach ($semaphorDataItems as $item) { if (isset($item['Session'])) { if (isset($semaphoreMetaDataActual['Value']['sessions'][$item['Session']])) { $semaphoreMetaDataValue['sessions'][$item['Session']] = $semaphoreMetaDataActual['Value']['sessions'][$item['Session']]; } } else { $this->kv->delete($item['Key']); } } } $resource->acquired = min($resource->acquire, $semaphoreMetaDataValue['limit'] - array_sum($semaphoreMetaDataValue['sessions'])); // add new elemet to metadata and save it if ($resource->acquired) { $semaphoreMetaDataValue['sessions'][$this->sessionId] = $resource->acquired; $result = $this->kv->put($this->getResourceKey($resource, $this->metaDataKey), json_encode($semaphoreMetaDataValue), ['cas' => isset($semaphoreMetaDataActual) ? $semaphoreMetaDataActual['ModifyIndex'] : 0])->json(); } else { $result = false; } } if (!$result) { break; } } if (!$result) { $this->release(); } return $result; }
/** * Determines if the given lock handle is currently valid for the given lock name. This method can be used to * verify if, for example, a particular lock session currently owns a given lock. * * @param string $lockName The name of the lock to check * @param mixed $lockHandle The opaque lock handle to validate against the lock * * @return bool True if the handle is valid for the lock, false otherwise */ public function isValid($lockName, $lockHandle) { if ($lockName != $lockHandle['name']) { return false; } $result = (string) $this->kvClient->get($lockHandle['name'])->getBody(); $result = json_decode($result, true); if (!is_array($result) || !array_key_exists(0, $result)) { return false; } $keyValue = $result[0]; if (!array_key_exists('Session', $keyValue)) { return false; } if ($keyValue['Session'] != $lockHandle['sessionId']) { return false; } return true; }