Skip to content

Commit 5e4fa5c

Browse files
jmikolaajdavis
authored andcommitted
CDRIVER-903: Hinted cursors should still apply read prefs
This fixes an issue with the slaveOk bit not being set when using hint to query a secondary directly. We introduce a new is_write_command property on the cursor (private API change) to avoid setting the slaveOk bit on write commands. Conflicts: src/mongoc/mongoc-collection.c src/mongoc/mongoc-cursor-private.h src/mongoc/mongoc-cursor.c
1 parent 8bb7ac3 commit 5e4fa5c

File tree

7 files changed

+36
-21
lines changed

7 files changed

+36
-21
lines changed

src/mongoc/mongoc-client-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ _mongoc_client_command_simple_with_hint (mongoc_client_t *client,
115115
const char *db_name,
116116
const bson_t *command,
117117
const mongoc_read_prefs_t *read_prefs,
118+
bool is_write_command,
118119
bson_t *reply,
119120
uint32_t hint,
120121
bson_error_t *error);

src/mongoc/mongoc-client.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1159,14 +1159,15 @@ mongoc_client_command_simple (mongoc_client_t *client,
11591159
bson_error_t *error)
11601160
{
11611161
return _mongoc_client_command_simple_with_hint (client, db_name, command,
1162-
read_prefs, reply, 0, error);
1162+
read_prefs, false, reply, 0, error);
11631163
}
11641164

11651165
bool
11661166
_mongoc_client_command_simple_with_hint (mongoc_client_t *client,
11671167
const char *db_name,
11681168
const bson_t *command,
11691169
const mongoc_read_prefs_t *read_prefs,
1170+
bool is_write_command,
11701171
bson_t *reply,
11711172
uint32_t hint,
11721173
bson_error_t *error)
@@ -1183,6 +1184,7 @@ _mongoc_client_command_simple_with_hint (mongoc_client_t *client,
11831184
command, NULL, read_prefs);
11841185

11851186
cursor->hint = hint;
1187+
cursor->is_write_command = is_write_command ? 1 : 0;
11861188

11871189
ret = mongoc_cursor_next (cursor, &doc);
11881190

src/mongoc/mongoc-collection.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1909,7 +1909,9 @@ mongoc_collection_find_and_modify (mongoc_collection_t *collection,
19091909
/*
19101910
* Submit the command to MongoDB server.
19111911
*/
1912-
ret = mongoc_collection_command_simple (collection, &command, NULL, reply, error);
1912+
ret = _mongoc_client_command_simple_with_hint (collection->client,
1913+
collection->db, &command, NULL,
1914+
true, reply, 0, error);
19131915

19141916
/*
19151917
* Cleanup.

src/mongoc/mongoc-cursor-private.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,15 @@ struct _mongoc_cursor_t
5555
uint32_t hint;
5656
uint32_t stamp;
5757

58-
unsigned is_command : 1;
59-
unsigned sent : 1;
60-
unsigned done : 1;
61-
unsigned failed : 1;
62-
unsigned end_of_event : 1;
63-
unsigned in_exhaust : 1;
64-
unsigned redir_primary: 1;
65-
unsigned has_fields : 1;
58+
unsigned is_command : 1;
59+
unsigned sent : 1;
60+
unsigned done : 1;
61+
unsigned failed : 1;
62+
unsigned end_of_event : 1;
63+
unsigned in_exhaust : 1;
64+
unsigned redir_primary : 1;
65+
unsigned has_fields : 1;
66+
unsigned is_write_command: 1;
6667

6768
bson_t query;
6869
bson_t fields;

src/mongoc/mongoc-cursor.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ _mongoc_cursor_new (mongoc_client_t *client,
166166
cursor->batch_size = batch_size;
167167
cursor->is_command = is_command;
168168
cursor->has_fields = !!fields;
169+
cursor->is_write_command = false;
169170

170171
#define MARK_FAILED(c) \
171172
do { \
@@ -598,11 +599,11 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
598599
rpc.query.fields = NULL;
599600
}
600601

602+
topology = cursor->client->topology;
603+
601604
if (cursor->hint) {
602-
rpc.query.query = bson_get_data (&cursor->query);
605+
sd = mongoc_topology_server_by_id(topology, cursor->hint);
603606
} else {
604-
topology = cursor->client->topology;
605-
606607
if (!cursor->read_prefs) {
607608
local_read_prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY);
608609
}
@@ -616,21 +617,29 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
616617
if (local_read_prefs) {
617618
mongoc_read_prefs_destroy (local_read_prefs);
618619
}
620+
}
619621

620-
if (!sd) {
621-
GOTO (failure);
622-
}
622+
if (!sd) {
623+
GOTO (failure);
624+
}
623625

626+
if (!cursor->hint) {
624627
cursor->hint = sd->id;
628+
}
629+
630+
if (!cursor->is_write_command) {
625631
_apply_read_preferences (cursor->read_prefs,
626632
topology->description.type,
627633
sd->type,
628634
&cursor->query,
629635
&rpc.query);
630-
631-
mongoc_server_description_destroy (sd);
636+
} else {
637+
/* we haven't called apply_read_preferences, must set query */
638+
rpc.query.query = bson_get_data (&cursor->query);
632639
}
633640

641+
mongoc_server_description_destroy (sd);
642+
634643
if (!mongoc_cluster_sendv_to_server (&cursor->client->cluster,
635644
&rpc, 1, cursor->hint,
636645
NULL, true, &cursor->error)) {

src/mongoc/mongoc-write-command.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ _mongoc_write_command(mongoc_write_command_t *command,
888888
ret = false;
889889
} else {
890890
ret = _mongoc_client_command_simple_with_hint (client, database, &cmd, NULL,
891-
&reply, hint, error);
891+
true, &reply, hint, error);
892892

893893
if (!ret) {
894894
result->failed = true;

tests/test-mongoc-collection.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ test_aggregate_legacy (void *data)
14511451

14521452
/* no "cursor" argument */
14531453
request = mock_server_receives_command (
1454-
server, "db", MONGOC_QUERY_NONE,
1454+
server, "db", MONGOC_QUERY_SLAVE_OK,
14551455
"{'aggregate': 'collection',"
14561456
" 'pipeline': [{'a': 1}]},"
14571457
" 'cursor': {'$exists': false} %s",
@@ -1500,7 +1500,7 @@ test_aggregate_modern (void *data)
15001500

15011501
/* "cursor" argument always sent if wire version >= 1 */
15021502
request = mock_server_receives_command (
1503-
server, "db", MONGOC_QUERY_NONE,
1503+
server, "db", MONGOC_QUERY_SLAVE_OK,
15041504
"{'aggregate': 'collection',"
15051505
" 'pipeline': [{'a': 1}],"
15061506
" 'cursor': %s %s}",

0 commit comments

Comments
 (0)