Skip to content

Commit a544bf1

Browse files
committed
Optimize dockey extraction by avoiding bson.Marshal.
This code gets called repeatedly, so it’s worth optimizing. This also optimizes the field-names uniqueness check.
1 parent 94563b7 commit a544bf1

File tree

4 files changed

+36
-42
lines changed

4 files changed

+36
-42
lines changed

dockey/agg_test.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

dockey/raw.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import (
44
"fmt"
55
"strings"
66

7+
"github.com/10gen/migration-verifier/mslices"
78
"github.com/pkg/errors"
8-
"github.com/samber/lo"
99
"go.mongodb.org/mongo-driver/bson"
1010
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
1111
)
1212

13-
// This extracts the document key from a document gets its field names.
13+
// ExtractTrueDocKeyFromDoc extracts the document key from a document
14+
// given its field names.
1415
//
1516
// NB: This avoids the problem documented in SERVER-109340; as a result,
1617
// the returned key may not always match the change stream’s `documentKey`
@@ -21,7 +22,8 @@ func ExtractTrueDocKeyFromDoc(
2122
) (bson.Raw, error) {
2223
assertFieldNameUniqueness(fieldNames)
2324

24-
var dk bson.D
25+
docBuilder := bsoncore.NewDocumentBuilder()
26+
2527
for _, field := range fieldNames {
2628
var val bson.RawValue
2729

@@ -38,19 +40,20 @@ func ExtractTrueDocKeyFromDoc(
3840
return nil, errors.Wrapf(err, "extracting doc key field %#q from doc %+v", field, doc)
3941
}
4042

41-
dk = append(dk, bson.E{field, val})
42-
}
43-
44-
docKey, err := bson.Marshal(dk)
45-
if err != nil {
46-
return nil, errors.Wrapf(err, "marshaling doc key %v from doc %v", dk, docKey)
43+
docBuilder.AppendValue(
44+
field,
45+
bsoncore.Value{
46+
Type: val.Type,
47+
Data: val.Value,
48+
},
49+
)
4750
}
4851

49-
return docKey, nil
52+
return bson.Raw(docBuilder.Build()), nil
5053
}
5154

5255
func assertFieldNameUniqueness(fieldNames []string) {
53-
if len(lo.Uniq(fieldNames)) != len(fieldNames) {
56+
if mslices.FindFirstDupe(fieldNames).IsSome() {
5457
panic(fmt.Sprintf("Duplicate field names: %v", fieldNames))
5558
}
5659
}

dockey/raw_test.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,4 @@ func TestExtractTrueDocKeyFromDoc(t *testing.T) {
4646
)
4747
}
4848
}
49-
50-
assert.Panics(
51-
t,
52-
func() {
53-
_, _ = ExtractTrueDocKeyFromDoc(
54-
[]string{"foo", "bar", "foo"},
55-
bson.Raw{0},
56-
)
57-
},
58-
"duplicate field name should cause panic",
59-
)
6049
}

mslices/slices.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package mslices
33
import (
44
"reflect"
55
"slices"
6+
7+
"github.com/10gen/migration-verifier/option"
68
)
79

810
// This package complements the Go standard library’s package of the
@@ -43,3 +45,23 @@ func Compact[T any, S ~[]T](slc S) S {
4345
func isZero[T any](val T) bool {
4446
return reflect.ValueOf(&val).Elem().IsZero()
4547
}
48+
49+
// FindFirstDupe returns the first item in the slice that has at
50+
// least 1 duplicate, or none if all slice members are unique.
51+
func FindFirstDupe[T comparable](items []T) option.Option[T] {
52+
for i := range items {
53+
j := 1 + i
54+
55+
if j == len(items) {
56+
break
57+
}
58+
59+
for ; j < len(items); j++ {
60+
if items[i] == items[j] {
61+
return option.Some(items[i])
62+
}
63+
}
64+
}
65+
66+
return option.None[T]()
67+
}

0 commit comments

Comments
 (0)