Skip to content

Commit

Permalink
Merge pull request #8 from ICanBoogie/ttl-reliability
Browse files Browse the repository at this point in the history
Improve ttl reliability
  • Loading branch information
olvlvl authored Sep 19, 2019
2 parents 9e5852f + 09dc2f2 commit 46e9e41
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 26 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,34 @@ $storage->exists('icanboogie'); // false
$storage->retrieve('icanboogie'); // null
```

### Time To Live

The Time To Live (TTL) of an item is the amount of seconds between when that item is stored and it
is considered stale.

> **Warning:** [`apc.use_request_time`][] needs to be set to `false` if you want to use that feature
with APCU.

```php
<?php

use ICanBoogie\Storage\RunTimeStorage;

$storage = new RunTimeStorage;
$storage->store('icanboogie', "Yes Sir, I Can Boogie", $ttl = 3);
$storage->retrieve('icanboogie'); // "Yes Sir, I Can Boogie"
sleep(4);
$storage->exists('icanboogie'); // false
$storage->retrieve('icanboogie'); // null
```





### Use storages like arrays
### Use storage like arrays

Storage implement the `ArrayAccess` interface and may be accessed as arrays.
Storage implements the `ArrayAccess` interface and may be accessed as arrays.

```php
<?php
Expand All @@ -79,7 +100,7 @@ $storage['icanboogie']; // null

### Iterate storage keys

Storage implement the `IteratorAggregate` interface and may be used in a `foreach` to
Storage implements the `IteratorAggregate` interface and may be used in a `foreach` to
iterate their keys:

```php
Expand Down Expand Up @@ -254,3 +275,4 @@ report in `build/coverag`.
[ArrayAccess]: https://icanboogie.org/api/storage/master/class-ICanBoogie.Storage.Storage.ArrayAccess.html
[StorageCollection]: https://icanboogie.org/api/storage/master/class-ICanBoogie.Storage.StorageCollection.html
[Docker]: https://www.docker.com/
[`apc.use_request_time`]: https://www.php.net/manual/en/apcu.configuration.php#ini.apcu.use-request-time
2 changes: 1 addition & 1 deletion lib/APCStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function retrieve(string $key)
*/
public function store(string $key, $data, int $ttl = null): void
{
apcu_store($this->prefix . $key, $data, $ttl);
apcu_store($this->prefix . $key, $data, $ttl ?: 0);
}

/**
Expand Down
22 changes: 11 additions & 11 deletions lib/FileStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,27 +59,27 @@ public function __construct(string $path, Adapter $adapter = null)
*/
public function exists(string $key): bool
{
return file_exists($this->format_pathname($key));
$pathname = $this->format_pathname($key);
$ttl_mark = $this->format_pathname_with_ttl($pathname);

if (file_exists($ttl_mark) && fileatime($ttl_mark) < time() || !file_exists($pathname))
{
return false;
}

return file_exists($pathname);
}

/**
* @inheritdoc
*
* @param mixed $default The value returned if the key does not exists. Defaults to `null`.
*/
public function retrieve(string $key)
{
$this->check_writable();

$pathname = $this->format_pathname($key);
$ttl_mark = $this->format_pathname_with_ttl($pathname);

if (file_exists($ttl_mark) && fileatime($ttl_mark) < time() || !file_exists($pathname))
{
if (!$this->exists($key)) {
return null;
}

return $this->read($pathname);
return $this->read($this->format_pathname($key));
}

/**
Expand Down
13 changes: 13 additions & 0 deletions lib/RunTimeStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,25 @@ class RunTimeStorage implements Storage, \ArrayAccess
{
use Storage\ArrayAccess;

/**
* @var array<string, mixed>
*/
private $values = [];

/**
* @var array<string, int|null>
*/
private $until = [];

/**
* @inheritdoc
*/
public function exists(string $key): bool
{
if (isset($this->until[$key]) && $this->until[$key] < time()) {
return false;
}

return array_key_exists($key, $this->values);
}

Expand All @@ -42,6 +54,7 @@ public function retrieve(string $key)
public function store(string $key, $value, int $ttl = null): void
{
$this->values[$key] = $value;
$this->until[$key] = time() + $ttl;
}

/**
Expand Down
24 changes: 13 additions & 11 deletions tests/StorageCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

class StorageCollectionTest extends TestCase
{
use TestStorageTrait;

/**
* @var StorageCollection
*/
Expand All @@ -33,26 +35,26 @@ class StorageCollectionTest extends TestCase
/**
* @var StorageCollection
*/
private $collection;
private $storage;

public function setUp()
{
$this->s1 = $s1 = new RunTimeStorage;
$this->s2 = $s2 = new RunTimeStorage;
$this->s3 = $s3 = new RunTimeStorage;
$this->collection = new StorageCollection([ $s1, $s2, $s3 ]);
$this->storage = new StorageCollection([ $s1, $s2, $s3 ]);
}

public function test_store()
{
$key = uniqid();
$value = uniqid();

$this->collection->store($key, $value);
$this->storage->store($key, $value);

/* @var $storage Storage */

foreach([ $this->collection, $this->s1, $this->s2, $this->s3 ] as $storage)
foreach([ $this->storage, $this->s1, $this->s2, $this->s3 ] as $storage)
{
$this->assertTrue($storage->exists($key));
$this->assertSame($value, $storage->retrieve($key));
Expand All @@ -64,7 +66,7 @@ public function test_update_up()
$s1 = $this->s1;
$s2 = $this->s2;
$s3 = $this->s3;
$collection = $this->collection;
$collection = $this->storage;
$key = uniqid();
$value = uniqid();

Expand All @@ -82,7 +84,7 @@ public function test_eliminate()
$s1 = $this->s1;
$s2 = $this->s2;
$s3 = $this->s3;
$collection = $this->collection;
$collection = $this->storage;
$k1 = uniqid();
$v1 = uniqid();
$k2 = uniqid();
Expand Down Expand Up @@ -113,7 +115,7 @@ public function test_clear()
$s1 = $this->s1;
$s2 = $this->s2;
$s3 = $this->s3;
$collection = $this->collection;
$collection = $this->storage;
$k1 = uniqid();
$v1 = uniqid();
$k2 = uniqid();
Expand All @@ -135,7 +137,7 @@ public function test_clear()

public function test_array_access()
{
$collection = $this->collection;
$collection = $this->storage;
$k = uniqid();
$v = uniqid();

Expand All @@ -150,16 +152,16 @@ public function test_array_access()

public function test_find_by_type()
{
$this->assertSame($this->s1, $this->collection->find_by_type(RunTimeStorage::class));
$this->assertSame($this->s1, $this->storage->find_by_type(RunTimeStorage::class));
}

public function test_find_by_type_undefined()
{
$this->assertNull($this->collection->find_by_type(RedisStorage::class));
$this->assertNull($this->storage->find_by_type(RedisStorage::class));
}

public function test_iterator()
{
$this->assertInstanceOf(\Iterator::class, $this->collection->getIterator());
$this->assertInstanceOf(\Iterator::class, $this->storage->getIterator());
}
}
11 changes: 11 additions & 0 deletions tests/TestStorageTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ public function test_storage()
$this->assertNull($s->retrieve($k2));
}

public function test_store_with_ttl()
{
$storage = $this->storage;
$storage->store($key = uniqid(), $value = uniqid(), $ttl = 1);
$this->assertTrue($storage->exists($key));
$this->assertSame($value, $storage->retrieve($key));
sleep($ttl + 1);
$this->assertFalse($storage->exists($key));
$this->assertNull($storage->retrieve($key));
}

public function test_iterator()
{
$s = $this->storage;
Expand Down
3 changes: 3 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@

define('ICanBoogie\Storage\SANDBOX_DIR', __DIR__ . '/sandbox');

// https://www.php.net/manual/en/apcu.configuration.php#ini.apcu.use-request-time
ini_set('apc.use_request_time', false);

require __DIR__ . '/../vendor/autoload.php';
require 'TestStorageTrait.php';

0 comments on commit 46e9e41

Please sign in to comment.