[ 
https://issues.apache.org/jira/browse/DRILL-4726?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15469088#comment-15469088
 ] 

ASF GitHub Bot commented on DRILL-4726:
---------------------------------------

Github user paul-rogers commented on a diff in the pull request:

    https://github.com/apache/drill/pull/574#discussion_r77743650
  
    --- Diff: 
exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/FunctionImplementationRegistry.java
 ---
    @@ -186,4 +226,105 @@ public boolean isFunctionComplexOutput(String name) {
         return false;
       }
     
    +  public RemoteFunctionRegistry getRemoteFunctionRegistry() {
    +    return remoteFunctionRegistry;
    +  }
    +
    +  public List<Func> validate(Path path) throws IOException {
    +    URL url = path.toUri().toURL();
    +    URL[] urls = {url};
    +    ClassLoader classLoader = new URLClassLoader(urls);
    +    return drillFuncRegistry.validate(path.getName(), scan(classLoader, 
path, urls));
    +  }
    +
    +  public void register(String jarName, ScanResult classpathScan, 
ClassLoader classLoader) {
    +    drillFuncRegistry.register(jarName, classpathScan, classLoader);
    +  }
    +
    +  public void unregister(String jarName) {
    +    drillFuncRegistry.unregister(jarName);
    +  }
    +
    +  /**
    +   * Loads all missing functions from remote registry.
    +   * Compares list of already registered jars and remote jars, loads 
missing jars.
    +   * Missing jars are stores in local DRILL_UDF_DIR.
    +   *
    +   * @return true if at least functions from one jar were loaded
    +   */
    +  public boolean loadRemoteFunctions() {
    +    List<String> missingJars = Lists.newArrayList();
    +    Registry registry = remoteFunctionRegistry.getRegistry();
    +
    +    List<String> localJars = drillFuncRegistry.getAllJarNames();
    +    for (Jar jar : registry.getJarList()) {
    +      if (!localJars.contains(jar.getName())) {
    +        missingJars.add(jar.getName());
    +      }
    +    }
    +
    +    for (String jarName : missingJars) {
    +      try {
    +        Path localUdfArea = new Path(new File(getUdfDir()).toURI());
    +        Path registryArea = remoteFunctionRegistry.getRegistryArea();
    +        FileSystem fs = remoteFunctionRegistry.getFs();
    +
    +        String sourceName = JarUtil.getSourceName(jarName);
    +
    +        Path remoteBinary = new Path(registryArea, jarName);
    +        Path remoteSource = new Path(registryArea, sourceName);
    +
    +        Path binary = new Path(localUdfArea, jarName);
    +        Path source = new Path(localUdfArea, sourceName);
    +
    +        fs.copyToLocalFile(remoteBinary, binary);
    +        fs.copyToLocalFile(remoteSource, source);
    +
    +        URL[] urls = {binary.toUri().toURL(), source.toUri().toURL()};
    +        ClassLoader classLoader = new URLClassLoader(urls);
    +        ScanResult scanResult = scan(classLoader, binary, urls);
    +        drillFuncRegistry.register(jarName, scanResult, classLoader);
    +      } catch (IOException | FunctionValidationException e) {
    +        logger.error("Problem during remote functions load from {}", 
jarName, e);
    +      }
    +    }
    +
    +    return missingJars.size() > 0;
    +  }
    +
    +  private ScanResult scan(ClassLoader classLoader, Path path, URL[] urls) 
throws IOException {
    +    Enumeration<URL> e = 
classLoader.getResources(CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME);
    +    while (e.hasMoreElements()) {
    +      URL res = e.nextElement();
    +      if (res.getPath().contains(path.toUri().getPath())) {
    +        DrillConfig drillConfig = 
DrillConfig.create(ConfigFactory.parseURL(res));
    +        return RunTimeScan.dynamicPackageScan(drillConfig, 
Sets.newHashSet(urls));
    +      }
    +    }
    +    throw new FunctionValidationException(String.format("Marker file %s is 
missing in %s.",
    +        CommonConstants.DRILL_JAR_MARKER_FILE_RESOURCE_PATHNAME, 
path.getName()));
    +  }
    +
    +  private static String getUdfDir() {
    +    return Preconditions.checkNotNull(System.getenv("DRILL_UDF_DIR"), 
"DRILL_UDF_DIR variable is not set");
    +  }
    +
    +  /**
    +   * Fires when jar name is submitted for unregistration.
    +   * Will unregister all functions associated with the jar name
    +   * and delete binary and source associated with the jar from local 
DRILL_UDF_DIR.
    +   */
    +  public class UnregistrationListener implements TransientStoreListener {
    +
    +    @Override
    +    public void onChange(TransientStoreEvent event) {
    +        String jarName = (String) event.getValue();
    +        String sourceName = JarUtil.getSourceName(jarName);
    +        String localDir = getUdfDir();
    +        FileUtils.deleteQuietly(new File(localDir, jarName));
    +        FileUtils.deleteQuietly(new File(localDir, sourceName));
    +        drillFuncRegistry.unregister(jarName);
    --- End diff --
    
    Race condition. We delete the jars before we unregister. Another thread can 
check the registry, then look for the jars, and not find them. Is 
synchronization needed here?


> Dynamic UDFs support
> --------------------
>
>                 Key: DRILL-4726
>                 URL: https://issues.apache.org/jira/browse/DRILL-4726
>             Project: Apache Drill
>          Issue Type: New Feature
>    Affects Versions: 1.6.0
>            Reporter: Arina Ielchiieva
>            Assignee: Arina Ielchiieva
>             Fix For: Future
>
>
> Allow register UDFs without  restart of Drillbits.
> Design is described in document below:
> https://docs.google.com/document/d/1FfyJtWae5TLuyheHCfldYUpCdeIezR2RlNsrOTYyAB4/edit?usp=sharing
>  



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to