Skip to content

[improve][ml] Reduce object allocation when iterate on LongPairRangeSet - #18357

Merged
Technoboy- merged 9 commits into
apache:masterfrom
lifepuzzlefun:avoid_object_alloction_when_iterator_long_pair_range_set
Dec 7, 2022
Merged

[improve][ml] Reduce object allocation when iterate on LongPairRangeSet#18357
Technoboy- merged 9 commits into
apache:masterfrom
lifepuzzlefun:avoid_object_alloction_when_iterator_long_pair_range_set

Conversation

@lifepuzzlefun

@lifepuzzlefun lifepuzzlefun commented Nov 6, 2022

Copy link
Copy Markdown
Contributor

Fixes #18356

Motivation

support direct perform logic on (long,long) pair without Range and PostionImpl object creation

Modifications

  1. add LongPairRangeSet.forEachWithRangeBoundMapper
  2. change ManagedCursorImpl.buildIndividualDeletedMessageRanges and LongPairRangeSet.size to use this function
  3. add unit test to check forEach and forEachWithRangeBoundMapper return the same result.

Verifying this change

  • Make sure that the change passes the CI checks.

This change is a trivial rework / code cleanup without any test coverage.

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • Anything that affects deployment

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

@github-actions github-actions Bot added the doc-not-needed Your PR changes do not impact docs label Nov 6, 2022
@lifepuzzlefun

lifepuzzlefun commented Nov 7, 2022

Copy link
Copy Markdown
Contributor Author

image

after jmh test. we can see both mem allocation and throughtput improves with this pr

@lifepuzzlefun

lifepuzzlefun commented Nov 7, 2022

Copy link
Copy Markdown
Contributor Author

origin jmh test here
lifepuzzlefun@ffca95d

the result json can achieve here
https://gist.github.com/WJL3333/bff704b2783b617fc0bc93413113e197

just upload to https://jmh.morethan.io/ get the picture.

@lifepuzzlefun

Copy link
Copy Markdown
Contributor Author

@lifepuzzlefun lifepuzzlefun changed the title [improve][broker] Reduce object allocation when iterate on LongPairRangeSet [improve][ml] Reduce object allocation when iterate on LongPairRangeSet Nov 8, 2022
}

@Override
public <O> void forEachWithRangeBoundMapper(LongPairConsumer<O> rawRangeBoundMapper,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of duplication of code with forEach, can it be optimized?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for review. the generic for range require for <T extands Comparable<T>> which is used in Range<T> but for iteration ops we may transform to non Comparable object. i try to reuse but we need the MLDataFormats.MessageRange implements Comparable

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ichange the signature and optimize the code. please take a look~

@lifepuzzlefun

Copy link
Copy Markdown
Contributor Author

return rangeList.size() <= config.getMaxUnackedRangesToPersist();
});

individualDeletedMessages.forEachWithRangeBoundMapper(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just have a callback like

individualDeletedMessages.forEach((l1, l2, u1, u2) -> {
})

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice suggestion ! I have done coding. please take a look again.

@lifepuzzlefun
lifepuzzlefun force-pushed the avoid_object_alloction_when_iterator_long_pair_range_set branch from d257efa to 94bb275 Compare November 12, 2022 14:51
@lifepuzzlefun
lifepuzzlefun force-pushed the avoid_object_alloction_when_iterator_long_pair_range_set branch from 06935e6 to 265dec6 Compare November 12, 2022 17:23
@codelipenghui codelipenghui added this to the 2.12.0 milestone Nov 16, 2022
@codelipenghui codelipenghui added type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages area/ML labels Nov 16, 2022
@codelipenghui

Copy link
Copy Markdown
Contributor

/pulsarbot run-failure-checks

@codecov-commenter

codecov-commenter commented Nov 19, 2022

Copy link
Copy Markdown

Codecov Report

Merging #18357 (653a7e9) into master (a2c1534) will decrease coverage by 2.05%.
The diff coverage is 36.84%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master   #18357      +/-   ##
============================================
- Coverage     47.23%   45.17%   -2.06%     
- Complexity    10430    10660     +230     
============================================
  Files           692      758      +66     
  Lines         67766    72750    +4984     
  Branches       7260     7805     +545     
============================================
+ Hits          32009    32865     +856     
- Misses        32192    36200    +4008     
- Partials       3565     3685     +120     
Flag Coverage Δ
unittests 45.17% <36.84%> (-2.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...pache/bookkeeper/mledger/impl/RangeSetWrapper.java 43.39% <33.33%> (-2.61%) ⬇️
...che/bookkeeper/mledger/impl/ManagedCursorImpl.java 37.06% <38.46%> (+0.24%) ⬆️
...tent/NonPersistentDispatcherMultipleConsumers.java 40.74% <0.00%> (-12.35%) ⬇️
...apache/pulsar/broker/service/TopicListService.java 42.62% <0.00%> (-12.30%) ⬇️
.../org/apache/bookkeeper/mledger/impl/EntryImpl.java 69.62% <0.00%> (-11.27%) ⬇️
...e/pulsar/broker/service/EntryBatchIndexesAcks.java 82.14% <0.00%> (-10.72%) ⬇️
...keeper/mledger/impl/cache/RangeEntryCacheImpl.java 45.79% <0.00%> (-6.31%) ⬇️
.../pulsar/broker/service/PublishRateLimiterImpl.java 58.00% <0.00%> (-6.00%) ⬇️
...ava/org/apache/pulsar/broker/service/Consumer.java 66.19% <0.00%> (-5.98%) ⬇️
...oker/service/schema/SchemaRegistryServiceImpl.java 59.45% <0.00%> (-5.41%) ⬇️
... and 129 more

@lifepuzzlefun

Copy link
Copy Markdown
Contributor Author

All CI passed in my local repository. see lifepuzzlefun#2

@Override
public void forEachRawRange(RawRangeProcessor action) {
for (Range<T> range : asRanges()) {
LongPair lowerEndpoint = this.rangeEndPointConsumer.apply(range.lowerEndpoint());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a range does not set the lower boundary, whether there will be NPE here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for review, after check the code, all range is insert by LongPairRangeSet.addOpenClosed(long,long,long,long) i think there is no chance to get a Range which boundary is not set. maybe i missed somewhere, correct me if im wrong

@Technoboy- Technoboy- left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tisonkun

tisonkun commented Dec 6, 2022

Copy link
Copy Markdown
Member

cc @codelipenghui @Technoboy- @Jason918 shall we merge this patch now?

@Technoboy-
Technoboy- merged commit 12b864e into apache:master Dec 7, 2022
Demogorgon314 pushed a commit to Demogorgon314/pulsar that referenced this pull request Dec 26, 2022
Demogorgon314 pushed a commit to Demogorgon314/pulsar that referenced this pull request Dec 29, 2022
lifepuzzlefun added a commit to lifepuzzlefun/pulsar that referenced this pull request Jan 10, 2023
ng-galien added a commit to ng-galien/pulsar that referenced this pull request Apr 17, 2026
The forEachRawRange callback used to append each range and then return
rangeList.size() <= maxRanges, which kept iteration alive until the list
reached maxRanges + 1 entries. One extra range was therefore serialized
on every persist, and a cursor whose exact ack-hole count equaled
maxRanges + 1 raised a spurious overflow warning even though nothing was
actually truncated.

Switch to the check-before-add pattern (symmetric with the existing
buildBatchEntryDeletionIndexInfoList logic) and derive the overflow
signal from a MutableBoolean set when the callback refuses an extra
range. MutableBoolean is used rather than AtomicBoolean because this
method runs under the cursor write lock and does not need atomic
semantics; the existing MutableBoolean usage in readEntries (around
line 2219) follows the same convention.

The regression lived since apache#3819 (2019), when the original
stream().limit(N) was translated to a forEach callback without keeping
the strict cap. PR apache#18357 later migrated to forEachRawRange and carried
the bug forward.

Extend testPersistOverflowRangesCounter to reopen the cursor after
ledger.close() in the overflow scenario and assert that exactly
maxRanges entries are recovered, guarding against a reintroduction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ML doc-not-needed Your PR changes do not impact docs ready-to-test type/enhancement The enhancements for the existing features or docs. e.g. reduce memory usage of the delayed messages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[improve][broker] Reduce object allocation when iterate on LongPairRangeSet

8 participants