Skip to content

Commit 59a21af

Browse files
authored
REP-6826 Fix memory corruption from pool usage without cloning (#175)
PR #169 made document comparison use a memory pool. That changeset neglected to update uses of bson.Raw.Lookup(), which does not clone the field’s raw value. Thus, when a mismatched document was “put back” into memory, another thread overwrote a part of it. Thus we got mismatch documents (i.e., in verifier metadata) where the same document ID showed up twice. This also, critically, made the verifier skip necessary rechecks because a later mismatch overwrote the buffer that contains the document ID meant for recheck. This changeset fixes that problem by always cloning the document ID as part of reporting a mismatch. It also beefs up testing to ensure that the expected document IDs are reported in the log and in the rechecks. This also makes the field-order-difference mismatch text more concise by removing a redundant document ID.
1 parent 2325945 commit 59a21af

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

internal/verifier/compare.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -721,13 +721,16 @@ func transformPipelineForToHashedIndexKey(
721721
func (verifier *Verifier) compareOneDocument(srcClientDoc, dstClientDoc bson.Raw, namespace string) ([]VerificationResult, error) {
722722
match := bytes.Equal(srcClientDoc, dstClientDoc)
723723
if match {
724+
// Happy path! The documents binary-match.
724725
return nil, nil
725726
}
726727

728+
docID := getDocIdFromComparison(verifier.docCompareMethod, srcClientDoc)
729+
727730
if verifier.docCompareMethod == DocCompareToHashedIndexKey {
728731
// With hash comparison, mismatches are opaque.
729732
return []VerificationResult{{
730-
ID: getDocIdFromComparison(verifier.docCompareMethod, srcClientDoc),
733+
ID: docID,
731734
Details: Mismatch,
732735
Cluster: ClusterTarget,
733736
NameSpace: namespace,
@@ -746,13 +749,15 @@ func (verifier *Verifier) compareOneDocument(srcClientDoc, dstClientDoc bson.Raw
746749

747750
// If we're respecting field order we have just done a binary compare so we have fields in different order.
748751
return []VerificationResult{{
749-
ID: srcClientDoc.Lookup("_id"),
750-
Details: Mismatch + fmt.Sprintf(" : Document %s has fields in different order", srcClientDoc.Lookup("_id")),
752+
ID: docID,
753+
Details: Mismatch + " : only field order differs",
751754
Cluster: ClusterTarget,
752755
NameSpace: namespace,
753756
dataSize: int32(dataSize),
754757
}}, nil
755758
}
756-
results := mismatchResultsToVerificationResults(mismatch, srcClientDoc, dstClientDoc, namespace, srcClientDoc.Lookup("_id"), "" /* fieldPrefix */)
759+
760+
results := mismatchResultsToVerificationResults(mismatch, srcClientDoc, dstClientDoc, namespace, docID, "" /* fieldPrefix */)
761+
757762
return results, nil
758763
}

internal/verifier/migration_verifier_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/10gen/migration-verifier/internal/testutil"
2626
"github.com/10gen/migration-verifier/internal/types"
2727
"github.com/10gen/migration-verifier/internal/util"
28+
"github.com/10gen/migration-verifier/internal/verifier/recheck"
2829
"github.com/10gen/migration-verifier/mbson"
2930
"github.com/10gen/migration-verifier/mslices"
3031
"github.com/10gen/migration-verifier/option"
@@ -1739,6 +1740,14 @@ func (suite *IntegrationTestSuite) TestVerifierDocMismatches() {
17391740
_, _, err = verifier.reportDocumentMismatches(ctx, builder)
17401741
suite.Require().NoError(err)
17411742

1743+
for _, specimen := range mslices.Of("100000", "100001") {
1744+
suite.Assert().Contains(
1745+
builder.String(),
1746+
specimen,
1747+
"summary should show all mismatched-content doc IDs",
1748+
)
1749+
}
1750+
17421751
suite.Assert().Contains(
17431752
builder.String(),
17441753
"100009",
@@ -1751,6 +1760,12 @@ func (suite *IntegrationTestSuite) TestVerifierDocMismatches() {
17511760
"summary should show the # of missing docs shown",
17521761
)
17531762

1763+
suite.Assert().Contains(
1764+
builder.String(),
1765+
" 2 ",
1766+
"summary should show the total # of content-mismatched documents",
1767+
)
1768+
17541769
suite.Assert().Contains(
17551770
builder.String(),
17561771
" 18 ",
@@ -1762,6 +1777,22 @@ func (suite *IntegrationTestSuite) TestVerifierDocMismatches() {
17621777
"100019",
17631778
"summary should NOT show a late mismatch",
17641779
)
1780+
1781+
rechecks := suite.fetchRecheckDocs(ctx, verifier)
1782+
recheckDocIDs := lo.Map(
1783+
rechecks,
1784+
func(r recheck.Doc, _ int) int {
1785+
num, err := mbson.CastRawValue[int32](r.PrimaryKey.DocumentID)
1786+
suite.Require().NoError(err)
1787+
return int(num)
1788+
},
1789+
)
1790+
1791+
suite.Assert().ElementsMatch(
1792+
lo.RangeFrom(100000, 20),
1793+
recheckDocIDs,
1794+
"all docs should be enqueued for recheck",
1795+
)
17651796
}
17661797

17671798
func (suite *IntegrationTestSuite) TestVerifierCompareIndexSpecs() {

0 commit comments

Comments
 (0)