[JBoss Microcontainer Development] New message: "Re: Optimizing ScopeKey"
by Kabir Khan
JBoss development,
A new message was posted in the thread "Optimizing ScopeKey":
http://community.jboss.org/message/526058#526058
Author : Kabir Khan
Profile : http://community.jboss.org/people/kabir.khan@jboss.com
Message:
--------------------------------------------------------------
Yes, the hashing function is broken
int iterations = 15;
public void testScopeKeyHashing()
{
List<ScopeKey> scopes = createScopeKeys();
List<ScopeKey> lockedScopes = createFroxenScopeKeys(scopes);
assertSame(scopes.size(), lockedScopes.size());
for (int i = 0 ; i < iterations ; i++)
{
assertTrue(scopes.get(i).equals(lockedScopes.get(i)));
assertTrue(lockedScopes.get(i).equals(scopes.get(i)));
assertEquals(scopes.get(i).hashCode(), lockedScopes.get(i).hashCode());
System.out.println(scopes.get(i).hashCode() + " " + scopes.get(i));
assertNotSame(scopes.get(i), lockedScopes.get(i));
}
}
private List<ScopeKey> createScopeKeys()
{
List<ScopeKey> keys = new ArrayList<ScopeKey>();
for (int i = 0 ; i < iterations ; i++)
{
ScopeKey scopeKey = ScopeKey.DEFAULT_SCOPE.clone();
scopeKey.addScope(CommonLevels.INSTANCE, "Bean" + i + Math.random() + 10000);
scopeKey.addScope(CommonLevels.CLASS, Object.class.getName());
keys.add(scopeKey);
}
return keys;
}
private List<ScopeKey> createFroxenScopeKeys(List<ScopeKey> scopes)
{
List<ScopeKey> frozens = new ArrayList<ScopeKey>();
for (ScopeKey key : scopes)
{
ScopeKey frozen = key.getOptimizedKey();
frozen.freeze();
frozens.add(frozen);
}
return frozens;
}
gives the same value 3400
> 3400 [JVM=THIS, APPLICATION=xyz0, CLASS=java.lang.Object, INSTANCE=Bean00.724748247059574310000]
>
> 3400 [JVM=THIS, APPLICATION=xyz1, CLASS=java.lang.Object, INSTANCE=Bean10.821575642383577510000]
>
> 3400 [JVM=THIS, APPLICATION=xyz2, CLASS=java.lang.Object, INSTANCE=Bean20.3658072070977499410000]
>
> 3400 [JVM=THIS, APPLICATION=xyz3, CLASS=java.lang.Object, INSTANCE=Bean30.17405710442802047
>
>
> 10000]
>
> 3400 [JVM=THIS, APPLICATION=xyz4, CLASS=java.lang.Object, INSTANCE=Bean40.328947822381441710000]
>
> 3400 [JVM=THIS, APPLICATION=xyz5, CLASS=java.lang.Object, INSTANCE=Bean50.853785127372253610000]
>
> 3400 [JVM=THIS, APPLICATION=xyz6, CLASS=java.lang.Object, INSTANCE=Bean60.308661441767311610000]
>
> 3400 [JVM=THIS, APPLICATION=xyz7, CLASS=java.lang.Object, INSTANCE=Bean70.3214439497564738310000]
>
> 3400 [JVM=THIS, APPLICATION=xyz8, CLASS=java.lang.Object, INSTANCE=Bean80.73783778624132910000]
>
> 3400 [JVM=THIS, APPLICATION=xyz9, CLASS=java.lang.Object, INSTANCE=Bean90.301807484250228210000]
>
> 3400 [JVM=THIS, APPLICATION=xyz10, CLASS=java.lang.Object, INSTANCE=Bean100.4474778106602691510000]
>
> 3400 [JVM=THIS, APPLICATION=xyz11, CLASS=java.lang.Object, INSTANCE=Bean110.1197707023336379610000]
>
> 3400 [JVM=THIS, APPLICATION=xyz12, CLASS=java.lang.Object, INSTANCE=Bean120.313969251914117510000]
>
> 3400 [JVM=THIS, APPLICATION=xyz13, CLASS=java.lang.Object, INSTANCE=Bean130.609491494722042910000]
>
> 3400 [JVM=THIS, APPLICATION=xyz14, CLASS=java.lang.Object, INSTANCE=Bean140.713736711778368310000]
>
>
That must be the real problem, causing UnmodifiableScopeKey.equals()->ScopeKey.getArray()->Collection.toArray() to be called too many times. Looking at the ScopeKey.computeHashCode function it only takes the levels into account:
protected static int computeHashCode(Iterable<Scope> scopeCollection)
{
int hashCode = 0;
for (Scope scope : scopeCollection)
hashCode += scope.getScopeLevel().hashCode();
return hashCode;
}
I've rewritten this to hash properly, which makes the retrievals map behave like a map, giving less ScopeKey.equals() hits
Scope constructor:
public Scope(ScopeLevel level, Object qualifier)
{
if (level == null)
throw new IllegalArgumentException("Null level");
if (qualifier == null)
throw new IllegalArgumentException("Null qualifier");
this.level = level;
this.qualifier = qualifier;
int hash = 17;
hash = 31 * hash + level.hashCode();
hash = 31 * hash + qualifier.hashCode();
hashcode = hash;
}
protected static int computeHashCode(Iterable<Scope> scopeCollection)
{
int hashCode = 0;
for (Scope scope : scopeCollection)
//hashCode += scope.getScopeLevel().hashCode();
hashCode += scope.hashCode();
return hashCode;
}
I'll add a test and commit against https://jira.jboss.org/jira/browse/JBMDR-65 and then see what this does to AS boot times
--------------------------------------------------------------
To reply to this message visit the message page: http://community.jboss.org/message/526058#526058
14 years, 4 months
[EJB 3.0 Development] New message: "Re: Proxy SPI"
by jaikiran pai
JBoss development,
A new message was posted in the thread "Proxy SPI":
http://community.jboss.org/message/526048#526048
Author : jaikiran pai
Profile : http://community.jboss.org/people/jaikiran
Message:
--------------------------------------------------------------
> jaikiran wrote:
>
> Based on our discussion yesterday about a need for a proxy-spi, here's what my initial thoughts are. The following SPI keeps in mind both nointerface view (which uses Javassist) and the other business view (which use j.l.r.Proxy).
>
> My initial thoughts around this were, to have a ProxyFactory which at the minimum has this:
>
> *public* *interface* ProxyFactory
> {
>
> /**
> * Creates a proxy which is castable to the interfaces passed and associates
> * the passed invocationHanlder with the proxy
> */
> Object createProxy(Class[] interfaces, InvocationHandler invocationHandler);
> ...
>
> }
>
>
>
>
> With this, we could then have had a JavaReflectProxyFactory which would return Proxy.newInstance(...) and a JavassistProxyFactory which would do its own proxy creation logic. Note that currently the Javassist proxy factory for nointerface view uses a j.l.r.InvocationHandler, but that's a implementation detail, and as such should not be exposed through the SPI. i.e. the createProxy shouldn't ideally be expecting a j.l.r.InvocationHandler as a param.
After discussing this with Carlo over IRC, i realize that expecting InvocationHandler isn't a bad deal after all. Infact the above SPI looks much simpler and better compared to what i came up with, in the rest of my previous post.
--------------------------------------------------------------
To reply to this message visit the message page: http://community.jboss.org/message/526048#526048
14 years, 4 months
[JBoss Web Services Development] New message: "Parallel invocations of JaxWS services and getPort"
by Andrew Dinn
JBoss development,
A new message was posted in the thread "Parallel invocations of JaxWS services and getPort":
http://community.jboss.org/message/526010#526010
Author : Andrew Dinn
Profile : http://community.jboss.org/people/adinn
Message:
--------------------------------------------------------------
The JBossTS/XTS multi-threaded test is failing with the trunk XTS and trunk AS. I investigated the problem and found that it relates to the use of client proxies in parallel. I think there is a big issue here which needs clarifying and probably requires a change in the Service/proxy implementation. Here's the situation and the symptoms:
The test runs within a web app in the same container as the XTS service. The test thread creates 10 child threads each of which executes a TX start and TX commit for a Web Services Atomic Transaction (WS-AT) then exits. The parent joins each child thread. The problem is that some of the commit messages never get delivered so the client thread waits forever fo ra committed response and, the test hangs.
The start and commit operations are implemented using JaxWS to invoke services provided by the XTS implementation. I will not go into the details of the actual sevice configuration as they are not particularly important. The important detail is that the threads all employ a specific JaxWS service -- ATTermination -- to commit the TX, invoking a one way operation. The service responds by routing a reply back to the client via another JaxWS service -- ATTerminationInitiator -- again using a one way operation.
My code employs one instance of the ATTermination Service class. Each thread obtains this Service instance and calls getPort() to obtain a client proxy. The thread configures a handler via the BindingProvider API. It also obtains the message properties from the proxy and installs addressing property data using my MAP abstraction API. It then casts the proxy to the service interface and invokes the remote operation. The MAP data includes a replyto endpoint for theATTerminationInitiator configured with a reference parameter which identifies the thread/client making the request. The ATTermination service retrieves this data from the incoming request and uses it to address and tag the one way message to the ATTerminationInitiator service. The latter can use the tag to dispatch the result to the relevant thread.
The problem is that on some occasions the messages received at the ATTermination Service end have the wrong tag. I traced the calls and found examples where, say, two threads would supply tag "<blah blah>:2fa" and "<blah blah>:2fe" but the service would receive two incoming requests with the same tag <blah blah>:2fe". It appears that the proxy returned to each thread is either the same object or, at least, shares the same message context with the result that one thread updates the MAP data on the request message context while another thread is in the middle of invoking the remote operation.
I checked the JaxWS spec and it does not clarify whether the port returned from the getPort call is thread safe or not. My assumption has been that each getPort call is supposed to return a new port object which can be configured and invoked by a client thread independent of any parallel configuration and invocation of a port returned by a different call to getPort . Whatever the status of the spec it does not look like this is happening in our native implementation.
One other way this behaviour migth be specified would be to require that each client thread employ its own instance of the Service. Thsi would also require the implementation to ensure that proxies obtained from different services could be used in a thread safe manner. That seems a bit perverse to me since the threads are actually using the same Sevrice -- they merely want to employ independent channels for communicating with it -- the port seems to me to be the correct level at which to achieve this.
Also, creating the Service instance requires checking the WSDL, initialising all the endpoint and operation info etc so this appears to be an expensive operation which I don't want to do for every JaxWS request. Yet the WS-AT protocol rtequires the use of 6 different services in a given TX but rarely involves more than one, or in some cases two, JaxWS invocation per service. I could maybe mitigate some of the creation costs using a cache to store Service instances per-thread but that would still multiply the Sevrice instances unnecessaril;y. It woudl also require use of a WeakHashMap to ensure that the cache was garbage collected. This has its own awful performance implications fo rgarbage collection so I don;t want to have to go down that route. If this is the expecte dmodel then it's a pretty unattractive proposition. Anyway, it seems to me to be inappropriate since I don't need lots of copies of the service I need lots of copies of a port (i.e. proxy) associated with the same service.
This thread-safe/unsafe behaviour is a critical issue which ought to be clearly documented in our code at least (it ought to be in the spec in bold font but the spec is pretty half-assed about many things so no surpirse I can't find it). Note that I cannot resolve this problem simply by introducing synchronization around the invocation of the proxy method. If I have to resort to inserting my own synchronization then I would have to synchronize from the point at which I obtain the port, maintain a lock while configuring the bindings and addressing properties and retain it throughout the duration of the call. In the case of an RPC message, I would also need keep the proxy locked while I grabbed the reply message context and retrieved and processed any data attached to it. Bye bye throughput.
So, any comments regarding what should be specified here and any ideas about what is actually implemented anbd whetehr it can be made thread-safe?
--------------------------------------------------------------
To reply to this message visit the message page: http://community.jboss.org/message/526010#526010
14 years, 4 months
[JBoss Microcontainer Development] New message: "Optimizing ScopeKey"
by Kabir Khan
JBoss development,
A new message was posted in the thread "Optimizing ScopeKey":
http://community.jboss.org/message/526003#526003
Author : Kabir Khan
Profile : http://community.jboss.org/people/kabir.khan@jboss.com
Message:
--------------------------------------------------------------
>From http://community.jboss.org/message/525925#525925
> Running a very simple benchmark for deploying a 1000 beans of type Object with no dependencies or configured properties, i.e.
>
> *protected* List<BeanMetaData> setupContexts()
> {
> List<BeanMetaData> beans = *new* ArrayList<BeanMetaData>(iterations);
> *for* (*int* i = 0 ; i < iterations ; i++)
> {
> BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder("Bean" + i, Object.class.getName());
> beans.add(builder.getBeanMetaData());
> }
> *return* beans;
> }
>
>
>
>
> shows 85% of this time to be spent in the PreInstallAction. A similar test deploying 500 beans with dependencies in the wrong order (which we know from http://community.jboss.org/message/525809#525809 is very slow) shows 25% of the time spent in PreInstallAction.
>
>
>
> Most of the time spent in PreInstallAction comes down to adding to and reading from the BasicMetaDataRepository.retrievals map, which hits UnmodifiableScopeKey.equals lots of times (~2M times in the 1000 beans case):
>
> *public* *boolean* equals(Object object)
> {
> *if* (object == *this*)
> *return* *true*;
> *if* (object == *null* || object *instanceof* ScopeKey == *false*)
> *return* *false*;
> ScopeKey other = (ScopeKey) object;
> Scope[] otherArray = other.getArray();
> *return* Arrays.equals(theScopes, otherArray);
> }
>
>
>
>
> I will dig into this tomorrow and see if this can be optimized somehow, and if it is a problem in MDR I'll open another thread for that.
1001 puts into BasicMetaDataRepository.retrievals results in 499500 UnmodifiableScopeKey calls. That is the sum of all numbers from 1 to 999, so it seems like the hashing is not working properly and that we iterate over all entries when doing a put to check if they exist.
--------------------------------------------------------------
To reply to this message visit the message page: http://community.jboss.org/message/526003#526003
14 years, 4 months