[CORE][Cache] Fix bug where empty lists must be stored as a string in Redis (not supported natively), so we can't directly push to it, but the key still exists
This commit is contained in:
parent
f8c1b0f71d
commit
4cc4d06b11
@ -248,7 +248,7 @@ abstract class Cache
|
|||||||
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
|
||||||
{
|
{
|
||||||
if (isset(self::$redis[$pool])) {
|
if (isset(self::$redis[$pool])) {
|
||||||
$result = self::redisMaybeRecompute(
|
return self::redisMaybeRecompute(
|
||||||
$key,
|
$key,
|
||||||
recompute: /**
|
recompute: /**
|
||||||
* Caculate and trim the list to the correct size
|
* Caculate and trim the list to the correct size
|
||||||
@ -270,11 +270,19 @@ abstract class Cache
|
|||||||
no_recompute: /**
|
no_recompute: /**
|
||||||
* Fetch (a portion of) the list from the cache
|
* Fetch (a portion of) the list from the cache
|
||||||
*/
|
*/
|
||||||
fn () => self::$redis[$pool]->lRange($key, $left ?? 0, ($right ?? $max_count ?? 0) - 1),
|
function () use ($pool, $key, $left, $right, $max_count) {
|
||||||
|
$res = self::$redis[$pool]->lRange($key, $left ?? 0, ($right ?? $max_count ?? 0) - 1);
|
||||||
|
if ($res === false) {
|
||||||
|
// Empty lists are not supported by redis, but MSGPACK stores them as a
|
||||||
|
// string, so check if they exist
|
||||||
|
return self::$redis[$pool]->get($key);
|
||||||
|
} else {
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
},
|
||||||
pool: $pool,
|
pool: $pool,
|
||||||
beta: $beta,
|
beta: $beta,
|
||||||
);
|
);
|
||||||
return empty($result) ? [] : $result; // TODO may be wrong? not sure
|
|
||||||
} else {
|
} else {
|
||||||
return self::get(
|
return self::get(
|
||||||
$key,
|
$key,
|
||||||
@ -359,13 +367,18 @@ abstract class Cache
|
|||||||
public static function listPushLeft(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]
|
$res = self::$redis[$pool]
|
||||||
// doesn't need to be atomic, adding at one end, deleting at the other
|
// doesn't need to be atomic, adding at one end, deleting at the other
|
||||||
->multi(Redis::PIPELINE)
|
->multi(Redis::PIPELINE)
|
||||||
->lPush($key, $value)
|
->lPush($key, $value)
|
||||||
// trim to $max_count, if given
|
// trim to $max_count, if given
|
||||||
->lTrim($key, 0, ($max_count ?? 0) - 1)
|
->lTrim($key, 0, ($max_count ?? 0) - 1)
|
||||||
->exec();
|
->exec();
|
||||||
|
// $res has a bool per operation in the pipeline. False means it failed
|
||||||
|
if (\in_array(false, $res)) {
|
||||||
|
// Empty lists are stored as strings, so you can't push to it. Delete it and then push
|
||||||
|
self::$redis[$pool]->multi(Redis::PIPELINE)->del($key)->lPush($key, $value)->exec();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$res = self::get($key, fn () => [], $pool, $beta);
|
$res = self::get($key, fn () => [], $pool, $beta);
|
||||||
array_unshift($res, $value);
|
array_unshift($res, $value);
|
||||||
@ -382,13 +395,18 @@ abstract class Cache
|
|||||||
public static function listPushRight(string $key, mixed $value, string $pool = 'default', ?int $max_count = null, float $beta = 1.0): void
|
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])) {
|
if (isset(self::$redis[$pool])) {
|
||||||
self::$redis[$pool]
|
$res = self::$redis[$pool]
|
||||||
// doesn't need to be atomic, adding at one end, deleting at the other
|
// doesn't need to be atomic, adding at one end, deleting at the other
|
||||||
->multi(Redis::PIPELINE)
|
->multi(Redis::PIPELINE)
|
||||||
->rPush($key, $value)
|
->rPush($key, $value)
|
||||||
// trim to $max_count, if given
|
// trim to $max_count, if given
|
||||||
->lTrim($key, -($max_count ?? 0), -1)
|
->lTrim($key, -($max_count ?? 0), -1)
|
||||||
->exec();
|
->exec();
|
||||||
|
// $res has a bool per operation in the pipeline. False means it failed
|
||||||
|
if (\in_array(false, $res)) {
|
||||||
|
// Empty lists are stored as strings, so you can't push to it. Delete it and then push
|
||||||
|
self::$redis[$pool]->multi(Redis::PIPELINE)->del($key)->rPush($key, $value)->exec();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$res = self::get($key, fn () => [], $pool, $beta);
|
$res = self::get($key, fn () => [], $pool, $beta);
|
||||||
$res[] = $value;
|
$res[] = $value;
|
||||||
|
Loading…
Reference in New Issue
Block a user