924060929 commented on PR #66717:
URL: https://github.com/apache/doris/pull/66717#issuecomment-5355800648

   Architecture follow-up after re-evaluating the estimator design and the 
earlier AI review findings on current head `f6812356`.
   
   My approval remains: I do not see a remaining P1 correctness blocker on this 
head. This comment is about converging the design before merge, especially the 
production sizing model.
   
   ## The PR has absorbed useful findings, but the estimator objective drifted
   
   The original operational goal is to keep long-lived external-metadata cache 
retention approximately bounded and let the JVM reclaim unused values under 
pressure. For that goal, the important architecture is now present:
   
   - `softValues`, without strong `V` references in reservation/refresh 
ownership;
   - entry/catalog/global admission budgets;
   - admission before publication and generation-fenced release;
   - O(1) Caffeine weighing/removal accounting using the publication weight;
   - count limits plus matching cleanup on replacement, eviction, collection, 
invalidation and close.
   
   However, `max-weight` was then treated as a near-exact retained-byte 
promise. The calibration tests require no under-estimation and at most 10% 
over-estimation against JOL. That changed the production estimator from a 
coarse cache governor into a hand-written model of JVM and third-party SDK 
object graphs.
   
   The review loop reinforced this drift. Individual P2 findings such as 
missing partition width, alias cardinality, Paimon store growth, default 
literals, shared strings, merged ranges and empty-table key width were locally 
valid under an exact-byte objective. Fixing every one at object-layout 
granularity led to more class fingerprints, lazy-map models, boxed-ID 
accounting, HashMap capacity calculations and JOL fixtures. Each local fix 
improved one oracle, but the accumulated result is substantially more complex 
and SDK-sensitive than the cache-governance problem requires.
   
   ## Size is now a design signal
   
   The current authoritative diff is `+16,349/-521` across 91 files. This is 
not 16K lines of production code:
   
   - production main/BE: about `+7,729/-398`;
   - FE unit tests: about `+7,100/-122`;
   - benchmarks: about `+1,414`;
   - regression tests: about `+89/-1`.
   
   The tests are valuable, but 7.7K production additions are still large for 
one cache-governance change. In particular:
   
   - `IcebergCacheSizeEstimator`: 1,230 lines;
   - `PaimonCacheSizeEstimator`: 592 lines;
   - `MetaCacheWeightUtils`: 368 lines.
   
   Those three files alone contain about 2.2K lines devoted mainly to sizing. 
That is a warning that the estimator is reproducing implementation details 
rather than expressing stable cache semantics.
   
   ## Which earlier AI findings should remain
   
   Retain findings that identify a missing **order-of-growth dimension** or a 
cache-lifecycle hole:
   
   - partition/file/snapshot/schema counts that can grow without bound;
   - partition width (`partitionCount * partitionColumnCount`);
   - total schema/type-node, spec-field and sort-field counts;
   - alias counts and metadata/property/summary entry counts;
   - skew-sensitive string/binary payload already available from the normal 
loader;
   - coarse reservation for post-admission lazy growth, such as Iceberg schema 
indexes or Paimon store-derived RowTypes;
   - a child entry independently retaining a frozen table generation;
   - arithmetic saturation, once-only publication weighing, and no remote 
I/O/lazy materialization for weighing;
   - generation-fenced reservation/removal correctness.
   
   These findings should be expressed as a small number of stable logical 
cardinalities.
   
   ## Which earlier AI suggestions should not drive production code
   
   Do not keep accepting findings whose only purpose is making a hand-written 
formula match JOL within 10%:
   
   - exact `HashMap` table/node capacity;
   - Guava singleton-versus-regular collection layouts;
   - boxed `Integer`/`Long` cache identities;
   - precise object alignment and compressed-oops assumptions;
   - exact `ByteBuffer`, `BigDecimal`, literal-wrapper or accessor instance 
sizes;
   - one formula per concrete Paimon `DataType` implementation;
   - Iceberg/Paimon private-field layout fingerprints;
   - exact counts of lazy lookup maps and accessor wrapper classes;
   - rejection of an otherwise supported value only because a future SDK 
subtype or private layout is unknown;
   - shared-string identity corrections whose only effect is a small JOL-ratio 
adjustment.
   
   These are not durable cache invariants. They bind Doris to private details 
of Iceberg 1.10.1, Paimon 1.4.2, Guava and the active JVM. They also turn 
ordinary SDK upgrades into weighted-cache rejection risks.
   
   An AI review suggestion should be rejected or reframed when it improves a 
local byte oracle but violates the system-level constraints: small production 
code, stable semantics, bounded hot-path work, no SDK-private coupling, and 
maintainable upgrades. The right response to a valid under-count observation is 
often "add one logical cardinality term", not "model every Java object it 
expands into".
   
   ## Recommended production formulas
   
   Use approximate byte-like units, rounded upward to simple constants and 
calibrated offline. Document `max-weight` as an estimated retained-cache 
admission budget, not an exact heap limit.
   
   ```text
   Hive partition values
     BASE
     + partitionColumnCount * KEY_COLUMN_WEIGHT
     + partitionCount * PARTITION_WEIGHT
     + partitionCount * partitionColumnCount * PARTITION_COLUMN_WEIGHT
     + retainedPartitionPayloadBytes
   ```
   
   ```text
   Iceberg table generation
     BASE
     + snapshotCount * SNAPSHOT_WEIGHT
     + schemaCount * SCHEMA_WEIGHT
     + totalSchemaFieldCount * FIELD_WEIGHT
     + specCount * SPEC_WEIGHT
     + totalPartitionFieldCount * PARTITION_FIELD_WEIGHT
     + sortOrderCount * SORT_ORDER_WEIGHT
     + totalSortFieldCount * SORT_FIELD_WEIGHT
     + metadataCollectionEntryCount * METADATA_ENTRY_WEIGHT
     + retainedPayloadBytes
   ```
   
   The lazy schema/spec indexes can be covered by increasing `FIELD_WEIGHT` and 
`PARTITION_FIELD_WEIGHT`; they do not require explicit HashMap/accessor models.
   
   ```text
   Iceberg snapshot projection
     BASE
     + partitionCount * PARTITION_WEIGHT
     + partitionCount * partitionColumnCount * PARTITION_COLUMN_WEIGHT
     + aliasCount * ALIAS_WEIGHT
     + nameMappingFieldCount * NAME_MAPPING_FIELD_WEIGHT
     + nameMappingAliasCount * NAME_MAPPING_ALIAS_WEIGHT
     + retainedPartitionPayloadBytes
     + retainedTableGenerationWeight
   ```
   
   Compute `retainedTableGenerationWeight` once and reuse it. If the table and 
snapshot entries independently own the same frozen generation, conservative 
duplicate reservation is acceptable for now; do not traverse and estimate the 
graph twice. Shared reservation ownership can be a later optimization if 
necessary.
   
   ```text
   Iceberg manifest
     BASE
     + dataFileCount * DATA_FILE_WEIGHT
     + deleteFileCount * DELETE_FILE_WEIGHT
     + metricEntryCount * METRIC_ENTRY_WEIGHT
     + retainedPayloadBytes
   ```
   
   Never read a remote manifest solely to obtain a weight.
   
   ```text
   Paimon table generation
     BASE
     + wrapperCount * WRAPPER_WEIGHT
     + schemaFieldCount * FIELD_WEIGHT
     + logicalTypeNodeCount * TYPE_NODE_WEIGHT
     + optionCount * OPTION_WEIGHT
     + partitionKeyCount * KEY_WEIGHT
     + primaryKeyCount * KEY_WEIGHT
     + bucketKeyCount * KEY_WEIGHT
     + derivedRowTypeCopies * schemaFieldCount * DERIVED_FIELD_WEIGHT
     + retainedPayloadBytes
   ```
   
   `logicalTypeNodeCount` is a stable schema concept; exact Java class instance 
layouts are not. Unknown future logical types should receive a conservative 
generic weight instead of disabling weighted caching.
   
   ```text
   Paimon snapshot projection
     BASE
     + partitionCount * PARTITION_WEIGHT
     + partitionCount * partitionColumnCount * PARTITION_COLUMN_WEIGHT
     + retainedPartitionPayloadBytes
     + retainedTableGenerationWeight
   ```
   
   Do not charge `Partition.fileCount()` as retained files: it is a scalar 
unless the value actually owns file objects.
   
   ## What JOL should do
   
   Keep JOL, if its license/dependency placement is acceptable, only in a 
benchmark/test-only calibration module. Use it to choose upward-rounded 
constants and periodically detect order-of-magnitude mistakes. Do not require 
every fixture to stay within `[1.00, 1.10]` of JOL.
   
   The production acceptance criteria should instead be:
   
   - monotonic weight for 1K/10K/100K cardinalities;
   - major narrow/wide and flat/nested dimensions are represented;
   - no remote I/O or lazy materialization during weighing;
   - bounded publication CPU/allocation;
   - saturated arithmetic;
   - hits/removals are O(1);
   - soft collection releases only the matching reservation generation;
   - typical fixtures have no order-of-magnitude under-estimation.
   
   ## Suggested convergence
   
   Please keep the now-hardened admission/lifecycle framework, but replace the 
production Iceberg/Paimon structural estimators and SDK field-signature 
machinery with the coarse formulas above. The full estimator/JOL fixtures can 
remain as offline calibration evidence rather than production correctness 
machinery.
   
   This is not a request to discard all prior review feedback. It is a request 
to retain the stable semantic dimensions discovered by review while stopping 
the object-by-object implementation strategy. Otherwise future 
Iceberg/Paimon/JDK upgrades will require repeatedly teaching Doris another 
version of third-party private object graphs, even though the mechanism still 
cannot bound load-time peak memory before admission.
   


-- 
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