Skip to content

Conversation

qingyang-hu
Copy link
Collaborator

@qingyang-hu qingyang-hu commented Oct 6, 2025

GODRIVER-3668
GODRIVER-3582

Summary

Add bypassEmptyTsReplacement option to:

  • insertOne
  • insertMany
  • updateOne
  • updateMany
  • replaceOne
  • findOneAndUpdate
  • findOneAndReplace
  • collection.bulkWrite
  • client.bulkWrite

Background & Motivation

Copy link
Contributor

mongodb-drivers-pr-bot bot commented Oct 6, 2025

🧪 Performance Results

Commit SHA: ef7d27c

The following benchmark tests for version 68e67f32b878170007586c17 had statistically significant changes (i.e., |z-score| > 1.96):

Benchmark Measurement % Change Patch Value Stable Region H-Score Z-Score
BenchmarkLargeDocInsertOne ops_per_second_min -53.4453 713.8345 Avg: 1533.3257
Med: 1597.1405
Stdev: 280.1539
0.8235 -2.9251
BenchmarkBSONFlatDocumentDecoding ops_per_second_min -41.5430 1234.2997 Avg: 2111.4669
Med: 2209.4418
Stdev: 283.9228
0.8273 -3.0895
BenchmarkSmallDocInsertOne ops_per_second_min -33.6423 1005.8379 Avg: 1515.7829
Med: 1569.1203
Stdev: 241.8192
0.7590 -2.1088
BenchmarkMultiFindMany ops_per_second_med -16.0389 3144654.0881 Avg: 3745370.8899
Med: 3745370.8899
Stdev: 19838.0311
0.9883 -30.2811
BenchmarkBSONDeepDocumentDecoding ns_per_op 15.6268 72705.0000 Avg: 62879.0000
Med: 62879.0000
Stdev: 741.0479
0.9733 13.2596
BenchmarkBSONFullDocumentDecoding ns_per_op 15.4395 85842.0000 Avg: 74361.0000
Med: 74361.0000
Stdev: 67.8823
0.9979 169.1311
BenchmarkMultiFindMany ops_per_second_max -15.0553 3584229.3907 Avg: 4219484.4039
Med: 4219484.4039
Stdev: 25178.2788
0.9860 -25.2303
BenchmarkBSONDeepDocumentDecoding total_mem_allocs -13.7227 11440117.0000 Avg: 13259700.5000
Med: 13259700.5000
Stdev: 147422.5715
0.9714 -12.3426
BenchmarkBSONDeepDocumentDecoding total_bytes_allocated -13.6931 248622496.0000 Avg: 288067960.0000
Med: 288067960.0000
Stdev: 3193961.7326
0.9714 -12.3500
BenchmarkBSONFlatDocumentEncoding ns_per_op 13.6351 16193.0000 Avg: 14250.0000
Med: 14250.0000
Stdev: 422.8499
0.9231 4.5950
BenchmarkBSONDeepDocumentDecoding ops_per_second_med -13.3970 14707.8290 Avg: 16983.0433
Med: 16983.0433
Stdev: 376.6983
0.9415 -6.0399
BenchmarkBSONDeepDocumentDecoding ops_per_second_max -13.2449 15225.5668 Avg: 17550.0516
Med: 17550.0516
Stdev: 305.0804
0.9536 -7.6193
BenchmarkBSONFullDocumentDecoding ops_per_second_med -13.2369 12663.0366 Avg: 14594.9582
Med: 14594.9582
Stdev: 123.1298
0.9775 -15.6901
BenchmarkBSONFullDocumentDecoding ops_per_second_max -13.0383 13217.3729 Avg: 15199.0668
Med: 15199.0668
Stdev: 58.4788
0.9896 -33.8874
BenchmarkBSONFlatDocumentDecoding ns_per_op 12.4231 59365.0000 Avg: 52805.0000
Med: 52805.0000
Stdev: 1268.5496
0.9316 5.1713
BenchmarkBSONFlatDocumentEncoding ops_per_second_med -12.2402 70338.3274 Avg: 80148.6853
Med: 80148.6853
Stdev: 3752.3824
0.8648 -2.6144
BenchmarkBSONFlatDocumentDecoding total_bytes_allocated -12.0335 362541128.0000 Avg: 412135396.0000
Med: 412135396.0000
Stdev: 9247480.2590
0.9341 -5.3630
BenchmarkBSONFlatDocumentDecoding total_mem_allocs -12.0024 9221482.0000 Avg: 10479244.5000
Med: 10479244.5000
Stdev: 235634.1424
0.9338 -5.3378
BenchmarkBSONFlatDocumentEncoding ops_per_second_max -11.5853 74030.2043 Avg: 83730.6417
Med: 83730.6417
Stdev: 2853.8031
0.8960 -3.3991
BenchmarkBSONFlatDocumentDecoding ops_per_second_max -10.9824 19104.7514 Avg: 21461.7681
Med: 21461.7681
Stdev: 344.8704
0.9483 -6.8345
BenchmarkBSONFlatDocumentDecoding ops_per_second_med -10.9061 18284.8784 Avg: 20523.1553
Med: 20523.1553
Stdev: 309.7114
0.9511 -7.2270
BenchmarkBSONFullDocumentEncoding ns_per_op 10.2516 25983.0000 Avg: 23567.0000
Med: 23567.0000
Stdev: 21.2132
0.9969 113.8913
BenchmarkBSONFullDocumentEncoding total_mem_allocs -9.5657 1374165.0000 Avg: 1519518.0000
Med: 1519518.0000
Stdev: 11602.2081
0.9718 -12.5280
BenchmarkBSONFullDocumentEncoding ops_per_second_med -8.9302 41786.8037 Avg: 45884.3582
Med: 45884.3582
Stdev: 334.9541
0.9711 -12.2332
BenchmarkBSONFullDocumentEncoding ops_per_second_max -8.7802 43192.8127 Avg: 47350.2788
Med: 47350.2788
Stdev: 412.1801
0.9649 -10.0865
BenchmarkSmallDocInsertOne allocated_bytes_per_op 0.7068 5699.0000 Avg: 5659.0000
Med: 5660.0000
Stdev: 6.4758
0.9121 6.1769
BenchmarkLargeDocInsertOne allocated_bytes_per_op 0.6598 5697.0000 Avg: 5659.6562
Med: 5660.0000
Stdev: 5.8398
0.9198 6.3946
BenchmarkBSONFlatDocumentDecoding allocated_bytes_per_op -0.0360 18046.0000 Avg: 18052.5000
Med: 18052.5000
Stdev: 0.7071
0.9615 -9.1924

For a comprehensive view of all microbenchmark results for this PR's commit, please check out the Evergreen perf task for this patch.

Copy link
Contributor

API Change Report

./v2/x/mongo/driver/operation

compatible changes

(*FindAndModify).AdditionalCmd: added
(*Insert).AdditionalCmd: added
(*Update).AdditionalCmd: added

@qingyang-hu qingyang-hu changed the title GODRIVER-3370 Add bypassEmptyTsReplacement option. GODRIVER-3668 Add bypassEmptyTsReplacement option. Oct 7, 2025
@qingyang-hu qingyang-hu marked this pull request as ready for review October 7, 2025 14:52
@qingyang-hu qingyang-hu requested a review from a team as a code owner October 7, 2025 14:52
@Copilot Copilot AI review requested due to automatic review settings October 7, 2025 14:52
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds the bypassEmptyTsReplacement option to various MongoDB write operations by implementing an "addCommandFields" mechanism that allows arbitrary command fields to be added to operations.

  • Adds support for bypassEmptyTsReplacement option across insert, update, replace, findOneAndUpdate, findOneAndReplace, and bulk write operations
  • Implements addCommandFields functionality in internal options handling to support additional command parameters
  • Adds comprehensive test coverage to verify the option is properly passed through to MongoDB commands

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
x/mongo/driver/xoptions/options.go Adds "addCommandFields" case handling to all internal option setters
x/mongo/driver/operation/update.go Adds additionalCmd field and AdditionalCmd method to Update operation
x/mongo/driver/operation/insert.go Adds additionalCmd field and AdditionalCmd method to Insert operation
x/mongo/driver/operation/find_and_modify.go Adds additionalCmd field and AdditionalCmd method to FindAndModify operation
mongo/collection.go Integrates addCommandFields option handling into collection methods
mongo/client_bulk_write.go Adds additionalCmd field to clientBulkWrite struct
mongo/client.go Integrates addCommandFields option handling into Client.BulkWrite
mongo/bulk_write.go Adds additionalCmd field and integrates it into bulk write operations
internal/integration/collection_test.go Adds comprehensive tests for bypassEmptyTsReplacement option
internal/integration/client_test.go Adds tests for client bulk write with bypassEmptyTsReplacement and fixes test assertions

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

})
}
})
mt.RunOpts("bulk write with bypassEmptyTsReplacement", mtBulkWriteOpts, func(mt *mtest.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Subtests in subtests are difficult to read. Consider splitting this subtest out into a separate test function.

Comment on lines 833 to 836
t.Helper()

valType, data, err := bson.MarshalValue(val)
require.Nil(t, err, "MarshalValue error: %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use mt and require.NoError.

Suggested change
t.Helper()
valType, data, err := bson.MarshalValue(val)
require.Nil(t, err, "MarshalValue error: %v", err)
mt.Helper()
valType, data, err := bson.MarshalValue(val)
require.NoError(mt, err, "MarshalValue error")

Comment on lines 847 to 850
{
"insert one",
mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}}),
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Keyed struct literals are easier to use. Consider including the key names.

Comment on lines 870 to 874
{
"empty",
options.ClientBulkWrite(),
bson.RawValue{},
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Keyed struct literals are easier to use. Consider including the key names.

return opts
}

marshalValue := func(val interface{}) bson.RawValue {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Consider factoring marshalValue into a separate function since an identical function is also used in TestBypassEmptyTsReplacement.

mongo/client.go Outdated
Comment on lines 958 to 962
if additionalCmd := optionsutil.Value(bwo.Internal, "addCommandFields"); additionalCmd != nil {
if ac, ok := additionalCmd.(bson.D); ok {
op.additionalCmd = ac
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine these conditions into one. This suggestion applies to all instances of this block in this PR.

Suggested change
if additionalCmd := optionsutil.Value(bwo.Internal, "addCommandFields"); additionalCmd != nil {
if ac, ok := additionalCmd.(bson.D); ok {
op.additionalCmd = ac
}
}
if ac, ok := optionsutil.Value(bwo.Internal, "addCommandFields").(bson.D); ok {
op.additionalCmd = ac
}

Comment on lines 406 to 408
if rawDataOpt := optionsutil.Value(args.Internal, "addCommandFields"); rawDataOpt != nil {
imOpts.Opts = append(imOpts.Opts, func(opts *options.InsertManyOptions) error {
opts.Internal = optionsutil.WithValue(opts.Internal, "addCommandFields", rawDataOpt)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rawDataOpt is confusingly named because we're copying the "addCommandFields" option here. Rename to something like ac or acOpt.

Suggested change
if rawDataOpt := optionsutil.Value(args.Internal, "addCommandFields"); rawDataOpt != nil {
imOpts.Opts = append(imOpts.Opts, func(opts *options.InsertManyOptions) error {
opts.Internal = optionsutil.WithValue(opts.Internal, "addCommandFields", rawDataOpt)
if ac := optionsutil.Value(args.Internal, "addCommandFields"); ac != nil {
imOpts.Opts = append(imOpts.Opts, func(opts *options.InsertManyOptions) error {
opts.Internal = optionsutil.WithValue(opts.Internal, "addCommandFields", ac)

@matthewdale matthewdale added the review-priority-normal Medium Priority PR for Review: within 1 business day label Oct 13, 2025
Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍

@qingyang-hu qingyang-hu merged commit 8fb0643 into master Oct 15, 2025
35 of 37 checks passed
@qingyang-hu qingyang-hu deleted the godriver3668 branch October 15, 2025 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature review-priority-normal Medium Priority PR for Review: within 1 business day

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants