Detecting multiple class loaders

C

Chris

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?
 
M

Matt Humphrey

Chris said:
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?

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/
 
M

Mark Space

Chris said:
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?
 
C

Chris

Mark said:
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?

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.
 
M

Mark Space

Chris said:
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.
 
L

Lasse Reichstein Nielsen

Chris said:
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
 
M

Mark Space

Lasse said:
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.


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.
 
L

Logan Shaw

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
 
S

Silvio Bierman

Chris said:
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?

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
 
M

Matt Humphrey

Logan Shaw said:
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.

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.

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.

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/
 
L

Logan Shaw

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
 
A

Arne Vajhøj

Chris said:
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?

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top