xiangfu0 commented on code in PR #19795:
URL: https://github.com/apache/pinot/pull/19795#discussion_r4216267277


##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/customobject/PercentileTDigestAccumulator.java:
##########
@@ -939,10 +957,11 @@ private boolean mergeSorted(double[] incomingMeans, 
double[] incomingWeights, in
       return false;
     }
 
+    double newTotalWeight = _totalWeight + incomingWeight;

Review Comment:
   **[duplication] The ~90-line K1 merge kernel appears twice in this file.**
   
   `mergeSorted()` is a near-verbatim copy of the merge loop inside 
`flush(double)` — same q0/q2 eligibility math, runBackwards indexing, and 
`inputIndex == 1 || inputIndex == numInputs - 1` boundary pinning; the only 
difference is the raw path reads `_rawValues` with implicit weight 1.0. 
Similarly, the static `normalizeBoundaries(means, weights, count, min, max)` 
duplicates the instance `normalizeBoundaryCentroids()` algorithm, and 
`addSerializedTDigestDirect` repeats `addSerializedTDigest`'s pending/legacy 
prologue plus `mergeSerializedTDigest`'s initialize block. A future fix to the 
merge criterion or boundary-repair rule applied to one copy would make 
raw-value ingestion and digest-merge ingestion (or in-memory vs deserialized 
digests) produce subtly different centroid layouts with no test to catch the 
drift. Consider one shared kernel (weights-or-null for unit weight) and 
delegating the instance normalizer to the static one.



##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/aggregator/PercentileTDigestValueAggregator.java:
##########
@@ -184,34 +197,37 @@ private static final class NonFiniteAwareTDigest extends 
TDigest {
     private static final int VERBOSE_CENTROID_SIZE = 16;
 
     private final TDigest _finiteDigest;
-    private long _negativeInfinityWeight;
-    private long _positiveInfinityWeight;
+    private double _negativeInfinityWeight;

Review Comment:
   **[duplication] Wire-format knowledge is now spread across four private 
copies.**
   
   The encoding constants (VERBOSE/SMALL encoding ids, header/centroid sizes) 
and the centroid-capacity formula are re-declared in TDigestUtils, 
PercentileTDigestAccumulator, this class's outer constants + 
`getDefaultCentroidCapacity`, and NonFiniteAwareTDigest (plus 
TDigestBenchmarkUtils) — and NonFiniteAwareTDigest additionally hand-parses the 
verbose/small header three times (`fromBytes`, `getFiniteCentroids`, 
`getSerializedBytes`) although `TDigestUtils.inspectSerialized` already returns 
a `SerializedTDigestMetadata` with encoding, centroidCount, centroidOffset and 
centroidSize (`fromBytes` even has it in hand via `SerializedTDigestInput`). 
The capacity formula is a wire-compat contract (it bounds what a legacy reader 
allocates); with Pinot now owning the format, one shared constants/metadata 
holder in TDigestUtils would prevent a header or padding tweak from missing a 
copy and reintroducing the legacy-reader AIOOBE class of bug this PR's comments 
describe.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to