8000 Write session data to master or slave (#203). · jrtkcoder/phpredis@e4ee953 · GitHub
[go: up one dir, main page]

Skip to content

Commit e4ee953

Browse files
committed
Write session data to master or slave (phpredis#203).
I had to introduce a "nothrow" flag in the RedisSock object in order to avoid throwing exceptions in the context of a session write. When PHP finishes and closes the session, it doesn't consider exceptions to be valid and simply bails out without giving the caller a chance to catch it. I replaced zend_throw_exception with redis_throw_exception which checks for this flag and just returns if we are in a session close context.
1 parent e2d2825 commit e4ee953

File tree

4 files changed

+68
-37
lines changed

4 files changed

+68
-37
lines changed

common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ typedef struct {
161161
int persistent;
162162
int watching;
163163
char *persistent_id;
164+
int nothrow;
164165

165166
int serializer;
166167
long dbNumber;

library.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ PHPAPI void redis_stream_close(RedisSock *redis_sock TSRMLS_DC) {
2929
}
3030
}
3131

32+
PHPAPI void redis_throw_exception(RedisSock *redis_sock, zend_class_entry *ce, char *msg, int code TSRMLS_DC) {
33+
34+
if(redis_sock && redis_sock->nothrow)
35+
return;
36+
37+
zend_throw_exception(ce, msg, code TSRMLS_CC);
38+
}
39+
3240
PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
3341
{
3442
int eof;
@@ -47,7 +55,7 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
4755
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
4856
redis_sock->watching = 0;
4957
}
50-
zend_throw_exception(redis_exception_ce, "Connection lost", 0 TSRMLS_CC);
58+
redis_throw_exception(redis_sock, redis_exception_ce, "Connection lost", 0 TSRMLS_CC);
5159
return -1;
5260
}
5361
if(redis_sock->stream) { /* close existing stream before reconnecting */
@@ -104,7 +112,7 @@ PHPAPI zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS,
104112
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
105113
redis_sock->mode = ATOMIC;
106114
redis_sock->watching = 0;
107-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
115+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
108116
return NULL;
109117
}
110118

@@ -147,7 +155,7 @@ PHPAPI char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes TSRMLS_
147155
got = php_stream_read(redis_sock->stream, reply + offset, bytes-offset);
148156
if (got <= 0) {
149157
/* Error or EOF */
150-
zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
158+
redis_throw_exception(redis_sock, redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
151159
break;
152160
}
153161
offset += got;
@@ -179,15 +187,15 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC)
179187
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
180188
redis_sock->mode = ATOMIC;
181189
redis_sock->watching = 0;
182-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
190+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
183191
return NULL;
184192
}
185193

186194
switch(inbuf[0]) {
187195
case '-':
188196
/* stale data */
189197
if(memcmp(inbuf + 1, "-ERR SYNC ", 10) == 0) {
190-
zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
198+
redis_throw_exception(redis_sock, redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
191199
}
192200
return NULL;
193201

@@ -687,7 +695,7 @@ PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PA
687695
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
688696
redis_sock->mode = ATOMIC;
689697
redis_sock->watching = 0;
690-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
698+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
691699
return -1;
692700
}
693701

@@ -1051,7 +1059,7 @@ PHPAPI int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSo
10511059
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
10521060
redis_sock->mode = ATOMIC;
10531061
redis_sock->watching = 0;
1054-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
1062+
redis_throw_exception(redis_sock, redis_exception_ce, "read err F438 or on connection", 0 TSRMLS_CC);
10551063
return -1;
10561064
}
10571065

@@ -1093,7 +1101,7 @@ PHPAPI int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, Red
10931101
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
10941102
redis_sock->mode = ATOMIC;
10951103
redis_sock->watching = 0;
1096-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
1104+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
10971105
return -1;
10981106
}
10991107

@@ -1167,7 +1175,7 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R
11671175
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
11681176
redis_sock->mode = ATOMIC;
11691177
redis_sock->watching = 0;
1170-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
1178+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
11711179
return -1;
11721180
}
11731181

@@ -1214,7 +1222,7 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R
12141222
PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz TSRMLS_DC)
12151223
{
12161224
if(redis_sock && redis_sock->status == REDIS_SOCK_STATUS_DISCONNECTED) {
1217-
zend_throw_exception(redis_exception_ce, "Connection closed", 0 TSRMLS_CC);
1225+
redis_throw_exception(redis_sock, redis_exception_ce, "Connection closed", 0 TSRMLS_CC);
12181226
return -1;
12191227
}
12201228
if(-1 == redis_check_eof(redis_sock TSRMLS_CC)) {
@@ -1399,7 +1407,7 @@ redis_sock_gets(RedisSock *redis_sock, char *buf, int buf_size, size_t *line_siz
13991407
redis_sock->watching = 0;
14001408

14011409
// Throw a read error exception
1402-
zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
1410+
redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
14031411
}
14041412

14051413
// We don't need \r\n
@@ -1421,7 +1429,7 @@ redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *
14211429

14221430
// Attempt to read the reply-type byte
14231431
if((*reply_type = php_stream_getc(redis_sock->stream)) == EOF) {
1424-
zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
1432+
redis_throw_exception(redis_sock, redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
14251433
}
14261434

14271435
// If this is a BULK, MULTI BULK, or simply an INTEGER response, we can extract the value or size info here
@@ -1459,7 +1467,7 @@ redis_read_variant_line(RedisSock *redis_sock, REDIS_REPLY_TYPE reply_type, zval
14591467
// If this is an error response, check if it is a SYNC error, and throw in that case
14601468
if(reply_type == TYPE_ERR) {
14611469
if(memcmp(inbuf, "ERR SYNC", 9) == 0) {
1462-
zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
1470+
redis_throw_exception(redis_sock, redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
14631471
}
14641472

14651473
// Set our last error

redis.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC, int no_thr
359359
sizeof("socket"), (void **) &socket) == FAILURE) {
360360
// Throw an exception unless we've been requested not to
361361
if(!no_throw) {
362-
zend_throw_exception(redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
362+
redis_throw_exception(*redis_sock, redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
363363
}
364364
return -1;
365365
}
@@ -369,7 +369,7 @@ PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC, int no_thr
369369
if (!*redis_sock || resource_type != le_redis_sock) {
370370
// Throw an exception unless we've been requested not to
371371
if(!no_throw) {
372-
zend_throw_exception(redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
372+
redis_throw_exception(*redis_sock, redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
373373
}
374374
return -1;
375375
}
@@ -569,7 +569,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
569569
}
570570

571571
if (timeout < 0L || timeout > INT_MAX) {
572-
zend_throw_exception(redis_exception_ce, "Invalid timeout", 0 TSRMLS_CC);
572+
redis_throw_exception(redis_sock, redis_exception_ce, "Invalid timeout", 0 TSRMLS_CC);
573573
return FAILURE;
574574
}
575575

@@ -6123,7 +6123,7 @@ PHP_METHOD(Redis, _unserialize) {
61236123
zval *z_ret = NULL;
61246124
if(redis_unserialize(redis_sock, value, value_len, &z_ret TSRMLS_CC) == 0) {
61256125
// Badly formed input, throw an execption
6126-
zend_throw_exception(redis_exception_ce, "Invalid serialized data, or unserialization error", 0 TSRMLS_CC);
6126+
redis_throw_exception(redis_sock, redis_exception_ce, "Invalid serialized data, or unserialization error", 0 TSRMLS_CC);
61276127
RETURN_FALSE;
61286128
}
61296129
RETURN_ZVAL(z_ret, 0, 1);

redis_session.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ redis_session_key(redis_pool_member *rpm, const char *key, int key_len, int *ses
340340
}
341341

342342
static int
343-
get_session(redis_pool_member *rpm, RedisSock *sock, const char *key, char **val, int *vallen)
343+
get_session(redis_pool_member *rpm, RedisSock *sock, const char *key, char **val, int *vallen TSRMLS_DC)
344344
{
345345
char *session, *cmd;
346346
int session_len, cmd_len, ret;
@@ -377,42 +377,32 @@ PS_READ_FUNC(redis)
377377
}
378378

379379
/* read session from main server or failover. */
380-
ret = get_session(rpm, redis_sock, key, val, vallen);
380+
ret = get_session(rpm, redis_sock, key, val, vallen TSRMLS_CC);
381381
if(EG(exception) && rpm->failover_sock) {
382382
zend_clear_exception(TSRMLS_C); /* clear exception flag. */
383-
ret = get_session(rpm, rpm->failover_sock, key, val, vallen);
383+
ret = get_session(rpm, rpm->failover_sock, key, val, vallen TSRMLS_CC);
384384
}
385385

386386
return ret;
387387
}
388388
/* }}} */
389389

390-
/* {{{ PS_WRITE_FUNC
391-
*/
392-
PS_WRITE_FUNC(redis)
390+
static int
391+
set_session(redis_pool_member *rpm, RedisSock *sock, const char *session, int session_len, const char *val, int vallen TSRMLS_DC)
393392
{
394-
char *cmd, *response, *session;
395-
int cmd_len, response_len, session_len;
396-
397-
redis_pool *pool = PS_GET_MOD_DATA();
398-
redis_pool_member *rpm = redis_pool_get_sock(pool, key TSRMLS_CC);
399-
RedisSock *redis_sock = rpm?rpm->redis_sock:NULL;
400-
if(!rpm || !redis_sock){
401-
return FAILURE;
402-
}
393+
char *cmd, *response;
394+
int cmd_len, response_len;
403395

404-
/* send SET command */
405-
session = redis_session_key(rpm, key, strlen(key), &session_len);
396+
/* send SET command */
406397
cmd_len = redis_cmd_format_static(&cmd, "SETEX", "sds", session, session_len, INI_INT("session.gc_maxlifetime"), val, vallen);
407-
efree(session);
408-
if(redis_sock_write(redis_sock, cmd, cmd_len TSRMLS_CC) < 0) {
398+
if(redis_sock_write(sock, cmd, cmd_len TSRMLS_CC) < 0) {
409399
efree(cmd);
410400
return FAILURE;
411401
}
412402
efree(cmd);
413403

414404
/* read response */
415-
if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) {
405+
if ((response = redis_sock_read(sock, &response_len TSRMLS_CC)) == NULL) {
416406
return FAILURE;
417407
}
418408

@@ -424,6 +414,38 @@ PS_WRITE_FUNC(redis)
424414
return FAILURE;
425415
}
426416
}
417+
418+
/* {{{ PS_WRITE_FUNC
419+
*/
420+
PS_WRITE_FUNC(redis)
421+
{
422+
int ret;
423+
char *session;
424+
int session_len;
425+
426+
redis_pool *pool = PS_GET_MOD_DATA();
427+
redis_pool_member *rpm = redis_pool_get_sock(pool, key TSRMLS_CC);
428+
RedisSock *redis_sock = rpm?rpm->redis_sock:NULL;
429+
if(!rpm || !redis_sock){
430+
return FAILURE;
431+
}
432+
433+
/* disable exceptions */
434+
redis_sock->nothrow = 1;
435+
436+
/* write session to main server or failover. */
437+
session = redis_session_key(rpm, key, strlen(key), &session_len);
438+
ret = set_session(rpm, redis_sock, session, session_len, val, vallen TSRMLS_CC);
439+
if(ret == FAILURE && rpm->failover_sock) {
440+
ret = set_session(rpm, rpm->failover_sock, session, session_len, val, vallen TSRMLS_CC);
441+
}
442+
efree(session);
443+
444+
/* re-enable exceptions */
445+
redis_sock->nothrow = 0;
446+
447+
return ret;
448+
}
427449
/* }}} */
428450

429451
/* {{{ PS_DESTROY_FUNC

0 commit comments

Comments
 (0)
0