All
I believe I have found a defect with XmlBeans which can cause a deadlock to occur under a specific situation. The situation can occur when calling a setter on an Object which synchronizes on Locale A, to set an Object which synchronizes on Locale B at the same time as calling a setter on an Object which synchronizes on Locale B to set an Object which synchronizes on Locale A. The code which XmlBeans generates follows this flow: 1. MyObjectUnderLocaleA.setMyElement(MyObjectUnderLocaleB) a) Synchronize on monitor() b) Delegates to XmlObjectBase.set(XmlObject src) i. Identifies that MyObjectUnderLocaleA.monitor() != MyObjectUnderLocaleB.monitor() ii. GlobalLock.acquire iii. Synchronize on monitor() iv. Synchronize on MyObjectUnderLocaleB.monitor() So if the reverse is happening concurrently, Thread 1 will have a lock on Locale A and the GlobalLock, and Thread 2 will have a lock on Locale B and wait to get the GlobalLock - hence the deadlock situation. It may be that this is arising from a strange/undesired use of XmlBeans - we have a HashMap which caches template XmlBean objects, and when we need an instance of the template, we were calling the copy() method and returning that. I believe this means the template and our instance share the same locale. Once the number of users ramps up, there are a lot of users sharing the same locale and consequently introducing a lot of contention. We have worked around the problem for now by performing an XmlObject.Factory.parse(...) and so each returned object is then in its own Locale. If someone can confirm this, can it be raised as a defect? If it's not a defect, then is there a way to do a deep copy that will create the new object in a new Locale? Thanks Paul -----Original Message----- From: Paul Hepworth Sent: 27 October 2008 14:28 To: 'dev@xmlbeans.apache.org' Subject: RE: XmlBeans and Synchronization Hi Radu Thanks for the explanation. In theory it all seems sound. Only our application is getting itself locked somehow. I've done a thread-dump from Weblogic, and have multiple threads waiting on XmlObjectBase.java:1944 which is fine and to be expected as per your explanation. I then have another thread which is stuck on XmlObjectBase.java:1949 - so this is the one that has the GlobalLock, but is in turn waiting on another lock which isn't getting released at all. I have several other threads that are blocked on XmlObjectBase.java:116 performing a copy which I believe are fine and just waiting for a lock. I then have a few threads performing simple gets that are blocked waiting for locks on Locale. I have no other threads that are doing any processing (I've left the app in this state for 10 or so minutes and all the threads are just locked up) As I can't find much info on the net, could you explain a bit more about the Local please? What I'd like to know is the following: - Is there a new Local per instance of a document or a shared one for all instances of the same type? i.e. if I call MyDocument.Factory.newInstance(), does this get a new Local each time, or 1 shared one for all MyDocument instances? - We have a template service that reads and parses XML stored in the DB, this is cached for performance reasons, and when we request a template, we call the copy() method. Does this mean that each copied instance shares the same Locale? If that's the case, this will greatly impact the performance of our app. - Basically... what determines the Locale? Additionally, you mention turning off synchronisation... I've attempted this in the code using XmlBeans 2.3.0 and run into the problems mentioned here: https://issues.apache.org/jira/browse/XMLBEANS-328 it should also be noted that we were having these errors in our performance test environment originally and applied the patch mentioned. This stopped the errors described, however we were still running into the deadlock situation. Is this something which has been fixed in 2.4? Is it a safe option to turn off synchronisation? Any help greatly appreciated! Thanks Paul Hi Paul, I can tell you what the synchronization strategy is. Each XmlObject belongs to an xml document, and each xml document belongs to what XmlBeans calls a Locale object (nothing to do with the Java Locale). This is the synchronization domain for XmlBeans. When doing a set, there are two XmlObjects involved: the source (the parameter of the "set" method) and the target (the object you're calling "set" on). XMLBeans requires that they both be synchronized. Now, if the synchronization domain for the two is the same (the same Locale object), then there's no problem (see check at XmlObjectBase.java:1934 if you have the 2.3.0 source). But if the synchronization domain is not the same, then it means that two locks must be acquired and so there is a possibility for deadlock. In order to avoid the deadlock, XMLBeans has the "GlobalLock". This global lock is held only for as long as it is necessary to acquire the two XmlObject locks and then it is immediately released. This guards against the deadlock, but doesn't guard against the possibility that one thread grabs the global lock and then blocks on waiting for another thread to finish with one of the XmlObject locks it is trying to acquire. Eventually, it will grab the lock it is waiting for and then release the Global lock, but while it is waiting, all the other threads in the whole system are prevented from initiating a set that requires two locks, which can be a problem. So I think first of all, it would be interesting for you to look at the stack traces for all the threads to confirm my scenario above. Then, as far as solution, the only reliable one that I know of is not use the "setMyValue" method and replace it with "addNewMyValue" whenever possible because it doesn't require synchronization (and the overall performance is better). In XMLBeans 2.4.0, I think, removing synchronization altogether from the XMLBeans layer would also solve the problem. Radu ________________________________ From: Paul Hepworth [mailto:[EMAIL PROTECTED] Sent: Friday, October 24, 2008 5:00 AM To: [EMAIL PROTECTED]; dev@xmlbeans.apache.org Subject: XmlBeans and Synchronization Hi (included dev list as this may be too in depth for the user list) I'm using XmlBeans 2.3.0 in a Weblogic 9.2 J2EE web application (JVM 1.5.0_10). We use XmlBeans to compile our schema and these effectively become our domain objects. These are looked up from the DB, stored in the Http Session, manipulated from the UI and passed to the DB again. The application appears to run fine with a single user, however when we test it with multiple users using LoadRunner, we hit issues. What we are seeing is that we're getting stuck threads with the following stack: at java.lang.Object.wait(Native Method) - waiting on <0xd4a816e8> (a org.apache.xmlbeans.impl.common.Mutex) at java.lang.Object.wait(Object.java:474) at org.apache.xmlbeans.impl.common.Mutex.acquire(Mutex.java:33) - locked <0xd4a816e8> (a org.apache.xmlbeans.impl.common.Mutex) at org.apache.xmlbeans.impl.common.GlobalLock.acquire(GlobalLock.java:27) at org.apache.xmlbeans.impl.values.XmlObjectBase.set(XmlObjectBase.java:194 4) at ...MyClassImpl.setMyValue(...) Can anyone shed any light on why this may happen? More specifically, does anyone know what the synchronisation strategy is in XmlBeans. From my investigation, the GlobalLock uses a static Mutex, which means that if an instance needs to take out more than 1 lock, it attempts to acquire a GlobalLock and will subsequently lock out all other threads in the JVM from making any changes to an XmlObject. If that's the case, it seems very strange that making an update to 1 instance of an XmlObject would lock out all other threads form updating any other instance of an XmlObject. I would have thought that the synchronisation would have solely been around the instance itself. We have also seen the same issues that have been recorded here: https://issues.apache.org/jira/browse/XMLBEANS-328 Any help on this would be much appreciated as it's causing major issues!! Thanks Paul This message should be regarded as confidential. If you have received this email in error please notify the sender and destroy it immediately. Statements of intent shall only become binding when confirmed in hard copy by an authorised signatory. The contents of this email may relate to dealings with other companies within the Detica Group plc group of companies. Detica Limited is registered in England under No: 1337451. Registered offices: Surrey Research Park, Guildford, Surrey, GU2 7YP, England.