Skip to content

Commit d4eb5cc

Browse files
committed
Exclude compaction MOVE ops from bucket report row estimates
1 parent 674bd85 commit d4eb5cc

1 file changed

Lines changed: 21 additions & 8 deletions

File tree

modules/module-mongodb-storage/src/storage/implementation/MongoSyncBucketStorage.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ export abstract class MongoSyncBucketStorage
593593
{
594594
$facet: {
595595
sampledOps: [{ $count: 'count' }],
596+
rowOps: [{ $match: { op: { $in: ['PUT', 'REMOVE'] } } }, { $count: 'count' }],
596597
distinctRows: [
597598
{ $match: { op: { $in: ['PUT', 'REMOVE'] } } },
598599
{ $group: { _id: { table: '$table', row_id: '$row_id' } } },
@@ -601,34 +602,46 @@ export abstract class MongoSyncBucketStorage
601602
}
602603
}
603604
];
604-
type FacetResult = { sampledOps: { count: number }[]; distinctRows: { count: number }[] };
605+
type FacetResult = {
606+
sampledOps: { count: number }[];
607+
rowOps: { count: number }[];
608+
distinctRows: { count: number }[];
609+
};
605610
const [result] = await collection
606611
.aggregate<FacetResult>(pipeline, { allowDiskUse: false, maxTimeMS: storage.BUCKET_REPORT_TIMEOUT_MS })
607612
.toArray();
608613
return {
609614
sampledOps: result?.sampledOps[0]?.count ?? 0,
615+
rowOps: result?.rowOps[0]?.count ?? 0,
610616
distinctRows: result?.distinctRows[0]?.count ?? 0
611617
};
612618
};
613619

614-
let { sampledOps, distinctRows } = await runCounts(sampled);
615-
if (sampled && sampledOps == 0) {
620+
let counts = await runCounts(sampled);
621+
if (sampled && counts.sampledOps == 0) {
616622
// A document-level `$sampleRate` can select nothing when a bucket spans very few storage documents
617623
// (v3 batches operations into a document). Fall back to an exact read so the bucket is not reported as
618624
// zero rows. This reads the whole bucket only in the rare empty-sample case, which cannot happen for a
619625
// bucket large enough to span many documents.
620-
distinctRows = (await runCounts(false)).distinctRows;
621-
return { rows: distinctRows, estimated: false };
626+
return { rows: (await runCounts(false)).distinctRows, estimated: false };
622627
}
623-
if (distinctRows == 0) {
628+
if (counts.distinctRows == 0) {
624629
// Nothing row-bearing was found (e.g. a bucket of only MOVE/CLEAR ops): treat as fully fragmented.
625630
return { rows: 0, estimated: sampled };
626631
}
627632
if (!sampled) {
628633
// Read in full: the distinct row count is exact.
629-
return { rows: distinctRows, estimated: false };
634+
return { rows: counts.distinctRows, estimated: false };
630635
}
631-
return { rows: storage.estimateDistinctRows(operations, sampledOps, distinctRows), estimated: true };
636+
// Only PUT/REMOVE operations carry a row identity; MOVE/CLEAR (produced by compaction) do not. Run the
637+
// estimator over the row-bearing operations only, scaling the bucket's operation count by the row-bearing
638+
// share observed in the sample. Including identity-less operations in the model under-counts rows on
639+
// compacted buckets. For uncompacted buckets rowOps equals sampledOps and this changes nothing.
640+
const rowBearingOperations = Math.round(operations * (counts.rowOps / counts.sampledOps));
641+
return {
642+
rows: storage.estimateDistinctRows(rowBearingOperations, counts.rowOps, counts.distinctRows),
643+
estimated: true
644+
};
632645
}
633646

634647
/**

0 commit comments

Comments
 (0)