Reputation: 3281
I am writing a messaging facade that takes in arbitrary POJOs and sends them across the wire in JSON format, with the following workflow:
MessagingFacade.sendMessage(Object)
JsonSerializer.serialize(Object, ByteBuffer)
Transport.send(ByteBuffer)
, keep a reference to a promise that will be notified when the message has been sentMessagingFacade.sendMessage(Object)
invocationThis is a relatively trivial use-case for pooling ByteBuffers, given we can invoke clear()
to reset the state when the object is returned to the pool.
Rather than writing my own object pool, I have attempted to utilize those already offered in Apache commons-pool
. However, there seems to be a rather large caveat with GenericObjectPool
and SoftReferenceObjectPool
...
When borrowing / returning objects, these two pools are using hashCode()
and / or equals()
to identify the associated PooledObject<ByteBuffer>
. This has a very real implications on ByteBuffer
, given the equals()
and hashCode()
implementations involve evaluating the contents of the underlying byte
array:
ByteBuffer
is returned to the pool, it has its state "cleaned". This simply involves calling ByteBuffer.clear()
. This does not zero-out all the bytes in the array, which means that equals()
and hashCode()
give different results when returning the ByteBuffer
, versus when it was borrowed.ByteBuffer
with a capacity of my maximum message size (1MB), evaluating both hashCode()
and equals()
has to linearly traverse this very large arrayThe Apache commons-pool implementations do not seem suitable for any use-case where either (a) the class has expensive equals()
and hashCode()
implementations or (b) hashCode()
does not yield stable results after being cleaned.
The only viable option to make GenericObjectPool
or SoftReferenceObjectPool
work for this use case seems to be to wrap the ByteBuffer
in another class which uses identity equality / hash-code logic.
This is working, but feels a little cumbersome given how vanilla this use-case is. Are there better alternatives to this approach?
One final note; due to the instability of equals()
and hashCode()
one will actually get exceptions from the GenericObjectPool
, because the pool believes you are attempting to return an object that was never borrrowed from the pool:
java.lang.IllegalStateException: Returned object not currently part of this pool
at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:537)
...
Upvotes: 2
Views: 1326
Reputation: 644
The limitation you are referring to was identified in the JIRA issues POOL-283 and POOL-284, which were resolved in version 2.4.1 of Commons Pool. Try upgrading to version 2.4.1.
Upvotes: 2