From 94212a90439ca7075fff68a40b7663ce96871b33 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Wed, 17 Jun 2020 21:48:50 -0400 Subject: [PATCH 1/3] redis clone --- common.h | 1 + library.c | 2 +- redis.c | 26 ++++++++++++++++++++++++++ redis_array.c | 1 + redis_cluster.c | 1 + sentinel_library.c | 1 + tests/RedisTest.php | 16 ++++++++++++++++ 7 files changed, 47 insertions(+), 1 deletion(-) diff --git a/common.h b/common.h index 14aefb53a3..edf8b557af 100644 --- a/common.h +++ b/common.h @@ -292,6 +292,7 @@ typedef struct { int readonly; int reply_literal; int tcp_keepalive; + int clone; } RedisSock; /* }}} */ diff --git a/library.c b/library.c index d9fc53a529..cfff02c3b4 100644 --- a/library.c +++ b/library.c @@ -2021,7 +2021,7 @@ redis_sock_disconnect(RedisSock *redis_sock, int force) { if (redis_sock == NULL) { return FAILURE; - } else if (redis_sock->stream) { + } else if (redis_sock->stream && !redis_sock->clone) { if (redis_sock->persistent) { ConnectionPool *p = NULL; if (INI_INT("redis.pconnect.pooling_enabled")) { diff --git a/redis.c b/redis.c index 71e301adb4..75c9129f5a 100644 --- a/redis.c +++ b/redis.c @@ -580,6 +580,31 @@ free_redis_object(zend_object *object) } } +static zend_object * +clone_redis_object(zval *this_ptr) +{ + zend_object *old_object = Z_OBJ_P(this_ptr); + redis_object *old_redis = PHPREDIS_GET_OBJECT(redis_object, this_ptr); + redis_object *redis = ecalloc(1, sizeof(redis_object) + zend_object_properties_size(old_object->ce)); + + if (old_redis->sock) { + redis->sock = ecalloc(1, sizeof(RedisSock)); + redis->sock = memcpy(redis->sock, old_redis->sock, sizeof(RedisSock)); + redis->sock->clone = 1; + } + + zend_object_std_init(&redis->std, old_object->ce); + object_properties_init(&redis->std, old_object->ce); + + memcpy(&redis_object_handlers, zend_get_std_object_handlers(), sizeof(redis_object_handlers)); + redis_object_handlers.offset = XtOffsetOf(redis_object, std); + redis_object_handlers.free_obj = free_redis_object; + redis_object_handlers.clone_obj = clone_redis_object; + redis->std.handlers = &redis_object_handlers; + + return &redis->std; +} + zend_object * create_redis_object(zend_class_entry *ce) { @@ -593,6 +618,7 @@ create_redis_object(zend_class_entry *ce) memcpy(&redis_object_handlers, zend_get_std_object_handlers(), sizeof(redis_object_handlers)); redis_object_handlers.offset = XtOffsetOf(redis_object, std); redis_object_handlers.free_obj = free_redis_object; + redis_object_handlers.clone_obj = clone_redis_object; redis->std.handlers = &redis_object_handlers; return &redis->std; diff --git a/redis_array.c b/redis_array.c index bdd7120efa..99023930a7 100644 --- a/redis_array.c +++ b/redis_array.c @@ -200,6 +200,7 @@ create_redis_array_object(zend_class_entry *ce) memcpy(&redis_array_object_handlers, zend_get_std_object_handlers(), sizeof(redis_array_object_handlers)); redis_array_object_handlers.offset = XtOffsetOf(redis_array_object, std); redis_array_object_handlers.free_obj = free_redis_array_object; + redis_array_object_handlers.clone_obj = NULL; obj->std.handlers = &redis_array_object_handlers; return &obj->std; diff --git a/redis_cluster.c b/redis_cluster.c index a2ced22a86..e9e7fc6fb0 100644 --- a/redis_cluster.c +++ b/redis_cluster.c @@ -326,6 +326,7 @@ zend_object * create_cluster_context(zend_class_entry *class_type) { memcpy(&RedisCluster_handlers, zend_get_std_object_handlers(), sizeof(RedisCluster_handlers)); RedisCluster_handlers.offset = XtOffsetOf(redisCluster, std); RedisCluster_handlers.free_obj = free_cluster_context; + RedisCluster_handlers.clone_obj = NULL; cluster->std.handlers = &RedisCluster_handlers; diff --git a/sentinel_library.c b/sentinel_library.c index 481985467f..e29d166c11 100644 --- a/sentinel_library.c +++ b/sentinel_library.c @@ -25,6 +25,7 @@ create_sentinel_object(zend_class_entry *ce) memcpy(&redis_sentinel_object_handlers, zend_get_std_object_handlers(), sizeof(redis_sentinel_object_handlers)); redis_sentinel_object_handlers.offset = XtOffsetOf(redis_sentinel_object, std); redis_sentinel_object_handlers.free_obj = free_redis_sentinel_object; + redis_sentinel_object_handlers.clone_obj = NULL; obj->std.handlers = &redis_sentinel_object_handlers; return &obj->std; diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 3cf753d8a9..383b699007 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -97,6 +97,22 @@ public function testMinimumVersion() $this->assertTrue(version_compare($this->version, "2.4.0") >= 0); } + public function testClone() + { + if (get_class($this->redis) !== 'Redis') { + $this->markTestSkipped(); + return; + } + + $new = clone $this->redis; + /* check that connection works */ + $this->assertTrue($new->ping()); + /* confirm socket settings are disconnected from source object */ + $this->assertTrue($new->setOption(Redis::OPT_PREFIX, 'test')); + $this->assertEquals($new->getOption(Redis::OPT_PREFIX), 'test'); + $this->assertFalse($this->redis->getOption(Redis::OPT_PREFIX)); + } + public function testPing() { /* Reply literal off */ $this->assertTrue($this->redis->ping()); From b9713e54d05a543753c64dfaaa4b0eb1eeb36163 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Fri, 19 Jun 2020 08:48:51 -0400 Subject: [PATCH 2/3] Create new socket on clone --- common.h | 1 - library.c | 2 +- redis.c | 24 ++++++++++++++++++++---- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/common.h b/common.h index edf8b557af..14aefb53a3 100644 --- a/common.h +++ b/common.h @@ -292,7 +292,6 @@ typedef struct { int readonly; int reply_literal; int tcp_keepalive; - int clone; } RedisSock; /* }}} */ diff --git a/library.c b/library.c index cfff02c3b4..d9fc53a529 100644 --- a/library.c +++ b/library.c @@ -2021,7 +2021,7 @@ redis_sock_disconnect(RedisSock *redis_sock, int force) { if (redis_sock == NULL) { return FAILURE; - } else if (redis_sock->stream && !redis_sock->clone) { + } else if (redis_sock->stream) { if (redis_sock->persistent) { ConnectionPool *p = NULL; if (INI_INT("redis.pconnect.pooling_enabled")) { diff --git a/redis.c b/redis.c index 75c9129f5a..c41b47239a 100644 --- a/redis.c +++ b/redis.c @@ -584,13 +584,29 @@ static zend_object * clone_redis_object(zval *this_ptr) { zend_object *old_object = Z_OBJ_P(this_ptr); - redis_object *old_redis = PHPREDIS_GET_OBJECT(redis_object, this_ptr); + redis_object *old_redis = PHPREDIS_GET_OBJECT(redis_object, old_object); redis_object *redis = ecalloc(1, sizeof(redis_object) + zend_object_properties_size(old_object->ce)); if (old_redis->sock) { - redis->sock = ecalloc(1, sizeof(RedisSock)); - redis->sock = memcpy(redis->sock, old_redis->sock, sizeof(RedisSock)); - redis->sock->clone = 1; + redis->sock = redis_sock_create(ZSTR_VAL(old_redis->sock->host), ZSTR_LEN(old_redis->sock->host), + old_redis->sock->port, + old_redis->sock->timeout, + old_redis->sock->read_timeout, + old_redis->sock->persistent, + ZSTR_VAL(old_redis->sock->persistent_id), + old_redis->sock->retry_interval); + + if (old_redis->sock->stream_ctx) { + redis_sock_set_stream_context(redis->sock, &old_redis->sock->stream_ctx->options); + } + + if (redis_sock_server_open(redis->sock) < 0) { + if (redis->sock->err) { + REDIS_THROW_EXCEPTION(ZSTR_VAL(redis->sock->err), 0); + } + redis_free_socket(redis->sock); + redis->sock = NULL; + } } zend_object_std_init(&redis->std, old_object->ce); From 7c43c54bc52168c6592ea99f32388f9a0980c529 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Tue, 21 Jul 2020 17:42:20 -0400 Subject: [PATCH 3/3] Added auth support --- redis.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/redis.c b/redis.c index 651d00387a..657c1f6745 100644 --- a/redis.c +++ b/redis.c @@ -618,6 +618,10 @@ clone_redis_object(zval *this_ptr) redis_sock_set_stream_context(redis->sock, &old_redis->sock->stream_ctx->options); } + if (old_redis->sock->user) { + redis_sock_set_auth(redis->sock, old_redis->sock->user, old_redis->sock->pass); + } + if (redis_sock_server_open(redis->sock) < 0) { if (redis->sock->err) { REDIS_THROW_EXCEPTION(ZSTR_VAL(redis->sock->err), 0);