Skip to content

Commit 0266789

Browse files
committed
CDRIVER-837: Add support for readConcern in mongoc_collection_count
1 parent 001a305 commit 0266789

File tree

2 files changed

+263
-11
lines changed

2 files changed

+263
-11
lines changed

src/mongoc/mongoc-collection.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ mongoc_collection_find (mongoc_collection_t *collection, /* IN */
468468
read_prefs = collection->read_prefs;
469469
}
470470

471-
return _mongoc_cursor_new(collection->client, collection->ns, flags, skip,
471+
return _mongoc_cursor_new (collection->client, collection->ns, flags, skip,
472472
limit, batch_size, false, query, fields, read_prefs);
473473
}
474474

@@ -605,12 +605,24 @@ mongoc_collection_count_with_opts (mongoc_collection_t *collection, /* IN
605605
const mongoc_read_prefs_t *read_prefs, /* IN */
606606
bson_error_t *error) /* OUT */
607607
{
608-
int64_t ret = -1;
608+
mongoc_server_stream_t *server_stream;
609+
mongoc_cluster_t *cluster;
609610
bson_iter_t iter;
611+
int64_t ret = -1;
612+
bool success;
610613
bson_t reply;
611614
bson_t cmd;
612615
bson_t q;
613616

617+
ENTRY;
618+
619+
620+
cluster = &collection->client->cluster;
621+
server_stream = mongoc_cluster_stream_for_writes (cluster, error);
622+
if (!server_stream) {
623+
RETURN (-1);
624+
}
625+
614626
BSON_ASSERT (collection);
615627

616628
bson_init(&cmd);
@@ -629,18 +641,38 @@ mongoc_collection_count_with_opts (mongoc_collection_t *collection, /* IN
629641
if (skip) {
630642
bson_append_int64(&cmd, "skip", 4, skip);
631643
}
644+
if (collection->read_concern->level != NULL) {
645+
const bson_t *read_concern_bson;
646+
647+
if (server_stream->sd->max_wire_version < WIRE_VERSION_READ_CONCERN) {
648+
bson_set_error (error,
649+
MONGOC_ERROR_COMMAND,
650+
MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION,
651+
"The selected server does not support readConcern");
652+
bson_destroy (&cmd);
653+
mongoc_server_stream_cleanup (server_stream);
654+
RETURN (-1);
655+
}
656+
657+
read_concern_bson = _mongoc_read_concern_get_bson (collection->read_concern);
658+
BSON_APPEND_DOCUMENT (&cmd, "readConcern", read_concern_bson);
659+
}
632660
if (opts) {
633661
bson_concat(&cmd, opts);
634662
}
635-
if (mongoc_collection_command_simple(collection, &cmd, read_prefs,
636-
&reply, error) &&
637-
bson_iter_init_find(&iter, &reply, "n")) {
663+
664+
success = mongoc_cluster_run_command (cluster, server_stream->stream,
665+
MONGOC_QUERY_SLAVE_OK, collection->db,
666+
&cmd, &reply, error);
667+
668+
if (success && bson_iter_init_find(&iter, &reply, "n")) {
638669
ret = bson_iter_as_int64(&iter);
639670
}
640-
bson_destroy(&reply);
641-
bson_destroy(&cmd);
671+
bson_destroy (&reply);
672+
bson_destroy (&cmd);
673+
mongoc_server_stream_cleanup (server_stream);
642674

643-
return ret;
675+
RETURN (ret);
644676
}
645677

646678

@@ -1628,17 +1660,17 @@ mongoc_collection_get_read_concern (const mongoc_collection_t *collection)
16281660

16291661
void
16301662
mongoc_collection_set_read_concern (mongoc_collection_t *collection,
1631-
const mongoc_read_concern_t *read_concern)
1663+
const mongoc_read_concern_t *read_concern)
16321664
{
16331665
BSON_ASSERT (collection);
16341666

16351667
if (collection->read_concern) {
1636-
mongoc_read_concern_destroy(collection->read_concern);
1668+
mongoc_read_concern_destroy (collection->read_concern);
16371669
collection->read_concern = NULL;
16381670
}
16391671

16401672
if (read_concern) {
1641-
collection->read_concern = mongoc_read_concern_copy(read_concern);
1673+
collection->read_concern = mongoc_read_concern_copy (read_concern);
16421674
}
16431675
}
16441676

tests/test-mongoc-collection.c

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,224 @@ test_count (void)
12211221
}
12221222

12231223

1224+
static void
1225+
test_count_read_concern (void)
1226+
{
1227+
mongoc_collection_t *collection;
1228+
mongoc_client_t *client;
1229+
mongoc_read_concern_t *rc;
1230+
mock_server_t *server;
1231+
request_t *request;
1232+
bson_error_t error;
1233+
future_t *future;
1234+
int64_t count;
1235+
bson_t b;
1236+
1237+
/* wire protocol version 4 */
1238+
server = mock_server_with_autoismaster (WIRE_VERSION_READ_CONCERN);
1239+
mock_server_run (server);
1240+
client = mongoc_client_new_from_uri (mock_server_get_uri (server));
1241+
ASSERT (client);
1242+
1243+
collection = mongoc_client_get_collection (client, "test", "test");
1244+
ASSERT (collection);
1245+
1246+
bson_init(&b);
1247+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1248+
0, 0, NULL, &error);
1249+
bson_destroy(&b);
1250+
request = mock_server_receives_command (
1251+
server, "test", MONGOC_QUERY_SLAVE_OK,
1252+
"{ 'count' : 'test', 'query' : { } }");
1253+
1254+
mock_server_replies_simple (request, "{ 'n' : 42, 'ok' : 1 } ");
1255+
count = future_get_int64_t (future);
1256+
ASSERT_OR_PRINT (count == 42, error);
1257+
1258+
/* readConcern: { level: majority } */
1259+
rc = mongoc_read_concern_new ();
1260+
mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY);
1261+
mongoc_collection_set_read_concern (collection, rc);
1262+
1263+
bson_init(&b);
1264+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1265+
0, 0, NULL, &error);
1266+
bson_destroy(&b);
1267+
request = mock_server_receives_command (
1268+
server, "test", MONGOC_QUERY_SLAVE_OK,
1269+
"{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'majority'}}");
1270+
1271+
mock_server_replies_simple (request, "{ 'n' : 43, 'ok' : 1 } ");
1272+
count = future_get_int64_t (future);
1273+
ASSERT_OR_PRINT (count == 43, error);
1274+
mongoc_read_concern_destroy (rc);
1275+
1276+
1277+
/* readConcern: { level: local } */
1278+
rc = mongoc_read_concern_new ();
1279+
mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL);
1280+
mongoc_collection_set_read_concern (collection, rc);
1281+
1282+
bson_init(&b);
1283+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1284+
0, 0, NULL, &error);
1285+
bson_destroy(&b);
1286+
request = mock_server_receives_command (
1287+
server, "test", MONGOC_QUERY_SLAVE_OK,
1288+
"{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'local'}}");
1289+
1290+
mock_server_replies_simple (request, "{ 'n' : 44, 'ok' : 1 } ");
1291+
count = future_get_int64_t (future);
1292+
ASSERT_OR_PRINT (count == 44, error);
1293+
mongoc_read_concern_destroy (rc);
1294+
1295+
/* readConcern: { level: futureCompatible } */
1296+
rc = mongoc_read_concern_new ();
1297+
mongoc_read_concern_set_level (rc, "futureCompatible");
1298+
mongoc_collection_set_read_concern (collection, rc);
1299+
1300+
bson_init(&b);
1301+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1302+
0, 0, NULL, &error);
1303+
bson_destroy(&b);
1304+
request = mock_server_receives_command (
1305+
server, "test", MONGOC_QUERY_SLAVE_OK,
1306+
"{ 'count' : 'test', 'query' : { }, 'readConcern': {'level': 'futureCompatible'}}");
1307+
1308+
mock_server_replies_simple (request, "{ 'n' : 45, 'ok' : 1 } ");
1309+
count = future_get_int64_t (future);
1310+
ASSERT_OR_PRINT (count == 45, error);
1311+
mongoc_read_concern_destroy (rc);
1312+
1313+
/* Setting readConcern to NULL should not send readConcern */
1314+
rc = mongoc_read_concern_new ();
1315+
mongoc_read_concern_set_level (rc, NULL);
1316+
mongoc_collection_set_read_concern (collection, rc);
1317+
1318+
bson_init(&b);
1319+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1320+
0, 0, NULL, &error);
1321+
bson_destroy(&b);
1322+
request = mock_server_receives_command (
1323+
server, "test", MONGOC_QUERY_SLAVE_OK,
1324+
"{ 'count' : 'test', 'query' : { } }");
1325+
1326+
mock_server_replies_simple (request, "{ 'n' : 46, 'ok' : 1 } ");
1327+
count = future_get_int64_t (future);
1328+
ASSERT_OR_PRINT (count == 46, error);
1329+
mongoc_read_concern_destroy (rc);
1330+
1331+
/* Fresh read_concern should not send readConcern */
1332+
rc = mongoc_read_concern_new ();
1333+
mongoc_collection_set_read_concern (collection, rc);
1334+
1335+
bson_init(&b);
1336+
future = future_collection_count (collection, MONGOC_QUERY_NONE, &b,
1337+
0, 0, NULL, &error);
1338+
bson_destroy(&b);
1339+
request = mock_server_receives_command (
1340+
server, "test", MONGOC_QUERY_SLAVE_OK,
1341+
"{ 'count' : 'test', 'query' : { } }");
1342+
1343+
mock_server_replies_simple (request, "{ 'n' : 47, 'ok' : 1 } ");
1344+
count = future_get_int64_t (future);
1345+
ASSERT_OR_PRINT (count == 47, error);
1346+
mongoc_read_concern_destroy (rc);
1347+
1348+
mongoc_collection_destroy (collection);
1349+
mongoc_client_destroy (client);
1350+
mock_server_destroy (server);
1351+
}
1352+
1353+
1354+
static void
1355+
_test_count_read_concern_live (bool supports_read_concern)
1356+
{
1357+
mongoc_collection_t *collection;
1358+
mongoc_client_t *client;
1359+
mongoc_read_concern_t *rc;
1360+
bson_error_t error;
1361+
int64_t count;
1362+
bson_t b;
1363+
1364+
1365+
client = test_framework_client_new ();
1366+
ASSERT (client);
1367+
1368+
collection = mongoc_client_get_collection (client, "test", "test");
1369+
ASSERT (collection);
1370+
1371+
mongoc_collection_drop (collection, &error);
1372+
1373+
bson_init(&b);
1374+
count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b,
1375+
0, 0, NULL, &error);
1376+
bson_destroy(&b);
1377+
ASSERT_OR_PRINT (count == 0, error);
1378+
1379+
/* Setting readConcern to NULL should not send readConcern */
1380+
rc = mongoc_read_concern_new ();
1381+
mongoc_read_concern_set_level (rc, NULL);
1382+
mongoc_collection_set_read_concern (collection, rc);
1383+
1384+
bson_init(&b);
1385+
count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b,
1386+
0, 0, NULL, &error);
1387+
bson_destroy(&b);
1388+
ASSERT_OR_PRINT (count == 0, error);
1389+
mongoc_read_concern_destroy (rc);
1390+
1391+
/* readConcern: { level: local } should raise error pre 3.2 */
1392+
rc = mongoc_read_concern_new ();
1393+
mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_LOCAL);
1394+
mongoc_collection_set_read_concern (collection, rc);
1395+
1396+
bson_init(&b);
1397+
count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b,
1398+
0, 0, NULL, &error);
1399+
bson_destroy(&b);
1400+
if (supports_read_concern) {
1401+
ASSERT_OR_PRINT (count == 0, error);
1402+
} else {
1403+
ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_COMMAND,
1404+
MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION,
1405+
"The selected server does not support readConcern")
1406+
}
1407+
mongoc_read_concern_destroy (rc);
1408+
1409+
/* readConcern: { level: majority } should raise error pre 3.2 */
1410+
rc = mongoc_read_concern_new ();
1411+
mongoc_read_concern_set_level (rc, MONGOC_READ_CONCERN_LEVEL_MAJORITY);
1412+
mongoc_collection_set_read_concern (collection, rc);
1413+
1414+
bson_init(&b);
1415+
count = mongoc_collection_count (collection, MONGOC_QUERY_NONE, &b,
1416+
0, 0, NULL, &error);
1417+
bson_destroy(&b);
1418+
if (supports_read_concern) {
1419+
ASSERT_OR_PRINT (count == 0, error);
1420+
} else {
1421+
ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_COMMAND,
1422+
MONGOC_ERROR_PROTOCOL_BAD_WIRE_VERSION,
1423+
"The selected server does not support readConcern")
1424+
}
1425+
mongoc_read_concern_destroy (rc);
1426+
1427+
mongoc_collection_destroy (collection);
1428+
mongoc_client_destroy (client);
1429+
}
1430+
1431+
static void
1432+
test_count_read_concern_live (void)
1433+
{
1434+
if (test_framework_max_wire_version_at_least (WIRE_VERSION_READ_CONCERN)) {
1435+
_test_count_read_concern_live (true);
1436+
} else {
1437+
_test_count_read_concern_live (false);
1438+
}
1439+
}
1440+
1441+
12241442
static void
12251443
test_count_with_opts (void)
12261444
{
@@ -2393,6 +2611,8 @@ test_collection_install (TestSuite *suite)
23932611
TestSuite_Add (suite, "/Collection/remove", test_remove);
23942612
TestSuite_Add (suite, "/Collection/count", test_count);
23952613
TestSuite_Add (suite, "/Collection/count_with_opts", test_count_with_opts);
2614+
TestSuite_Add (suite, "/Collection/count/read_concern", test_count_read_concern);
2615+
TestSuite_Add (suite, "/Collection/count/read_concern_live", test_count_read_concern_live);
23962616
TestSuite_Add (suite, "/Collection/drop", test_drop);
23972617
TestSuite_Add (suite, "/Collection/aggregate", test_aggregate);
23982618
TestSuite_Add (suite, "/Collection/aggregate/large", test_aggregate_large);

0 commit comments

Comments
 (0)