vlingo / xoom-actors

The VLINGO XOOM platform SDK for the type-safe Actor Model, delivering Reactive concurrency, high scalability, high-throughput, and resiliency using Java and other JVM languages.
https://vlingo.io
Mozilla Public License 2.0
229 stars 28 forks source link

Grid related changes #66

Closed buritos closed 4 years ago

buritos commented 4 years ago
buritos commented 4 years ago

related: https://github.com/buritos/vlingo-lattice/pull/1

buritos commented 4 years ago

ActorEnvironmentTest#testSecuredEnvironment fails with:

java.lang.LinkageError: loader (instance of  io/vlingo/common/compiler/DynaClassLoader): attempted  duplicate class definition for name: "io/vlingo/actors/ActorEnvironmentTestEnvironmentProvider__Proxy"

    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:635)
    at io.vlingo.common.compiler.DynaClassLoader.addDynaClass(DynaClassLoader.java:18)
    at io.vlingo.common.compiler.DynaCompiler.compile(DynaCompiler.java:70)
    at io.vlingo.actors.ActorProxy.tryGenerateCreate(ActorProxy.java:103)
    at io.vlingo.actors.ActorProxy.tryGenerateCreate(ActorProxy.java:86)
    at io.vlingo.actors.ActorProxy.createFor(ActorProxy.java:34)
    at io.vlingo.actors.Stage.actorProxyFor(Stage.java:514)
    at io.vlingo.actors.Stage.actorProtocolFor(Stage.java:466)
    at io.vlingo.actors.Stage.testActorFor(Stage.java:285)
    at io.vlingo.actors.testkit.TestWorld.actorFor(TestWorld.java:75)
    at io.vlingo.actors.ActorEnvironmentTest.testSecuredEnvironment(ActorEnvironmentTest.java:54)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
VaughnVernon commented 4 years ago

@buritos The class io.vlingo.actors.ActorEnvironmentTestEnvironmentProvider__Proxy is already in the ClassLoader that is evidently not being cleared between tests.

Inside ActorProxy you can see that the specific World's ClassLoader is being used, so maybe the World is being reused across tests. Or it could be that there is a race and the io.vlingo.actors.ActorEnvironmentTestEnvironmentProvider__Proxy is not yet in the ClassLoader but will be there before a second thread completes its generation, compile, and put into the ClassLoader.

This unfortunate code is supposed to protect against that, but maybe it's not:

synchronized (protocol) {

WDYT?

Possibly the fix is to catch the exception and try to get the class again out of the ClassLoader as now it is there but it wasn't on first try to fetch it.

buritos commented 4 years ago

@VaughnVernon

maybe the World is being reused across tests

The test creates a new World instance for every test method execution.

Or it could be that there is a race and the io.vlingo.actors.ActorEnvironmentTestEnvironmentProvider__Proxy is not yet in the ClassLoader

That's a good theory. But why hasn't this been the case before the last commit here? I would love to understand how this works :)

synchronized (protocol)

I guess we either fix this or catch and retry as you suggested.

buritos commented 4 years ago

@VaughnVernon

  1. proper locking on the protocol has the same issue (implemented using a similar approach to https://stackoverflow.com/a/28347825)
  2. retry by recursively calling createFor on LinkageError stack overflows
VaughnVernon commented 4 years ago

@buritos I am pretty sure I haven't made any changes to vlingo-actors that could make this behavior newly appear. The ActorProxy has been working for 2+ years. I can't think of how the synchronized (protocol) { ... } could be a problem. The actor instance will not receive messages until after the protocol exists for it, so I don't see how there could be a race from the actor itself. The smart money says back out your changes for grid and re-add them one at a time until the problem reappears.

VaughnVernon commented 4 years ago

@buritos I am concerned that this is not building on Travis. I think it is due to running a test that should have been marked @Ignore 

[ERROR] ActorEnvironmentTest.testSecuredEnvironment:55 » Linkage loader (instance of ...