2016-01-15 00:44:43 +01:00
|
|
|
<?php
|
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
namespace Amp\Concurrent\Worker;
|
2016-01-15 00:44:43 +01:00
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
use Interop\Async\Loop;
|
|
|
|
|
|
|
|
class BasicEnvironment implements Environment {
|
2016-01-15 00:44:43 +01:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $data = [];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $ttl = [];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private $expire = [];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var \SplPriorityQueue
|
|
|
|
*/
|
|
|
|
private $queue;
|
|
|
|
|
|
|
|
/**
|
2016-08-18 18:04:48 +02:00
|
|
|
* @var string
|
2016-01-15 00:44:43 +01:00
|
|
|
*/
|
|
|
|
private $timer;
|
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
public function __construct() {
|
|
|
|
$this->queue = new \SplPriorityQueue;
|
2016-01-15 00:44:43 +01:00
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
$this->timer = Loop::repeat(1000, function () {
|
|
|
|
$time = \time();
|
2016-01-15 00:44:43 +01:00
|
|
|
while (!$this->queue->isEmpty()) {
|
|
|
|
$key = $this->queue->top();
|
|
|
|
|
|
|
|
if (isset($this->expire[$key])) {
|
|
|
|
if ($time <= $this->expire[$key]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
unset($this->data[$key], $this->expire[$key], $this->ttl[$key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->queue->extract();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->queue->isEmpty()) {
|
2016-08-18 18:04:48 +02:00
|
|
|
Loop::disable($this->timer);
|
2016-01-15 00:44:43 +01:00
|
|
|
}
|
|
|
|
});
|
2016-08-18 18:04:48 +02:00
|
|
|
|
|
|
|
Loop::disable($this->timer);
|
|
|
|
Loop::unreference($this->timer);
|
2016-01-15 00:44:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $key
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function exists(string $key): bool {
|
2016-01-23 07:00:56 +01:00
|
|
|
return isset($this->data[$key]);
|
2016-01-15 00:44:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $key
|
|
|
|
*
|
|
|
|
* @return mixed|null Returns null if the key does not exist.
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function get(string $key) {
|
2016-01-15 00:44:43 +01:00
|
|
|
if (isset($this->ttl[$key]) && 0 !== $this->ttl[$key]) {
|
|
|
|
$this->expire[$key] = time() + $this->ttl[$key];
|
|
|
|
$this->queue->insert($key, -$this->expire[$key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return isset($this->data[$key]) ? $this->data[$key] : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value Using null for the value deletes the key.
|
|
|
|
* @param int $ttl Number of seconds until data is automatically deleted. Use 0 for unlimited TTL.
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function set(string $key, $value, int $ttl = 0) {
|
2016-01-15 00:44:43 +01:00
|
|
|
if (null === $value) {
|
|
|
|
$this->delete($key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$ttl = (int) $ttl;
|
|
|
|
if (0 > $ttl) {
|
|
|
|
$ttl = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 !== $ttl) {
|
|
|
|
$this->ttl[$key] = $ttl;
|
|
|
|
$this->expire[$key] = time() + $ttl;
|
|
|
|
$this->queue->insert($key, -$this->expire[$key]);
|
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
Loop::enable($this->timer);
|
2016-01-15 00:44:43 +01:00
|
|
|
} else {
|
|
|
|
unset($this->expire[$key], $this->ttl[$key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->data[$key] = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $key
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function delete(string $key) {
|
2016-01-15 00:44:43 +01:00
|
|
|
$key = (string) $key;
|
|
|
|
unset($this->data[$key], $this->expire[$key], $this->ttl[$key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias of exists().
|
|
|
|
*
|
|
|
|
* @param $key
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function offsetExists($key) {
|
2016-01-15 00:44:43 +01:00
|
|
|
return $this->exists($key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias of get().
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function offsetGet($key) {
|
2016-01-15 00:44:43 +01:00
|
|
|
return $this->get($key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias of set() with $ttl = 0.
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
* @param mixed $value
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function offsetSet($key, $value) {
|
2016-01-15 00:44:43 +01:00
|
|
|
$this->set($key, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias of delete().
|
|
|
|
*
|
|
|
|
* @param string $key
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function offsetUnset($key) {
|
2016-01-15 00:44:43 +01:00
|
|
|
$this->delete($key);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return int
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function count(): int {
|
2016-01-15 00:44:43 +01:00
|
|
|
return count($this->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes all values.
|
|
|
|
*/
|
2016-08-18 18:04:48 +02:00
|
|
|
public function clear() {
|
2016-01-15 00:44:43 +01:00
|
|
|
$this->data = [];
|
|
|
|
$this->expire = [];
|
|
|
|
$this->ttl = [];
|
|
|
|
|
2016-08-18 18:04:48 +02:00
|
|
|
Loop::disable($this->timer);
|
2016-01-15 00:44:43 +01:00
|
|
|
$this->queue = new \SplPriorityQueue();
|
|
|
|
}
|
|
|
|
}
|