Permalink
Browse files

Write session data to master or slave (#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.
  • Loading branch information...
1 parent e2d2825 commit e4ee953cad151fc11519140f2da7c2ce4858c0e7 @nicolasff nicolasff committed Jul 4, 2012
Showing with 68 additions and 37 deletions.
  1. +1 −0 common.h
  2. +21 −13 library.c
  3. +4 −4 redis.c
  4. +42 −20 redis_session.c
View
@@ -161,6 +161,7 @@ typedef struct {
int persistent;
int watching;
char *persistent_id;
+ int nothrow;
int serializer;
long dbNumber;
View
@@ -29,6 +29,14 @@ PHPAPI void redis_stream_close(RedisSock *redis_sock TSRMLS_DC) {
}
}
+PHPAPI void redis_throw_exception(RedisSock *redis_sock, zend_class_entry *ce, char *msg, int code TSRMLS_DC) {
+
+ if(redis_sock && redis_sock->nothrow)
+ return;
+
+ zend_throw_exception(ce, msg, code TSRMLS_CC);
+}
+
PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
{
int eof;
@@ -47,7 +55,7 @@ PHPAPI int redis_check_eof(RedisSock *redis_sock TSRMLS_DC)
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->watching = 0;
}
- zend_throw_exception(redis_exception_ce, "Connection lost", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "Connection lost", 0 TSRMLS_CC);
return -1;
}
if(redis_sock->stream) { /* close existing stream before reconnecting */
@@ -104,7 +112,7 @@ PHPAPI zval *redis_sock_read_multibulk_reply_zval(INTERNAL_FUNCTION_PARAMETERS,
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return NULL;
}
@@ -147,7 +155,7 @@ PHPAPI char *redis_sock_read_bulk_reply(RedisSock *redis_sock, int bytes TSRMLS_
got = php_stream_read(redis_sock->stream, reply + offset, bytes-offset);
if (got <= 0) {
/* Error or EOF */
- zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
break;
}
offset += got;
@@ -179,15 +187,15 @@ PHPAPI char *redis_sock_read(RedisSock *redis_sock, int *buf_len TSRMLS_DC)
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return NULL;
}
switch(inbuf[0]) {
case '-':
/* stale data */
if(memcmp(inbuf + 1, "-ERR SYNC ", 10) == 0) {
- zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
}
return NULL;
@@ -687,7 +695,7 @@ PHPAPI int redis_sock_read_multibulk_reply_zipped_with_flag(INTERNAL_FUNCTION_PA
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return -1;
}
@@ -1051,7 +1059,7 @@ PHPAPI int redis_sock_read_multibulk_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSo
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return -1;
}
@@ -1093,7 +1101,7 @@ PHPAPI int redis_sock_read_multibulk_reply_raw(INTERNAL_FUNCTION_PARAMETERS, Red
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return -1;
}
@@ -1167,7 +1175,7 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R
redis_sock->status = REDIS_SOCK_STATUS_FAILED;
redis_sock->mode = ATOMIC;
redis_sock->watching = 0;
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
return -1;
}
@@ -1214,7 +1222,7 @@ PHPAPI int redis_sock_read_multibulk_reply_assoc(INTERNAL_FUNCTION_PARAMETERS, R
PHPAPI int redis_sock_write(RedisSock *redis_sock, char *cmd, size_t sz TSRMLS_DC)
{
if(redis_sock && redis_sock->status == REDIS_SOCK_STATUS_DISCONNECTED) {
- zend_throw_exception(redis_exception_ce, "Connection closed", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "Connection closed", 0 TSRMLS_CC);
return -1;
}
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
redis_sock->watching = 0;
// Throw a read error exception
- zend_throw_exception(redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "read error on connection", 0 TSRMLS_CC);
}
// We don't need \r\n
@@ -1421,7 +1429,7 @@ redis_read_reply_type(RedisSock *redis_sock, REDIS_REPLY_TYPE *reply_type, int *
// Attempt to read the reply-type byte
if((*reply_type = php_stream_getc(redis_sock->stream)) == EOF) {
- zend_throw_exception(redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "socket error on read socket", 0 TSRMLS_CC);
}
// 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
// If this is an error response, check if it is a SYNC error, and throw in that case
if(reply_type == TYPE_ERR) {
if(memcmp(inbuf, "ERR SYNC", 9) == 0) {
- zend_throw_exception(redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "SYNC with master in progress", 0 TSRMLS_CC);
}
// Set our last error
View
@@ -359,7 +359,7 @@ PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC, int no_thr
sizeof("socket"), (void **) &socket) == FAILURE) {
// Throw an exception unless we've been requested not to
if(!no_throw) {
- zend_throw_exception(redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
+ redis_throw_exception(*redis_sock, redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
}
return -1;
}
@@ -369,7 +369,7 @@ PHPAPI int redis_sock_get(zval *id, RedisSock **redis_sock TSRMLS_DC, int no_thr
if (!*redis_sock || resource_type != le_redis_sock) {
// Throw an exception unless we've been requested not to
if(!no_throw) {
- zend_throw_exception(redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
+ redis_throw_exception(*redis_sock, redis_exception_ce, "Redis server went away", 0 TSRMLS_CC);
}
return -1;
}
@@ -569,7 +569,7 @@ PHPAPI int redis_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) {
}
if (timeout < 0L || timeout > INT_MAX) {
- zend_throw_exception(redis_exception_ce, "Invalid timeout", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "Invalid timeout", 0 TSRMLS_CC);
return FAILURE;
}
@@ -6123,7 +6123,7 @@ PHP_METHOD(Redis, _unserialize) {
zval *z_ret = NULL;
if(redis_unserialize(redis_sock, value, value_len, &z_ret TSRMLS_CC) == 0) {
// Badly formed input, throw an execption
- zend_throw_exception(redis_exception_ce, "Invalid serialized data, or unserialization error", 0 TSRMLS_CC);
+ redis_throw_exception(redis_sock, redis_exception_ce, "Invalid serialized data, or unserialization error", 0 TSRMLS_CC);
RETURN_FALSE;
}
RETURN_ZVAL(z_ret, 0, 1);
View
@@ -340,7 +340,7 @@ redis_session_key(redis_pool_member *rpm, const char *key, int key_len, int *ses
}
static int
-get_session(redis_pool_member *rpm, RedisSock *sock, const char *key, char **val, int *vallen)
+get_session(redis_pool_member *rpm, RedisSock *sock, const char *key, char **val, int *vallen TSRMLS_DC)
{
char *session, *cmd;
int session_len, cmd_len, ret;
@@ -377,42 +377,32 @@ PS_READ_FUNC(redis)
}
/* read session from main server or failover. */
- ret = get_session(rpm, redis_sock, key, val, vallen);
+ ret = get_session(rpm, redis_sock, key, val, vallen TSRMLS_CC);
if(EG(exception) && rpm->failover_sock) {
zend_clear_exception(TSRMLS_C); /* clear exception flag. */
- ret = get_session(rpm, rpm->failover_sock, key, val, vallen);
+ ret = get_session(rpm, rpm->failover_sock, key, val, vallen TSRMLS_CC);
}
return ret;
}
/* }}} */
-/* {{{ PS_WRITE_FUNC
- */
-PS_WRITE_FUNC(redis)
+static int
+set_session(redis_pool_member *rpm, RedisSock *sock, const char *session, int session_len, const char *val, int vallen TSRMLS_DC)
{
- char *cmd, *response, *session;
- int cmd_len, response_len, session_len;
-
- redis_pool *pool = PS_GET_MOD_DATA();
- redis_pool_member *rpm = redis_pool_get_sock(pool, key TSRMLS_CC);
- RedisSock *redis_sock = rpm?rpm->redis_sock:NULL;
- if(!rpm || !redis_sock){
- return FAILURE;
- }
+ char *cmd, *response;
+ int cmd_len, response_len;
- /* send SET command */
- session = redis_session_key(rpm, key, strlen(key), &session_len);
+ /* send SET command */
cmd_len = redis_cmd_format_static(&cmd, "SETEX", "sds", session, session_len, INI_INT("session.gc_maxlifetime"), val, vallen);
- efree(session);
- if(redis_sock_write(redis_sock, cmd, cmd_len TSRMLS_CC) < 0) {
+ if(redis_sock_write(sock, cmd, cmd_len TSRMLS_CC) < 0) {
efree(cmd);
return FAILURE;
}
efree(cmd);
/* read response */
- if ((response = redis_sock_read(redis_sock, &response_len TSRMLS_CC)) == NULL) {
+ if ((response = redis_sock_read(sock, &response_len TSRMLS_CC)) == NULL) {
return FAILURE;
}
@@ -424,6 +414,38 @@ PS_WRITE_FUNC(redis)
return FAILURE;
}
}
+
+/* {{{ PS_WRITE_FUNC
+ */
+PS_WRITE_FUNC(redis)
+{
+ int ret;
+ char *session;
+ int session_len;
+
+ redis_pool *pool = PS_GET_MOD_DATA();
+ redis_pool_member *rpm = redis_pool_get_sock(pool, key TSRMLS_CC);
+ RedisSock *redis_sock = rpm?rpm->redis_sock:NULL;
+ if(!rpm || !redis_sock){
+ return FAILURE;
+ }
+
+ /* disable exceptions */
+ redis_sock->nothrow = 1;
+
+ /* write session to main server or failover. */
+ session = redis_session_key(rpm, key, strlen(key), &session_len);
+ ret = set_session(rpm, redis_sock, session, session_len, val, vallen TSRMLS_CC);
+ if(ret == FAILURE && rpm->failover_sock) {
+ ret = set_session(rpm, rpm->failover_sock, session, session_len, val, vallen TSRMLS_CC);
+ }
+ efree(session);
+
+ /* re-enable exceptions */
+ redis_sock->nothrow = 0;
+
+ return ret;
+}
/* }}} */
/* {{{ PS_DESTROY_FUNC

0 comments on commit e4ee953

Please sign in to comment.