Java Forum / General / March 2008
Detecting multiple class loaders
Chris - 19 Mar 2008 16:39 GMT Is there any way to detect when a class has been loaded by two different class loaders?
Our app has a class that reads and writes a file on disk. The file gets corrupt if more than one process gets at it at once. We can detect multiple processes by locking the file on disk and throwing an error; no problem. We can control access by multiple threads using synchronization. So far, so good.
The problem is Websphere. When this class gets used in a webapp, Websphere, like most other app servers, creates a classloader just for that webapp. But it does more than that; it creates multiple classloaders and they all load the class independently. And we get corruption.
Other than fix Websphere (and we're working on it), is there another way, in general, we can use to ensure that only one classloader within a JVM loads a given class?
Matt Humphrey - 19 Mar 2008 17:37 GMT > Is there any way to detect when a class has been loaded by two different > class loaders? [quoted text clipped - 13 lines] > in general, we can use to ensure that only one classloader within a JVM > loads a given class? Have the writing code allocate a server socket on a rarely used port. If successful, the file write can proceed. Otherwise, someone else has the socket and is writing. Afer writing, release the socket. Note that the socket is never actually used. Sockets are a global resource independent of classloaders and allocation qualifies as atomic test-and-set.
Matt Humphrey http://www.iviz.com/
Logan Shaw - 20 Mar 2008 06:36 GMT >> Is there any way to detect when a class has been loaded by two different >> class loaders? [quoted text clipped - 8 lines] >> Websphere, like most other app servers, creates a classloader just for >> that webapp. But it does more than that; it creates multiple classloaders
> Have the writing code allocate a server socket on a rarely used port. If > successful, the file write can proceed. Otherwise, someone else has the > socket and is writing. Afer writing, release the socket. Note that the > socket is never actually used. Sockets are a global resource independent of > classloaders and allocation qualifies as atomic test-and-set. Alternatively, I have never tried using it, but from the javadocs it would appear that java.nio.channels.FileChannel's lock() could maybe do the locking in a global way. That method returns a FileLock, and the documentation for FileLock says,
This file-locking API is intended to map directly to the native locking facility of the underlying operating system. Thus the locks held on a file should be visible to all programs that have access to the file, regardless of the language in which those programs are written.
That would certainly imply the scope of the lock goes beyond the classloader and beyond the JVM as well.
The advantages of this over the socket method is that (a) you don't grab a serversocket port that somebody might actually *need*, and (b) you don't have to worry about maintaining some mapping between pathnames and port numbers. The disadvantage is that the behavior is platform-specific and not exactly completely guaranteed to do what you want, maybe.
- Logan
Matt Humphrey - 20 Mar 2008 13:17 GMT > Alternatively, I have never tried using it, but from the javadocs > it would appear that java.nio.channels.FileChannel's lock() could [quoted text clipped - 6 lines] > to all programs that have access to the file, regardless > of the language in which those programs are written. The paragraph that follows the one above says their behavior is platform-dependent. FileLock functionality has been discussed here several times in the past (Google archive) and I find they have too many issues. However, because only the OP's code will access the file--always heeding the advisory lock--FileLock might work out fine. I would certainly want to test it extensively before trusting it--and on each platform. I have read of other people having trouble with file locks (e.g. NFS or networked files and other platform oddities.) I would also want to test that it works across classloaders.
> That would certainly imply the scope of the lock goes beyond > the classloader and beyond the JVM as well. [quoted text clipped - 5 lines] > is platform-specific and not exactly completely guaranteed to do > what you want, maybe. To me, the disadvantage of non-guaranteed behavior is overwhelming. As for sockets, there are plenty of ports available, their behavior is not system-dependent and they are automatically released when the application exits or crashes. If it turns out there are hundreds of such files to be managed instead of just one, it's possible to scale up to a resource manager as single process that manages either the data or shared lock access through the port connection.
Matt Humphrey http://www.iviz.com/
Logan Shaw - 21 Mar 2008 04:45 GMT >> it would appear that java.nio.channels.FileChannel's lock() could >> maybe do the locking in a global way.
> To me, the disadvantage of non-guaranteed behavior is overwhelming. It is ultimately a matter of relative values of the positives and negatives of each approach.
Personally, I wouldn't be afraid too much of behavior that varies somewhat from one platform to the next, but I am going on the basic assumption that the lock will do some sort of useful locking on every platform (else it wouldn't be a lock).
> As for > sockets, there are plenty of ports available, It depends on what you mean by plenty. The space is only 16 bits to begin with, and many systems reserve half or more of that for privileged and/or ephemeral ports. And the birthday paradox means that if ports are chosen at random (which in practice is not unlike how people choose them!), the chance of collision is not really that low.
Beyond that, there is the disadvantage of creating an extra item that requires correct configuration in order for the system to function correctly. Every time you do that, you incur cost: of communicating the requirement, of increased deployment work, and of tracking the required configuration across all the hosts/instances on a host on which it is deployed. You also incur risk that the configuration requirement will not be communicated or understood or tracked properly and problems will occur. In this case, two separate webapps would need to agree on the same port for every file they want to mediate access to. This agreement would have to be maintained and stay in sync somehow. This could very easily go wrong, and you could end up back where you started: with file corruption, because webapp #1 is using port 5432 and webapp #2 is using port 2345.
Because of stuff like this, I place a high value on getting close to a zero-configuration system as possible. To me, that would be a compelling reason not to want to use a socket. I'm probably more scared of error-prone configuration than I am of platform-specific behavior.
- Logan
Mark Space - 19 Mar 2008 19:35 GMT > Our app has a class that reads and writes a file on disk. The file gets > corrupt if more than one process gets at it at once. We can detect My feeling is that you have multiple web apps all writing to one single file. That sounds like bad design. I think you should look into some method that supports multiple reader/writers inherantly. Maybe a small database or something that you can do transactions on.
Could I ask what the heck this file is? What the idea of having one file that all web apps need to process?
Chris - 19 Mar 2008 22:49 GMT >> Our app has a class that reads and writes a file on disk. The file >> gets corrupt if more than one process gets at it at once. We can detect [quoted text clipped - 6 lines] > Could I ask what the heck this file is? What the idea of having one > file that all web apps need to process? No, it's actually only one webapp. It's a data file. Using a database is not an option. The only approach is to access the file through only one synchronized class.
Mark Space - 19 Mar 2008 23:22 GMT > No, it's actually only one webapp. It's a data file. Using a database is > not an option. The only approach is to access the file through only one > synchronized class. I think you may have already decided on which approach is best, but I'm still somewhat confused. I don't know everything, so it helps me out sometimes if I ask questions.
You have one web app, which is implemented as multiple "web apps" on Websphere? So conceptually you have one app, but Websphere sees multiple apps?
I'm asking because I assume I may run into the same problem at some point in my career, and I'd like to know about problems before I hit them, at least, if not also have some idea what a solution might be....
The only other reason for multiple classloaders that I can think of is if there's multiple JVMs, on one or multiple machines.
It sounds like you need some sort of global or JVM wide context object, where you can store one class object that all web apps can use. I've never heard of such a thing though.
Lasse Reichstein Nielsen - 20 Mar 2008 00:21 GMT > No, it's actually only one webapp. It's a data file. Using a database > is not an option. The only approach is to access the file through only > one synchronized class. Have you considered creating a separate session bean that accesses the file, and accessing that bean from the web-applications instead of going directly to the file.
Preferably you can build some sort of transaction control on top of it.
/l
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Mark Space - 20 Mar 2008 01:02 GMT >> No, it's actually only one webapp. It's a data file. Using a database >> is not an option. The only approach is to access the file through only [quoted text clipped - 5 lines] > > Preferably you can build some sort of transaction control on top of it. Wouldn't a session bean have exactly the problem he's having now? There will be multiple sessions beans (one per user now, instead of one per webapp) and they'll still need to synchronize amongst themselves on one file?
Obviously, if there is one file per session, then this is an ideal solution, but I didn't read that in the OPs problem statement.
Silvio Bierman - 20 Mar 2008 09:12 GMT > Is there any way to detect when a class has been loaded by two different > class loaders? [quoted text clipped - 14 lines] > way, in general, we can use to ensure that only one classloader within a > JVM loads a given class? Are you by any chance using the broken singleton pattern based on a static instance member? If so your only option is to use an external resource to lock on as a workaround. As others have pointed out sockets are among the obvious candidates.
Silvio Bierman
Arne Vajhøj - 30 Mar 2008 03:26 GMT > Is there any way to detect when a class has been loaded by two different > class loaders? [quoted text clipped - 14 lines] > way, in general, we can use to ensure that only one classloader within a > JVM loads a given class? Put the class in a place where it will be loaded by the same classloader for all web apps.
Classloaders always try to delegate to their parent, so if the class can be loaded by a classloader that is ancestor to all the relevant classloader it will be loaded by that. And therefore only exist in one copy.
And no need to "fix" WebSphere, because this is how Java and app servers are supposed to work.
Arne
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|