xiangfu0 commented on code in PR #19797:
URL: https://github.com/apache/pinot/pull/19797#discussion_r4227230370
##########
pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java:
##########
@@ -134,6 +141,55 @@ private static void
initForwardIndexConfig(PinotConfiguration instanceConfig) {
LOGGER.info("Setting forward index default target docs per chunk to:
{}", defaultTargetDocsPerChunk);
ForwardIndexConfig.setDefaultTargetDocsPerChunk(Integer.parseInt(defaultTargetDocsPerChunk));
}
+ String defaultCompressionCodec =
+
instanceConfig.getProperty(CommonConstants.ForwardIndexConfigs.CONFIG_OF_DEFAULT_COMPRESSION_CODEC);
+ if (defaultCompressionCodec != null) {
+ setDefaultCompressionCodec(defaultCompressionCodec);
Review Comment:
**[correctness] Multi-role single-JVM deployments: the last starter to run
silently overwrites the JVM-global default for all roles.**
`ForwardIndexConfig.setDefaultCompressionType` mutates a process-global
static, and every role starter (controller/broker/server/minion) re-runs
`initForwardIndexConfig` from its own merged config. In a single-JVM deployment
(quickstart, `ServiceManager`), `addConfigIfNotExists` gives each component's
local conf precedence over the ZK value, so if the roles' effective values
differ (e.g. server conf sets `ZSTANDARD`, minion conf omits it while ZK says
`LZ4`), the last-started role flips the shared static *after* earlier roles
have begun building segments. A segment build that straddles the flip can even
get mixed codecs across columns, since `ForwardIndexCreatorFactory` resolves
the default per column at creator-construction time. The three sibling defaults
share this mechanism, but this PR adds the first value operators are explicitly
invited to set per-instance.
##########
pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java:
##########
@@ -3024,6 +3024,8 @@ public static class ForwardIndexConfigs {
"pinot.forward.index.default.target.max.chunk.size";
public static final String CONFIG_OF_DEFAULT_TARGET_DOCS_PER_CHUNK =
"pinot.forward.index.default.target.docs.per.chunk";
+ public static final String CONFIG_OF_DEFAULT_COMPRESSION_CODEC =
+ "pinot.forward.index.default.compression.codec";
Review Comment:
**[scope gap] Segment builds outside the cluster never see this config —
tables end up permanently mixed-compression.**
Only the four in-cluster starters call
`ServiceStartableUtils.applyClusterConfig`. Standalone/Spark/Hadoop batch
ingestion (`SegmentGenerationTaskRunner`) and `pinot-admin CreateSegment` build
segments in their own JVM through the same `ForwardIndexCreatorFactory`
null-codec path, so they keep the compiled-in LZ4 while server/minion-built
segments of the same table use the configured codec. Because
`shouldRewriteRawForwardIndex` deliberately ignores defaults, reload never
reconciles them. The same gap exists for the sibling forward-index defaults,
but the new doc on `ForwardIndexType.getDefaultCompressionType` ("unless
`pinot.forward.index.default.compression.codec` says otherwise") implies
cluster-wide reach it doesn't have — worth a doc note here stating the config
only affects components that apply cluster config at startup.
##########
pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java:
##########
@@ -134,6 +141,55 @@ private static void
initForwardIndexConfig(PinotConfiguration instanceConfig) {
LOGGER.info("Setting forward index default target docs per chunk to:
{}", defaultTargetDocsPerChunk);
ForwardIndexConfig.setDefaultTargetDocsPerChunk(Integer.parseInt(defaultTargetDocsPerChunk));
}
+ String defaultCompressionCodec =
+
instanceConfig.getProperty(CommonConstants.ForwardIndexConfigs.CONFIG_OF_DEFAULT_COMPRESSION_CODEC);
Review Comment:
**[operator trap] The documented `pinot.all.` spelling of this key is
silently dropped.**
`applyClusterConfig`'s javadoc advertises that `pinot.all.*` cluster keys
are rewritten to role-specific keys
(`pinot.server.forward.index.default.compression.codec`, ...), but
`initForwardIndexConfig` reads only the bare key
`pinot.forward.index.default.compression.codec`. An operator who follows the
documented convention and sets
`pinot.all.forward.index.default.compression.codec=ZSTANDARD` gets no warning
at all (the warn paths in `setDefaultCompressionCodec` never run because the
bare key is absent), and the cluster keeps building LZ4. Pre-existing for the
sibling keys, but the new key inherits the trap and it is invisible by design —
consider also checking the role-prefixed spelling or logging when it is present.
##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java:
##########
@@ -335,11 +335,20 @@ private ForwardIndexConfig
createConfigFromFieldConfig(FieldConfig fieldConfig,
return builder.build();
}
+ /// The compression type used for a raw column whose table config does not
name one.
+ ///
+ /// Metrics stay uncompressed: they are usually small fixed-width values
where compression costs more
+ /// than it saves. Everything else uses
[ForwardIndexConfig#getDefaultCompressionType()], which is LZ4
+ /// unless `pinot.forward.index.default.compression.codec` says otherwise.
+ ///
+ /// This is a default, not a table config value, so changing it does not
rewrite existing segments:
+ /// `ForwardIndexHandler` deliberately ignores it when deciding whether a
reload must rewrite a forward
+ /// index.
public static ChunkCompressionType
getDefaultCompressionType(FieldSpec.FieldType fieldType) {
if (fieldType == FieldSpec.FieldType.METRIC) {
return ChunkCompressionType.PASS_THROUGH;
} else {
- return ChunkCompressionType.LZ4;
+ return ForwardIndexConfig.getDefaultCompressionType();
Review Comment:
**[behavior change] Columns declared via legacy `noDictionaryConfig: {"col":
"SNAPPY"}` now follow the mutable cluster default instead of deterministic
LZ4.**
`noDictionaryConfig` values are consumed by `keySet()` only (this file
L239-241, `DictionaryIndexType` L127-128) — the per-column codec value is never
parsed into the `ForwardIndexConfig`, so such columns carry a null chunk
compression type and get filled at `ForwardIndexCreatorFactory:107`. Before
this PR that fill-in was the constant LZ4; now it is whatever the cluster
default is set to. So a user's *explicit* legacy `"SNAPPY"` is overridden by
the cluster knob, and `shouldRewriteRawForwardIndex` (null
`newCompressionType`) will never rewrite it back. The value-ignoring is
pre-existing, but this PR changes the substitute from deterministic to
cluster-mutable — either honor the legacy value or document the interaction.
##########
pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/forward/ForwardIndexType.java:
##########
@@ -335,11 +335,20 @@ private ForwardIndexConfig
createConfigFromFieldConfig(FieldConfig fieldConfig,
return builder.build();
}
+ /// The compression type used for a raw column whose table config does not
name one.
+ ///
+ /// Metrics stay uncompressed: they are usually small fixed-width values
where compression costs more
+ /// than it saves. Everything else uses
[ForwardIndexConfig#getDefaultCompressionType()], which is LZ4
Review Comment:
**[missed call sites] "Everything else uses the default" is not true for
OPEN_STRUCT-derived columns — `OpenStructColumnSplitter` still hardcodes LZ4.**
`OpenStructColumnSplitter` pins `CompressionCodec.LZ4` for materialized raw
key columns (~L575) and `ChunkCompressionType.LZ4` for the sparse remainder
column (~L767). With a cluster default of e.g. ZSTANDARD, the dense child is
originally written with ZSTANDARD (via this default), then the split re-encodes
it as LZ4 — the opposite of the adjacent rationale comment "LZ4 preserves the
dense child's current on-disk layout", which assumed LZ4 *was* the default. The
precondition message there ("always use a dictionary-encoded or LZ4 raw forward
index") also becomes inaccurate. Either route those sites through
`ForwardIndexType.getDefaultCompressionType(fieldType)` / leave the codec null,
or update the comments to say "LZ4 regardless of the cluster default".
##########
pinot-common/src/main/java/org/apache/pinot/common/utils/ServiceStartableUtils.java:
##########
@@ -134,6 +141,55 @@ private static void
initForwardIndexConfig(PinotConfiguration instanceConfig) {
LOGGER.info("Setting forward index default target docs per chunk to:
{}", defaultTargetDocsPerChunk);
ForwardIndexConfig.setDefaultTargetDocsPerChunk(Integer.parseInt(defaultTargetDocsPerChunk));
}
+ String defaultCompressionCodec =
+
instanceConfig.getProperty(CommonConstants.ForwardIndexConfigs.CONFIG_OF_DEFAULT_COMPRESSION_CODEC);
+ if (defaultCompressionCodec != null) {
+ setDefaultCompressionCodec(defaultCompressionCodec);
+ }
+ }
+
+ /// Applies the cluster-wide default compression codec for raw forward
indexes.
+ ///
+ /// The value is a [CompressionCodec], the same spelling used by
`compressionCodec` in a table config,
+ /// so that an operator setting a cluster default and a table author setting
a column override write the
+ /// same word. Codecs that are not applicable to a raw forward index -- the
CLP family, `MV_ENTRY_DICT`,
+ /// `DELTA` -- are rejected rather than applied, since they describe
whole-index or dictionary formats
+ /// that cannot stand in for a chunk codec.
+ ///
+ /// Unlike the numeric defaults above, an unusable value is logged and
ignored instead of failing
+ /// startup: this one is routinely set as a *cluster* config, where throwing
would take down every
+ /// component that restarts after the bad value is saved.
+ @VisibleForTesting
+ static void setDefaultCompressionCodec(String defaultCompressionCodec) {
+ CompressionCodec codec;
+ try {
+ codec =
CompressionCodec.valueOf(defaultCompressionCodec.trim().toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("Unknown forward index default compression codec: {},
expected one of: {}, keeping: {}",
Review Comment:
**[silent misconfiguration + policy asymmetry] A near-miss spelling keeps
LZ4 forever with only a startup WARN, while the sibling configs three blocks
above crash on a typo.**
`ZSTD` — the spelling of the codecSpec DSL and of the zstd tool itself,
explicitly anticipated by this PR's own `unrecognisedValues` test — is
warn-and-ignored, so the operator sees every component start cleanly, believes
ZSTANDARD is active, and only discovers otherwise by inspecting segment
metadata later. There is no way to retroactively distinguish "default never
applied" from "tables overrode it". Meanwhile a typo in
`pinot.forward.index.default.target.docs.per.chunk` still throws from the
uncaught `Integer.parseInt` and takes down every restarting component — the
exact risk the doc comment above cites as justification for *not* throwing
here. One policy for all four defaults (uniformly lenient-with-warn, or
fail-fast plus controller-side validation), or at least aliasing `ZSTD`, would
remove both the trap and the contradiction.
##########
pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/ForwardIndexConfig.java:
##########
@@ -76,6 +77,16 @@ public static void setDefaultTargetDocsPerChunk(int
defaultTargetDocsPerChunk) {
_defaultTargetDocsPerChunk = defaultTargetDocsPerChunk;
}
+ /// The chunk compression type applied to a raw column whose table config
does not name one, except
Review Comment:
**[doc contract] This javadoc promises a metric exemption the method does
not implement.**
"...except for metrics, which stay uncompressed" is enforced only in
`ForwardIndexType.getDefaultCompressionType(FieldType)` in pinot-segment-local
— a module this SPI getter cannot reference. The getter itself returns the
configured codec for every field type. A future caller in segment-spi or below
segment-local that trusts this doc and calls the getter directly for a metric
column would start compressing metrics once the cluster default is set,
violating the invariant the PR's own `testConfiguredDefaultDoesNotAffectMetric`
pins down. Reword to state that the metric exemption is applied by the caller
(`ForwardIndexType`), not by this method.
--
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]