[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-15 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473416
 ] 

Abe White commented on OPENJPA-141:
---

 The two-way check in FetchConfigurationImpl was overlooked. Thank you. But, 
 that brings up a new question... Do we do the two-way check in this new 
 utility method (even though BrokerImpl didn't require this in the past)? Or, 
 is the one-way check sufficient for FetchConfigurationImpl's usage? 

It should be a one-way check and code that needs to check both directions 
should invoke it twice with the arguments swapped the second time.  Simple.

 There have been several viewpoints on the use of these reference types and 
 what the impact would be. To be honest, at this point, all that I am looking 
 for is the ability to cache these assignable types. Whether it's 
 redployment-friendly or memory-friendly, I don't really care at this point.

I don't care either, so long as it's one of the two reference type combinations 
I outlined that actually make sense.  We can't just pick reference types 
randomly.

As to whether we should use a static cache vs. a Configuration instance 
cache... doesn't matter much to me.  The static cache keeps the API simpler. 
  
 Definitely beneficial over no caching of the TM whatsoever. Sorry for the 
 confusion. 

So the question now is whether it is beneficial over the use of an instance 
variable.  In normal usage, there's no reason it should be.  And so we should 
use an instance variable.  You could code an entire app using static maps in 
place of all instance variables if you really wanted to, so yes, in that sense 
they're equivalent, but there are good reasons not to.  Same goes for this.

And finally, I'm going to harp on something that is no longer even relevant, 
because I'm sure it will come up again in API design moving forward:

==
 5. Even if ImplHelper.isAssignable retains its map parameter (and per #1 
 above I question why it should), it should just be a Map; I don't see why 
 you'd have the method require a ConcurrentMap. 

 I did this way to be thread safe. If I only used a Map parameter, then the 
 caller would have to ensure that any updates to the Cache are thread safe. 

The caller is giving you the Map in your scheme. It's up to him whether the 
Map he's giving you is used concurrently or not. The helper method itself has 
no threading issues at all, and only requires a Map. But I agree that if we 
move to a single cache in ImplHelper it's a moot point. 

That's definitely one way around it. I prefer to enforce the requirement via 
the signature of the contract. ===

This is a stateless static helper method.  You're not enforcing anything, 
because the method itself has no threading concerns whatsoever.  You're 
*imposing* a requirement to use a certain kind of Map on a method that would 
function perfectly well with anything that implements the Map interface.  That 
is not something a helper method should do.  What if I want to use the method 
from single threaded code?  What if I want to use it from a method that's 
already synchronized?  Or what if I want to pass it a synchronized map instead 
of a concurrent one?  Why should a helper method that knows nothing about who 
is calling it and has no threading concerns itself be forcing any concurrency 
strategy on me, much less a particular one?  By this reasoning, every public 
method in the entire codebase should either be synchronized or should require 
thread safe arguments, because someone who calls the method *might* be doing so 
from multi-threaded code that is not already synchronized.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-15 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473527
 ] 

Craig Russell commented on OPENJPA-141:
---

Just posted another version of the performance patch for openjpa-141. I 
believe I have honored the comments as posted to this Issue. Please take a 
look and let's see if we can put this one to bed... 

Looks good.

I have more performance-related items to pursue... :-) 

I was hoping you did.

Thanks!

Thanks for your patience.


 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt, openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-15 Thread Patrick Linskey (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473537
 ] 

Patrick Linskey commented on OPENJPA-141:
-

 That's because I ran up against the other OpenJPA convention of limiting the 
 line length to 80 characters. 

Ah, yes... the clash of the code standards.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt, openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  -_typeHash = base.hashCode();
  +Integer typeHashInt = (Integer) _typeCache.get(type);
  +if (typeHashInt == null) {
  +

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473172
 ] 

Abe White commented on OPENJPA-141:
---

1. Why not keep a single assignable types map in ImplHelper?
2. I thought we had decided on the assignable types map having hard keys and 
soft values.  Using soft keys and hard values is odd to say the least.  First, 
as I mentioned in a previous note, using soft Class keys is pointless.  Once a 
Class is eligible for GC there's no point in keeping it in cache, so weak is 
better.  Second, using hard values means that other than adapting to class 
redeploys, this is basically a hard cache, because the only time entries are 
removed is when a Class disappears, and that only happens on redeploy.  It's 
not necessarily bad to make this a hard cache, but it should be discussed.
3. Why keep dedicated isAssignable methods in BrokerImpl and 
FetchConfigurationImpl if all they do is delegate to ImplHelper?  Why not call 
ImplHelper directly?
4. Why are you using a static JNDI location - TM cache in 
JNDITransactionManager rather than just caching the TM in an instance variable? 
 The only time that would help performance is if you're creating a bunch of 
BrokerFactories all using the same TM location.  Most applications will only 
use a single BrokerFactory.  If your benchmarks is constantly creating 
BrokerFactories, I'd question the validity of the benchmark.
5. Even if ImplHelper.isAssignable retains its map parameter (and per #1 above 
I question why it should), it should just be a Map; I don't see why you'd have 
the method require a ConcurrentMap.
6. #2 above applies also to the Class-base hash map in OpenJPAId.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Kevin Sutter (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473228
 ] 

Kevin Sutter commented on OPENJPA-141:
--

Good thing I posted the patch...  ;-)

1. Why not keep a single assignable types map in ImplHelper?

I actually thought about doing that, but then I had concerns about the size of 
the Cache.  So, I decided to isolate the changes (and the caches) to the 
problems at hand.  If you don't see a problem with this, I can change to a 
single assignable types map.

2. I thought we had decided on the assignable types map having hard keys and 
soft values. Using soft keys and hard values is odd to say the least. First, 
as I mentioned in a previous note, using soft Class keys is pointless. Once a 
Class is eligible for GC there's no point in keeping it in cache, so weak is 
better. Second, using hard values means that other than adapting to class 
redeploys, this is basically a hard cache, because the only time entries are 
removed is when a Class disappears, and that only happens on redeploy. It's 
not necessarily bad to make this a hard cache, but it should be discussed.

Hmmm..  If I understand what you are saying, it really doesn't matter whether 
we use hard, weak, or soft keys, since the resulting cache will be hard no 
matter what -- since we're using Class objects in the cache.  And, using weak 
keys actually sounds better due to the class redeploy scenario.  I can 
understand your hesitance with soft keys, but from your arguments, it sounds 
like we should go with weak keys and hard values.
 
3. Why keep dedicated isAssignable methods in BrokerImpl and 
FetchConfigurationImpl if all they do is delegate to ImplHelper? Why not call 
ImplHelper directly?

Certainly could.  Cleans up the code a bit.

4. Why are you using a static JNDI location - TM cache in 
JNDITransactionManager rather than just caching the TM in an instance 
variable? The only time that would help performance is if you're creating a 
bunch of BrokerFactories all using the same TM location. Most applications 
will only use a single BrokerFactory. If your benchmarks is constantly 
creating BrokerFactories, I'd question the validity of the benchmark.

It's probably six of one, half a dozen of the other.  I can make the change to 
use an instance variable.

The benchmark is a set of primitives based on the SpecJApp application using 
the SunOne Application Server.  The profiling data from this set of tests 
indicate that caching of the JNDI lookup is beneficial.  Maybe this change only 
helps with this particular Application Server, but I'm trying to isolate our 
OpenJPA implementation from the RI (SunOne).

5. Even if ImplHelper.isAssignable retains its map parameter (and per #1 above 
I question why it should), it should just be a Map; I don't see why you'd have 
the method require a ConcurrentMap.

I did this way to be thread safe.  If I only used a Map parameter, then the 
caller would have to ensure that any updates to the Cache are thread safe.  
Instead of putting that :artificial requirement on the caller, why not just 
use the ConcurrentMap type to ensure the safety?  Of course, this point is 
moot, if you are okay with going with a single Cache.

6. #2 above applies also to the Class-base hash map in OpenJPAId.

Yep, all the same issue.


 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473234
 ] 

Abe White commented on OPENJPA-141:
---

Craig, good catch.  I didn't even look at the actual assignable method code... 
I was saving that for when we had settled on a caching strategy.

 1. Why not keep a single assignable types map in ImplHelper? 
 I actually thought about doing that, but then I had concerns about the size 
 of the Cache. 

How are two static maps going to end up being smaller overall than one combined 
static map?

 Hmmm.. If I understand what you are saying, it really doesn't matter whether 
 we use hard, weak, or soft keys, since the resulting cache will be hard no 
 matter what -- since we're using Class objects in the cache.

No, it does matter.  And the type of value references we use matters way more.  
If we want a hard cache that drops entries for classes that are redeployed, 
then we should be using weak keys and hard values.  If we want a memory 
sensitive cache, then we should be using hard keys and soft values.  I'm not 
sure where the disconnect is coming from with these reference types.

 The benchmark is a set of primitives based on the SpecJApp application using 
 the SunOne Application Server. The profiling data from this set of tests 
 indicate that caching of the JNDI lookup is beneficial.

Beneficial over the suggested use of an instance variable?  Or beneficial over 
no caching of the TM whatsoever?  There's a big difference.

 5. Even if ImplHelper.isAssignable retains its map parameter (and per #1 
 above I question why it should), it should just be a Map; I don't see why 
 you'd have the method require a ConcurrentMap. 
 I did this way to be thread safe. If I only used a Map parameter, then the 
 caller would have to ensure that any updates to the Cache are thread safe. 

The caller is giving you the Map in your scheme.  It's up to him whether the 
Map he's giving you is used concurrently or not.  The helper method itself has 
no threading issues at all, and only requires a Map.  But I agree that if we 
move to a single cache in ImplHelper it's a moot point.


 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Kevin Sutter (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473243
 ] 

Kevin Sutter commented on OPENJPA-141:
--

Yes, good catch, Craig.  The original location that I wanted to resolve the 
isAssignableFrom() overhead was in BrokerImpl and that was just a one-way 
check.  The two-way check in FetchConfigurationImpl was overlooked.  Thank you. 
 But, that brings up a new question...  Do we do the two-way check in this new 
utility method (even though BrokerImpl didn't require this in the past)?  Or, 
is the one-way check sufficient for FetchConfigurationImpl's usage?  Any 
historical perspective?

 1. Why not keep a single assignable types map in ImplHelper?
 I actually thought about doing that, but then I had concerns about the size 
 of the Cache.
 How are two static maps going to end up being smaller overall than one 
 combined static map?

Never mind.  Since we're dealing with (hopefully) unique Class keys, a single 
map will suffice.

 Hmmm.. If I understand what you are saying, it really doesn't matter whether 
 we use hard, weak, or soft keys, since the resulting cache will be hard no 
 matter what -- since we're using Class objects in the cache.
 No, it does matter. And the type of value references we use matters way more. 
 If we want a hard cache that drops entries for classes that are redeployed, 
 then we should be using weak keys and hard values. If we want a memory 
 sensitive cache, then we should be using hard keys and soft values. I'm not 
 sure where the disconnect is coming from with these reference types.

There have been several viewpoints on the use of these reference types and what 
the impact would be.  To be honest, at this point, all that I am looking for is 
the ability to cache these assignable types.  Whether it's redployment-friendly 
or memory-friendly, I don't really care at this point.  We can worry about that 
later.  If you have a preference for this first iteration, let me know.  Thanks.

 The benchmark is a set of primitives based on the SpecJApp application using 
 the SunOne Application Server. The profiling data from this set of tests 
 indicate that caching of the JNDI lookup is beneficial.
Beneficial over the suggested use of an instance variable? Or beneficial over 
no caching of the TM whatsoever? There's a big difference.

Definitely beneficial over no caching of the TM whatsoever.  Sorry for the 
confusion.

 5. Even if ImplHelper.isAssignable retains its map parameter (and per #1 
 above I question why it should), it should just be a Map; I don't see why 
 you'd have the method require a ConcurrentMap.
 I did this way to be thread safe. If I only used a Map parameter, then the 
 caller would have to ensure that any updates to the Cache are thread safe.
The caller is giving you the Map in your scheme. It's up to him whether the 
Map he's giving you is used concurrently or not. The helper method itself has 
no threading issues at all, and only requires a Map. But I agree that if we 
move to a single cache in ImplHelper it's a moot point.

That's definitely one way around it.  I prefer to enforce the requirement via 
the signature of the contract.  Changing to a single map anyway...

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Patrick Linskey (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473254
 ] 

Patrick Linskey commented on OPENJPA-141:
-

 If we want a hard cache that drops entries for classes that are redeployed, 
 then 
 we should be using weak keys and hard values. If we want a memory sensitive 
 cache, then we should be using hard keys and soft values.

I vaguely prefer a hard cache that drops entries for classes that are 
redeployed, since I care more about speed than memory footprint.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-14 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12473285
 ] 

Craig Russell commented on OPENJPA-141:
---

 If we want a hard cache that drops entries for classes that are 
 redeployed, then 
 we should be using weak keys and hard values. If we want a memory 
 sensitive 
 cache, then we should be using hard keys and soft values. 

I vaguely prefer a hard cache that drops entries for classes that are 
redeployed, since I care more about speed than memory footprint.

This is also affected by whether we use a giant cache (including all the EMFs) 
or one cache per EMF. I prefer one cache per EMF because it simplifies the 
cache entry life cycle. During EMF close, the cache can be explicitly cleared, 
which allows the garbage collector to be more efficient since it doesn't have 
to scan all the entries in the cache. 

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter
 Attachments: openjpa-141.txt


 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472758
 ] 

Abe White commented on OPENJPA-141:
---

Craig: 
There doesn't appear to be any hashCode/equals performance issues. As Kevin 
pointed out earlier in the thread (and I should have realized) he's only 
caching Class-hash in OpenJPAId to prevent having to traverse to the base 
class... apparently Class.getSuperclass() is slow.  It could just as well be a 
cache of Class-base Class, but given the restriction Kevin pointed out that 
ConcurrentReferenceHashMaps need at least one ref type to be hard, that'd 
result in a cache that would maintain refs to classes that should be dropped 
due to redeployment.  

Kevin:
It's unfortunate that ConcurrentReferenceHashMaps need at least one ref type to 
be hard.  It would have been nice to use weak Class keys and soft values for 
most of the caches.  As is, I guess hard keys will do... we'll rely on the 
value getting GC'd to expire entries for classes that disappear due to 
redeployment.  Note that the inner maps in your map-of-maps scheme of 
assignables might as well just be a normal ConcurrentHashMaps too -- the outer 
map already will let inner maps drop when memory is low.  I also agree with 
craig about mapping to Boolean.TRUE/FALSE instead of new Object().  And I'd 
still like to see the assignable logic moved to ImplHelper or some new common 
helper class.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Kevin Sutter (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472790
 ] 

Kevin Sutter commented on OPENJPA-141:
--

Sounds good, Abe.  Thanks for the comments, Abe and Craig.  Here's the plan for 
the changes (for this Issue)...

o  Fix up the TM caching
o  Change to using Hard/Soft reference types as required
o  Store true/false in the inner map
o  Make isAssignable common code
o  Use ConcurrentHashMap for the inner class

That should cover it for now.

Thanks,
Kevin


 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  -_typeHash = 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472795
 ] 

Craig Russell commented on OPENJPA-141:
---

Nice work, Kevin and Abe.

Just a reminder. Please attach an svn patch to this JIRA when it's ready. I'd 
like to be able to see the patch right along side this discussion here. And 
when the patch is committed, please put OPENJPA-141 into the commit comments so 
svn will back link to this page. Thanks.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  -_typeHash = base.hashCode();
  +Integer typeHashInt = 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Patrick Linskey (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472813
 ] 

Patrick Linskey commented on OPENJPA-141:
-

 Please attach an svn patch to this JIRA when it's ready. I'd like to be able 
 to see the 
 patch right along side this discussion here. And when the patch is committed, 
 please put OPENJPA-141 into the commit comments so svn will back link to this 
 page.

Actually, if you put OPENJPA-141 in the comments, JIRA will automatically 
create a link to the commit in svn, which allows you to see a patch. IMO, if 
the issue number goes in the commit message, then we needn't bother with a 
patch.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != 

Re: [jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Kevin Sutter

Exactly.

On 2/13/07, Patrick Linskey (JIRA) [EMAIL PROTECTED] wrote:



[
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472813]

Patrick Linskey commented on OPENJPA-141:
-

 Please attach an svn patch to this JIRA when it's ready. I'd like to be
able to see the
 patch right along side this discussion here. And when the patch is
committed,
 please put OPENJPA-141 into the commit comments so svn will back link to
this page.

Actually, if you put OPENJPA-141 in the comments, JIRA will automatically
create a link to the commit in svn, which allows you to see a patch. IMO, if
the issue number goes in the commit message, then we needn't bother with a
patch.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be
working with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472829
 ] 

Craig Russell commented on OPENJPA-141:
---

Given the number of iterations already documented on this issue, wouldn't it be 
better to attach the real patch here for review?

In other words, this issue might be a case of review then commit instead of 
our normal commit then review approach.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  -_typeHash = base.hashCode();
  +Integer typeHashInt = (Integer) _typeCache.get(type);
  +if 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Kevin Sutter (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472840
 ] 

Kevin Sutter commented on OPENJPA-141:
--

Personally, I think I provide sufficient due diligence on the Issues that I own 
to stick with the normal commit then review approach.  There are many, many 
changes that get incorporated into OpenJPA without even a JIRA Issue 
discussion.  So, until I totally screw up, I'm going along with Patrick's 
comment and will do my normal commit with the JIRA Issue in the comment field.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so that it doesn't have to be generated each time.
  + */
   public int hashCode() {
   if (_typeHash == 0) {
  -Class base = type;
  -while (base.getSuperclass() != null
  - base.getSuperclass() != Object.class)
  -base = base.getSuperclass();
  -

Re: [jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-13 Thread Craig L Russell

Hi Kevin,

On Feb 13, 2007, at 11:25 AM, Kevin Sutter (JIRA) wrote:


Kevin Sutter commented on OPENJPA-141:
--

Personally, I think I provide sufficient due diligence on the  
Issues that I own to stick with the normal commit then review  
approach.  There are many, many changes that get incorporated into  
OpenJPA without even a JIRA Issue discussion.  So, until I totally  
screw up,


I don't expect that any committer is going to totally screw up, and  
I hope you don't take my comments as accusing you of such. But this  
issue seems to be full of interesting nuances that might better be  
discussed before the fact.


This issue is already the result of a commit with serious issues  
raised against it after the fact. So I'm a bit perplexed at the  
emotional reaction to my request to separate this steer from the herd.


I'm going along with Patrick's comment and will do my normal commit  
with the JIRA Issue in the comment field.


Certainly this is your choice.

Just one final comment. The Apache Way calls for thorough and public  
discussion on contentious issues, and this is complicated  
substantially by having the appearance of shadow implementers, as  
reflected in your comments in the original JIRA: I will be working  
with Abe and my performance team to work through these issues.


Craig


More performance improvements (in response to changes for  
OPENJPA-138)
- 
-


Key: OPENJPA-141
URL: https://issues.apache.org/jira/browse/ 
OPENJPA-141


Craig Russell
Architect, Sun Java Enterprise System http://java.sun.com/products/jdo
408 276-5638 mailto:[EMAIL PROTECTED]
P.S. A good JDO? O, Gasp!



smime.p7s
Description: S/MIME cryptographic signature


[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-12 Thread Kevin Sutter (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472440
 ] 

Kevin Sutter commented on OPENJPA-141:
--

Re:  Caching the TransactionManager in a static...

Although we could cache the TM in an instance variable or even do a hashmap 
with the name as the key, I'm wondering what the scenario is where we could 
have multiple TMs at different JNDI locations.  I've looked at the code and it 
seems that we have a single TM per runtime instance and we have one of those 
per configuration.  We attempt to find or create an appropriate runtime 
instance which in turn creates an appropriate TM.  Where or how can we run into 
the multiple TM problem?

Re:  Caching of the assignable from/to types

Yeah, the HARD/WEAK reference types probably weren't the right choices.  For 
the outer map, we could change to SOFT/SOFT references, and the inner map we 
could change to SOFT/WEAK references (since we don't really care about the 
values in the inner map).  We'll do some experimenting with this to determine 
the proper configuration.

Moving this common isAssignable code to ImplHelper or something similar is a 
good suggestion.  I had the same thoughts, but ran out of time over the 
weekend...

Re:  Use a different JVM

We are actually doing these performance runs using the Sun JDK.  We are also 
verifying the results with the IBM JDK, but the Sun JDK is the one used for the 
primary performance runs and analysis.

Re:  Hashcode performance

It's actually not the calls to Class.hashCode() that take up so much time, it's 
the calls to Class.getSuperClass() that we're trying to avoid.  I'm not 
familiar with the System.identityHashCode() method.  Maybe this method does the 
proper getSuperClass processing more efficiently?  Not sure.

Also, same comment about the HARD/WEAK references.  I'll probably end up 
changing that to SOFT/SOFT.

Re:  Class.getClassLoader performance

Unfortunately, this call is expensive.  Although in theory, this invocation 
should be cheap since each Class needs a reference to its ClassLoader, the 
caching of the ClassLoader is beneficial.  Here again, this is with the Sun JDK 
as our primary JVM.

Re:  Overall

As stated previously, we are using the Sun JDK for all of these performance 
benchmarks.  We also verify the results using the IBM JDK.  (We've even done 
some comparisons with JRockit.)  I've asked our performance team to generalize 
our results for consumption by the OpenJPA community (we're not ready to go 
public with any specific numbers).  I should be able to post something shortly.

Thanks,
Kevin

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-12 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472455
 ] 

Abe White commented on OPENJPA-141:
---

1. Each BrokerFactory has a ManagedRuntime.  You can have multiple 
BrokerFactories, each of which is supposed to be completely independent.  
Therefore you can have multiple ManagedRuntimes, each of which is supposed to 
be completely independent.  Caching the TM in a static in JNDIManagedRuntime 
breaks that.

2. I still don't understand how the caches were working at all with the weak 
refs, unless GC just wasn't kicking in very often.  Any info on this?

As to the proposed changes: there's no point in caching on Class keys with soft 
refs.  As soon as a Class is no longer referenced anywhere, there's no point in 
keeping it around.  So all Class keys should be weak refs.  The corresponding 
values can be soft.  

3. System.identityHashCode isn't going to help with superclasses... I didn't 
realize that that was the slow part.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-12 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472478
 ] 

Craig Russell commented on OPENJPA-141:
---

Abe opined:
1. Each BrokerFactory has a ManagedRuntime. You can have multiple 
BrokerFactories, each of which is supposed to be completely independent. 
Therefore you can have multiple ManagedRuntimes, each of which is supposed to 
be completely independent. Caching the TM in a static in JNDIManagedRuntime 
breaks that. 

Craig thinks: +1. There is no reason to optimize the number of lookups of the 
ManagedRuntime, since it's only done once per EMF creation. I agree that making 
the reference static goes too far. 

2. I still don't understand how the caches were working at all with the weak 
refs, unless GC just wasn't kicking in very often. Any info on this? 

Craig thinks: Weak references are supposed to be cleaned up if the referenced 
instance is not otherwise referenced. What would cause the referred classes to 
be garbage collected immediately? I don't quite understand the issue here.

But this might beg the real issue, which is what to use as the key for the Map 
if you want to effectively use the Class as the key but the hashCode and equals 
methods are just too slow. It might be well to look more closely at 
IdentityHashMap, in particular to see if there exists a 
ConcurrentIdentityHashMap or if we can create one. The IdentityHashMap uses 
System.identityHashCode(Object) instead of the overridden hashCode and == 
instead of equals. Even with Class instances as keys, this kind of Map should 
perform well.

I also don't understand all the logic when caching the assignableTo info. 
 + if (isAssignable) { 
 + assignableTo.put(to, new Object()); 
Seems like you would want to cache all instances of To and From, whether or not 
the answer is True. Once anyone asks if two types are assignable, and you find 
out the answer, why not cache the answer? From the code, it looks like you only 
cache True results. What if you change the above code to:
Boolean isAssignableResult = Boolean.valueOf(isAssignable);
assignableTo.put(to, isAssignableResult);
 

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-12 Thread Abe White (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472506
 ] 

Abe White commented on OPENJPA-141:
---

 Craig thinks: Weak references are supposed to be cleaned up if the referenced 
 instance is not otherwise referenced. What would cause the referred classes 
 to be garbage collected immediately? I don't quite understand the issue here. 

No, the current code holds the Classes with hard refs, and maps them to various 
values with weak refs.  Nothing else refers to these weak values.  Therefore 
they should be eligible for GC immediately, and their map entries should be 
removed on the next map mutation (reference maps only clean up their expired 
entries on mutation).  That's why I don't understand how the current caches are 
working at all to boost performance, unless GC isn't happening very often.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen profilers skew results in random ways like this) or even a
 bug in ConcurrentReferenceHashMap.
 The same goes for all the repeat logic in FetchConfigurationImpl.
 And if we keep this code or some variant of it, I strongly suggest
 moving it to a common place like ImplHelper.
  +/**
  + * Generate the hashcode for this Id.  Cache the type's
  generated hashcode
  + * so 

[jira] Commented: (OPENJPA-141) More performance improvements (in response to changes for OPENJPA-138)

2007-02-12 Thread Craig Russell (JIRA)

[ 
https://issues.apache.org/jira/browse/OPENJPA-141?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_12472510
 ] 

Craig Russell commented on OPENJPA-141:
---

 Craig thinks: Weak references are supposed to be cleaned up if the 
 referenced instance is not otherwise referenced. What would cause the 
 referred classes to be garbage collected immediately? I don't quite 
 understand the issue here. 

No, the current code holds the Classes with hard refs, and maps them to 
various values with weak refs. Nothing else refers to these weak values. 
Therefore they should be eligible for GC immediately, and their map entries 
should be removed on the next map mutation (reference maps only clean up their 
expired entries on mutation). That's why I don't understand how the current 
caches are working at all to boost performance, unless GC isn't happening very 
often.

Roger that. Thanks for the explanation, I'm now confused as well. :-(

So what might work is having the keys be weak, and the otherwise unreferenced 
values strong. That way, the values will always be there as long as the keys 
are there. But if you do this, then you have to actually use the Class 
instances as keys, which implies solving the hashCode/equals problem.

 More performance improvements (in response to changes for OPENJPA-138)
 --

 Key: OPENJPA-141
 URL: https://issues.apache.org/jira/browse/OPENJPA-141
 Project: OpenJPA
  Issue Type: Sub-task
  Components: jpa
Reporter: Kevin Sutter
 Assigned To: Kevin Sutter

 Abe's response to my committed changes for OPENJPA-138.  I will be working 
 with Abe and my performance team to work through these issues...
  ==
  
  --- incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java (original)
  +++ incubator/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/
  openjpa/ee/JNDIManagedRuntime.java Sun Feb 11 18:33:05 2007
  @@ -29,6 +29,7 @@
   implements ManagedRuntime {
 
   private String _tmLoc = java:/TransactionManager;
  +private static TransactionManager _tm;
 Whoa, I didn't think you meant caching the TM statically.  That has
 to be backed out.  You can cache it in an instance variable, but not
 statically.  Nothing should prevent someone having two different
 BrokerFactories accessing two different TMs at two different JNDI
 locations.
 BrokerImpl:
  + * Cache from/to assignments to avoid Class.isAssignableFrom
  overhead
  + * @param from the target Class
  + * @param to the Class to test
  + * @return true if the to class could be assigned to from
  class
  + */
  +private boolean isAssignable(Class from, Class to) {
  +  boolean isAssignable;
  +  ConcurrentReferenceHashMap assignableTo =
  +  (ConcurrentReferenceHashMap) _assignableTypes.get(from);
  +
  +  if (assignableTo != null) { // to cache exists...
  +  isAssignable = (assignableTo.get(to) != null);
  +  if (!isAssignable) { // not in the map yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  } else { // no to cache yet...
  +  isAssignable = from.isAssignableFrom(to);
  +  if (isAssignable) {
  +  assignableTo = new ConcurrentReferenceHashMap(
  +  ReferenceMap.HARD, ReferenceMap.WEAK);
  +  _assignableTypes.put(from, assignableTo);
  +  assignableTo.put(to, new Object());
  +  }
  +  }
  +  return isAssignable;
  +}
 This code could be simplified a lot.  Also, I don't understand what
 you're trying to do from a memory management perspective.  For the
 _assignableTypes member you've got the Class keys using hard refs and
 the Map values using weak refs.  No outside code references the Map
 values, so all entries should be eligible for GC pretty much
 immediately.  The way reference hash maps work prevents them from
 expunging stale entries except on mutators, but still... every time a
 new entry is added, all the old entries should be getting GC'd and
 removed.  Same for the individual Map values, which again map a hard
 class ref to an unreferenced object value with a weak ref.  Basically
 the whole map-of-maps system should never contain more than one entry
 total after a GC run and a mutation.
 I'd really like to see you run your tests under a different JVM,
 because it seems to me like (a) this shouldn't be necessary in the
 first place, and (b) if this is working, it's again only because of
 some JVM particulars or GC timing particulars or testing particulars
 (I've seen