[jbosscache-dev] New collections

Jason T. Greene jason.greene at redhat.com
Tue Aug 5 09:42:25 EDT 2008


Manik Surtani wrote:
> 
> On 5 Aug 2008, at 01:31, Jason T. Greene wrote:
> 
>>
>> Manik Surtani wrote:
>>> Guys,
>>> I have created 3 new collection impls in trunk - ImmutableListCopy, 
>>> ImmutableSetCopy and ImmutableMapCopy.  I have also ported the first 
>>> 2 to branch 2.2.x (the reason why I didnt port the third is because 
>>> the MapCopy which it replaces can get serialized and I don't want to 
>>> break binary compat).
>>
>> I took a look at adjusting these to be more efficient with the 
>> FastCopyHashMap. After doing some analysis and sanity benchmarks, I 
>> have determined that we should switch to unmodifiableXXX(obj.clone() 
>> or copy constructor) in all cases, for the following reasons:
>>
>> 1. There is no performance advantage with lists.
> 
> Agreed, this part was just convenience and perhaps removing a little bit 
> of superfluous object instantiation.
> 
>> 2. While the construction time in the Map and Set variants is faster, 
>> since it doesn't use hashing, it sacrifices way too much (O(n) lookup 
>> times). I did verify that the performance difference will be the same 
>> with just about every map implementation, since it's mostly allocation 
>> that is being measured here.
> 
> These were originally optimised for iteration only, but I expected 
> lookups to be a problem - hence my comment below.
> 
>> 3. It prevents the copy optimization in FastCopyHashMap, so removing 
>> usage of ImmutableMapCopy will improve copy performance of anything 
>> using FastCopyHashMap.
> 
> Thats what I suspected, and hence my thoughts on extending 
> FastCopyHashMap to an ImmutableFastCopyHashMap - so we have fast 
> construction, decent lookup times, immutability as well as reduce 
> unnecessary object construction/wrapping.

I measured this, and there is *no difference* between FastCopyHashMap 
and HashMap when it comes to copying a different map. So all a 
ImmutableFastCopyHashMap would do, is save the creation of the 
unmodifiableXXX wrapper, which also ends up not making a difference (see 
below).

> 
>> 4. The construction of the immutable wrapper is barely noticeable, and 
>> it's done per call, so the value is likely temporary.
> 
> Depends.  This does happen in many different places, for different reasons:
> 
> - retrieval of collections from Node or Cache - which means the 
> reference goes into userland and may not be temporary
> - used to pass data values into cache listeners.  Again, may not be 
> temporary.
> - Other internal uses are likely to be temporary though, such as 
> retrieving of invocation or transaction locks.  These *may* not be 
> immutable if code written around it is careful, but for the sake of 
> correctness and thoroughness I have made these immutable.

What I meant was that the Collections.unmodifiableXXX object is very 
short lived, so doesn't impact our memory footprint much. It also made 
practically no difference when measuring the construction time.

>> Also I noticed that we have some duplicate copying going on. For 
>> example , CacheInvocationDelegate copies a set that is constructed by 
>> the command, per call.
> 
> It makes sense for CID to provide a wrapIfNecessary transformation, 
> which only defensively copies/wraps the collection to be returned if it 
> has not already been wrapped/copied elsewhere in the chain, e.g., in the 
> command.
> 
>>
>>
>> What I would like to do, provided everyone is ok with this, is switch 
>> this code to static factory methods like so:
>>
>> Immutables.immutableCopy(Map map);
>> Immutables.immutableCopy(List list);
>> Immutables.immutableCopy(Set set);
>>
>> These will then just call clone and Collections.unmodifiableXXX as 
>> appropriate. We can then add optimizations later if they become 
>> available.
> 
> Would these be more generic, to suit any collection implementation?  
> Remember that not all Maps, for example, implement Cloneable or have a 
> copy constructor.  And wrapping any Map passed in as a FastCopyHashMap 
> may break correctness, for example, if a SortedMap were passed in.

Right, they would use instanceof to check all the known map types as a 
fast-path optimization. After that it would check for cloneable, and use 
reflection to invoke clone. It would then look for a copy constructor, 
and failing that it would then create a different collection type. We 
could for example, in the case of a non-copyable SortedMap, use a 
TreeMap, and order is maintained.

-Jason

-- 
Jason T. Greene
JBoss, a division of Red Hat



More information about the jbosscache-dev mailing list