[
https://issues.apache.org/jira/browse/YARN-4577?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15246170#comment-15246170
]
Sangjin Lee commented on YARN-4577:
-----------------------------------
Thanks for your comments [~vinodkv].
bq. Xuan Gong reminded me offline that we do pass a shared configuration as
part of serviceInit(). In that case, the solution is simply to pass a private
cloned Configuration for each of the aux-services?
Yes, that's exactly the scenario under which an aux service gets a reference to
the shared configuration. Resetting the configuration classloader on a shared
configuration is a big risk.
I like your idea about creating a copy of the configuration. The only
implication is that the aux services will then never see any changes made to
the configuration past {{serviceInit()}}. I don't think that's a deal breaker.
We could tweak the above code pattern I suggested to achieve this:
{code}
class AuxiliaryServiceWithCustomClassLoader extends AuxiliaryService {
private final AuxiliaryService wrapped;
private final ClassLoader customClassLoader;
private Configuration conf;
public AuxiliaryServiceWithCustomClassLoader(AuxiliaryService s, ClassLoader
cl) {
this.wrapped = s;
this.customClassLoader = cl;
}
@Override
protected void serviceInit(Configuration conf) throws Exception {
this.conf = new Configuration(conf);
this.conf.setClassLoader(customClassLoader);
// call the wrapped service
callWithCustomClassLoader(wrapped.serviceInit(this.conf));
}
...
@Override
protected void serviceStart() throws Exception {
callWithCustomClassLoader(wrapped.serviceStart());
}
...
@Override
public void initializeApplication(ApplicationInitializationContext context) {
callWithCustomClassLoader(wrapper.initializeApplication(context));
}
...
private callWithCustomClassLoader(...) {
}
}
{code}
Then the only thing {{callWithCustomClassLoader()}} needs to deal with is
setting and unsetting the thread context classloader.
{quote}
In addition to wrapping aux-service API calls under a class-loader, wouldn't it
suffice to simply have NM make all aux-services API calls in a separate thread
whose ContextClassLoader is changed to be another custom one that resolves both
System classes as well as AuxServices classes?
{quote}
If you can dedicate a thread for each aux service, that can work too. However,
we need to ensure *all* calls to the aux services (*including* the
{{service*()}} methods) are made on those threads and not on any other thread.
I think that might make things more complicated than the other way around. The
{{callWithCustomClassLoader()}} method can be very simple. All it needs to do is
{code}
ClassLoader original = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(customClassLoader);
try {
// the code that is being wrapped
} finally {
Thread.currentThread().setContextClassLoader(original);
}
{code}
> Enable aux services to have their own custom classpath/jar file
> ---------------------------------------------------------------
>
> Key: YARN-4577
> URL: https://issues.apache.org/jira/browse/YARN-4577
> Project: Hadoop YARN
> Issue Type: Improvement
> Affects Versions: 2.8.0
> Reporter: Xuan Gong
> Assignee: Xuan Gong
> Attachments: YARN-4577.1.patch, YARN-4577.2.patch,
> YARN-4577.20160119.1.patch, YARN-4577.20160204.patch, YARN-4577.3.patch,
> YARN-4577.3.rebase.patch, YARN-4577.4.patch
>
>
> Right now, users have to add their jars to the NM classpath directly, thus
> put them on the system classloader. But if multiple versions of the plugin
> are present on the classpath, there is no control over which version actually
> gets loaded. Or if there are any conflicts between the dependencies
> introduced by the auxiliary service and the NM itself, they can break the NM,
> the auxiliary service, or both.
> The solution could be: to instantiate aux services using a classloader that
> is different from the system classloader.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)