[Improv]: enable max ordinal check after write state engine prepare write;#787
[Improv]: enable max ordinal check after write state engine prepare write;#787azeng-netflix merged 1 commit intomasterfrom
Conversation
7745b1a to
53aef77
Compare
hollow/src/main/java/com/netflix/hollow/core/write/HollowTypeWriteState.java
Outdated
Show resolved
Hide resolved
690a96d to
f30e000
Compare
| * @param ignoreOrdinalThresholdBreach the supplier that returns true to ignore threshold breaches | ||
| * @return this builder | ||
| */ | ||
| public B withIgnoreOrdinalThresholdBreachConfig(Supplier<Boolean> ignoreOrdinalThresholdBreach) { |
There was a problem hiding this comment.
Can make this more generic to all soft limits- ignoreSoftLimits
| private static final long ORDINAL_MASK = (1L << BITS_PER_ORDINAL) - 1; | ||
| private static final long MAX_BYTE_DATA_LENGTH = 1L << BITS_PER_POINTER; | ||
| // a safe limit for the ordinal. Even though the ordinal value range is [0, (1<<29) - 1], in production, | ||
| // the user should be warned whenever the ordinal value exceeds (1<<28) - 1. |
There was a problem hiding this comment.
nit: drop "in production" and replace "the user should be warned" with something like- fail the producer cycle unless soft limits are overridden
|
|
||
| if (ordinal >= SOFT_ORDINAL_LIMIT) { | ||
| if (logOrdinalThresholBreach && ignoreOrdinalThresholdBreach) { | ||
| logOrdinalThresholBreach = false; |
There was a problem hiding this comment.
nit: typo in logOrdinalThresholBreach - but I guess it will be renamed to logSoftLimitBreach anyway
| */ | ||
| public void prepareForNextCycle() { | ||
| ordinalMap.compact(currentCyclePopulated, numShards, stateEngine.isFocusHoleFillInFewestShards()); | ||
| ordinalMap.setIgnoreOrdinalThresholdBreach(ignoreOrdinalThresholdBreachSupplier == null ? false : ignoreOrdinalThresholdBreachSupplier.get()); |
There was a problem hiding this comment.
here and anywhere else where there isn't a way to override the soft limit failure, lets default to not failing on soft limits
| */ | ||
| void onBlobPublish(Status status, HollowProducer.Blob blob, Duration elapsed); | ||
|
|
||
| default void onPublishHeaderBlob(HollowWriteStateEngine writeStateEngine) { |
There was a problem hiding this comment.
This is used for listener to do customized report
There was a problem hiding this comment.
coupling with onPublishHeaderBlob doesn't feel great, can we explore reusing the onPopulateComplete listener method?
There was a problem hiding this comment.
I have moved it to onPublishComplete.
The reason of not doing it in onPopulateComplete, is that the WriteStateEngine has not been prepared for write yet.
308129f to
a80d8cc
Compare
|
@azeng-netflix Before merge, check again to see if missing any places where the limit supplier are not properly propagated/copied over. |
| } | ||
|
|
||
| // check if ByteArrayOrdinalMap.ignoreSoftLimits has been updated to the expected value. | ||
| private void checkBaomIgnoreOrdinalSoftLimit(boolean expected, HollowProducer producer) { |
There was a problem hiding this comment.
NOTE: Modified this test file to check if ignore ordinal limit can be updated between cycles/restore
| * | ||
| * @return a {@link ByteArrayOrdinalMapStats} containing map statistics | ||
| */ | ||
| public ByteArrayOrdinalMapStats getOrdinalMapStatsAfterPreparation() { |
There was a problem hiding this comment.
nit: could simplify name to getStats , the clarification you have in javadoc feels sufficient
There was a problem hiding this comment.
Changed to getOrdinalMapStats in case in the future other stats also need to be exposed from HollowTypeWriteState
| //// adjust number of shards per type during the course of the delta chain to realize consumer-side delta applications at constant space overhead | ||
| private boolean allowTypeResharding = false; | ||
| //// supplier to determine whether to ignore ordinal threshold breaches (log warning instead of throwing exception) | ||
| private Supplier<Boolean> ignoreOrdinalSoftLimitsSupplier; |
There was a problem hiding this comment.
nit: name this more generic ignoreSoftLimitsSupplier, becuase we would reuse it for any other limits. Could also drop supplier from the name
There was a problem hiding this comment.
Changed to ignoreSoftLimits
| } | ||
| // continue silently after first log | ||
| } else { | ||
| String message = String.format("Ordinal %d exceeds the soft ordinal limit of %d.", |
There was a problem hiding this comment.
nit: adding a hint in the log msg about support for ignoring soft limits could be useful
| this(schema, -1); | ||
| } | ||
|
|
||
| public HollowListTypeWriteState(HollowListSchema schema, Supplier<Boolean> ignoreOrdinalSoftLimitsSupplier) { |
There was a problem hiding this comment.
I dont think we really need this new constructor, could just reuse the other one you added?
| } | ||
|
|
||
| public HollowListTypeWriteState(HollowListSchema schema, int numShards) { | ||
| super(schema, numShards); |
There was a problem hiding this comment.
nit: changing to this(schema, numShards, null) would be a bit more readable
| * @param version version that was published. | ||
| * @param elapsed duration of the publish stage in {@code unit} units | ||
| */ | ||
| default void onPublishComplete(HollowWriteStateEngine writeStateEngine, Status status, long version, Duration elapsed) { |
There was a problem hiding this comment.
An alternative would be to add a Stats within the State object, where different stages like publish, etc. could implement their stats like PublishStage could implement stats like duration which could be generic to all stages, or specific ones like ordinap map stats for publish stage. If you think it fits well, otherwise the current approach seems fine too, but if we're doing this then lets also deprecate the older 3 param onPublishComplete, and make this default impl call that one. Could also add to the javadoc- The default implementation delegates to the deprecated 3 param onPublishComplete for backwards compatibility.
There was a problem hiding this comment.
Made this commit to address the comment, but during the implementation, I think a general Stats would require the Listener side to do type casting like stats instanceof PublishStageStats. would like your opinion on this.
There was a problem hiding this comment.
add and use PublishListener.onPublishComplete(Status status, long version, Duration elapsed, PublishStageStats stats)
4952801 to
9f0ef02
Compare
…poses ordinal map statistics to PublishListeners for monitoring.
9f0ef02 to
775b98a
Compare
Summary:
This change adds configurable soft limit validation to ByteArrayOrdinalMap and exposes ordinal map
statistics to PublishListeners for monitoring.
Changes:
- Adds soft limit threshold at 268,435,456 (2^28) - half of the hard limit
- Throws exception when soft limit exceeded (configurable behavior)
- Override mechanism via HollowProducer.withIgnoreSoftLimits(Supplier)
- One-time logging per cycle to prevent log spam
- New ByteArrayOrdinalMapStats class captures maxOrdinal, byteDataLength, and loadFactor
- New PublishStageStats wraps stats for all type write states
- Extended PublishListener.onPublishComplete() to receive stats (backward compatible)
- Stats collected after successful publish and passed through listener chain
3. Perf Improvement
- Remove redundant scan of
pointersAndOrdinalsto find the max ordinal inHollowWriteTypeState. Instead, find and return the max ordinal when doingprepareForWriteBackward Compatibility: