phasync
Resource management / Cache

Class

Cache

The cache every worker shares, from Swerve::cache(): a PSR-16 cache held by the master process, the least recently used entries evicted past --cache-size.

Introduction#

Two layers. Each worker keeps what it read (and what it found missing) in a local layer of LOCAL_BYTES, so a repeated read costs no trip to the master. Writes go to the master, which then tells every worker, the writer included, to forget those keys; it sends no values, a worker fetches a value when it next reads it. The master's messages to a worker arrive in the order it sent them, and a worker stores what it fetched as it reads the reply, so a worker never keeps a value older than the last write it was told of. A trip to the master costs about 0.1 ms, during which only the calling coroutine waits.

Values are serialized in the worker; the master keeps the strings and never unserializes them, so application classes never load there. An entry with a TTL expires at the same moment in every layer (the monotonic clock is the machine's). The contents last as long as the master: a rolling reload keeps them, a restart empties them. Without a master (the application served by something other than swerve's workers), the cache is the process's own.

It needs the master: in a coroutine that swerve.php starts, a call that has to ask it waits for the worker to serve, and directly in swerve.php it throws a LogicException. A key is a non-empty string without {}()/\@:, else a CacheKeyException is thrown.

It implements every version of PSR-16 (psr/simple-cache 1, 2 and 3; the application's Composer picks one): parameters are untyped, as 1.0 declares them, and checked here instead -- a key that is no string throws a CacheKeyException, a TTL that is no int, DateInterval or null a TypeError.

Class synopsis#

final class Cache implements CacheInterface {
    /* Methods */
    public static Cache::instance(): Cache
    public Cache::get($key, mixed $default = null): mixed
    public Cache::getMultiple($keys, mixed $default = null): array
    public Cache::has($key): bool
    public Cache::set($key, mixed $value, $ttl = null): bool
    public Cache::setMultiple($values, $ttl = null): bool
    public Cache::delete($key): bool
    public Cache::deleteMultiple($keys): bool
    public Cache::clear(): bool
}

Constants#

NameValueDescription
LOCAL_BYTES8388608Bytes of a worker's local layer.

Properties#

NameTypeDescription
$listeningstatic boolSet once the worker reads its pipe: before that no reply could arrive.
$loaderstatic ?FiberThe coroutine that requires swerve.php, while it does: it can't wait for the worker to serve.

Methods#

MethodDescription
instanceThe cache of this process: the one Swerve::cache returns.
getThe value stored under $key, or $default when there is none or it has expired.
getMultipleThe values of $keys, by key: $default for those missing or expired.
hasWhether a value is stored under $key and has not expired.
setStore $value under $key for every worker, for $ttl seconds or until evicted.
setMultipleStore several values, by key, with one $ttl, as Cache::set does.
deleteRemove $key from the cache of every worker.
deleteMultipleRemove several keys, as Cache::delete does.
clearRemove everything from the cache of every worker.

Examples#

Example 1Set, get and expire values
use Swerve\Swerve;

phasync::run(function () {
    $cache = Swerve::cache();                 // PSR-16: Psr\SimpleCache\CacheInterface

    $cache->set('greeting', 'hello', 60);     // 60 seconds
    $cache->set('config', ['debug' => false, 'level' => 3]);   // until evicted

    echo $cache->get('greeting'), "\n";
    var_dump($cache->get('config'));
    var_dump($cache->get('missing', 'a default'));

    $cache->set('greeting', 'gone', 0);       // a ttl of zero or less deletes
    var_dump($cache->has('greeting'));
});
Output
hello
array(2) {
  ["debug"]=>
  bool(false)
  ["level"]=>
  int(3)
}
string(9) "a default"
bool(false)
Example 2
$cache = Swerve::cache();
$user  = $cache->get("user.$id") ?? load_user($id);
$cache->set("user.$id", $user, 60);

See also#