newbiettn / ambienttalk

Automatically exported from code.google.com/p/ambienttalk
0 stars 0 forks source link

Synthesis Exception of M2MI handle classes when using at/ambient/discovery.at #26

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Victor Ramiro reported the following problem:

"I'm running the test: testAsyncTypedDiscoveryViaDefaultTracker from the 
DiscoveryModuleTest 
(at/ambient/discovery.at)

If I run the test, everything goes just perfect. But if I put apart the client 
code from the service 
code (the code written within the actor) in two different files and run it as 
two separate VM I got 
an exception:

>>> Exception in actor <actormirror:1911694>: Java exception from packet[<async 
msg:reportTo(<m2mi ref for handle Unihandle(011CAFCA97B2-000D93EB3A50-
2FCA9713,Tracker)>)>].unpackUsingClassLoader: 
edu.rit.m2mi.SynthesisExceptionM2MIClassLoader: Unknown class Unihandle_1
origin:
at packet.unpackUsingClassLoader(M2MI_getClassLoader())
Mon Sep 29 16:26:50 CLT 2008 ERROR at.eventloops.actors - asynchronous 
symbiotic invocation 
of invoke failed
edu.rit.m2mi.SynthesisException: M2MIClassLoader: Unknown class Unihandle_1
    at edu.rit.m2mi.M2MIClassLoader.getClassFile(M2MIClassLoader.java:491)
    at edu.rit.m2mi.M2MIClassLoader.findClass(M2MIClassLoader.java:527)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at edu.vub.at.actors.natives.Packet$HookedObjectInputStream.resolveClass(Packet.java:132)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1544)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)
       ...."

Original issue reported on code.google.com by tvcut...@gmail.com on 30 Sep 2008 at 7:59

GoogleCodeExporter commented 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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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