Discussion:
[jira] [Created] (POOL-284) "Returned object not currently part of this pool" when using mutable objects
Valentin Mayamsin (JIRA)
2015-01-27 23:54:34 UTC
Permalink
Valentin Mayamsin created POOL-284:
--------------------------------------

Summary: "Returned object not currently part of this pool" when using mutable objects
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin


I'm using pool to reuse expensive Sets (storing millions of items). Here is a test which fails:
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return Sets.newHashSet ();
}

@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}

@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );

Set set = aPool.borrowObject ();

set.add ( new Object () );

aPool.returnObject ( set );
{code}

This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Valentin Mayamsin (JIRA)
2015-01-28 00:09:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Valentin Mayamsin updated POOL-284:
-----------------------------------
Description:
I'm using pool to reuse expensive Sets (storing millions of items). Here is a test which fails:
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}

@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}

@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );

Set set = aPool.borrowObject ();

set.add ( new Object () );

aPool.returnObject ( set );
{code}

This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode

was:
I'm using pool to reuse expensive Sets (storing millions of items). Here is a test which fails:
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return Sets.newHashSet ();
}

@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}

@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );

Set set = aPool.borrowObject ();

set.add ( new Object () );

aPool.returnObject ( set );
{code}

This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Bernd Eckenfels (JIRA)
2015-01-28 00:36:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14294485#comment-14294485 ]

Bernd Eckenfels commented on POOL-284:
--------------------------------------

I think both (this and POOL-283) is by design of the generic implementation: users need to have stable, idendity-preserving equals() and hashcode() implementations (like with normal maps, too).

It might be possible to check for idendity and accept them anyway, but since the hashCode has to be stable for managing them, I dont think it helps much.

I havent found this requirement documented in the Javadoc, not of the API/interfaces or the generic implementation. One or both should state that. (I wonder if a implementation based on IdendityHashMap for the generic pool would be fine or if this would be a more specific pool).
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Mark Thomas (JIRA)
2015-01-28 11:12:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14295009#comment-14295009 ]

Mark Thomas commented on POOL-284:
----------------------------------

The problem with IdentityHashMap is that it is not thread-safe. Adding the necessary synchronisation would have a noticeable impact on pool performance.

An alternative option would be to add a IdentityHashcodeWrapper that wrapped the key in the allObjects Map that delegated Hashcode() to the identity hashcode of the wrapped object. That should provide a solution to this issue and POOL-283. There would be a performance cost associated with creating the wrappers and wrapping / unwrapping the pooled objects. I'm not sure if this is something best left to the client code, something we should do in POOL by default or if we should/can add something to PoolUtils to create an 'IdentityPool'.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-01-28 13:57:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14295157#comment-14295157 ]

Phil Steitz commented on POOL-284:
----------------------------------

It's probably worth looking carefully at what performance (and bug-generating) impact would be for

1. Fully sync-protected IdentityHashMap
2. Selective syncs added to create / destroy
3. IdentityHashcodeWrapper

I was tempted to add 4. hack internals of IdentityHashMap to get something protected enough for our use, but that is probably a *bad idea*

If 1 and 3 are both noticeably bad and 2 is too scary (or also bad), then probably the PoolUtils approach is best. In any case, we should clarify javadoc to make current behavior clear.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Bernd Eckenfels (JIRA)
2015-01-28 19:31:37 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14295680#comment-14295680 ]

Bernd Eckenfels commented on POOL-284:
--------------------------------------

Yes (what I mean is "similar to idendity hashmap"). Aren't the objects in the pools map wrapped already? then it wont be much overhead (and it would be good to provide Comparable interface, as Java 8 hashmap can benefit from that). (if they are not we could move from map to set and have the metadata be the wrapper)
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-01-28 19:39:35 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14295696#comment-14295696 ]

Phil Steitz commented on POOL-284:
----------------------------------

They are wrapped "in the pool." The map that is causing the problem is the allObjects map that is used to associate the PooledObject wrappers with the unwrapped instances that are handed out to and received back from clients. Since borrowObject returns an unwrapped object, returnObject needs to accept an unwrapped instance and the pool needs to determine which PooledObject the returning instance corresponds to. That is why allObjects uses "naked" objects as keys and PooledObject wrappers as values.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-02-02 15:43:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14301382#comment-14301382 ]

Phil Steitz commented on POOL-284:
----------------------------------

An alternative to 3. above that may be a little cheaper: just make allObjects use Integer keys and wrap gets/puts in System.identityHashCode calls.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Sebb (JIRA)
2015-02-02 17:07:35 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14301465#comment-14301465 ]

Sebb commented on POOL-284:
---------------------------

I'm not sure if this matters here, but note that System.identityHashCode does not guarantee distinct hashes for different objects.
There may be multiple objects with the same hash (but obviously only one hash for a given object).
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-02-02 17:49:36 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14301527#comment-14301527 ]

Phil Steitz commented on POOL-284:
----------------------------------

Good point, sebb. Unfortunately it does matter, so the System.identityHashCode solution will not work.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Thomas Neidhart (JIRA)
2015-02-05 20:00:36 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14307879#comment-14307879 ]

Thomas Neidhart commented on POOL-284:
--------------------------------------

Another idea would be to use a modified StaticBucketMap from collections that uses System.identityHashCode and reference comparison for equality checks.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Thomas Neidhart (JIRA)
2015-02-05 22:15:34 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14308096#comment-14308096 ]

Thomas Neidhart commented on POOL-284:
--------------------------------------

I have found a paper about performance regression testing. Interestingly, they evaluated both, GenericObjectPool and StaticBucketMap:

http://mp.binaervarianz.de/issta2014.pdf

The test code is available here: https://github.com/michaelpradel/ConTeGe/tree/SpeedGun
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-02-22 20:55:12 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz updated POOL-284:
-----------------------------
Attachment: pool-283-4.patch

Some WIP to review and performance test. Passes the (disabled) tests for this issue and POOL-283. Replaces ConcurrentHashMap with a slightly modified StaticBucketMap from Commons Collections.

I did not set up configurability; but we could make the allObjects map type configurable, using something like this patch when the requirements of this issue and / or pool-283 are required.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-02-22 20:57:11 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz updated POOL-284:
-----------------------------
Attachment: StaticBucketMap-mods.patch

Diff showing mods on the original Collections class. Objective was to use system identity hash codes as hash codes for keys and force reference equality checks. Also, eliminate dependencies on other Collections classes. This class could be stripped down further if we decide to go this route.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Thomas Neidhart (JIRA)
2015-02-23 08:32:12 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14333099#comment-14333099 ]

Thomas Neidhart commented on POOL-284:
--------------------------------------

When using the StaticBucketMap, we need to ensure that the number of elements in the pool does not exceed the number of buckets as otherwise the performance will degrade.
Fortunately, a pool is limited in size, so we can use the getMaxTotal() to initialize the map, but it would also mean that we need to re-create the map when using the setter.

To make the behavior configurable, we could also do the following:

* take the Equator interface from collections
* change the StaticBucketMap to use an Equator when calling hashCode / equals for an element
* depending on the setting, we use an IdentityEquator (uses System.identityHashCode and reference equality) or an DefaultEquator (delegates to the object's hashCode / equals methods)
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-02-23 22:16:12 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14333889#comment-14333889 ]

Phil Steitz commented on POOL-284:
----------------------------------

Thanks for pointing out the buckets consideration. I guess there is no way around re-creating the map if the setter expands maxTotal beyond the previous value. That may be OK; but will have to be documented carefully if we go this way.

The Equator interface idea is interesting. I was actually thinking more conservatively - leave current impl as is and have config option switch to SBM with my hacks to basically do (IIUC) what the IdentityEquator does for users who need reference identity semantics. If we can get performance and scalability as good with SBM as CHM, then it would make sense to allow Equator configurability.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-03-09 13:06:38 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz updated POOL-284:
-----------------------------
Attachment: identityWrapper.patch

Here is another patch to consider, implementing wrapping. Note that there is no "unwrapping" required - we just need to wrap instances when creating hash keys.

I have been able to measure a 5-7% decrease in throughput when using StaticBucketMap, but no consistent decrease with this patch. I don't have a machine with a lot of cores to test with though. Anyone with interest and available cores can use the primitive JMH setup I have [here | https://github.com/psteitz/pool-test]
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Mark Thomas (JIRA)
2015-03-09 13:10:38 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14352951#comment-14352951 ]

Mark Thomas commented on POOL-284:
----------------------------------

people.a.o has 48 cores for you to play with. That should be plenty (and is where I did some of my concurrecy testing for the Pool 2.x design).
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Sebb (JIRA)
2015-03-09 15:15:38 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14353088#comment-14353088 ]

Sebb commented on POOL-284:
---------------------------

protected T instance; // should be final
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-05-12 13:34:00 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz resolved POOL-284.
------------------------------
Resolution: Fixed
Fix Version/s: 2.4

I was not able to consistently measure negative impact associated with the IdentityWrapper modification. Testing on a 16-way machine with thread counts ranging from 5 - 200, I saw a maximum of 3% reduced throughput (5 threads, one of 5 runs); though on 2 out of 12 runs the IdentityWrapper implementation showed better throughput and in general the difference was less than 1%. Under higher concurrency (50+ threads), I was able to measure consistent loss of throughput under the StaticBucketMap solution. I implemented and tested a configurable IdentityWrapper solution; but I was not able to demonstrate consistently better throughput with the configured option turned off.

So...I decided to commit, in r1678941, the simplest fix, which is non-configurable IdentityWrapper.
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Fix For: 2.4
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-06-01 15:49:18 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz updated POOL-284:
-----------------------------
Fix Version/s: (was: 2.4)
2.4.1
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Fix For: 2.4.1
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)
Phil Steitz (JIRA)
2015-06-01 15:49:19 UTC
Permalink
[ https://issues.apache.org/jira/browse/POOL-284?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Phil Steitz closed POOL-284.
----------------------------

Fix released in 2.4.1
Post by Valentin Mayamsin (JIRA)
"Returned object not currently part of this pool" when using mutable objects
----------------------------------------------------------------------------
Key: POOL-284
URL: https://issues.apache.org/jira/browse/POOL-284
Project: Commons Pool
Issue Type: Bug
Affects Versions: 2.2
Reporter: Valentin Mayamsin
Fix For: 2.4.1
Attachments: StaticBucketMap-mods.patch, identityWrapper.patch, pool-283-4.patch
{code}
GenericObjectPoolConfig config = new GenericObjectPoolConfig ();
GenericObjectPool<Set> aPool = new GenericObjectPool<> ( new BasePooledObjectFactory<Set> ()
{
@Override
public Set create () throws Exception
{
return new HashSet();
}
@Override
public PooledObject<Set> wrap ( Set o )
{
return new DefaultPooledObject<> ( o );
}
@Override
public void passivateObject ( PooledObject<Set> p ) throws Exception
{
p.getObject ().clear ();
super.passivateObject ( p );
}
}, config );
Set set = aPool.borrowObject ();
set.add ( new Object () );
aPool.returnObject ( set );
{code}
This is because GenericObjectPool uses a HashMap<Object, PooledObject> to correlate objects and state. HashMap stores objects correlated to their hashCode. So in case object's state change then hashCode will change, thus Map will fail to correlate this object since it stores old hashCode
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Loading...