-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Improve join index memory accounting #15672
Improve join index memory accounting #15672
Conversation
Still WIP |
core/trino-main/src/main/java/io/trino/operator/join/unspilled/HashBuilderOperator.java
Show resolved
Hide resolved
@@ -79,9 +82,29 @@ public JoinHashSupplier( | |||
positionLinksFactoryBuilder = ArrayPositionLinks.builder(addresses.size()); | |||
} | |||
|
|||
this.pages = channelsToPages(channels); | |||
long additionalPagesRetainedSizeInBytes = 0; | |||
// Currently PageIndex is retained by the HashBuilderOperator after JoinHash is created. |
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.
Is or is-not. If it is retained then why do we need to account for this memory once again?
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.
This is rather convoluted. HashBuilderOperator
retains PageIndex
. When PageIndex
is being built memory usage is set to PageIndex#getEstimatedSize
. After LookupSource
(JoinHash
) is created memory usage of HashBuilderOperator
is set to JoinHash#getInMemorySizeInBytes
while a reference to PageIndex
is still retained. I think the assumption is that the JoinHash
retains same data what PageIndex
does, and it had been (almost) true up until the introduction of positionCounts
. However the overhead of pages created for JoinHash
have never been accounted, that's also what I'm trying to accommodate here.
It feels like ideally it has to be refactored:
- Once
JoinHash
is createdPageIndex
has to be released. This is problematic with spilling, but should be doable in a version that doesn't support spilling JoinHash
ideally has to be refactored to avoid this duality of havingList<Page>
in addition toList<List<Block>>
. However it is not a straightforward change.
this.pages = channelsToPages(channels); | ||
long additionalPagesRetainedSizeInBytes = 0; | ||
// Currently PageIndex is retained by the HashBuilderOperator after JoinHash is created. | ||
// JoinHash has to account for all data structures retained by PageIndex as after JoinHash is created memory retained by PageIndex is no longer accounted for. |
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.
Also can we just see how much much memory PageIndex
consumed instead recomputing piece by piece here?
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.
PageIndex
stores data as a List<List<Block>>
. However JoinHash
nees the same data in a form of List<Page>
, so we have to account the overhead of Page
wrappers, but avoid accounting the size of blocks twice. Ideally it would be great to refactor and only use data in one form.
4d635cf
to
f6dd7fa
Compare
@@ -306,6 +306,11 @@ private void finishInput() | |||
return; | |||
} | |||
|
|||
ListenableFuture<Void> reserved = localUserMemoryContext.setBytes(index.getEstimatedLookupSourceSizeInBytes(hashArraySizeSupplier)); | |||
if (!reserved.isDone()) { | |||
// Yield when not enough memory is available to proceed, finish is expected to be called again when some memory is freed |
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.
That seems to be awfully dependent on Driver
detail. Could we make operator return blocked future instead.
Please add tests also
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.
That seems to be awfully dependent on Driver detail. Could we make operator return blocked future instead.
It is generally true that currently it is responsibility of the system to "park" Drivers when the system is low on memory. For example if the HashAggregationOperator
pushes the memory pool over the limit we currently don't explicitly block the operator, instead we simply update the memory utilization and expect the engine not to proceed if the system is low on memory.
Please add tests also
Yeah, still working on it.
f6dd7fa
to
8e0cd24
Compare
Ready for review |
core/trino-main/src/main/java/io/trino/operator/join/JoinHashSupplier.java
Outdated
Show resolved
Hide resolved
8e0cd24
to
1ca769a
Compare
@@ -616,4 +618,12 @@ public Page computeNext() | |||
} | |||
}; | |||
} | |||
|
|||
public long getEstimatedLookupSourceSizeInBytes(HashArraySizeSupplier hashArraySizeSupplier) |
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.
Estimate will depend on which PagesHash
implementation is used and is also subject to change in the future.
You could pass LocalMemoryContext
to io.trino.operator.PagesIndex#createLookupSourceSupplier
and make createLookupSourceSupplier
return a future.
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.
Discussed offline. Decided to extract helper methods for estimating every part of the JoinHash
@@ -79,7 +83,20 @@ public JoinHashSupplier( | |||
positionLinksFactoryBuilder = ArrayPositionLinks.builder(addresses.size()); | |||
} | |||
|
|||
long additionalPagesRetainedSizeInBytes = 0; | |||
// Currently PageIndex is retained by the HashBuilderOperator after JoinHash is created. | |||
// JoinHash has to account for all data structures retained by PageIndex as after JoinHash is created memory retained by PageIndex is no longer accounted for. |
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.
for all data structures retained by PageIndex as after JoinHash
Where PagesIndex
is still referenced? Can we simplify it (composite retained memory computation or use memory context) rather than feeding back special parameters?
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.
Discussed offline. Decided to set PageIndex
to null
once it is no longer needed.
1ca769a
to
36c42eb
Compare
Updated |
36c42eb
to
31b33c1
Compare
core/trino-main/src/main/java/io/trino/operator/join/unspilled/HashBuilderOperator.java
Outdated
Show resolved
Hide resolved
@@ -321,14 +323,13 @@ private void disposeLookupSourceIfRequested() | |||
return; | |||
} | |||
|
|||
index.clear(); |
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.
check state index is null?
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.
close
set's it to null unconditionally (as well as lookupSourceSupplier
). Actually let me remove the lookupSourceSupplier = null
as well
core/trino-main/src/main/java/io/trino/operator/join/JoinUtils.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/operator/join/JoinHashSupplier.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/test/java/io/trino/operator/join/unspilled/TestHashJoinOperator.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/operator/join/JoinHashSupplier.java
Outdated
Show resolved
Hide resolved
core/trino-main/src/main/java/io/trino/operator/join/BigintPagesHash.java
Outdated
Show resolved
Hide resolved
31b33c1
to
fabf99c
Compare
@sopel39 Updated |
close assigns lookupSourceSupplier to null unconditionally
fabf99c
to
702d868
Compare
@@ -322,7 +322,6 @@ private void disposeLookupSourceIfRequested() | |||
return; | |||
} | |||
|
|||
lookupSourceSupplier = null; |
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.
squash?
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.
It is pre-existing
Description
Additional context and related issues
Release notes
(X) This is not user-visible or 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: