-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Combined ByteBufferPool #8171
Combined ByteBufferPool #8171
Conversation
Signed-off-by: Greg Wilkins <gregw@webtide.com>
This is an alternative to #8169 |
Retained pool acquires from outer pool Signed-off-by: Greg Wilkins <gregw@webtide.com>
updated modules and xml Signed-off-by: Greg Wilkins <gregw@webtide.com>
don't make a private pool Signed-off-by: Greg Wilkins <gregw@webtide.com>
improved dump Signed-off-by: Greg Wilkins <gregw@webtide.com>
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.
AFAICT all the classes using the retainable pool still access it via RetainableByteBufferPool.findOrAdapt()
except that we're not registering a retainable pool in the connector anymore.
I'm not sure what this brings compared to what we have now.
@@ -99,13 +99,13 @@ public MappedByteBufferPool(int factor, int maxQueueLength, Function<Integer, Bu | |||
*/ | |||
public MappedByteBufferPool(int factor, int maxQueueLength, Function<Integer, Bucket> newBucket, long maxHeapMemory, long maxDirectMemory) | |||
{ | |||
super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory); | |||
super(factor, 0, maxQueueLength, maxHeapMemory, maxDirectMemory, -1, -1); |
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.
The default heap and direct memory should be 0 to use the heuristic, not -1 for unlimited.
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.
I don't think all pools should have a retained pool by default.... or maybe that is OK since it will start empty and only fill if used???
Need to consider defaults... also some strangeness with -1 vs 0 for disabled vs heuristic. more review needed.
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.
The MappedByteBufferPool is primarily used by the client which benefits from a RBBP too, I don't see why we would disable the retainability by default.
That -1 vs 0 change you made breaks the pre-existing contract, perhaps you should revert to 0 for heuristic, -1 for unlimited and add -2 for non-retaining retainable pool?
@lorban said:
All abstract byte buffer pools now contain a retainable pool (either a null one or real one). This means we need to pass and configure only a single pool. I've kept findOrAdapt for now for backwards comparability for those who currently set a retainable pool on the server, but it could be simplified and then inlined/removed in 12. |
if (retainedHeapMemory < 0 && retainedDirectMemory < 0) | ||
_retainableByteBufferPool = RetainableByteBufferPool.from(this); | ||
else | ||
_retainableByteBufferPool = newRetainableByteBufferPool(maxCapacity, maxBucketSize, | ||
(retainedHeapMemory != 0) ? retainedHeapMemory : Runtime.getRuntime().maxMemory() / 4, | ||
(retainedDirectMemory != 0) ? retainedDirectMemory : Runtime.getRuntime().maxMemory() / 4); | ||
} |
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.
@lorban this is the substantive change. Every AbstractByteBufferPool
contains a RetainableByteBufferPool
that can be configured by only two properties: retainedHeapMemory
and retainedHeapMemory
. This allows minimal changes to XML (see below) to support simple configuration of both types of pool.
jetty-io/src/main/java/org/eclipse/jetty/io/ArrayRetainableByteBufferPool.java
Show resolved
Hide resolved
@sbordet your thoughts? |
release retained buffers when removed Signed-off-by: Greg Wilkins <gregw@webtide.com>
Move Bucket out of interface into abstract pool Signed-off-by: Greg Wilkins <gregw@webtide.com>
{ | ||
return RetainableByteBufferPool.from(this); | ||
} | ||
|
||
public static class Lease |
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.
@sbordet is Lease
really the right name for this? It's kind of a ByteBufferCollection
? Eitherway, can you add some javadoc for the class
* buffers and possibly a more efficient lookup mechanism based on the {@link org.eclipse.jetty.util.Pool} class. | ||
* @return This pool wrapped as a RetainableByteBufferPool. | ||
*/ | ||
default RetainableByteBufferPool asRetainableByteBufferPool() |
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.
Having the default implementation return a new instance each time while the AbstractByteBufferPool
implementation always returns the same instance sounds like the lifecycle of the objects returned by this method is underdefined.
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.
Perhaps. We can return a new instance here because it is a non allocating one - ie it is the null implementations. So would it be OK to say that if the pool returned does actually retain buffers then the pool returned must always be the same (or a wrapper of the same) retained pool.
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.
removed default impl and javadoc now says must be the same instance always
_maxHeapMemory = (maxHeapMemory != 0) ? maxHeapMemory : Runtime.getRuntime().maxMemory() / 4; | ||
_maxDirectMemory = (maxDirectMemory != 0) ? maxDirectMemory : Runtime.getRuntime().maxMemory() / 4; | ||
|
||
if (retainedHeapMemory < 0 && retainedDirectMemory < 0) |
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.
Since the allocation of the _retainableByteBufferPool
instance is done in the constructor, its release should be done in the clear
method, shouldn't it?
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.
I don't think so. The main byte buffer pool is keep hold of idle buffers only - ie ones that it has previously been acquired and released. The retainableByteBufferPool is kind of just like a client that has acquired but not yet released the buffer.
So clear should not release retained buffers any more than it should "take back" buffers allocated to other users. But perhaps it could trigger a shrinking of the retained pool to only buffers that are in use? Is t hat semantic already supported?
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.
@lorban I think we need to review exactly what clear does on a retainable pool.... which means we need to review what remove does on a Pool. I don't think the semantic for that is correct, specially for removing active items. Also for multi items, remove might return false, but the item is actually closed so will eventually be removed?? this makes accounting on the return value of remove difficult. Needs review. So for now, let's not wire up 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.
The clear
contracts of both pools are slightly different, but not incompatible IMHO.
clear
on BBP immediately stops holding onto its buffers.
clear
on RBBP immediately stops holding onto the unused buffers it contains, and marks the ones still in use as to-be-removed-when-released.
If you clear the RBBP then clear the BBP you make RBBP give all its unused buffers back to the BBP then make BBP drop all its buffers. I think this is what we want.
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.
clear
on RBBP immediately stops holding onto the unused buffers it contains, and marks the ones still in use as to-be-removed-when-released.
Yeah I think that is the intention, but it is not the implementation! So I think it needs review and javadocing before linking the clears together
*/ | ||
static RetainableByteBufferPool findOrAdapt(Container container, ByteBufferPool byteBufferPool) | ||
{ | ||
RetainableByteBufferPool retainableByteBufferPool = container == null ? null : container.getBean(RetainableByteBufferPool.class); | ||
if (retainableByteBufferPool == null) | ||
return retainableByteBufferPool == null ? byteBufferPool.asRetainableByteBufferPool() : retainableByteBufferPool; |
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.
If a RetainableByteBufferPool
bean is added, this means there's going to be a useless ArrayRetainableByteBufferPool
instance kept in the ByteBufferPool
. This is going to be confusing in server dumps.
Plus, in the current implementation you return an object for whom the caller is sometimes responsible for its releasee and sometimes not.
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.
We are not adding it. I'm just supportin the use-case where a user has added their own with a specific configuration. If they also configure the main pool to have a retained buffers, then there is duplication.
Perhaps, since this is a major release, we don't support this backwards compatibility?
In which case, this method just become a call to asRetainableByteBufferPool
and can be inlined. Maybe that is simplest.
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.
removed and inlined
jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
Outdated
Show resolved
Hide resolved
…one-buffer-pool-to-rule-them-all
Updates from review. removed findOrAdapt removed default asRetainableByteBuffer Signed-off-by: Greg Wilkins <gregw@webtide.com>
@lorban we need to think a bit harder about the default values. Currently we have lots of parameters that are defined as:
But I think we also want the ability to disable via these parameters. Ie how do you say you don't want to pool any direct memory or to not retain any heap memory. Perhaps it would be better to have:
We need to determine a single scheme and use it and document it in several places (all the javadoc in the constructors is currently different). Pity you can't inherit constructor javadoc! thoughts? |
@gregw the fact that we have two distinct pools in 10/11 is a design mistake we made. BBP/RBBP should have been better integrated from the start, like what you're suggesting. But do we want to break backward compatibility with the 0 / -1 values? If not, we should keep 0 for heuristic, -1 for unlimited and maybe add -2 to disable the retaining feature? But do we want to disable the retaining feature, knowing that This is something that should be totally cleaned up in 12. I don't mind the queue-based pool algorithm, but maybe 12 should only use the RBBP API everywhere? |
@lorban I think this PR shows that having one BBP that contains a RBBP works pretty well and is the same to ThreadPool containing a ReservedThreadPool. I think we do have some scope to clean up the -1, 0, values because they are mostly used internally... but perhaps best to leave to 12??? I'm on the fence. I'm dubious we have the ability to remove the BBP/RBBP duality from jetty-12 entirely. I also think that this PR shows that it is not strictly necessary. The combined pool model can pretty much achieve most outcomes - ie we could configure to have a non zero RBBP, but a zero BBP if we wanted to. It's really just a matter of how much each API is used. I think we have more important things to work on rather than hunting down usages of BBP only to then find out days/weeks/months/years later that we have buffer leak as we were not handling all scenarios correctly. |
@gregw I like the idea of the combined BBP / RBBP, it's a strong +1 but we definitely have to resolve what we want to do with the -1, 0, values as those are public, they're even in the Regarding 12, we could keep the leak-resilient pool impl by default and still replace all BBP usages with RBBP. |
I like the idea, but I think the implementations should give up using queues in favor of |
jetty-server/src/main/config/etc/jetty-bytebufferpool-logarithmic.xml
Outdated
Show resolved
Hide resolved
jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod
Outdated
Show resolved
Hide resolved
jetty-server/src/main/config/modules/bytebufferpool-logarithmic.mod
Outdated
Show resolved
Hide resolved
@@ -1,5 +1,6 @@ | |||
[description] | |||
Configures the ByteBufferPool used by ServerConnectors. | |||
Use module "bytebufferpool-logarithmic" for a more space efficient pool. |
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.
"more space efficient" is debatable. SSL requires buffers that are a few bytes over 16 KB large, meaning a log pool would waste nearly 50% of the memory it hands off in this scenario.
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.
Well more space efficient in the pool, but may be less space efficient in the buffer itself.
For the sizes we are commonly using, I'm actually thinking that just increasing the default factor to 4K is pretty good..... except for tiny buffers. Geting 1K when you only needed 6 bytes was bad enough, but 4K get's a bit ridiculous.
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.
"less space efficient in the buffer" is indeed what my comment is about and your remark about tiny buffers is exactly my point, but it also applies to other scenarios.
When you consider that in a typical SSL scenario where the buffer pool is limited in size, configuring a logarithmic pool may very well be noticeably less efficient; i.e.: a pool configured to hold a maximum of 16 MB is only going to be able to hold at most ~500 SSL buffers when using a logarithmic divide while it could hold up to ~950 with a linear divide.
I'm just not sure if it's a real issue in practice, so I'm conservatively thinking that we should not change the default nor recommend alternatives until we have a clearer view.
jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
Outdated
Show resolved
Hide resolved
I've had a look at This happens when So |
@lorban isn't that a bug in the unit test? Small buffets might not be desirable, but it is bigger than asked for, so the test should not assume it can write 330 bytes without blocking |
Avoid double bean add. Signed-off-by: Greg Wilkins <gregw@webtide.com>
Updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com>
Fixed JPMS issue Signed-off-by: Greg Wilkins <gregw@webtide.com>
Fixed async IO write test Signed-off-by: Greg Wilkins <gregw@webtide.com>
Fixed BufferedResponseHandlerTest Signed-off-by: Greg Wilkins <gregw@webtide.com>
hmmm so we appear to have a few tests that are relying on either getting extra space in a buffer or not getting extra space in a buffer.... so changing the buffer pool algorithm and/or defaults has broken a few tests. Not good. Fixing as I find them. |
Fixed more tests Signed-off-by: Greg Wilkins <gregw@webtide.com>
Fixed FastCGI that was expecting a larger buffer than requested Signed-off-by: Greg Wilkins <gregw@webtide.com>
minor cleanups Signed-off-by: Greg Wilkins <gregw@webtide.com>
I've been thinking that we could add some statistics collection to the pools that would record the monitored buffer sizes requested vs the ones served for each bucket. This would help figuring out how to tune the bucket sizes. |
@lorban So my thinking on sizing/algorithm goes likes this:
Without stats, I think options 2, 3 or 4 are all OK, with a slight preference for 4. We'd need stats to say if 5 is worth it or if yet another strategy would be better. |
@gregw with the default memory limit being Option 5 is IIRC how kernel slab allocation is usually done as most sizes are known at compilation time. If we had stats, we could go that route but without such guidance, I'd prefer to rely on either linear or log. |
jetty-io/src/main/java/org/eclipse/jetty/io/AbstractByteBufferPool.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/MappedByteBufferPool.java
Outdated
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/NullByteBufferPool.java
Outdated
Show resolved
Hide resolved
Updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com>
Updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com>
jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java
Outdated
Show resolved
Hide resolved
jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java
Outdated
Show resolved
Hide resolved
jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java
Show resolved
Hide resolved
jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java
Show resolved
Hide resolved
jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java
Show resolved
Hide resolved
jetty-io/src/main/java/org/eclipse/jetty/io/ArrayByteBufferPool.java
Outdated
Show resolved
Hide resolved
Updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com>
WIP on the concept of a single ByteBufferPool that can act either as a normal pool or as a retainable pool
Signed-off-by: Greg Wilkins gregw@webtide.com