Closed GoogleCodeExporter closed 9 years ago
I reproduced the problem and more or less know what the cause is, but I can't
find a good way to solve it. The
reason why it works on one JVM but not on 2 is because of Class loading issues.
The at/ambient/*
abstractions use the M2MI library to do multicast discovery and communication.
The M2MI library generates
little proxies for objects known as unihandles, multihandles and omnihandles.
Apparently, what goes wrong is
that one JVM serializes a proxy class (named Unihandle_1), passes it to a
second JVM, and when this JVM tries
to deserialize the proxy, it cannot find the class Unihandle_1. When executing
within only 1 JVM, this problem
does not occur because the class is correctly found in the local JVM where it
was first serialized.
I have encountered similar problems previously. Back then, I solved the issues
by making sure that the proxy
classes are loaded by a special 'M2MI class loader'. This fixed my problem
previously, but now it does not
seem to work anymore. I also cannot find any good information on dealing with
class loading issues on the
M2MI website or in its documentation.
To look at:
edu.vub.at.actors.natives.Packet -> HookedObjectInputStream.resolveClass
This is where the SynthesisException is raised by the call to loader_.loadClass.
The loader_ is the M2MI class loader (cf. /.at.m2mi.api =>
packet.deserizalizeUsingClassLoader(M2MI_Classloader())
What is also weird is that you can get different errors by forcing M2MI to
generate proxies by doing something
like:
/.at.m2mi.api.unihandle: jlobby.java.lang.Runnable for: (object: { });
Adding this statement to the JVM on which the exported M2MI proxy resides
causes an invalidclass exception
stating that the SerialVersionUIDs of Unihandle_1 on both JVMs does not match.
Adding this statement to both JVMs before exporting/discovering via M2MI shifts
the problem from
'Unihandle_1' to 'Unihandle_2'.
This seems to indicate that M2MI proxy classes cannot be correctly passed to
other JVMs, but this seems
really strange. Maybe these proxy classes can only be deserialized by M2MI
invocation threads?
Original comment by tvcut...@gmail.com
on 30 Sep 2008 at 8:05
Hi Tom,
I tried creating different Java threads and using M2MI (creating handles in one
thread and using it in another)
but everything just have gone fine in Java. I'm not completely sure how the
proxy classes are passed between
different VM's, maybe could be there the bug.
Do you have any ideas? This bug is freaking me out :-P
Original comment by vram...@gmail.com
on 30 Oct 2008 at 6:33
I finally found some time to fix this bug. As mentioned previously, I noticed
that the bug was caused due to
the fact that the discovering VM broadcasts a unihandle to a 'tracker' object
via an omnihandle. The VM that
hosts an exported object receives these broacasts but fails to deserialize the
unihandle passed along in the
message.
I circumvented this bug by now enforcing the exporting VM to export its object
as a unihandle (of type
"Tracker"). By forcing it to be a unihandle, the M2MI library on the exporting
JVM knows about unihandles of
this type and can correctly deserialize the incoming tracker unihandle.
Here is a short test-case:
First, activate the M2MP daemon.
On a first AmbientTalk VM do:
<code>
import /.at.ambient.discovery;
deftype DiscoveryTest;
def pub := export: (object: {
def test() {
system.println("test invoked");
};
}) as: DiscoveryTest;
system.println("exported " + pub);
</code>
On a second AmbientTalk VM (in a separate JVM) do:
<code>
import /.at.ambient.discovery;
deftype DiscoveryTest;
def sub := when: DiscoveryTest discovered: { |service|
system.println("Discovered service " + service);
service<-test();
};
</code>
This issue has been fixed in trunk/atlib r1335
Original comment by tvcut...@gmail.com
on 31 Oct 2008 at 1:49
Tom,
(long time ago I found this, but now I have time to see it...)
with the following code, there is a bug:
first VM:
<code>
deftype DiscoveryTest;
import /.at.support.timer;
import /.at.ambient.discovery;
def pub := export: (object: {
def add(x,y) { x + y };
}) as: DiscoveryTest;
when: seconds(100) elapsed: {
pub.unexport();
}
</code>
second VM:
<code>
deftype DiscoveryTest;
import /.at.ambient.discovery;
import /.at.lang.futures;
def [fut, res] := makeFuture();
def sub := when: DiscoveryTest discovered: { |service|
system.println("discovered");
when: service<-add(1,2)@FutureMessage becomes: { |val|
system.println(val);
sub.cancel();
res.resolve(true);
};
nil
};
fut;
</code>
what you expect is to see in the second VM the value 3 printed on the screen,
but
nothing happens.
Apparently there is a problem if the method returns a value.
Original comment by vram...@gmail.com
on 27 Jan 2009 at 11:29
Original issue reported on code.google.com by
tvcut...@gmail.com
on 30 Sep 2008 at 7:59