我使用Apache Twill将一个使用Janino进行动态编译类的开源项目移植到YARN。这除了最后一个错误外,效果很好。当Janino与twill一起使用时,我得到一个异常,即无法找到类,尽管Classpath中的类甚至可以使用。
我得到的例外是:
2014-06-09T18:30:40,093Z ERROR o.a.d.e.p.i.p.ProjectRecordBatch [zk1] [37daf04b-7d82-4d2f-987c-59851f2aeafe:FRAG:0:0] AbstractSingleRecordBatch:next(AbstractSingleRecordBatch.java:60) - 查询失败 org.apache.drill.exec.exception.SchemaChangeException:失败时 试图加载生成的类 在org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.setupNewSchema(ProjectRecordBatch.java:243) 在org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:57) 在org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.next(ProjectRecordBatch.java:83) 在org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在org.apache.drill.exec.physical.impl.limit.LimitRecordBatch.next(LimitRecordBatch.java:99) 在org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在org.apache.drill.exec.physical.impl.svremover.RemovingRecordBatch.next(RemovingRecordBatch.java:94) 在org.apache.drill.exec.physical.impl.ScreenCreator $ ScreenRoot.next(ScreenCreator.java:80) 在org.apache.drill.exec.work.fragment.FragmentExecutor.run(FragmentExecutor.java:104) 在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744)引起:org.apache.drill.exec.exception.ClassTransformationException:失败
为值生成转换类:
package org.apache.drill.exec.test.generated;
import org.apache.drill.exec.exception.SchemaChangeException;
import org.apache.drill.exec.expr.holders.BitHolder;
import org.apache.drill.exec.expr.holders.VarCharHolder;
import org.apache.drill.exec.ops.FragmentContext;
import org.apache.drill.exec.record.RecordBatch;
import org.apache.drill.exec.vector.RepeatedVarCharVector;
import org.apache.drill.exec.vector.VarCharVector;
import org.apache.drill.exec.vector.complex.impl.RepeatedVarCharReaderImpl;
public class ProjectorGen0 {
RepeatedVarCharVector vv0;
RepeatedVarCharReaderImpl reader4;
VarCharVector vv5;
public boolean doEval(int inIndex, int outIndex)
throws SchemaChangeException
{
{
VarCharHolder out3 = new VarCharHolder();
complex:
vv0 .getAccessor().getReader().setPosition((inIndex));
reader4 .read(0, out3);
BitHolder out8 = new BitHolder();
out8 .value = 1;
if (!vv5 .getMutator().setSafe((outIndex), out3)) {
out8 .value = 0;
}
if (out8 .value == 0) {
return false;
}
}
{
return true;
}
}
public void doSetup(FragmentContext context, RecordBatch incoming, RecordBatch outgoing)
throws SchemaChangeException
{
{
int[] fieldIds1 = new int[ 1 ] ;
fieldIds1 [ 0 ] = 0;
Object tmp2 = (incoming).getValueAccessorById(RepeatedVarCharVector.class, fieldIds1).getValueVector();
if (tmp2 == null) {
throw new SchemaChangeException("Failure while loading vector vv0 with id: org.apache.drill.exec.record.TypedFieldId@1cf4a5a0.");
}
vv0 = ((RepeatedVarCharVector) tmp2);
reader4 = ((RepeatedVarCharReaderImpl) vv0 .getAccessor().getReader());
int[] fieldIds6 = new int[ 1 ] ;
fieldIds6 [ 0 ] = 0;
Object tmp7 = (outgoing).getValueAccessorById(VarCharVector.class, fieldIds6).getValueVector();
if (tmp7 == null) {
throw new SchemaChangeException("Failure while loading vector vv5 with id: org.apache.drill.exec.record.TypedFieldId@1ce776c0.");
}
vv5 = ((VarCharVector) tmp7);
}
}
}
在 org.apache.drill.exec.compile.ClassTransformer.getImplementationClass(ClassTransformer.java:302) 在 org.apache.drill.exec.ops.FragmentContext.getImplementationClass(FragmentContext.java:185) 在 org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.setupNewSchema(ProjectRecordBatch.java:240) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:57) 在 org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.next(ProjectRecordBatch.java:83) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在 org.apache.drill.exec.physical.impl.limit.LimitRecordBatch.next(LimitRecordBatch.java:99) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在 org.apache.drill.exec.physical.impl.svremover.RemovingRecordBatch.next(RemovingRecordBatch.java:94) 在 org.apache.drill.exec.physical.impl.ScreenCreator $ ScreenRoot.next(ScreenCreator.java:80) 在 org.apache.drill.exec.work.fragment.FragmentExecutor.run(FragmentExecutor.java:104) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:615) 在java.lang.Thread.run(Thread.java:744)引起: org.codehaus.commons.compiler.CompileException:第4行,第8列: 导入的类" org.apache.drill.exec.exception.SchemaChangeException" 无法载入 org.codehaus.janino.UnitCompiler.compileError(UnitCompiler.java:9014) 在org.codehaus.janino.UnitCompiler.import2(UnitCompiler.java:192)at org.codehaus.janino.UnitCompiler.access $ 000(UnitCompiler.java:104)at at org.codehaus.janino.UnitCompiler $ 1.visitSingleTypeImportDeclaration(UnitCompiler.java:166) 在 org.codehaus.janino.Java $ CompilationUnit $ SingleTypeImportDeclaration.accept(Java.java:171) 在org.codehaus.janino.UnitCompiler。(UnitCompiler.java:164)at org.apache.drill.exec.compile.JaninoClassCompiler.getClassByteCode(JaninoClassCompiler.java:53) 在 org.apache.drill.exec.compile.QueryClassLoader.getClassByteCode(QueryClassLoader.java:69) 在 org.apache.drill.exec.compile.ClassTransformer.getImplementationClass(ClassTransformer.java:256) 在 org.apache.drill.exec.ops.FragmentContext.getImplementationClass(FragmentContext.java:185) 在 org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.setupNewSchema(ProjectRecordBatch.java:240) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:57) 在 org.apache.drill.exec.physical.impl.project.ProjectRecordBatch.next(ProjectRecordBatch.java:83) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在 org.apache.drill.exec.physical.impl.limit.LimitRecordBatch.next(LimitRecordBatch.java:99) 在 org.apache.drill.exec.record.AbstractSingleRecordBatch.next(AbstractSingleRecordBatch.java:45) 在 org.apache.drill.exec.physical.impl.svremover.RemovingRecordBatch.next(RemovingRecordBatch.java:94) 在 org.apache.drill.exec.physical.impl.ScreenCreator $ ScreenRoot.next(ScreenCreator.java:80) 在 org.apache.drill.exec.work.fragment.FragmentExecutor.run(FragmentExecutor.java:104) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:615) 在java.lang.Thread.run(Thread.java:744)
如您所见,异常的类型为SchemaChangeException
,但ClassNotFoundException
的内部异常为SchemaChangeException
:
第4行,第8列:导入的类 " org.apache.drill.exec.exception.SchemaChangeException"不可能 装载
所以类加载器有问题,当使用Apache Twill运行应用程序时,它会发生变化。它可以单独使用,但在这两种情况下,底层罐子都是相同的。
Apache Twill还有一个添加额外资源的功能,但添加我的jar也没有工作,而是我得到一个例外,jar已经包含在内:
线程中的异常" ServiceDelegate STARTING" java.lang.RuntimeException:java.util.zip.ZipException:重复条目:lib / drill-java-exec-1.0.0-m2-incubating-SNAPSHOT-rebuffed.jar
在com.google.common.base.Throwables.propagate(Throwables.java:160)at at org.apache.twill.yarn.YarnTwillController.doStartUp(YarnTwillController.java:133) 在 org.apache.twill.internal.AbstractZKServiceController.startUp(AbstractZKServiceController.java:82) 在 org.apache.twill.internal.AbstractExecutionServiceController $ ServiceDelegate.startUp(AbstractExecutionServiceController.java:109) 在 com.google.common.util.concurrent.AbstractIdleService $ 1 $ 1.run(AbstractIdleService.java:43) 在java.lang.Thread.run(Thread.java:744)引起: java.util.zip.ZipException:重复条目: lib / drill-java-exec-1.0.0-m2-incubating-SNAPSHOT-rebuffed.jar at java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:215) 在 java.util.jar.JarOutputStream.putNextEntry(JarOutputStream.java:109) 在 org.apache.twill.internal.ApplicationBundler.copyResource(ApplicationBundler.java:347) 在 org.apache.twill.internal.ApplicationBundler.createBundle(ApplicationBundler.java:140) 在 org.apache.twill.yarn.YarnTwillPreparer.createContainerJar(YarnTwillPreparer.java:388) 在 org.apache.twill.yarn.YarnTwillPreparer.access $ 300(YarnTwillPreparer.java:106) 在 org.apache.twill.yarn.YarnTwillPreparer $ 1.call(YarnTwillPreparer.java:264) 在 org.apache.twill.yarn.YarnTwillPreparer $ 1.call(YarnTwillPreparer.java:253) 在 org.apache.twill.yarn.YarnTwillController.doStartUp(YarnTwillController.java:98) ......还有4个
使用的基础类加载器是URLClassLoader
。它是用一个空数组初始化的,但是它适用于独立应用程序,只有当它与Apache Twill一起运行时才会出现问题,它从哪里获取它应该查找的URL?我怎么检查它?
类加载器定义:
public class QueryClassLoader extends URLClassLoader {
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(QueryClassLoader.class);
private final ClassCompiler classCompiler;
private AtomicLong index = new AtomicLong(0);
private ConcurrentMap<String, byte[]> customClasses = new MapMaker().concurrencyLevel(4).makeMap();
public QueryClassLoader(boolean useJanino) {
super(new URL[0]);
if (useJanino) {
this.classCompiler = new JaninoClassCompiler(this);
} else {
throw new UnsupportedOperationException("Drill no longer supports using the JDK class compiler.");
}
}
...
我可以查看的任何想法,错误发生的原因或解决方法?
答案 0 :(得分:-1)
Apache Twill邮件列表中提出了同样的问题。以下是对它的讨论和建议解决方案。
在邮件内容中重复我的回答:
我不熟悉janino如何工作,但在我看来,它可能没有使用上下文ClassLoader来加载类,或者至少编译生成的类的线程没有上下文 ClassLoader设置正确。
Twill的工作方式非常简单。它创建了一个“launcher.jar”,它不依赖于任何库并在YARN容器中启动JVM,如下所示:
java -cp launcher.jar ....
因此系统类加载器没有用户/库类,只有Launcher类。
然后在Launcher.main()
方法中,它使用“container.jar”文件中的所有jar + .class文件创建URLClassLoader
,以加载用户TwillRunnable。它还将其设置为调用“run()”方法的线程的上下文ClassLoader。因此,如果要在与“run()”线程不同的线程中手动加载类(通过ClassLoader或Class.forName),则必须使用该线程的上下文ClassLoader或使用该线程显式构造ClassLoader。正确的父类ClassLoader。