-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Cleanup OutputBufferMemoryManager and peak memory calculations #26883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cleanup OutputBufferMemoryManager and peak memory calculations #26883
Conversation
Reviewer's GuideThis PR refactors OutputBufferMemoryManager to improve performance by replacing expensive atomic operations with cheaper alternatives, reducing volatile writes for peak memory tracking, streamlining utilization recording logic, and enforcing immutability by making the class final. Class diagram for refactored OutputBufferMemoryManagerclassDiagram
class OutputBufferMemoryManager {
-AtomicLong bufferedBytes
-AtomicLong peakMemoryUsage
-long maxBufferedBytes
-TDigest bufferUtilization
-long lastBufferUtilizationRecordTime
-double lastBufferUtilization
-Ticker ticker
-ListenableFuture<Void> blockedOnMemory
-ListenableFuture<Void> bufferBlockedFuture
-MemoryContext memoryContext
+updateMemoryUsage(long bytesAdded)
+getBufferedBytes()
+getUtilization()
+getUtilizationHistogram()
-recordBufferUtilization(long currentBufferedBytes)
-getUtilization(long currentBufferedBytes)
}
note for OutputBufferMemoryManager "Class is now final"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `core/trino-main/src/main/java/io/trino/execution/buffer/OutputBufferMemoryManager.java:102-105` </location>
<code_context>
- checkArgument(result >= 0, "bufferedBytes (%s) plus delta (%s) would be negative", bytes, bytesAdded);
- return result;
- });
+ currentBufferedBytes = bufferedBytes.addAndGet(bytesAdded);
+ if (currentBufferedBytes < 0) {
+ bufferedBytes.set(currentBufferedBytes - bytesAdded);
+ throw new IllegalStateException("bufferedBytes (%s) plus delta (%s) is negative".formatted(bufferedBytes.get(), bytesAdded));
+ }
ListenableFuture<Void> blockedOnMemory = memoryContext.setBytes(currentBufferedBytes);
</code_context>
<issue_to_address>
**issue (bug_risk):** Switching from updateAndGet with checkArgument to addAndGet with post-check changes error handling.
This method allows bufferedBytes to be negative briefly, which may be visible to other threads. Evaluate if this could lead to issues, or consider using a compare-and-set loop for stricter consistency.
</issue_to_address>
### Comment 2
<location> `core/trino-main/src/main/java/io/trino/execution/buffer/OutputBufferMemoryManager.java:127-128` </location>
<code_context>
+ recordBufferUtilization(currentBufferedBytes);
+ }
+ // Reduce contention by reading first and only updating if the new value might become the maximum (uncommon)
+ if (currentBufferedBytes > peakMemoryUsage.get()) {
+ peakMemoryUsage.accumulateAndGet(currentBufferedBytes, Math::max);
}
- peakMemoryUsage.accumulateAndGet(currentBufferedBytes, Math::max);
</code_context>
<issue_to_address>
**issue (bug_risk):** Optimizing peakMemoryUsage update reduces contention but may miss some updates.
This approach can miss updates to peakMemoryUsage due to race conditions between threads. Assess if this potential inaccuracy aligns with your application's requirements.
</issue_to_address>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
core/trino-main/src/main/java/io/trino/execution/buffer/OutputBufferMemoryManager.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/execution/buffer/OutputBufferMemoryManager.java
Show resolved
Hide resolved
a429b22
to
8faba62
Compare
8faba62
to
731ee19
Compare
core/trino-main/src/main/java/io/trino/execution/buffer/OutputBufferMemoryManager.java
Outdated
Show resolved
Hide resolved
731ee19
to
6536da3
Compare
Description
OutputBufferMemoryManager
AtomicLong#updateAndGet
forAtomicLong#accumulateAndGet
operationcurrentBufferedBytes > bufferedBytes.get()
before callingbufferedBytes.accumulateAndGet(currentBufferedBytes, Math::max)
since a volatile read is cheaper than a volatile write and updating the maximum is not the common case.getUtilization
logic to avoid unnecessary volatile readsPeak Memory Calculations
AtomicLong
to check whether the value is greater than peak before calling intoAtomicLong::accumulateAndGet
so to avoid unnecessary contention on volatile updatesRelease notes
(x) This is not user-visible or is docs only, and no release notes are required.
( ) Release notes are required. Please propose a release note for me.
( ) Release notes are required, with the following suggested text:
Summary by Sourcery
Improve performance and simplify synchronization in OutputBufferMemoryManager by replacing atomic operations, reducing volatile writes, refactoring utilization tracking, and marking the class as final
Bug Fixes:
Enhancements: