Skip to content

Commit aa35241

Browse files
authored
CDRIVER-3905 Change estimatedDocumentCount to use collStats on 4.9+ (#758)
1 parent 4c6f743 commit aa35241

File tree

102 files changed

+1909
-26
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1909
-26
lines changed

src/libmongoc/src/mongoc/mongoc-client-private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ BSON_BEGIN_DECLS
9090
#define WIRE_VERSION_RETRYABLE_WRITE_ERROR_LABEL 9
9191
/* first version to support server hedged reads */
9292
#define WIRE_VERSION_HEDGED_READS 9
93+
/* first version to support estimatedDocumentCount with collStats */
94+
#define WIRE_VERSION_4_9 12
9395

9496
struct _mongoc_collection_t;
9597

src/libmongoc/src/mongoc/mongoc-collection.c

Lines changed: 96 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,56 @@ mongoc_collection_count_with_opts (
796796
RETURN (ret);
797797
}
798798

799+
/* --------------------------------------------------------------------------
800+
*
801+
* _make_aggregate_for_edc --
802+
*
803+
* Construct an aggregate pipeline with the following form:
804+
*
805+
*
806+
* { pipeline: [
807+
* { $collStats: { count: {} } },
808+
* { $group: { _id: 1, n: { $sum: $count } } },
809+
* ]
810+
* }
811+
*
812+
*--------------------------------------------------------------------------
813+
*/
814+
static void
815+
_make_aggregate_for_edc (const mongoc_collection_t *coll, bson_t *out)
816+
{
817+
bson_t pipeline;
818+
bson_t coll_stats_stage;
819+
bson_t coll_stats_stage_doc;
820+
bson_t group_stage;
821+
bson_t group_stage_doc;
822+
bson_t sum;
823+
bson_t cursor_empty;
824+
bson_t empty;
825+
826+
BSON_APPEND_UTF8 (out, "aggregate", coll->collection);
827+
BSON_APPEND_DOCUMENT_BEGIN (out, "cursor", &cursor_empty);
828+
bson_append_document_end (out, &cursor_empty);
829+
BSON_APPEND_ARRAY_BEGIN (out, "pipeline", &pipeline);
830+
831+
BSON_APPEND_DOCUMENT_BEGIN (&pipeline, "0", &coll_stats_stage);
832+
BSON_APPEND_DOCUMENT_BEGIN (
833+
&coll_stats_stage, "$collStats", &coll_stats_stage_doc);
834+
BSON_APPEND_DOCUMENT_BEGIN (&coll_stats_stage_doc, "count", &empty);
835+
bson_append_document_end (&coll_stats_stage_doc, &empty);
836+
bson_append_document_end (&coll_stats_stage, &coll_stats_stage_doc);
837+
bson_append_document_end (&pipeline, &coll_stats_stage);
838+
839+
BSON_APPEND_DOCUMENT_BEGIN (&pipeline, "1", &group_stage);
840+
BSON_APPEND_DOCUMENT_BEGIN (&group_stage, "$group", &group_stage_doc);
841+
BSON_APPEND_INT32 (&group_stage_doc, "_id", 1);
842+
BSON_APPEND_DOCUMENT_BEGIN (&group_stage_doc, "n", &sum);
843+
BSON_APPEND_UTF8 (&sum, "$sum", "$count");
844+
bson_append_document_end (&group_stage_doc, &sum);
845+
bson_append_document_end (&group_stage, &group_stage_doc);
846+
bson_append_document_end (&pipeline, &group_stage);
847+
bson_append_array_end (out, &pipeline);
848+
}
799849

800850
int64_t
801851
mongoc_collection_estimated_document_count (
@@ -811,11 +861,15 @@ mongoc_collection_estimated_document_count (
811861
bson_t reply_local;
812862
bson_t *reply_ptr;
813863
bson_t cmd = BSON_INITIALIZER;
864+
mongoc_server_stream_t *server_stream = NULL;
814865

815866
ENTRY;
816867

817868
BSON_ASSERT_PARAM (coll);
818869

870+
server_stream = mongoc_cluster_stream_for_reads (
871+
&coll->client->cluster, read_prefs, NULL, reply, error);
872+
819873
if (opts && bson_has_field (opts, "sessionId")) {
820874
bson_set_error (error,
821875
MONGOC_ERROR_COMMAND,
@@ -825,24 +879,45 @@ mongoc_collection_estimated_document_count (
825879
}
826880

827881
reply_ptr = reply ? reply : &reply_local;
828-
bson_append_utf8 (&cmd, "count", 5, coll->collection, coll->collectionlen);
829-
830-
ret = _mongoc_client_command_with_opts (coll->client,
831-
coll->db,
832-
&cmd,
833-
MONGOC_CMD_READ,
834-
opts,
835-
MONGOC_QUERY_NONE,
836-
read_prefs,
837-
coll->read_prefs,
838-
coll->read_concern,
839-
coll->write_concern,
840-
reply_ptr,
841-
error);
842-
843-
if (ret) {
844-
if (bson_iter_init_find (&iter, reply_ptr, "n")) {
845-
count = bson_iter_as_int64 (&iter);
882+
if (server_stream->sd->max_wire_version < WIRE_VERSION_4_9) {
883+
/* On < 4.9, use actual count command for estimatedDocumentCount */
884+
BSON_APPEND_UTF8 (&cmd, "count", coll->collection);
885+
ret = _mongoc_client_command_with_opts (coll->client,
886+
coll->db,
887+
&cmd,
888+
MONGOC_CMD_READ,
889+
opts,
890+
MONGOC_QUERY_NONE,
891+
read_prefs,
892+
coll->read_prefs,
893+
coll->read_concern,
894+
coll->write_concern,
895+
reply_ptr,
896+
error);
897+
if (ret) {
898+
if (bson_iter_init_find (&iter, reply_ptr, "n")) {
899+
count = bson_iter_as_int64 (&iter);
900+
}
901+
}
902+
} else {
903+
/* On >= 4.9, use aggregate with collStats for estimatedDocumentCount */
904+
_make_aggregate_for_edc (coll, &cmd);
905+
ret = mongoc_collection_read_command_with_opts (
906+
coll, &cmd, read_prefs, opts, reply_ptr, error);
907+
908+
if (error && error->code == MONGOC_ERROR_COLLECTION_DOES_NOT_EXIST) {
909+
/* Collection does not exist. From spec: return 0 but no err:
910+
* https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#estimateddocumentcount
911+
*/
912+
memset (error, 0, sizeof *error);
913+
count = 0;
914+
GOTO (done);
915+
}
916+
if (ret && bson_iter_init (&iter, reply_ptr)) {
917+
if (bson_iter_find_descendant (
918+
&iter, "cursor.firstBatch.0.n", &iter)) {
919+
count = bson_iter_as_int64 (&iter);
920+
}
846921
}
847922
}
848923

@@ -851,6 +926,7 @@ mongoc_collection_estimated_document_count (
851926
bson_destroy (&reply_local);
852927
}
853928
bson_destroy (&cmd);
929+
mongoc_server_stream_cleanup (server_stream);
854930

855931
RETURN (count);
856932
}
@@ -3380,9 +3456,8 @@ mongoc_collection_find_and_modify_with_opts (
33803456
retry_server_stream = mongoc_cluster_stream_for_writes (
33813457
cluster, parts.assembled.session, NULL /* reply */, &ignored_error);
33823458

3383-
if (retry_server_stream &&
3384-
retry_server_stream->sd->max_wire_version >=
3385-
WIRE_VERSION_RETRY_WRITES) {
3459+
if (retry_server_stream && retry_server_stream->sd->max_wire_version >=
3460+
WIRE_VERSION_RETRY_WRITES) {
33863461
parts.assembled.server_stream = retry_server_stream;
33873462
GOTO (retry);
33883463
}

0 commit comments

Comments
 (0)