Skip to content

Commit d0de220

Browse files
committed
- adds a new cache client (ShmopClient)
- removed `FileConfiguration` class
1 parent 8f7a215 commit d0de220

3 files changed

Lines changed: 168 additions & 22 deletions

File tree

Client/CacheClientFactory.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
use Exception;
1616
use Koded\Caching\{Cache, CacheException};
17-
use Koded\Caching\Configuration\{FileConfiguration, MemcachedConfiguration, PredisConfiguration, RedisConfiguration};
17+
use Koded\Caching\Configuration\{MemcachedConfiguration, PredisConfiguration, RedisConfiguration};
1818
use Koded\Stdlib\Interfaces\{Configuration, ConfigurationFactory, Serializer};
1919
use Koded\Stdlib\Serializer\SerializerFactory;
2020
use Psr\Log\{LoggerInterface, NullLogger};
@@ -58,8 +58,10 @@ public function new(string $client = ''): Cache
5858
/** @var PredisConfiguration $config */
5959
return $this->createPredisClient($config);
6060

61+
case 'shmop':
62+
return new ShmopClient((string)$config->get('dir'), $config->get('ttl'));
63+
6164
case 'file':
62-
/** @var FileConfiguration $config */
6365
return new FileClient($this->getLogger($config), (string)$config->get('dir'), $config->get('ttl'));
6466

6567
case 'memory':

Client/ShmopClient.php

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Koded package.
5+
*
6+
* (c) Mihail Binev <mihail@kodeart.com>
7+
*
8+
* Please view the LICENSE distributed with this source code
9+
* for the full copyright and license information.
10+
*
11+
*/
12+
13+
namespace Koded\Caching\Client;
14+
15+
use Exception;
16+
use Koded\Caching\{Cache, CacheException};
17+
use function Koded\Caching\verify_key;
18+
19+
/**
20+
* @property ShmopClient client
21+
*
22+
*/
23+
final class ShmopClient implements Cache
24+
{
25+
use ClientTrait, MultiplesTrait;
26+
27+
/** @var string */
28+
private $dir;
29+
30+
public function __construct(string $dir, ?int $ttl)
31+
{
32+
$this->dir = $dir;
33+
$this->ttl = $ttl;
34+
$this->setDirectory($dir);
35+
}
36+
37+
38+
public function get($key, $default = null)
39+
{
40+
if (false === $this->has($key, $filename)) {
41+
return $default;
42+
}
43+
44+
try {
45+
$resource = shmop_open(fileinode($filename), 'a', 0, 0);
46+
return unserialize(shmop_read($resource, 0, shmop_size($resource)));
47+
} finally {
48+
shmop_close($resource);
49+
}
50+
}
51+
52+
53+
public function set($key, $value, $ttl = null)
54+
{
55+
verify_key($key);
56+
57+
if (1 > $expiration = $this->timestampWithGlobalTtl($ttl, Cache::DATE_FAR_FAR_AWAY)) {
58+
// The item is considered expired and must be deleted
59+
return $this->delete($key);
60+
}
61+
62+
$value = serialize($value);
63+
$size = strlen($value);
64+
$filename = $this->filename($key, true);
65+
66+
try {
67+
$resource = shmop_open(fileinode($filename), 'n', 0666, $size);
68+
} catch (Exception $e) {
69+
$resource = shmop_open(fileinode($filename), 'w', 0666, $size);
70+
}
71+
72+
try {
73+
return shmop_write($resource, $value, 0) === $size
74+
&& false !== file_put_contents($filename . '-ttl', $expiration);
75+
76+
} finally {
77+
shmop_close($resource);
78+
}
79+
}
80+
81+
82+
public function delete($key)
83+
{
84+
if (false === $this->has($key, $filename)) {
85+
return true;
86+
}
87+
88+
return $this->expire($filename);
89+
}
90+
91+
92+
public function clear()
93+
{
94+
foreach ((glob($this->dir . 'shmop-*.cache*') ?: []) as $filename) {
95+
$this->expire($filename);
96+
}
97+
return true;
98+
}
99+
100+
101+
public function has($key, &$filename = '')
102+
{
103+
verify_key($key);
104+
$filename = $this->filename($key, false);
105+
$expiration = (int)(@file_get_contents($filename . '-ttl') ?: 0);
106+
107+
if ($expiration <= time()) {
108+
$this->expire($filename);
109+
return false;
110+
}
111+
112+
return true;
113+
}
114+
115+
116+
private function filename(string $key, bool $create): string
117+
{
118+
$filename = $this->dir . 'shmop-' . sha1($key) . '.cache';
119+
120+
if ($create) {
121+
touch($filename);
122+
touch($filename . '-ttl');
123+
chmod($filename, 0666);
124+
chmod($filename . '-ttl', 0666);
125+
}
126+
127+
return $filename;
128+
}
129+
130+
/**
131+
* Prepares the cache directory.
132+
*
133+
* @param string $directory
134+
*
135+
* @throws CacheException
136+
*/
137+
private function setDirectory(string $directory): void
138+
{
139+
// Overrule shell misconfiguration or the web server
140+
umask(umask() | 0002);
141+
$dir = $directory ?: sys_get_temp_dir();
142+
$dir = rtrim($dir, '/') . '/';
143+
144+
if (false === is_dir($dir) && false === mkdir($dir, 0775, true)) {
145+
throw CacheException::forCreatingDirectory($dir);
146+
}
147+
148+
$this->dir = $dir;
149+
}
150+
151+
private function expire(string $filename): bool
152+
{
153+
if (false === $resource = @shmop_open(fileinode($filename), 'w', 0, 0)) {
154+
return false;
155+
}
156+
157+
try {
158+
unlink($filename . '-ttl');
159+
return shmop_delete($resource);
160+
} finally {
161+
shmop_close($resource);
162+
}
163+
}
164+
}

Configuration/FileConfiguration.php

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)