Skip to content

Commit 24e30e2

Browse files
mongo: address PR review comments (round 2)
- Add utils.FullTablePartition() helper and use it in place of the local fullTablePartitions() in qrep_partition.go and the inline construction in qrep.go - Remove slices.Compact() from computeStringBoundaries: the seen map already deduplicates interior values, and the quantile index formula is strictly increasing when len(interior) >= numPartitions, so no consecutive duplicates can occur in the else branch - Tighten e2e partition count assertions to exact counts (10) instead of >1 for string and numeric _id tests - Delete Test_Snapshot_Non_ObjectID_Falls_Back_To_Single_Partition: string _id collections are now partitioned rather than falling back to full-table, so the test expectation no longer holds
1 parent 9015912 commit 24e30e2

4 files changed

Lines changed: 19 additions & 78 deletions

File tree

flow/connectors/mongo/qrep.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,9 @@ func (c *MongoConnector) GetQRepPartitions(
2626
config *protos.QRepConfig,
2727
last *protos.QRepPartition,
2828
) ([]*protos.QRepPartition, error) {
29-
fullTablePartition := []*protos.QRepPartition{
30-
{
31-
PartitionId: utils.FullTablePartitionID,
32-
Range: nil,
33-
FullTablePartition: true,
34-
},
35-
}
36-
3729
if config.WatermarkColumn != DefaultDocumentKeyColumnName {
3830
c.logger.Warn("unexpected watermark column, falling back to full table partition")
39-
return fullTablePartition, nil
31+
return utils.FullTablePartition(), nil
4032
}
4133

4234
if config.NumRowsPerPartition <= 0 {
@@ -70,7 +62,7 @@ func (c *MongoConnector) GetQRepPartitions(
7062

7163
if adjustedPartitions.AdjustedNumPartitions <= 1 {
7264
c.logger.Info("[mongo] insufficient partitions for parallel snapshot, falling back to full table partition")
73-
return fullTablePartition, nil
65+
return utils.FullTablePartition(), nil
7466
}
7567

7668
return c.buildPartitions(ctx, collection, adjustedPartitions.AdjustedNumPartitions)

flow/connectors/mongo/qrep_partition.go

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"fmt"
66
"log/slog"
77
"math/big"
8-
"slices"
9-
108
"github.com/google/uuid"
119
"go.mongodb.org/mongo-driver/v2/bson"
1210
"go.mongodb.org/mongo-driver/v2/mongo"
@@ -25,17 +23,6 @@ const (
2523
stringSampleMaxSize = 100000
2624
)
2725

28-
// fullTablePartitions returns the single-partition full-table fallback used when a
29-
// collection cannot be partitioned (unsupported/mixed _id type, empty collection,
30-
// or degenerate min/max range).
31-
func fullTablePartitions() []*protos.QRepPartition {
32-
return []*protos.QRepPartition{{
33-
PartitionId: utils.FullTablePartitionID,
34-
Range: nil,
35-
FullTablePartition: true,
36-
}}
37-
}
38-
3926
// buildPartitions reads the collection's min and max _id (cheap, leverages the
4027
// default _id index) and dispatches to a type-specific partitioner:
4128
// - ObjectID -> uniform division of the 12-byte ObjectID keyspace
@@ -56,15 +43,15 @@ func (c *MongoConnector) buildPartitions(
5643
}
5744
if minRaw.IsZero() {
5845
c.logger.Info("[mongo] no documents found, falling back to full table partition")
59-
return fullTablePartitions(), nil
46+
return utils.FullTablePartition(), nil
6047
}
6148
maxRaw, err := findBoundaryID(ctx, collection, Upper, c.config.ReadPreference)
6249
if err != nil {
6350
return nil, fmt.Errorf("failed to find max _id: %w", err)
6451
}
6552
if maxRaw.IsZero() {
6653
c.logger.Info("[mongo] no documents found, falling back to full table partition")
67-
return fullTablePartitions(), nil
54+
return utils.FullTablePartition(), nil
6855
}
6956

7057
switch {
@@ -80,7 +67,7 @@ func (c *MongoConnector) buildPartitions(
8067
c.logger.Info("[mongo] _id type not supported for partitioning (or mixed types), falling back to full table partition",
8168
slog.String("minType", minRaw.Type.String()),
8269
slog.String("maxType", maxRaw.Type.String()))
83-
return fullTablePartitions(), nil
70+
return utils.FullTablePartition(), nil
8471
}
8572
}
8673

@@ -97,7 +84,7 @@ func (c *MongoConnector) objectIDPartitions(
9784
intRange := new(big.Int).Sub(maxInt, minInt)
9885
if intRange.Sign() <= 0 {
9986
c.logger.Info("[mongo] min/max ObjectID range is non-positive, falling back to full table partition")
100-
return fullTablePartitions(), nil
87+
return utils.FullTablePartition(), nil
10188
}
10289

10390
c.logger.Info("[mongo] using min/max ObjectID partitioning",
@@ -155,7 +142,7 @@ func (c *MongoConnector) numericPartitions(
155142
) ([]*protos.QRepPartition, error) {
156143
if maxVal <= minVal {
157144
c.logger.Info("[mongo] numeric min/max range is non-positive, falling back to full table partition")
158-
return fullTablePartitions(), nil
145+
return utils.FullTablePartition(), nil
159146
}
160147

161148
c.logger.Info("[mongo] using numeric _id partitioning",
@@ -183,7 +170,7 @@ func (c *MongoConnector) stringPartitions(
183170
) ([]*protos.QRepPartition, error) {
184171
if minVal >= maxVal {
185172
c.logger.Info("[mongo] string min/max range is non-positive, falling back to full table partition")
186-
return fullTablePartitions(), nil
173+
return utils.FullTablePartition(), nil
187174
}
188175

189176
samples, err := c.sampleStringIDs(ctx, collection, numPartitions)
@@ -195,7 +182,7 @@ func (c *MongoConnector) stringPartitions(
195182
if len(ranges) < 2 {
196183
c.logger.Info("[mongo] insufficient string boundaries from sampling, falling back to full table partition",
197184
slog.Int("sampleCount", len(samples)))
198-
return fullTablePartitions(), nil
185+
return utils.FullTablePartition(), nil
199186
}
200187

201188
c.logger.Info("[mongo] using sampled string _id partitioning",
@@ -310,7 +297,6 @@ func computeStringBoundaries(minVal string, maxVal string, samples []string, num
310297
}
311298
picked = append(picked, interior[idx])
312299
}
313-
picked = slices.Compact(picked) // drop consecutive duplicate quantiles
314300
}
315301

316302
// Build ranges: [min, p0), [p0, p1), ..., [pLast-1, pLast), [pLast, max].

flow/connectors/utils/partition.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ import (
1717

1818
const FullTablePartitionID = "full-table-partition-id"
1919

20+
func FullTablePartition() []*protos.QRepPartition {
21+
return []*protos.QRepPartition{{
22+
PartitionId: FullTablePartitionID,
23+
Range: nil,
24+
FullTablePartition: true,
25+
}}
26+
}
27+
2028
type PartitionRangeType string
2129

2230
const (

flow/e2e/mongo_test.go

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ func (s MongoClickhouseSuite) Test_Simple_Flow_Partitioned_StringID() {
196196
require.NoError(t, catalogPool.QueryRow(t.Context(),
197197
`SELECT COUNT(*) FROM peerdb_stats.qrep_partitions WHERE parent_mirror_name = $1`,
198198
flowConnConfig.FlowJobName).Scan(&partitionCount))
199-
require.Greater(t, partitionCount, 1, "expected multiple partitions for 100 string-id rows")
199+
require.Equal(t, 10, partitionCount, "expected 10 partitions for 100 rows with 10 rows per partition")
200200

201201
SetupCDCFlowStatusQuery(t, env, flowConnConfig)
202202
cdcDocs := make([]any, 10)
@@ -253,7 +253,7 @@ func (s MongoClickhouseSuite) Test_Simple_Flow_Partitioned_NumericID() {
253253
require.NoError(t, catalogPool.QueryRow(t.Context(),
254254
`SELECT COUNT(*) FROM peerdb_stats.qrep_partitions WHERE parent_mirror_name = $1`,
255255
flowConnConfig.FlowJobName).Scan(&partitionCount))
256-
require.Greater(t, partitionCount, 1, "expected multiple partitions for 100 numeric-id rows")
256+
require.Equal(t, 10, partitionCount, "expected 10 partitions for 100 rows with 10 rows per partition")
257257

258258
SetupCDCFlowStatusQuery(t, env, flowConnConfig)
259259
cdcDocs := make([]any, 10)
@@ -349,51 +349,6 @@ func (s MongoClickhouseSuite) Test_Snapshot_Empty_Collection() {
349349
RequireEnvCanceled(t, env)
350350
}
351351

352-
func (s MongoClickhouseSuite) Test_Snapshot_Non_ObjectID_Falls_Back_To_Single_Partition() {
353-
t := s.T()
354-
srcDatabase := GetTestDatabase(s.Suffix())
355-
srcTable := "test_non_objectid_snapshot"
356-
dstTable := "test_non_objectid_snapshot_dst"
357-
358-
connectionGen := FlowConnectionGenerationConfig{
359-
FlowJobName: AddSuffix(s, srcTable),
360-
TableMappings: TableMappings(s, srcTable, dstTable),
361-
Destination: s.Peer().Name,
362-
}
363-
flowConnConfig := s.generateFlowConnectionConfigsDefaultEnv(connectionGen)
364-
flowConnConfig.DoInitialSnapshot = true
365-
flowConnConfig.SnapshotNumRowsPerPartition = 5
366-
367-
adminClient := s.Source().(*MongoSource).AdminClient()
368-
collection := adminClient.Database(srcDatabase).Collection(srcTable)
369-
370-
docs := make([]any, 10)
371-
for i := range 10 {
372-
docs[i] = bson.D{
373-
{Key: "_id", Value: fmt.Sprintf("string_id_%d", i)},
374-
{Key: "value", Value: fmt.Sprintf("value_%d", i)},
375-
}
376-
}
377-
_, err := collection.InsertMany(t.Context(), docs)
378-
require.NoError(t, err)
379-
380-
tc := NewTemporalClient(t)
381-
env := ExecutePeerflow(t, tc, flowConnConfig)
382-
383-
EnvWaitForEqualTablesWithNames(env, s, "initial load", srcTable, dstTable, "_id,doc")
384-
385-
catalogPool, err := internal.GetCatalogConnectionPoolFromEnv(t.Context())
386-
require.NoError(t, err)
387-
var partitionCount int
388-
require.NoError(t, catalogPool.QueryRow(t.Context(),
389-
`SELECT COUNT(*) FROM peerdb_stats.qrep_partitions WHERE parent_mirror_name = $1`,
390-
flowConnConfig.FlowJobName).Scan(&partitionCount))
391-
require.Equal(t, 1, partitionCount)
392-
393-
env.Cancel(t.Context())
394-
RequireEnvCanceled(t, env)
395-
}
396-
397352
func (s MongoClickhouseSuite) Test_Snapshot_Mixed_ObjectID_Falls_Back_To_Single_Partition() {
398353
t := s.T()
399354
srcDatabase := GetTestDatabase(s.Suffix())

0 commit comments

Comments
 (0)