Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sharding adapter #20

Merged
merged 5 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ notifications:
email:
- [email protected]

services:
- docker
before_script: docker run --rm --interactive --tty --volume "$(pwd)":/app composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist

before_install:
# - curl -fsSL https://get.docker.com | sh
# - echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json
# - mkdir -p $HOME/.docker
# - echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
# - sudo service docker start
- curl -fsSL https://get.docker.com | sh
- echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json
- mkdir -p $HOME/.docker
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
- sudo service docker start
- >
if [ ! -z "${DOCKERHUB_PULL_USERNAME:-}" ]; then
echo "${DOCKERHUB_PULL_PASSWORD}" | docker login --username "${DOCKERHUB_PULL_USERNAME}" --password-stdin
Expand Down
397 changes: 200 additions & 197 deletions composer.lock

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,32 @@ services:
dockerfile: php8.0.Dockerfile
networks:
- database
# volumes:
# - ./:/usr/src/code
volumes:
- ./:/usr/src/code

redis:
image: redis:6.0-alpine
container_name: redis
networks:
- database

shardA:
image: redis:6.0-alpine
container_name: shardA
networks:
- database

shardB:
image: redis:6.0-alpine
container_name: shardB
networks:
- database

shardC:
image: redis:6.0-alpine
container_name: shardC
networks:
- database

networks:
database:
1 change: 1 addition & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<file>./tests/Cache/MemoryTest.php</file>
<file>./tests/Cache/NoneTest.php</file>
<file>./tests/Cache/RedisTest.php</file>
<file>./tests/Cache/ShardingTest.php</file>
</testsuite>
</testsuites>
</phpunit>
6 changes: 3 additions & 3 deletions src/Cache/Adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ interface Adapter
* @param int $ttl time in seconds
* @return mixed
*/
public function load($key, $ttl);
public function load(string $key, int $ttl): mixed;

/**
* @param string $key
* @param string|array $data
* @return bool|string|array
*/
public function save($key, $data);
public function save(string $key, $data): bool|string|array;

/**
* @param string $key
* @return bool
*/
public function purge($key): bool;
public function purge(string $key): bool;
}
10 changes: 5 additions & 5 deletions src/Cache/Adapter/Filesystem.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Filesystem implements Adapter
* Filesystem constructor.
* @param string $path
*/
public function __construct($path)
public function __construct(string $path)
{
$this->path = $path;
}
Expand All @@ -26,7 +26,7 @@ public function __construct($path)
* @return mixed
* @throws \Exception
*/
public function load($key, $ttl)
public function load(string $key, int $ttl): mixed
{
$file = $this->getPath($key);

Expand All @@ -43,7 +43,7 @@ public function load($key, $ttl)
* @throws \Exception
* @return bool|string|array
*/
public function save($key, $data)
public function save(string $key, mixed $data): bool|string|array
{
if (empty($data)) {
return false;
Expand All @@ -69,7 +69,7 @@ public function save($key, $data)
* @throws \Exception
* @return bool
*/
public function purge($key): bool
public function purge(string $key): bool
{
$file = $this->getPath($key);

Expand All @@ -84,7 +84,7 @@ public function purge($key): bool
* @param string $filename
* @return string
*/
public function getPath($filename)
public function getPath(string $filename): string
{
return $this->path . DIRECTORY_SEPARATOR . $filename;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Cache/Adapter/Memory.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public function __construct()
* @param int $ttl time in seconds
* @return mixed
*/
public function load($key, $ttl)
public function load(string $key, int $ttl): mixed
{
if (!empty($key) && isset($this->store[$key])) {
/** @var array{time: int, data: string} */
Expand All @@ -40,7 +40,7 @@ public function load($key, $ttl)
* @param string|array $data
* @return bool|string|array
*/
public function save($key, $data)
public function save(string $key, $data): bool|string|array
{
if (empty($key) || empty($data)) {
return false;
Expand All @@ -60,7 +60,7 @@ public function save($key, $data)
* @param string $key
* @return bool
*/
public function purge($key): bool
public function purge(string $key): bool
{
if (!empty($key) && isset($this->store[$key])) { // if a key is passed and it exists in cache
unset($this->store[$key]);
Expand Down
6 changes: 3 additions & 3 deletions src/Cache/Adapter/None.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct()
* @param int $ttl time in seconds
* @return mixed
*/
public function load($key, $ttl)
public function load(string $key, int $ttl): mixed
{
return false;
}
Expand All @@ -29,7 +29,7 @@ public function load($key, $ttl)
* @param string|array $data
* @return bool|string|array
*/
public function save($key, $data)
public function save(string $key, $data): bool|string|array
{
return false;
}
Expand All @@ -38,7 +38,7 @@ public function save($key, $data)
* @param string $key
* @return bool
*/
public function purge($key): bool
public function purge(string $key): bool
{
return true;
}
Expand Down
8 changes: 4 additions & 4 deletions src/Cache/Adapter/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Redis implements Adapter
/**
* @var Client
*/
protected $redis;
protected Client $redis;

/**
* Redis constructor.
Expand All @@ -26,7 +26,7 @@ public function __construct(Client $redis)
* @param int $ttl time in seconds
* @return mixed
*/
public function load($key, $ttl)
public function load(string $key, int $ttl): mixed
{
/** @var array{time: int, data: string} */
$cache = json_decode($this->redis->get($key), true);
Expand All @@ -43,7 +43,7 @@ public function load($key, $ttl)
* @param string|array $data
* @return bool|string|array
*/
public function save($key, $data)
public function save(string $key, $data): bool|string|array
{
if (empty($key) || empty($data)) {
return false;
Expand All @@ -61,7 +61,7 @@ public function save($key, $data)
* @param string $key
* @return bool
*/
public function purge($key): bool
public function purge(string $key): bool
{
if (\str_ends_with($key, ':*')) {
return (bool) $this->redis->del($this->redis->keys($key));
Expand Down
86 changes: 86 additions & 0 deletions src/Cache/Adapter/Sharding.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Utopia\Cache\Adapter;

use Utopia\Cache\Adapter;

class Sharding implements Adapter
{
/**
* @var Adapter[]
*/
protected array $adapters;

/**
* @var int
*/
protected int $count = 0;

/**
* Sharding Adapter.
*
* Allows to shard cache across multiple adapters in a consistent way.
* Using sharding we can increase cache size and balance the read
* and write load between multiple adapters.
*
* Each cache key will be hashed and the hash will be used to determine
* which adapter to use for fetching or storing this key. Only one
* adapter will always match a specific key unless a new adapter is
* added to the pool.
*
* When adding a new adapter to the pool, cached will gradually
* get re-distributed to fill the new adapter, this might cause a
* significant drop in hit-rate for a short period of time.
*
* @param Adapter[] $adapters
*/
public function __construct(array $adapters)
{
if(empty($adapters)) {
throw new \Exception('No adapters provided');
};

$this->count = \count($adapters);
$this->adapters = $adapters;
}

/**
* @param string $key
* @param int $ttl time in seconds
* @return mixed
*/
public function load(string $key, int $ttl): mixed
{
return $this->getAdapter($key)->load($key, $ttl);
}

/**
* @param string $key
* @param string|array $data
* @return bool|string|array
*/
public function save(string $key, $data): bool|string|array
{
return $this->getAdapter($key)->save($key, $data);
}

/**
* @param string $key
* @return bool
*/
public function purge(string $key): bool
{
return (bool) $this->getAdapter($key)->purge($key);
}

/**
* @param string $key
* @return Adapter
*/
protected function getAdapter(string $key): Adapter
{
$hash = \crc32($key);
$index = $hash % $this->count;
return $this->adapters[$index];
}
}
10 changes: 5 additions & 5 deletions src/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public function __construct(Adapter $adapter)
*
* @param string $key
* @param boolean $value if true, cache keys will be case sensitive
* @return mixed
* @return bool
*/
public static function setCaseSensitivity(bool $value)
public static function setCaseSensitivity(bool $value): bool
{
return self::$caseSensitive = $value;
}
Expand All @@ -41,7 +41,7 @@ public static function setCaseSensitivity(bool $value)
* @param int $ttl time in seconds
* @return mixed
*/
public function load($key, $ttl)
public function load(string $key, int $ttl): mixed
{
$key = self::$caseSensitive ? $key : \strtolower($key);
return $this->adapter->load($key, $ttl);
Expand All @@ -54,7 +54,7 @@ public function load($key, $ttl)
* @param string|array $data
* @return bool|string|array
*/
public function save($key, $data)
public function save(string $key, mixed $data): bool|string|array
{
$key = self::$caseSensitive ? $key : \strtolower($key);
return $this->adapter->save($key, $data);
Expand All @@ -66,7 +66,7 @@ public function save($key, $data)
* @param string $key
* @return bool
*/
public function purge($key): bool
public function purge(string $key): bool
{
$key = self::$caseSensitive ? $key : \strtolower($key);
return $this->adapter->purge($key);
Expand Down
1 change: 1 addition & 0 deletions tests/Cache/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Utopia\Tests;

use Utopia\Cache\Cache;
use PHPUnit\Framework\TestCase;

abstract class Base extends TestCase
Expand Down
11 changes: 0 additions & 11 deletions tests/Cache/FilesystemTest.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
<?php
/**
* Utopia PHP Framework
*
* @package Framework
* @subpackage Tests
*
* @link https://github.com/utopia-php/framework
* @author Eldad Fux <[email protected]>
* @version 1.0 RC4
* @license The MIT License (MIT) <https://www.opensource.org/licenses/mit-license.php>
*/

namespace Utopia\Tests;

Expand Down
11 changes: 0 additions & 11 deletions tests/Cache/MemoryTest.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
<?php
/**
* Utopia PHP Framework
*
* @package Framework
* @subpackage Tests
*
* @link https://github.com/utopia-php/framework
* @author Eldad Fux <[email protected]>
* @version 1.0 RC4
* @license The MIT License (MIT) <https://www.opensource.org/licenses/mit-license.php>
*/

namespace Utopia\Tests;

Expand Down
Loading