Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Kill all cursors whenever a connection is disconnected PHP-313

  • Loading branch information...
commit b155ecbc315eeb6bd9b7adf568533eb80190700a 1 parent 9e4c768
Kristina kchodorow authored
5 bson.c
View
@@ -784,17 +784,16 @@ int php_mongo_write_query(buffer *buf, mongo_cursor *cursor TSRMLS_DC) {
return php_mongo_serialize_size(buf->start + start, buf TSRMLS_CC);
}
-int php_mongo_write_kill_cursors(buffer *buf, mongo_cursor *cursor TSRMLS_DC) {
+int php_mongo_write_kill_cursors(buffer *buf, int64_t cursor_id TSRMLS_DC) {
mongo_msg_header header;
CREATE_MSG_HEADER(MonGlo(request_id)++, 0, OP_KILL_CURSORS);
APPEND_HEADER(buf, 0);
- cursor->send.request_id = header.request_id;
// # of cursors
php_mongo_serialize_int(buf, 1);
// cursor ids
- php_mongo_serialize_long(buf, cursor->cursor_id);
+ php_mongo_serialize_long(buf, cursor_id);
return php_mongo_serialize_size(buf->start, buf TSRMLS_CC);
}
2  bson.h
View
@@ -77,7 +77,7 @@ int php_mongo_write_query(buffer*, mongo_cursor* TSRMLS_DC);
int php_mongo_write_get_more(buffer*, mongo_cursor* TSRMLS_DC);
int php_mongo_write_delete(buffer*, char*, int, zval* TSRMLS_DC);
int php_mongo_write_update(buffer*, char*, int, zval*, zval* TSRMLS_DC);
-int php_mongo_write_kill_cursors(buffer*, mongo_cursor* TSRMLS_DC);
+int php_mongo_write_kill_cursors(buffer*, int64_t TSRMLS_DC);
#define php_mongo_set_type(buf, type) php_mongo_serialize_byte(buf, (char)type)
#define php_mongo_serialize_null(buf) php_mongo_serialize_byte(buf, (char)0)
82 cursor.c
View
@@ -697,11 +697,14 @@ int mongo_cursor__do_query(zval *this_ptr, zval *return_value TSRMLS_DC) {
/* }}} */
int mongo_util_cursor_failed(mongo_cursor *cursor TSRMLS_DC) {
+ mongo_server *old = cursor->server;
+
// kill cursor so that the server stops and the new connection doesn't try
// to kill something it doesn't own
mongo_util_cursor_reset(cursor TSRMLS_CC);
- mongo_util_link_failed(cursor->link, cursor->server TSRMLS_CC);
+ // reset sets cursor->server to 0, so we use "old" here
+ mongo_util_link_failed(cursor->link, old TSRMLS_CC);
return FAILURE;
}
@@ -1105,15 +1108,44 @@ void mongo_cursor_free_le(void *val, int type TSRMLS_DC) {
while (current) {
cursor_node *next = current->next;
- if (type == MONGO_LINK) {
- if (current->cursor->link == (mongo_link*)val) {
- kill_cursor(current, le TSRMLS_CC);
+ if (type == MONGO_SERVER) {
+ mongo_server *server = (mongo_server*)val;
+ if (server != 0 && current->socket == server->socket) {
+ if (!server->connected) {
+ php_mongo_free_cursor_node(current, le);
+ }
+ else {
+ kill_cursor(current, le TSRMLS_CC);
+ }
// keep going, free all cursor for this connection
}
}
else if (type == MONGO_CURSOR) {
- if (current->cursor == (mongo_cursor*)val) {
- kill_cursor(current, le TSRMLS_CC);
+ mongo_cursor *cursor = (mongo_cursor*)val;
+ if (current->cursor_id == cursor->cursor_id &&
+ cursor->server != 0 &&
+ current->socket == cursor->server->socket) {
+
+ // If the cursor_id is 0, the db is out of results anyway
+ // If the connection is not connected, just return
+ if (current->cursor_id == 0 || !cursor->server->connected) {
+ php_mongo_free_cursor_node(current, le);
+ }
+ else {
+ kill_cursor(current, le TSRMLS_CC);
+
+ /*
+ * if the connection is closed before the cursor is destroyed, the cursor
+ * might try to fetch more results with disasterous consequences. Thus, the
+ * cursor_id is set to 0, so no more results will be fetched.
+ *
+ * this might not be the most elegant solution, since you could fetch 100
+ * results, get the first one, close the connection, get 99 more, and suddenly
+ * not be able to get any more. Not sure if there's a better one, though. I
+ * guess the user can call dead() on the cursor.
+ */
+ cursor->cursor_id = 0;
+ }
// only one cursor to be freed
break;
}
@@ -1134,7 +1166,13 @@ int php_mongo_create_le(mongo_cursor *cursor, char *name TSRMLS_DC) {
LOCK(cursor);
new_node = (cursor_node*)pemalloc(sizeof(cursor_node), 1);
- new_node->cursor = cursor;
+ new_node->cursor_id = cursor->cursor_id;
+ if (cursor->server) {
+ new_node->socket = cursor->server->socket;
+ }
+ else {
+ new_node->socket = 0;
+ }
new_node->next = new_node->prev = 0;
/*
@@ -1160,7 +1198,8 @@ int php_mongo_create_le(mongo_cursor *cursor, char *name TSRMLS_DC) {
* if we find the current cursor in the cursor list, we don't need another
* dtor for it so unlock the mutex & return.
*/
- if (current->cursor == cursor) {
+ if (current->cursor_id == cursor->cursor_id &&
+ current->socket == cursor->server->socket) {
pefree(new_node, 1);
UNLOCK(cursor);
return 0;
@@ -1204,13 +1243,8 @@ static int cursor_list_pfree_helper(zend_rsrc_list_entry *rsrc TSRMLS_DC) {
while (node->next) {
cursor_node *temp = node;
node = node->next;
-
- pefree(temp->cursor->buf.start, 1);
- pefree(temp->cursor, 1);
pefree(temp, 1);
}
- pefree(node->cursor->buf.start, 1);
- pefree(node->cursor, 1);
pefree(node, 1);
}
@@ -1258,7 +1292,6 @@ void php_mongo_free_cursor_node(cursor_node *node, zend_rsrc_list_entry *le) {
// tell db to destroy its cursor
static void kill_cursor(cursor_node *node, zend_rsrc_list_entry *le TSRMLS_DC) {
- mongo_cursor *cursor = node->cursor;
char quickbuf[128];
buffer buf;
zval temp;
@@ -1266,7 +1299,7 @@ static void kill_cursor(cursor_node *node, zend_rsrc_list_entry *le TSRMLS_DC) {
/*
* If the cursor_id is 0, the db is out of results anyway.
*/
- if (cursor->cursor_id == 0) {
+ if (node->cursor_id == 0) {
php_mongo_free_cursor_node(node, le);
return;
}
@@ -1275,30 +1308,15 @@ static void kill_cursor(cursor_node *node, zend_rsrc_list_entry *le TSRMLS_DC) {
buf.start = buf.pos;
buf.end = buf.start + 128;
- php_mongo_write_kill_cursors(&buf, cursor TSRMLS_CC);
+ php_mongo_write_kill_cursors(&buf, node->cursor_id TSRMLS_CC);
- if (!cursor->server) {
- return;
- }
Z_TYPE(temp) = IS_NULL;
- _mongo_say(cursor->server->socket, &buf, &temp TSRMLS_CC);
+ _mongo_say(node->socket, &buf, &temp TSRMLS_CC);
if (Z_TYPE(temp) == IS_STRING) {
efree(Z_STRVAL(temp));
Z_TYPE(temp) = IS_NULL;
}
- /*
- * if the connection is closed before the cursor is destroyed, the cursor
- * might try to fetch more results with disasterous consequences. Thus, the
- * cursor_id is set to 0, so no more results will be fetched.
- *
- * this might not be the most elegant solution, since you could fetch 100
- * results, get the first one, close the connection, get 99 more, and suddenly
- * not be able to get any more. Not sure if there's a better one, though. I
- * guess the user can call dead() on the cursor.
- */
- cursor->cursor_id = 0;
-
// free this cursor/link pair
php_mongo_free_cursor_node(node, le);
}
1  mongo.c
View
@@ -158,7 +158,6 @@ static void php_mongo_link_free(void *object TSRMLS_DC) {
return;
}
- mongo_cursor_free_le(link, MONGO_LINK TSRMLS_CC);
if (link->rs) {
mongo_server *current = link->server_set->server;
5 php_mongo.h
View
@@ -230,7 +230,7 @@ typedef struct {
char *rs;
} mongo_link;
-#define MONGO_LINK 0
+#define MONGO_SERVER 0
#define MONGO_CURSOR 1
@@ -453,7 +453,8 @@ typedef struct {
* cursors for that link.
*/
typedef struct _cursor_node {
- mongo_cursor *cursor;
+ int64_t cursor_id;
+ int socket;
struct _cursor_node *next;
struct _cursor_node *prev;
71 util/io.c
View
@@ -71,28 +71,6 @@ int php_mongo__get_reply(mongo_cursor *cursor, zval *errmsg TSRMLS_DC) {
int sock;
mongo_log(MONGO_LOG_IO, MONGO_LOG_FINE TSRMLS_CC, "hearing something");
-
- // this cursor has already been processed
- if (cursor->send.request_id < MonGlo(response_num)) {
- cursor_node *response = 0;
- zend_rsrc_list_entry *le;
-
- if (zend_hash_find(&EG(persistent_list), "response_list", strlen("response_list") + 1, (void**)&le) == SUCCESS) {
- response = le->ptr;
- }
-
- while (response) {
- if (response->cursor->recv.response_to == cursor->send.request_id) {
- make_unpersistent_cursor(response->cursor, cursor);
- php_mongo_free_cursor_node(response, le);
- return SUCCESS;
- }
- response = response->next;
- }
-
- // if we didn't find it, it might have been send out of order so keep going
- }
-
sock = cursor->server->socket;
if (get_cursor_header(sock, cursor TSRMLS_CC) == FAILURE) {
@@ -100,54 +78,11 @@ int php_mongo__get_reply(mongo_cursor *cursor, zval *errmsg TSRMLS_DC) {
}
// check that this is actually the response we want
- while (cursor->send.request_id != cursor->recv.response_to) {
+ if (cursor->send.request_id != cursor->recv.response_to) {
mongo_log(MONGO_LOG_IO, MONGO_LOG_FINE TSRMLS_CC, "request/cursor mismatch: %d vs %d", cursor->send.request_id, cursor->recv.response_to);
- // if it's not...
-
- // if we're getting the response to an earlier request, put the response on
- // the queue
- if (cursor->send.request_id > cursor->recv.response_to) {
- if (FAILURE != get_cursor_body(sock, cursor TSRMLS_CC)) {
- mongo_cursor *pcursor = make_persistent_cursor(cursor);
- // add to list
- php_mongo_create_le(pcursor, "response_list" TSRMLS_CC);
- }
- else {
- // else if we've failed, just don't add to queue
- mongo_cursor_throw(cursor->server, 9 TSRMLS_CC, "lost db connection");
- return FAILURE;
- }
- }
- // otherwise, check if the response is on the queue
- else {
- cursor_node *response = 0;
- zend_rsrc_list_entry *le;
-
- if (zend_hash_find(&EG(persistent_list), "response_list", strlen("response_list") + 1, (void**)&le) == SUCCESS) {
- response = le->ptr;
- }
-
- while (response) {
- // if it is, then pull it off & use it
- if (response->cursor->send.request_id == cursor->recv.response_to) {
- memcpy(cursor, response->cursor, sizeof(mongo_cursor));
- php_mongo_free_cursor_node(response, le);
- return SUCCESS;
- }
- response = response->next;
- }
-
- if (!response) {
- mongo_cursor_throw(cursor->server, 9 TSRMLS_CC, "couldn't find a response");
- return FAILURE;
- }
- }
-
- // get the next db response
- if (get_cursor_header(sock, cursor TSRMLS_CC) == FAILURE) {
- return FAILURE;
- }
+ mongo_cursor_throw(cursor->server, 9 TSRMLS_CC, "request/cursor mismatch: %d vs %d", cursor->send.request_id, cursor->recv.response_to);
+ return FAILURE;
}
if (FAILURE == get_cursor_body(sock, cursor TSRMLS_CC)) {
3  util/pool.c
View
@@ -466,6 +466,9 @@ void mongo_util_pool__close_connections(stack_monitor *monitor TSRMLS_DC) {
void mongo_util_pool__disconnect(stack_monitor *monitor, mongo_server *server) {
int was_connected = server->connected;
+ // kill any cursor associated with this connection before deleting it
+ mongo_cursor_free_le(server, MONGO_SERVER TSRMLS_CC);
+
mongo_util_disconnect(server);
if (was_connected &&
Please sign in to comment.
Something went wrong with that request. Please try again.