Re: [OJB-developers] Serious threading/lock problem
Brought to you by:
thma
From: Georg S. <ge...@me...> - 2002-03-24 22:34:23
|
Hi Thomas, Thanks for your prompt reply. Please excuse if I can't go into full detail or take up some of your suggestions yet, but my problem is that since yesterday I am about 600 km west of Buenos Aires in the Argentinean Pampa visiting my parents in law (normally I work in Vienna). This means I have an awfully slow Internet connection, no access to my development environment and the not so remote possibility of getting hit on my head by mey wife with an Argentinean Steak ( which are quite big) if I spend too much time of my vacation of working matters. Taking that risk, I would still like to discuss a few things On Fri, 22 Mar 2002, Thomas Mahler wrote: > > public boolean readLock(TransactionImpl tx, Object obj) > > { > > > > LockEntry writer = getWriter(obj); > > > > ====> race condition, another thread could put a writer > > > > if (writer == null) > > { > > > > ------------------------------------------------------- > > > > maybe synchronization happens somewhere else, but to make sure, I put > > synchronized to all the methods in LockManagerDefaultImpl.java > > > > > This strange thing has been "detected" by others before and there have > been some discussions on this topic. > > Here is the management summary: > The OJB Lockmanagement does not rely on Java Locking mechanisms! > The reason. Java locks only works within a single JVM. > But OJB Lockmanagement must properly work accross multiple JVMs. > Thus relying on Java's "synchronized" could result in severe data > corruption. > The C/S mode PersistentLockMapImpl is backed by a database table that > may be accessed from any number of clients residing in different JVMs. > > The SingleVM mode InMemoryLockMapImpl is meant for use for singlevm mode > only! But it also does not rely on "synchronized" & co. > > The double lock checking is done in the Methods of the LockMapImpl > classes (getWriter() & co.). I have tried both the InMemory and database-based locking mechanism and both showed the same behaviour. Taking an (admittedly) quick look at the LockMapImpl classes, I haven't found anything that would prevent one thread of adding a writer, after the first thread had already passed the if (writter == null) condition check Please tell me, if I am understanding something wrong there. > > > > > > I have to mention that Object A is a dynamic Proxy. > > > Mh. This may be somewhat problematic in your scenario. Using (dynamic) > Proxies in OJB/ODMG uses a "lazy locking". That is the lock is not > placed immediately but only when the proxy materializes the "real" > object. Please try your scneario without dynamic proxies. > Sorry, but my location (as mentioned above) prevents me from checking that out at the moment (I'll be back in 3 weeks, maybe I'll somehow manage to start things from here, then I'll try -:)). Am I right, that you are saying, one shouldn't be using dynamic proxies in a multithreaded environment? > > Mh, on commiting objects a PB.invalidate(obj) is performed that should > avoid this behaviour ??? > I think the problem is that in ObjectEnvelopeTable.java broker.invalidate(new Identity(mod.getObject())); } broker.commitTransaction(); the call to broker.invalidate and broker.comitTransaction aren't atomic which gives another thread the chance of filling up the cache with values from the database that are old, before borker.comitTransaction actually writes them to the database > > > > > e) I just put throw new LockNotGrantedException() to stop obj from > > materializing. This reduced the incident of the aforementioned > > problem, but it didn't stop it completly, so I assume there are > > other parts of the code which show a similar effect. > > > > > The best thing to get clearity about your analysis is to provide a JUnit > testcase that reproduces this behaviour! > Without such a testcase it's really difficult to verify your report. The steak-on-the-head problem will probably prevent me from doing that in the next weeks, but I'll try. Nevertheless it is going to be difficult to put this in a JUnit test case, since it is virtually impossible to make it reproducible in a predictable way. In our system, it happens during high load and in a massively multithreaded environment (and then not all of the time). One would have to put code into ojb to make certain threads sleep at different points. (if I have time I'll try) > > It seems that read-locks associated with the 1 result are not > > being released (the ObjectEnvelopeTable doesn't have any entries) > > > > My only solution is to actually materialize the queried subject > > by doing the following: > > > > SomeClass A = (SomeClass) l.get(0); > > > > and then calling a method on it > > > > => object is materialized and is in the ObjectEnvelopeTable and > > read-locks are release when calling tx.abort(); > > > > > This is a again the "lazy-locking" effect mentioned above. Works as > designed ! The problem in the case mentioned above is that the read lock stays with the object forever. Is that really what is intended? > > It won't be difficult to implement such a mechanism. > But ODMG wants the implemtor to throw exceptions if Locking fails. > We simply stick to the rules here. I didn't bring the ODMG standard with me, but are you sure, that having to wait for a lock constitutes a failure to obtain a lock (as opposed to let's say a timeout, where a LockNotGrantedException would make sense to me). Thanks again for your info Georg |