Skip to content

Commit fb44d11

Browse files
committed
CDRIVER-1082 proper bulk op splitting at the margin
1 parent 016b5d7 commit fb44d11

File tree

3 files changed

+88
-9
lines changed

3 files changed

+88
-9
lines changed

NEWS

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
mongo-c-driver 1.3.3
2+
====================
3+
4+
It is my pleasure to announce MongoDB C Driver 1.3.3. This fixes a bug where
5+
a slightly-oversized bulk write operation was not split into batches; instead,
6+
it was sent whole to the server, which rejected it.
7+
8+
Peace,
9+
10+
A. Jesse Jiryu Davis
11+
12+
113
mongo-c-driver 1.3.2
214
====================
315

src/mongoc/mongoc-write-command.c

+16-8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ static bson_t gEmptyWriteConcern = BSON_INITIALIZER;
5151
/* indexed by MONGOC_WRITE_COMMAND_DELETE, INSERT, UPDATE */
5252
static const char *gCommandNames[] = { "delete", "insert", "update"};
5353
static const char *gCommandFields[] = { "deletes", "documents", "updates"};
54+
static const uint32_t gCommandFieldLens[] = { 7, 9, 7 };
5455

5556
static int32_t
5657
_mongoc_write_result_merge_arrays (uint32_t offset,
@@ -589,14 +590,13 @@ _mongoc_write_command_will_overflow (uint32_t len_so_far,
589590
int32_t max_bson_size,
590591
int32_t max_write_batch_size)
591592
{
592-
/* max BSON object size + 16k - 2 bytes for ending NUL bytes.
593+
/* max BSON object size + 16k bytes.
593594
* server guarantees there is enough room: SERVER-10643
594595
*/
595-
int32_t max_cmd_size = max_bson_size + 16382;
596+
int32_t max_cmd_size = max_bson_size + 16384;
596597

597598
BSON_ASSERT (max_bson_size);
598599

599-
600600
if (len_so_far + document_len > max_cmd_size) {
601601
return true;
602602
} else if (max_write_batch_size > 0 &&
@@ -799,6 +799,7 @@ _mongoc_write_command(mongoc_write_command_t *command,
799799
int32_t max_bson_obj_size;
800800
int32_t max_write_batch_size;
801801
int32_t min_wire_version;
802+
uint32_t overhead;
802803
uint32_t key_len;
803804

804805
ENTRY;
@@ -856,18 +857,25 @@ _mongoc_write_command(mongoc_write_command_t *command,
856857
!!command->flags.bypass_document_validation);
857858
}
858859

859-
if (!_mongoc_write_command_will_overflow (0,
860+
/* 1 byte to specify array type, 1 byte for field name's null terminator */
861+
overhead = cmd.len + 2 + gCommandFieldLens[command->type];
862+
863+
if (!_mongoc_write_command_will_overflow (overhead,
860864
command->documents->len,
861865
command->n_documents,
862866
max_bson_obj_size,
863867
max_write_batch_size)) {
864868
/* copy the whole documents buffer as e.g. "updates": [...] */
865-
BSON_APPEND_ARRAY (&cmd,
869+
bson_append_array (&cmd,
866870
gCommandFields[command->type],
871+
gCommandFieldLens[command->type],
867872
command->documents);
868873
i = command->n_documents;
869874
} else {
870-
bson_append_array_begin (&cmd, gCommandFields[command->type], -1, &ar);
875+
bson_append_array_begin (&cmd,
876+
gCommandFields[command->type],
877+
gCommandFieldLens[command->type],
878+
&ar);
871879

872880
do {
873881
if (!BSON_ITER_HOLDS_DOCUMENT (&iter)) {
@@ -877,8 +885,8 @@ _mongoc_write_command(mongoc_write_command_t *command,
877885
bson_iter_document (&iter, &len, &data);
878886
key_len = (uint32_t) bson_uint32_to_string (i, &key, str, sizeof str);
879887

880-
if (_mongoc_write_command_will_overflow (ar.len,
881-
key_len + len + 2,
888+
if (_mongoc_write_command_will_overflow (overhead,
889+
key_len + len + 2 + ar.len,
882890
i,
883891
max_bson_obj_size,
884892
max_write_batch_size)) {

tests/test-bulk.c

+60-1
Original file line numberDiff line numberDiff line change
@@ -876,8 +876,65 @@ test_replace_one (bool ordered)
876876
}
877877

878878

879+
/*
880+
* check that we include command overhead in msg size when deciding to split,
881+
* CDRIVER-1082
882+
*/
879883
static void
880884
test_upsert_large (void)
885+
{
886+
mongoc_bulk_operation_t *bulk;
887+
mongoc_collection_t *collection;
888+
mongoc_client_t *client;
889+
bool has_write_cmds;
890+
bson_t *selector = tmp_bson ("{'_id': 'aaaaaaaaaa'}");
891+
size_t sz = 8396691; /* a little over 8 MB */
892+
char *large_str = bson_malloc (sz);
893+
bson_t update = BSON_INITIALIZER;
894+
bson_t child;
895+
bson_error_t error;
896+
int i;
897+
bson_t reply;
898+
899+
client = test_framework_client_new ();
900+
has_write_cmds = server_has_write_commands (client);
901+
collection = get_test_collection (client, "test_upsert_large");
902+
bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
903+
904+
bson_append_document_begin (&update, "$set", 4, &child);
905+
bson_append_utf8 (&child, "big", 3, large_str, (int) sz);
906+
bson_append_document_end (&update, &child);
907+
908+
/* two 8MB+ docs could fit in 16MB + 16K, if not for command overhead,
909+
* check the driver splits into two msgs */
910+
for (i = 0; i < 2; i++) {
911+
mongoc_bulk_operation_update (bulk, selector, &update, true);
912+
}
913+
914+
ASSERT_OR_PRINT ((bool) mongoc_bulk_operation_execute (bulk, &reply, &error),
915+
error);
916+
917+
ASSERT_MATCH (&reply, "{'nInserted': 0,"
918+
" 'nMatched': 1,"
919+
" 'nRemoved': 0,"
920+
" 'nUpserted': 1,"
921+
" 'upserted': [{'index': 0, '_id': 'aaaaaaaaaa'}],"
922+
" 'writeErrors': []}");
923+
924+
check_n_modified (has_write_cmds, &reply, 0);
925+
ASSERT_COUNT (1, collection);
926+
927+
bson_destroy (&reply);
928+
mongoc_bulk_operation_destroy (bulk);
929+
mongoc_collection_destroy (collection);
930+
mongoc_client_destroy (client);
931+
bson_destroy (&update);
932+
bson_free (large_str);
933+
}
934+
935+
936+
static void
937+
test_upsert_huge (void)
881938
{
882939
mongoc_bulk_operation_t *bulk;
883940
mongoc_collection_t *collection;
@@ -897,7 +954,7 @@ test_upsert_large (void)
897954
assert (client);
898955
has_write_cmds = server_has_write_commands (client);
899956

900-
collection = get_test_collection (client, "test_upsert_large");
957+
collection = get_test_collection (client, "test_upsert_huge");
901958
assert (collection);
902959

903960
bulk = mongoc_collection_create_bulk_operation (collection, true, NULL);
@@ -2852,6 +2909,8 @@ test_bulk_install (TestSuite *suite)
28522909
test_upsert_unordered);
28532910
TestSuite_Add (suite, "/BulkOperation/upsert_large",
28542911
test_upsert_large);
2912+
TestSuite_Add (suite, "/BulkOperation/upsert_huge",
2913+
test_upsert_huge);
28552914
TestSuite_Add (suite, "/BulkOperation/upserted_index_ordered",
28562915
test_upserted_index_ordered);
28572916
TestSuite_Add (suite, "/BulkOperation/upserted_index_unordered",

0 commit comments

Comments
 (0)