Skip to content

Commit 84728bd

Browse files
authored
CDRIVER-4363 add client bulk write (#1590)
* fix comment in `_mongoc_write_opmsg` This is a drive-by fix to fix the referenced payload numbers. * quote key in match error * propagate error for numeric mismatch Otherwise, if the type mismatches, the test runner aborts with an error: "expected int64, int32, or double [...]" that does not identify the field. * add `ASSERT_EQUAL_BSON` To do exact BSON matches * align print on match failure To ease reading error message * implement client bulk write include some tests of basic usage and libmongoc-specific behavior. Specification and prose tests test driver-agnostic behavior. * add example use * add prose tests * add specification tests * support string `w` URI option in test runner To support `w=majority` * update unified test runner * add `BSON_OPTIONAL_PARAM` macro * replace `BSON_ASSERT (X || true)` with `BSON_OPTIONAL_PARAM (X)`
1 parent 151975f commit 84728bd

Some content is hidden

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

50 files changed

+17011
-142
lines changed

src/common/common-macros-private.h

+15
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,19 @@
1212
#define MONGOC_DEBUG_ASSERT(statement) ((void) 0)
1313
#endif
1414

15+
// `MC_ENABLE_CONVERSION_WARNING_BEGIN` enables -Wconversion to check for potentially unsafe integer conversions.
16+
// The `bson_in_range_*` functions can help address these warnings by ensuring a cast is within bounds.
17+
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) // gcc 4.6 added support for "diagnostic push".
18+
#define MC_ENABLE_CONVERSION_WARNING_BEGIN \
19+
_Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic warning \"-Wconversion\"")
20+
#define MC_ENABLE_CONVERSION_WARNING_END _Pragma ("GCC diagnostic pop")
21+
#elif defined(__clang__)
22+
#define MC_ENABLE_CONVERSION_WARNING_BEGIN \
23+
_Pragma ("clang diagnostic push") _Pragma ("clang diagnostic warning \"-Wconversion\"")
24+
#define MC_ENABLE_CONVERSION_WARNING_END _Pragma ("clang diagnostic pop")
25+
#else
26+
#define MC_ENABLE_CONVERSION_WARNING_BEGIN
27+
#define MC_ENABLE_CONVERSION_WARNING_END
28+
#endif
29+
1530
#endif

src/common/common-thread.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void
2424
{
2525
BSON_ASSERT_PARAM (thread);
2626
BSON_ASSERT_PARAM (func);
27-
BSON_ASSERT (arg || true); // optional.
27+
BSON_OPTIONAL_PARAM (arg); // optional.
2828
return pthread_create (thread, NULL, func, arg);
2929
}
3030
int
@@ -47,7 +47,7 @@ mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void
4747
{
4848
BSON_ASSERT_PARAM (thread);
4949
BSON_ASSERT_PARAM (func);
50-
BSON_ASSERT (arg || true); // optional.
50+
BSON_OPTIONAL_PARAM (arg); // optional.
5151

5252
*thread = (HANDLE) _beginthreadex (NULL, 0, func, arg, 0, NULL);
5353
if (0 == *thread) {

src/libbson/src/bson/bson-macros.h

+4
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@
232232
} \
233233
} while (0)
234234

235+
// `BSON_OPTIONAL_PARAM` is a documentation-only macro to document X may be NULL.
236+
// Useful in combination with `BSON_ASSERT_PARAM` to document and assert pointer parameters.
237+
#define BSON_OPTIONAL_PARAM(param) (void) 0
238+
235239
/* obsolete macros, preserved for compatibility */
236240
#define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__)
237241
#define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b)

src/libmongoc/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ set (SOURCES ${SOURCES}
658658
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-tls-openssl-bio.c
659659
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-openssl.c
660660
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ocsp-cache.c
661+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-bulkwrite.c
661662
)
662663

663664
set (HEADERS
@@ -666,6 +667,7 @@ set (HEADERS
666667
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc.h
667668
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-apm.h
668669
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-bulk-operation.h
670+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-bulkwrite.h
669671
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-change-stream.h
670672
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-client.h
671673
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-client-pool.h
@@ -713,6 +715,7 @@ set (HEADERS
713715
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-rand.h
714716
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-tls.h
715717
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ssl.h
718+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-bulkwrite.h
716719
)
717720

718721
set (HEADERS_FORWARDING
@@ -1012,6 +1015,7 @@ set (test-libmongoc-sources
10121015
${PROJECT_SOURCE_DIR}/tests/test-mongoc-background-monitoring.c
10131016
${PROJECT_SOURCE_DIR}/tests/test-mongoc-buffer.c
10141017
${PROJECT_SOURCE_DIR}/tests/test-mongoc-bulk.c
1018+
${PROJECT_SOURCE_DIR}/tests/test-mongoc-bulkwrite.c
10151019
${PROJECT_SOURCE_DIR}/tests/test-mongoc-change-stream.c
10161020
${PROJECT_SOURCE_DIR}/tests/test-mongoc-client-pool.c
10171021
${PROJECT_SOURCE_DIR}/tests/test-mongoc-client-session.c
@@ -1226,6 +1230,7 @@ if (ENABLE_EXAMPLES AND ENABLE_SHARED)
12261230
mongoc_add_example (mongoc-ping ${PROJECT_SOURCE_DIR}/examples/mongoc-ping.c)
12271231
mongoc_add_example (mongoc-tail ${PROJECT_SOURCE_DIR}/examples/mongoc-tail.c)
12281232
mongoc_add_example (example-collection-command ${PROJECT_SOURCE_DIR}/examples/example-collection-command.c)
1233+
mongoc_add_example (example-bulkwrite ${PROJECT_SOURCE_DIR}/examples/example-bulkwrite.c)
12291234

12301235
# examples/aggregation/
12311236
mongoc_add_example (aggregation1 ${PROJECT_SOURCE_DIR}/examples/aggregation/aggregation1.c)
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// example-bulkwrite shows use of `mongoc_client_bulkwrite`.
2+
3+
#include <mongoc/mongoc.h>
4+
5+
#define HANDLE_ERROR(...) \
6+
if (1) { \
7+
fprintf (stderr, __VA_ARGS__); \
8+
fprintf (stderr, "\n"); \
9+
goto fail; \
10+
} else \
11+
(void) 0
12+
13+
int
14+
main (int argc, char *argv[])
15+
{
16+
bool ok = false;
17+
18+
mongoc_init ();
19+
20+
bson_error_t error;
21+
mongoc_client_t *client = mongoc_client_new ("mongodb://localhost:27017");
22+
mongoc_bulkwriteopts_t *bwo = mongoc_bulkwriteopts_new ();
23+
mongoc_bulkwriteopts_set_verboseresults (bwo, true);
24+
mongoc_bulkwrite_t *bw = mongoc_client_bulkwrite_new (client);
25+
26+
// Insert a document to `db.coll1`
27+
{
28+
bson_t *doc = BCON_NEW ("foo", "bar");
29+
if (!mongoc_bulkwrite_append_insertone (bw, "db.coll1", doc, NULL, &error)) {
30+
HANDLE_ERROR ("Error appending insert one: %s", error.message);
31+
}
32+
bson_destroy (doc);
33+
}
34+
// Insert a document to `db.coll2`
35+
{
36+
bson_t *doc = BCON_NEW ("foo", "baz");
37+
if (!mongoc_bulkwrite_append_insertone (bw, "db.coll2", doc, NULL, &error)) {
38+
HANDLE_ERROR ("Error appending insert one: %s", error.message);
39+
}
40+
bson_destroy (doc);
41+
}
42+
43+
mongoc_bulkwritereturn_t bwr = mongoc_bulkwrite_execute (bw, bwo);
44+
45+
// Print results.
46+
{
47+
BSON_ASSERT (bwr.res); // Has results. NULL only returned for unacknowledged writes.
48+
printf ("Insert count : %" PRId64 "\n", mongoc_bulkwriteresult_insertedcount (bwr.res));
49+
const bson_t *ir = mongoc_bulkwriteresult_insertresults (bwr.res);
50+
BSON_ASSERT (ir); // Has verbose results. NULL only returned if verbose results not requested.
51+
char *ir_str = bson_as_relaxed_extended_json (ir, NULL);
52+
printf ("Insert results : %s\n", ir_str);
53+
bson_free (ir_str);
54+
}
55+
56+
// Print all error information. To observe: try setting the `_id` fields to cause a duplicate key error.
57+
if (bwr.exc) {
58+
const char *msg = "(none)";
59+
if (mongoc_bulkwriteexception_error (bwr.exc, &error)) {
60+
msg = error.message;
61+
}
62+
const bson_t *we = mongoc_bulkwriteexception_writeerrors (bwr.exc);
63+
char *we_str = bson_as_relaxed_extended_json (we, NULL);
64+
const bson_t *wce = mongoc_bulkwriteexception_writeconcernerrors (bwr.exc);
65+
char *wce_str = bson_as_relaxed_extended_json (wce, NULL);
66+
const bson_t *er = mongoc_bulkwriteexception_errorreply (bwr.exc);
67+
char *er_str = bson_as_relaxed_extended_json (er, NULL);
68+
printf ("Top-level error : %s\n", msg);
69+
printf ("Write errors : %s\n", we_str);
70+
printf ("Write concern errors : %s\n", wce_str);
71+
printf ("Error reply : %s\n", er_str);
72+
bson_free (er_str);
73+
bson_free (wce_str);
74+
bson_free (we_str);
75+
}
76+
77+
mongoc_bulkwriteresult_destroy (bwr.res);
78+
mongoc_bulkwriteexception_destroy (bwr.exc);
79+
mongoc_bulkwrite_destroy (bw);
80+
81+
ok = true;
82+
fail:
83+
mongoc_client_destroy (client);
84+
mongoc_bulkwriteopts_destroy (bwo);
85+
mongoc_cleanup ();
86+
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
87+
}

src/libmongoc/src/mongoc/mcd-nsinfo.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ mcd_nsinfo_append (mcd_nsinfo_t *self, const char *ns, bson_error_t *error)
6363
{
6464
BSON_ASSERT_PARAM (self);
6565
BSON_ASSERT_PARAM (ns);
66-
BSON_ASSERT (error || true);
66+
BSON_OPTIONAL_PARAM (error);
6767

6868
const int32_t ns_index = self->count;
6969
if (self->count == INT32_MAX) {

src/libmongoc/src/mongoc/mcd-rpc.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ _consume_bson_objects (const uint8_t **ptr, size_t *remaining_bytes, int32_t *nu
270270
{
271271
BSON_ASSERT_PARAM (ptr);
272272
BSON_ASSERT_PARAM (remaining_bytes);
273-
BSON_ASSERT (num_parsed || true);
273+
BSON_OPTIONAL_PARAM (num_parsed);
274274

275275
int32_t count = 0;
276276

@@ -814,7 +814,7 @@ mcd_rpc_message *
814814
mcd_rpc_message_from_data (const void *data, size_t length, const void **data_end)
815815
{
816816
BSON_ASSERT_PARAM (data);
817-
BSON_ASSERT (data_end || true);
817+
BSON_OPTIONAL_PARAM (data_end);
818818

819819
mcd_rpc_message *rpc = bson_malloc (sizeof (mcd_rpc_message));
820820
mcd_rpc_message *ret = NULL;
@@ -838,7 +838,7 @@ mcd_rpc_message_from_data_in_place (mcd_rpc_message *rpc, const void *data, size
838838
{
839839
ASSERT_MCD_RPC_ACCESSOR_PRECONDITIONS;
840840
BSON_ASSERT_PARAM (data);
841-
BSON_ASSERT (data_end || true);
841+
BSON_OPTIONAL_PARAM (data_end);
842842

843843
bool ret = false;
844844

0 commit comments

Comments
 (0)