Skip to content

Commit 9338849

Browse files
committed
do not use bson_iter_t to store _id location
The `bson_iter_t` stores a pointer to the referred data. The payload buffer `mongoc_bulkwrite_t::ops` may be reallocated and invalidate existing iterators. Instead, store integral offsets into the payload.
1 parent 67bb7e8 commit 9338849

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

src/libmongoc/src/mongoc/mongoc-bulkwrite.c

+18-14
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,12 @@ mongoc_bulkwriteopts_destroy (mongoc_bulkwriteopts_t *self)
139139
typedef enum { MODEL_OP_INSERT, MODEL_OP_UPDATE, MODEL_OP_DELETE } model_op_t;
140140
typedef struct {
141141
model_op_t op;
142-
bson_iter_t id_iter;
142+
// `id_loc` locates the "_id" field of an insert document.
143+
struct {
144+
size_t op_start; // Offset in `mongoc_bulkwrite_t::ops` to the BSON for the insert op: { "document": ... }
145+
size_t op_len; // Length of insert op.
146+
uint32_t id_offset; // Offset in the insert op to the "_id" field.
147+
} id_loc;
143148
char *ns;
144149
} modeldata_t;
145150

@@ -277,19 +282,13 @@ mongoc_bulkwrite_append_insertone (mongoc_bulkwrite_t *self,
277282
persisted_id_offset += existing_id_offset;
278283
}
279284

285+
size_t op_start = self->ops.len; // Save location of `op` to retrieve `_id` later.
280286
BSON_ASSERT (_mongoc_buffer_append (&self->ops, bson_get_data (&op), op.len));
281287

282-
// Store an iterator to the document's `_id` in the persisted payload:
283-
bson_iter_t persisted_id_iter;
284-
{
285-
BSON_ASSERT (mcommon_in_range_size_t_unsigned (op.len));
286-
size_t start = self->ops.len - (size_t) op.len;
287-
BSON_ASSERT (bson_iter_init_from_data_at_offset (
288-
&persisted_id_iter, self->ops.data + start, (size_t) op.len, persisted_id_offset, strlen ("_id")));
289-
}
290-
291288
self->n_ops++;
292-
modeldata_t md = {.op = MODEL_OP_INSERT, .id_iter = persisted_id_iter, .ns = bson_strdup (ns)};
289+
modeldata_t md = {.op = MODEL_OP_INSERT,
290+
.id_loc = {.op_start = op_start, .op_len = (size_t) op.len, .id_offset = persisted_id_offset},
291+
.ns = bson_strdup (ns)};
293292
_mongoc_array_append_val (&self->arrayof_modeldata, md);
294293
bson_destroy (&op);
295294
return true;
@@ -1340,7 +1339,8 @@ static bool
13401339
_bulkwritereturn_apply_result (mongoc_bulkwritereturn_t *self,
13411340
const bson_t *result,
13421341
size_t ops_doc_offset,
1343-
const mongoc_array_t *arrayof_modeldata)
1342+
const mongoc_array_t *arrayof_modeldata,
1343+
const mongoc_buffer_t *ops)
13441344
{
13451345
BSON_ASSERT_PARAM (self);
13461346
BSON_ASSERT_PARAM (result);
@@ -1458,7 +1458,10 @@ _bulkwritereturn_apply_result (mongoc_bulkwritereturn_t *self,
14581458
break;
14591459
}
14601460
case MODEL_OP_INSERT: {
1461-
_bulkwriteresult_set_insertresult (self->res, &md->id_iter, models_idx);
1461+
bson_iter_t id_iter;
1462+
BSON_ASSERT (bson_iter_init_from_data_at_offset (
1463+
&id_iter, ops->data + md->id_loc.op_start, md->id_loc.op_len, md->id_loc.id_offset, strlen ("_id")));
1464+
_bulkwriteresult_set_insertresult (self->res, &id_iter, models_idx);
14621465
break;
14631466
}
14641467
default:
@@ -1903,7 +1906,8 @@ mongoc_bulkwrite_execute (mongoc_bulkwrite_t *self, const mongoc_bulkwriteopts_t
19031906
// Iterate over cursor results.
19041907
const bson_t *result;
19051908
while (mongoc_cursor_next (reply_cursor, &result)) {
1906-
if (!_bulkwritereturn_apply_result (&ret, result, ops_doc_offset, &self->arrayof_modeldata)) {
1909+
if (!_bulkwritereturn_apply_result (
1910+
&ret, result, ops_doc_offset, &self->arrayof_modeldata, &self->ops)) {
19071911
goto batch_fail;
19081912
}
19091913
}

0 commit comments

Comments
 (0)