[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

re: the evils of multithreading: correction




Seems I was wrong -- that's what I get for not waiting the extra day to run
(yet) more tests.

The 'solution' described below just changes the run-time of portions of the
code, which may or may not affect the occurrance of the problem. It would
seem that the created object in the example below -- or any similar code --
is not available to other threads until the outermost transaction of the
thread that created it is complete.

This would seem to mean that you just can't write code to run inside the
Ozone server that creates persistant objects and then uses them inside
methods. Or at least, you can't expect it to work at all in a multithreaded
environment.

My solution for the moment is to completely rewrite my code such that no
persistant objects are created and then used before the creating transaction
is complete. This works pretty well so far.

However, it does occur to me that if my suppositions above are what is
actually happening, then anyone can come along and create an application on
top of my data layer that will break when multithreaded because they use an
explicit transaction to combine a number of my (individually thread-safe)
transactions/method calls into something that isn't thread safe. This
doesn't seem good and I'm not yet sure what I can do about that.

A few questions first:

1) am I correct in assuming that objects are not available to other threads
(as described below) until the outermost transaction is complete?

2) Am I even correct in assuming that transactions are layered? (i.e. a
public method calls another public method, or a public method is called
within an explicit transaction -- are these one transaction, or a
transaction that contains another transaction?)

3) Does anyone else on the list have any insights on using Ozone in a
heavily multithreaded environment?

Reason


-----Original Message-----
From: Reason [mailto:reason@exratio.com]
Sent: Sunday, May 27, 2001 9:57 PM
To: ozone-users@ozone-db.org
Subject: the evils of multithreading



Synopsis:

In a multithreaded environment, you can't always create ozone objects in a
method that you plan to use later in that method. Synchronization won't fix
the problem, but putting object creation code in its own method will.

------

I thought I should share this one, given the two days of watching Ozone
blowing up that it took me to work things out. (Disclaimer -- all testing
done on Windows 2000). Assume the following is in an ObjectImpl class
extending OzoneObject implementing OzoneRemote, et al:

private mic = null;

public importantMethod(blah, blah) throws Exception
{

	[do stuff...]
	if(mic == null)
		mic =
(MyImportantClass)database.createObject(MyImportantClass.class.getName(),
access_level);

	[do stuff...]

	mic.doSomething();

	[do stuff...]

}

If you run two or three threads through this method at once, the new mic
object will not be visible by ID in the grand index of objects to any of the
threads until one of the threads exits the method and thus closes out the
transaction. The following exception (or something like it) will be thrown
at mic.doSomething() and entered into the Ozone log --

Transaction: ta(117): uncaught exception: (org.ozoneDB.ObjectNotFoundExc: No
such object ID: 129)

And then all hell will break loose by degrees. In my test code, I usually
end up locking up Ozone entirely after some nasty looking
NullPointerExceptions in the WizardStore and a deadlock.

Funnily enough, declaring segments or all of the code in importantMethod as
synchronized doesn't fix things. Declaring the method synchronized doesn't
fix things either -- although it does seem to narrow the margin by which
threads have to follow on each others heels in order to cause problems.

The fix in this case is to put the object creation in its own method; in
this case, the object will be available to other threads.

public importantMethod(blah, blah) throws Exception
{

	[do stuff...]

	if(mic == null)
		mic = createMic();

	[do stuff...]

	mic.doSomething();

	[do stuff...]

}


public createMic() throws Exception
{
	return
(MyImportantClass)database.createObject(MyImportantClass.class.getName(),
access_level);
}

Reason
http://www.exratio.com/