Skip to content

Commit d3a0983

Browse files
committed
Merge pull request #1059
2 parents 5d6001e + 9ecb50a commit d3a0983

File tree

12 files changed

+615
-7
lines changed

12 files changed

+615
-7
lines changed

php_phongo.c

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ void phongo_session_init(zval* return_value, mongoc_client_session_t* client_ses
384384

385385
session = Z_SESSION_OBJ_P(return_value);
386386
session->client_session = client_session;
387+
session->client = mongoc_client_session_get_client(client_session);
387388
}
388389
/* }}} */
389390

@@ -2623,8 +2624,8 @@ static void php_phongo_persist_client(const char* hash, size_t hash_len, mongoc_
26232624
{
26242625
php_phongo_pclient_t* pclient = (php_phongo_pclient_t*) pecalloc(1, sizeof(php_phongo_pclient_t), 1);
26252626

2626-
pclient->pid = (int) getpid();
2627-
pclient->client = client;
2627+
pclient->created_by_pid = (int) getpid();
2628+
pclient->client = client;
26282629

26292630
#if PHP_VERSION_ID >= 70000
26302631
zend_hash_str_update_ptr(&MONGODB_G(pclients), hash, hash_len, pclient);
@@ -2879,13 +2880,71 @@ PHP_INI_BEGIN()
28792880
PHP_INI_END()
28802881
/* }}} */
28812882

2883+
static void phongo_pclient_reset_once(php_phongo_pclient_t* pclient, int pid)
2884+
{
2885+
if (pclient->last_reset_by_pid != pid) {
2886+
mongoc_client_reset(pclient->client);
2887+
pclient->last_reset_by_pid = pid;
2888+
}
2889+
}
2890+
2891+
/* Resets the libmongoc client if it has not already been reset for the current
2892+
* PID (based on information in the hash table of persisted libmongoc clients).
2893+
* This ensures that we do not reset a client multiple times from the same child
2894+
* process. */
2895+
void php_phongo_client_reset_once(mongoc_client_t* client, int pid)
2896+
{
2897+
HashTable* pclients;
2898+
2899+
TSRMLS_FETCH();
2900+
pclients = &MONGODB_G(pclients);
2901+
2902+
#if PHP_VERSION_ID >= 70000
2903+
{
2904+
zval* z_ptr;
2905+
php_phongo_pclient_t* pclient;
2906+
2907+
ZEND_HASH_FOREACH_VAL(pclients, z_ptr)
2908+
{
2909+
if ((Z_TYPE_P(z_ptr) != IS_PTR)) {
2910+
continue;
2911+
}
2912+
2913+
pclient = (php_phongo_pclient_t*) Z_PTR_P(z_ptr);
2914+
2915+
if (pclient->client == client) {
2916+
phongo_pclient_reset_once(pclient, pid);
2917+
return;
2918+
}
2919+
}
2920+
ZEND_HASH_FOREACH_END();
2921+
}
2922+
#else
2923+
{
2924+
HashPosition pos;
2925+
php_phongo_pclient_t** pclient;
2926+
2927+
for (
2928+
zend_hash_internal_pointer_reset_ex(pclients, &pos);
2929+
zend_hash_get_current_data_ex(pclients, (void**) &pclient, &pos) == SUCCESS;
2930+
zend_hash_move_forward_ex(pclients, &pos)) {
2931+
2932+
if ((*pclient)->client == client) {
2933+
phongo_pclient_reset_once((*pclient), pid);
2934+
return;
2935+
}
2936+
}
2937+
}
2938+
#endif
2939+
}
2940+
28822941
static inline void php_phongo_pclient_destroy(php_phongo_pclient_t* pclient)
28832942
{
28842943
/* Do not destroy mongoc_client_t objects created by other processes. This
28852944
* ensures that we do not shutdown sockets that may still be in use by our
28862945
* parent process (see: CDRIVER-2049). While this is a leak, we are already
28872946
* in MSHUTDOWN at this point. */
2888-
if (pclient->pid == getpid()) {
2947+
if (pclient->created_by_pid == getpid()) {
28892948
mongoc_client_destroy(pclient->client);
28902949
}
28912950

php_phongo.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ extern zend_module_entry mongodb_module_entry;
3333
* forking). We avoid using pid_t for Windows compatibility. */
3434
typedef struct {
3535
mongoc_client_t* client;
36-
int pid;
36+
int created_by_pid;
37+
int last_reset_by_pid;
3738
} php_phongo_pclient_t;
3839

3940
ZEND_BEGIN_MODULE_GLOBALS(mongodb)
@@ -168,6 +169,8 @@ bool php_phongo_parse_int64(int64_t* retval, const char* data, phongo_zpp_char_l
168169
zend_bool phongo_writeerror_init(zval* return_value, bson_t* bson TSRMLS_DC);
169170
zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson TSRMLS_DC);
170171

172+
void php_phongo_client_reset_once(mongoc_client_t* client, int pid);
173+
171174
#if PHP_VERSION_ID >= 70000
172175
#define PHONGO_CE_FINAL(ce) \
173176
do { \
@@ -217,6 +220,19 @@ zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson TSRMLS_
217220
#define PHONGO_ZVAL_EXCEPTION_NAME(e) (ZSTR_VAL(Z_OBJCE_P(e)->name))
218221
#endif
219222

223+
#define PHONGO_SET_CREATED_BY_PID(intern) \
224+
do { \
225+
(intern)->created_by_pid = (int) getpid(); \
226+
} while (0);
227+
228+
#define PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern) \
229+
do { \
230+
int pid = (int) getpid(); \
231+
if ((intern)->created_by_pid != pid) { \
232+
php_phongo_client_reset_once((intern)->client, pid); \
233+
} \
234+
} while (0);
235+
220236
#endif /* PHONGO_H */
221237

222238
/*

php_phongo_structs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ typedef struct {
5555
PHONGO_ZEND_OBJECT_PRE
5656
mongoc_cursor_t* cursor;
5757
mongoc_client_t* client;
58+
int created_by_pid;
5859
uint32_t server_id;
5960
bool advanced;
6061
php_phongo_bson_state visitor_data;
@@ -78,6 +79,7 @@ typedef struct {
7879
typedef struct {
7980
PHONGO_ZEND_OBJECT_PRE
8081
mongoc_client_t* client;
82+
int created_by_pid;
8183
PHONGO_ZEND_OBJECT_POST
8284
} php_phongo_manager_t;
8385

@@ -107,13 +109,16 @@ typedef struct {
107109
typedef struct {
108110
PHONGO_ZEND_OBJECT_PRE
109111
mongoc_client_t* client;
112+
int created_by_pid;
110113
uint32_t server_id;
111114
PHONGO_ZEND_OBJECT_POST
112115
} php_phongo_server_t;
113116

114117
typedef struct {
115118
PHONGO_ZEND_OBJECT_PRE
116119
mongoc_client_session_t* client_session;
120+
mongoc_client_t* client;
121+
int created_by_pid;
117122
PHONGO_ZEND_OBJECT_POST
118123
} php_phongo_session_t;
119124

src/MongoDB/Cursor.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,11 @@ static void php_phongo_cursor_free_object(phongo_free_object_arg* object TSRMLS_
405405

406406
zend_object_std_dtor(&intern->std TSRMLS_CC);
407407

408+
/* If this Cursor was created in a different process, reset the client so
409+
* that mongoc_cursor_destroy does not issue a killCursors command for an
410+
* active cursor owned by a parent process. */
411+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
412+
408413
if (intern->cursor) {
409414
mongoc_cursor_destroy(intern->cursor);
410415
}
@@ -451,6 +456,8 @@ static phongo_create_object_retval php_phongo_cursor_create_object(zend_class_en
451456
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
452457
object_properties_init(&intern->std, class_type);
453458

459+
PHONGO_SET_CREATED_BY_PID(intern);
460+
454461
#if PHP_VERSION_ID >= 70000
455462
intern->std.handlers = &php_phongo_handler_cursor;
456463

src/MongoDB/Manager.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ static PHP_METHOD(Manager, executeCommand)
387387
goto cleanup;
388388
}
389389

390+
/* If the Manager was created in a different process, reset the client so
391+
* that cursors created by this process can be differentiated. */
392+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
393+
390394
phongo_execute_command(intern->client, PHONGO_COMMAND_RAW, db, command, options, server_id, return_value, return_value_used TSRMLS_CC);
391395

392396
cleanup:
@@ -430,6 +434,10 @@ static PHP_METHOD(Manager, executeReadCommand)
430434
return;
431435
}
432436

437+
/* If the Manager was created in a different process, reset the client so
438+
* that cursors created by this process can be differentiated. */
439+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
440+
433441
phongo_execute_command(intern->client, PHONGO_COMMAND_READ, db, command, options, server_id, return_value, return_value_used TSRMLS_CC);
434442
} /* }}} */
435443

@@ -462,6 +470,10 @@ static PHP_METHOD(Manager, executeWriteCommand)
462470
return;
463471
}
464472

473+
/* If the Manager was created in a different process, reset the client so
474+
* that cursors created by this process can be differentiated. */
475+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
476+
465477
phongo_execute_command(intern->client, PHONGO_COMMAND_WRITE, db, command, options, server_id, return_value, return_value_used TSRMLS_CC);
466478
} /* }}} */
467479

@@ -494,6 +506,10 @@ static PHP_METHOD(Manager, executeReadWriteCommand)
494506
return;
495507
}
496508

509+
/* If the Manager was created in a different process, reset the client so
510+
* that cursors created by this process can be differentiated. */
511+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
512+
497513
phongo_execute_command(intern->client, PHONGO_COMMAND_READ_WRITE, db, command, options, server_id, return_value, return_value_used TSRMLS_CC);
498514
} /* }}} */
499515

@@ -535,6 +551,10 @@ static PHP_METHOD(Manager, executeQuery)
535551
goto cleanup;
536552
}
537553

554+
/* If the Manager was created in a different process, reset the client so
555+
* that cursors created by this process can be differentiated. */
556+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
557+
538558
phongo_execute_query(intern->client, namespace, query, options, server_id, return_value, return_value_used TSRMLS_CC);
539559

540560
cleanup:
@@ -750,6 +770,11 @@ static PHP_METHOD(Manager, startSession)
750770
}
751771
}
752772

773+
/* If the Manager was created in a different process, reset the client so
774+
* that its session pool is cleared. This will ensure that we do not re-use
775+
* a server session (i.e. LSID) created by a parent process. */
776+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
777+
753778
cs = mongoc_client_start_session(intern->client, cs_opts, &error);
754779

755780
if (cs) {
@@ -855,6 +880,8 @@ static phongo_create_object_retval php_phongo_manager_create_object(zend_class_e
855880
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
856881
object_properties_init(&intern->std, class_type);
857882

883+
PHONGO_SET_CREATED_BY_PID(intern);
884+
858885
#if PHP_VERSION_ID >= 70000
859886
intern->std.handlers = &php_phongo_handler_manager;
860887

src/MongoDB/Server.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ static PHP_METHOD(Server, executeCommand)
4747

4848
options = php_phongo_prep_legacy_option(options, "readPreference", &free_options TSRMLS_CC);
4949

50+
/* If the Server was created in a different process, reset the client so
51+
* that cursors created by this process can be differentiated. */
52+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
53+
5054
phongo_execute_command(intern->client, PHONGO_COMMAND_RAW, db, command, options, intern->server_id, return_value, return_value_used TSRMLS_CC);
5155

5256
if (free_options) {
@@ -71,6 +75,10 @@ static PHP_METHOD(Server, executeReadCommand)
7175
return;
7276
}
7377

78+
/* If the Server was created in a different process, reset the client so
79+
* that cursors created by this process can be differentiated. */
80+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
81+
7482
phongo_execute_command(intern->client, PHONGO_COMMAND_READ, db, command, options, intern->server_id, return_value, return_value_used TSRMLS_CC);
7583
} /* }}} */
7684

@@ -91,6 +99,10 @@ static PHP_METHOD(Server, executeWriteCommand)
9199
return;
92100
}
93101

102+
/* If the Server was created in a different process, reset the client so
103+
* that cursors created by this process can be differentiated. */
104+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
105+
94106
phongo_execute_command(intern->client, PHONGO_COMMAND_WRITE, db, command, options, intern->server_id, return_value, return_value_used TSRMLS_CC);
95107
} /* }}} */
96108

@@ -111,6 +123,10 @@ static PHP_METHOD(Server, executeReadWriteCommand)
111123
return;
112124
}
113125

126+
/* If the Server was created in a different process, reset the client so
127+
* that cursors created by this process can be differentiated. */
128+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
129+
114130
phongo_execute_command(intern->client, PHONGO_COMMAND_READ_WRITE, db, command, options, intern->server_id, return_value, return_value_used TSRMLS_CC);
115131
} /* }}} */
116132

@@ -134,6 +150,10 @@ static PHP_METHOD(Server, executeQuery)
134150

135151
options = php_phongo_prep_legacy_option(options, "readPreference", &free_options TSRMLS_CC);
136152

153+
/* If the Server was created in a different process, reset the client so
154+
* that cursors created by this process can be differentiated. */
155+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
156+
137157
phongo_execute_query(intern->client, namespace, query, options, intern->server_id, return_value, return_value_used TSRMLS_CC);
138158

139159
if (free_options) {
@@ -568,6 +588,8 @@ static phongo_create_object_retval php_phongo_server_create_object(zend_class_en
568588
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
569589
object_properties_init(&intern->std, class_type);
570590

591+
PHONGO_SET_CREATED_BY_PID(intern);
592+
571593
#if PHP_VERSION_ID >= 70000
572594
intern->std.handlers = &php_phongo_handler_server;
573595

src/MongoDB/Session.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ static PHP_METHOD(Session, getServer)
284284
RETURN_NULL();
285285
}
286286

287-
phongo_server_init(return_value, mongoc_client_session_get_client(intern->client_session), server_id TSRMLS_CC);
287+
phongo_server_init(return_value, intern->client, server_id TSRMLS_CC);
288288
} /* }}} */
289289

290290
/* {{{ proto array|null MongoDB\Driver\Session::getTransactionOptions()
@@ -639,6 +639,13 @@ static void php_phongo_session_free_object(phongo_free_object_arg* object TSRMLS
639639

640640
zend_object_std_dtor(&intern->std TSRMLS_CC);
641641

642+
/* If this Session was created in a different process, reset the client so
643+
* that its session pool is cleared and mongoc_client_session_destroy will
644+
* destroy the corresponding server session rather than return it to the
645+
* now-empty pool. This will ensure that we do not re-use a server session
646+
* (i.e. LSID) created by a parent process. */
647+
PHONGO_RESET_CLIENT_IF_PID_DIFFERS(intern);
648+
642649
if (intern->client_session) {
643650
mongoc_client_session_destroy(intern->client_session);
644651
}
@@ -657,6 +664,8 @@ static phongo_create_object_retval php_phongo_session_create_object(zend_class_e
657664
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
658665
object_properties_init(&intern->std, class_type);
659666

667+
PHONGO_SET_CREATED_BY_PID(intern);
668+
660669
#if PHP_VERSION_ID >= 70000
661670
intern->std.handlers = &php_phongo_handler_session;
662671

@@ -772,13 +781,13 @@ static HashTable* php_phongo_session_get_debug_info(zval* object, int* is_temp T
772781
#if PHP_VERSION_ID >= 70000
773782
zval server;
774783

775-
phongo_server_init(&server, mongoc_client_session_get_client(intern->client_session), server_id TSRMLS_CC);
784+
phongo_server_init(&server, intern->client, server_id TSRMLS_CC);
776785
ADD_ASSOC_ZVAL_EX(&retval, "server", &server);
777786
#else
778787
zval* server = NULL;
779788

780789
MAKE_STD_ZVAL(server);
781-
phongo_server_init(server, mongoc_client_session_get_client(intern->client_session), server_id TSRMLS_CC);
790+
phongo_server_init(server, intern->client, server_id TSRMLS_CC);
782791
ADD_ASSOC_ZVAL_EX(&retval, "server", server);
783792
#endif
784793
} else {

0 commit comments

Comments
 (0)