[CORE][Cache] Implement listPushRight

This commit is contained in:
Diogo Peralta Cordeiro 2022-02-27 00:29:26 +00:00
parent b630d530f4
commit d4c908c194
No known key found for this signature in database
GPG Key ID: 18D2D35001FBFAB0
4 changed files with 45 additions and 8 deletions

View File

@ -93,7 +93,7 @@ class Tag extends Component
'use_canonical' => $extra_args['tag_use_canonical'] ?? false, 'use_canonical' => $extra_args['tag_use_canonical'] ?? false,
'language_id' => $lang_id, 'language_id' => $lang_id,
])); ]));
Cache::pushList("tag-{$canonical_tag}", $note); Cache::listPushLeft("tag-{$canonical_tag}", $note);
foreach (self::cacheKeys($canonical_tag) as $key) { foreach (self::cacheKeys($canonical_tag) as $key) {
Cache::delete($key); Cache::delete($key);
} }

View File

@ -290,7 +290,7 @@ class Note extends Model
'use_canonical' => $ap_tag->get('canonical') ?? false, 'use_canonical' => $ap_tag->get('canonical') ?? false,
'language_id' => $lang_id ?? null, 'language_id' => $lang_id ?? null,
])); ]));
Cache::pushList("tag-{$canonical_tag}", $obj); Cache::listPushLeft("tag-{$canonical_tag}", $obj);
foreach (Tag::cacheKeys($canonical_tag) as $key) { foreach (Tag::cacheKeys($canonical_tag) as $key) {
Cache::delete($key); Cache::delete($key);
} }

View File

@ -225,7 +225,7 @@ abstract class Cache
public static function exists(string $key, string $pool = 'default'): bool public static function exists(string $key, string $pool = 'default'): bool
{ {
if (isset(self::$redis[$pool])) { if (isset(self::$redis[$pool])) {
return self::$redis[$pool]->exists($key); return self::$redis[$pool]->exists($key) === 1;
} else { } else {
// there's no set method, must be done this way // there's no set method, must be done this way
return self::$pools[$pool]->hasItem($key); return self::$pools[$pool]->hasItem($key);
@ -237,7 +237,13 @@ abstract class Cache
* for redis and others, trimming to $max_count if given * for redis and others, trimming to $max_count if given
* TODO(hugo): $calculate = [] is the same as false miss * TODO(hugo): $calculate = [] is the same as false miss
* *
* @param string $key Cache key
* @param callable(?CacheItem $item, bool &$save): (string|object|array<int,mixed>) $calculate * @param callable(?CacheItem $item, bool &$save): (string|object|array<int,mixed>) $calculate
* @param string $pool Cache pool being used (between different cache managers (of the same or different systems))
* @param null|int $max_count When setting cache, it trims to max count
* @param null|int $left Offset on Get
* @param null|int $right Limit on Get
* @param float $beta Likelihood of recomputing value (1 to infinity)
*/ */
public static function getList(string $key, callable $calculate, string $pool = 'default', ?int $max_count = null, ?int $left = null, ?int $right = null, float $beta = 1.0): array public static function getList(string $key, callable $calculate, string $pool = 'default', ?int $max_count = null, ?int $left = null, ?int $right = null, float $beta = 1.0): array
{ {
@ -314,7 +320,7 @@ abstract class Cache
/** /**
* Push a value to the list * Push a value to the list
*/ */
public static function pushList(string $key, mixed $value, string $pool = 'default', ?int $max_count = null, float $beta = 1.0): void public static function listPushLeft(string $key, mixed $value, string $pool = 'default', ?int $max_count = null, float $beta = 1.0): void
{ {
if (isset(self::$redis[$pool])) { if (isset(self::$redis[$pool])) {
self::$redis[$pool] self::$redis[$pool]
@ -334,6 +340,29 @@ abstract class Cache
} }
} }
/**
* Push a value to the list
*/
public static function listPushRight(string $key, mixed $value, string $pool = 'default', ?int $max_count = null, float $beta = 1.0): void
{
if (isset(self::$redis[$pool])) {
self::$redis[$pool]
// doesn't need to be atomic, adding at one end, deleting at the other
->multi(Redis::PIPELINE)
->rPush($key, $value)
// trim to $max_count, if given
->lTrim($key, -($max_count ?? 0), -1)
->exec();
} else {
$res = self::get($key, fn () => [], $pool, $beta);
$res[] = $value;
if (!\is_null($max_count)) {
$res = \array_slice($res, -$max_count, null); // Trim away the older values
}
self::set($key, $res, $pool);
}
}
/** /**
* Delete a whole list at $key * Delete a whole list at $key
*/ */

View File

@ -106,10 +106,14 @@ class CacheTest extends KernelTestCase
static::assertSame(['foo'], Cache::getList($key . '1', fn ($i) => ['foo'])); static::assertSame(['foo'], Cache::getList($key . '1', fn ($i) => ['foo']));
static::assertSame(['foo', 'bar'], Cache::getList($key, fn ($i) => ['foo', 'bar'])); static::assertSame(['foo', 'bar'], Cache::getList($key, fn ($i) => ['foo', 'bar']));
static::assertSame(['foo', 'bar'], Cache::getList($key, function () { $this->assertFalse('should not be called'); })); // Repeat to test no recompute lrange static::assertSame(['foo', 'bar'], Cache::getList($key, function () { $this->assertFalse('should not be called'); })); // Repeat to test no recompute lrange
Cache::pushList($key, 'quux'); Cache::listPushLeft($key, 'quux');
static::assertSame(['quux', 'foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); })); static::assertSame(['quux', 'foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
Cache::pushList($key, 'foobar', max_count: 2); Cache::listPushLeft($key, 'foobar', max_count: 2);
static::assertSame(['foobar', 'quux'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); })); static::assertSame(['foobar', 'quux'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
Cache::listPushRight($key, 'foo');
static::assertSame(['foobar', 'quux', 'foo'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
Cache::listPushRight($key, 'bar', max_count: 2);
static::assertSame(['foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
static::assertTrue(Cache::deleteList($key)); static::assertTrue(Cache::deleteList($key));
} }
@ -132,10 +136,14 @@ class CacheTest extends KernelTestCase
static::assertSame(['foo'], Cache::getList($key . '1', fn ($i) => ['foo'], pool: 'file')); static::assertSame(['foo'], Cache::getList($key . '1', fn ($i) => ['foo'], pool: 'file'));
static::assertSame(['foo', 'bar'], Cache::getList($key, fn ($i) => ['foo', 'bar'], pool: 'file')); static::assertSame(['foo', 'bar'], Cache::getList($key, fn ($i) => ['foo', 'bar'], pool: 'file'));
static::assertSame(['foo', 'bar'], Cache::getList($key, function () { $this->assertFalse('should not be called'); }, pool: 'file')); // Repeat to test no recompute lrange static::assertSame(['foo', 'bar'], Cache::getList($key, function () { $this->assertFalse('should not be called'); }, pool: 'file')); // Repeat to test no recompute lrange
Cache::pushList($key, 'quux', pool: 'file'); Cache::listPushLeft($key, 'quux', pool: 'file');
static::assertSame(['quux', 'foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }, pool: 'file')); static::assertSame(['quux', 'foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }, pool: 'file'));
Cache::pushList($key, 'foobar', max_count: 2, pool: 'file'); Cache::listPushLeft($key, 'foobar', max_count: 2, pool: 'file');
static::assertSame(['foobar', 'quux'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }, pool: 'file')); static::assertSame(['foobar', 'quux'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }, pool: 'file'));
Cache::listPushRight($key, 'foo');
static::assertSame(['foobar', 'quux', 'foo'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
Cache::listPushRight($key, 'bar', max_count: 2);
static::assertSame(['foo', 'bar'], Cache::getList($key, function ($i) { $this->assertFalse('should not be called'); }));
static::assertTrue(Cache::deleteList($key, pool: 'file')); static::assertTrue(Cache::deleteList($key, pool: 'file'));
} }
} }