Implement new RESTORE options

Add the new RESTORE options REPLACE, ABSTTL, FREQ <freq> and IDLETIME <idletime>

Fixes #1410
This commit is contained in:
michael-grunder
2022-10-08 09:24:57 -07:00
committed by Michael Grunder
parent 6ea978eb72
commit 9a3fe401dc
11 changed files with 142 additions and 12 deletions
+1 -2
View File
@@ -3025,8 +3025,7 @@ PHP_METHOD(Redis, dump) {
/* {{{ proto Redis::restore(ttl, key, value) */
PHP_METHOD(Redis, restore) {
REDIS_PROCESS_KW_CMD("RESTORE", redis_key_long_str_cmd,
redis_boolean_response);
REDIS_PROCESS_CMD(restore, redis_boolean_response);
}
/* }}} */
+1 -1
View File
@@ -364,7 +364,7 @@ public function persist(string $key): bool;
public function reset(): bool;
public function restore(string $key, int $timeout, string $value): bool;
public function restore(string $key, int $timeout, string $value, ?array $options = NULL): bool;
public function role(): mixed;
+2 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: f547b5f24c4d373043c89dab57d450d27f959b08 */
* Stub hash: 2c4ee6dc4a5aa66b1700df8859233c349aa00519 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null")
@@ -642,6 +642,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_restore, 0, 3, _IS_B
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "NULL")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_role arginfo_class_Redis_getAuth
+1 -2
View File
@@ -1418,8 +1418,7 @@ PHP_METHOD(RedisCluster, pfmerge) {
/* {{{ proto boolean RedisCluster::restore(string key, long ttl, string val) */
PHP_METHOD(RedisCluster, restore) {
CLUSTER_PROCESS_KW_CMD("RESTORE", redis_key_long_str_cmd,
cluster_bool_resp, 0);
CLUSTER_PROCESS_CMD(restore, cluster_bool_resp, 0);
}
/* }}} */
+1 -1
View File
@@ -248,7 +248,7 @@ class RedisCluster {
public function renamenx(string $key, string $newkey): bool;
public function restore(string $key, int $timeout, string $value): bool;
public function restore(string $key, int $timeout, string $value, ?array $options = NULL): bool;
public function role(string|array $key_or_address): mixed;
+7 -2
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 75e03c96590793af52efbea1d6440d3daa57a5d8 */
* Stub hash: 956f295e74025def86150d0acdf7a11594c72d47 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
@@ -526,7 +526,12 @@ ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_renamenx arginfo_class_RedisCluster_rename
#define arginfo_class_RedisCluster_restore arginfo_class_RedisCluster_psetex
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_restore, 0, 3, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, timeout, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "NULL")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_RedisCluster_role, 0, 1, IS_MIXED, 0)
ZEND_ARG_TYPE_MASK(0, key_or_address, MAY_BE_STRING|MAY_BE_ARRAY, NULL)
+7 -2
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 75e03c96590793af52efbea1d6440d3daa57a5d8 */
* Stub hash: 956f295e74025def86150d0acdf7a11594c72d47 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_INFO(0, name)
@@ -459,7 +459,12 @@ ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_renamenx arginfo_class_RedisCluster_rename
#define arginfo_class_RedisCluster_restore arginfo_class_RedisCluster_psetex
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_restore, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_role arginfo_class_RedisCluster_bgrewriteaof
+101
View File
@@ -65,6 +65,13 @@ typedef struct redisLcsOptions {
zend_bool withmatchlen;
} redisLcsOptions;
typedef struct redisRestoreOptions {
zend_bool replace;
zend_bool absttl;
zend_long idletime;
zend_long freq;
} redisRestoreOptions;
/* Local passthrough macro for command construction. Given that these methods
* are generic (so they work whether the caller is Redis or RedisCluster) we
* will always have redis_sock, slot*, and */
@@ -2411,6 +2418,100 @@ int redis_lcs_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
return SUCCESS;
}
void redis_get_restore_options(redisRestoreOptions *dst, HashTable *ht) {
zend_string *key;
zend_long lval;
zval *zv;
ZEND_ASSERT(dst != NULL);
memset(dst, 0, sizeof(*dst));
dst->idletime = dst->freq = -1;
if (ht == NULL)
return;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, zv) {
ZVAL_DEREF(zv);
if (key) {
if (zend_string_equals_literal_ci(key, "IDLETIME")) {
lval = zval_get_long(zv);
if (lval < 0) {
php_error_docref(NULL, E_WARNING, "IDLETIME must be >= 0");
} else {
dst->idletime = lval;
dst->freq = -1;
}
} else if (zend_string_equals_literal_ci(key, "FREQ")) {
lval = zval_get_long(zv);
if (lval < 0 || lval > 255) {
php_error_docref(NULL, E_WARNING, "FREQ must be >= 0 and <= 255");
} else {
dst->freq = lval;
dst->idletime = -1;
}
} else {
php_error_docref(NULL, E_WARNING, "Unknown RESTORE option '%s'", ZSTR_VAL(key));
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
if (zend_string_equals_literal_ci(Z_STR_P(zv), "REPLACE")) {
dst->replace = 1;
} else if (zend_string_equals_literal_ci(Z_STR_P(zv), "ABSTTL")) {
dst->absttl = 1;
} else {
php_error_docref(NULL, E_WARNING, "Unknown RESTORE option '%s'", Z_STRVAL_P(zv));
}
}
} ZEND_HASH_FOREACH_END();
}
/* RESTORE */
int redis_restore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
zend_string *key, *value = NULL;
smart_string cmdstr = {0};
HashTable *options = NULL;
redisRestoreOptions opt;
zend_long timeout = 0;
int argc;
ZEND_PARSE_PARAMETERS_START(3, 4) {
Z_PARAM_STR(key)
Z_PARAM_LONG(timeout)
Z_PARAM_STR(value)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(options)
} ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
redis_get_restore_options(&opt, options);
argc = 3 + (opt.idletime>-1?2:0) + (opt.freq>-1?2:0) + !!opt.absttl + !!opt.replace;
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "RESTORE");
redis_cmd_append_sstr_key(&cmdstr, ZSTR_VAL(key), ZSTR_LEN(key), redis_sock, slot);
redis_cmd_append_sstr_long(&cmdstr, timeout);
redis_cmd_append_sstr_zstr(&cmdstr, value);
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.replace, "REPLACE");
REDIS_CMD_APPEND_SSTR_OPT_STATIC(&cmdstr, opt.absttl, "ABSTTL");
if (opt.idletime > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "IDLETIME");
redis_cmd_append_sstr_long(&cmdstr, opt.idletime);
}
if (opt.freq > -1) {
REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FREQ");
redis_cmd_append_sstr_long(&cmdstr, opt.freq);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* BITPOS */
int redis_bitpos_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+3
View File
@@ -135,6 +135,9 @@ int redis_lcs_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_mpop_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char *kw,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_restore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_subscribe_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
+2 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: f547b5f24c4d373043c89dab57d450d27f959b08 */
* Stub hash: 2c4ee6dc4a5aa66b1700df8859233c349aa00519 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_INFO(0, options)
@@ -552,6 +552,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_restore, 0, 0, 3)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, timeout)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_role arginfo_class_Redis___destruct
+16
View File
@@ -5096,6 +5096,22 @@ class Redis_Test extends TestSuite
$this->assertTrue($this->redis->get('foo') === 'this-is-bar');
$this->assertTrue($this->redis->get('bar') === 'this-is-foo');
/* Test that we can REPLACE a key */
$this->assertTrue($this->redis->set('foo', 'some-value'));
$this->assertTrue($this->redis->restore('foo', 0, $d_bar, ['REPLACE']));
/* Ensure we can set an absolute TTL */
$this->assertTrue($this->redis->restore('foo', time() + 10, $d_bar, ['REPLACE', 'ABSTTL']));
$this->assertTrue($this->redis->ttl('foo') <= 10);
/* Ensure we can set an IDLETIME */
$this->assertTrue($this->redis->restore('foo', 0, $d_bar, ['REPLACE', 'IDLETIME' => 200]));
$this->assertTrue($this->redis->object('idletime', 'foo') > 100);
/* We can't neccissarily check this depending on LRU policy, but at least attempt to use
the FREQ option */
$this->assertTrue($this->redis->restore('foo', 0, $d_bar, ['REPLACE', 'FREQ' => 200]));
$this->redis->del('foo');
$this->redis->del('bar');
}