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

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

Github user arina-ielchiieva commented on a diff in the pull request:

    https://github.com/apache/drill/pull/574#discussion_r78300858
  
    --- Diff: 
exec/java-exec/src/test/java/org/apache/drill/TestDynamicUDFSupport.java ---
    @@ -0,0 +1,292 @@
    +/**
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + * <p/>
    + * http://www.apache.org/licenses/LICENSE-2.0
    + * <p/>
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.drill;
    +
    +import mockit.NonStrictExpectations;
    +import org.apache.drill.common.config.DrillConfig;
    +import org.apache.drill.common.exceptions.UserRemoteException;
    +import org.apache.drill.common.util.TestTools;
    +import org.apache.drill.exec.ExecConstants;
    +import org.apache.drill.exec.expr.fn.RemoteFunctionRegistry;
    +import org.apache.drill.exec.proto.UserBitShared.Registry;
    +import org.apache.drill.exec.util.JarUtil;
    +import org.apache.hadoop.fs.FileSystem;
    +import org.apache.hadoop.fs.Path;
    +import org.junit.Before;
    +import org.junit.Rule;
    +import org.junit.Test;
    +import org.junit.rules.TemporaryFolder;
    +
    +import java.io.File;
    +import java.io.IOException;
    +import java.util.Properties;
    +
    +import static org.hamcrest.CoreMatchers.containsString;
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertThat;
    +import static org.junit.Assert.assertTrue;
    +
    +public class TestDynamicUDFSupport extends BaseTestQuery {
    +
    +  private static final File jars = new File(TestTools.getWorkingPath() + 
"/src/test/resources/jars");
    +  private static final String jName = "DrillUDF-1.0.jar";
    +  private static String sName = JarUtil.getSourceName(jName);
    +
    +  @Rule
    +  public final TemporaryFolder drillUdfDir = new TemporaryFolder();
    +
    +  @Rule
    +  public final TemporaryFolder base = new TemporaryFolder();
    +
    +  @Before
    +  public void setEnvVariables()
    +  {
    +    new NonStrictExpectations(System.class)
    +    {
    +      {
    +        invoke(System.class, "getenv", "DRILL_UDF_DIR");
    +        returns(drillUdfDir.getRoot().getPath());
    +      }
    +    };
    +  }
    +
    +  @Before
    +  public void setup() {
    +    String root = base.getRoot().getPath();
    +    if 
(!root.equals(getDrillbitContext().getConfig().getString(ExecConstants.UDF_DIRECTORY_STAGING)))
 {
    +    Properties overrideProps = new Properties();
    +      overrideProps.setProperty(ExecConstants.UDF_DIRECTORY_BASE, root);
    +      updateTestCluster(1, DrillConfig.create(overrideProps));
    +    }
    +  }
    +
    +  @Test
    +  public void testSyntax() throws Exception {
    +    test("create function using jar 'jar_name.jar'");
    +    test("drop function using jar 'jar_name.jar'");
    +  }
    +
    +  @Test
    +  public void testEnableDynamicSupport() throws Exception {
    +    try {
    +      test("alter system set `exec.udf.enable_dynamic_support` = true");
    +      test("create function using jar 'jar_name.jar'");
    +      test("drop function using jar 'jar_name.jar'");
    +    } finally {
    +      test("alter system reset `exec.udf.enable_dynamic_support`");
    +    }
    +  }
    +
    +  @Test
    +  public void testDisableDynamicSupport() throws Exception {
    +    try {
    +      test("alter system set `exec.udf.enable_dynamic_support` = false");
    +      String[] actions = new String[] {"create", "drop"};
    +      String query = "%s function using jar 'jar_name.jar'";
    +      for (String action : actions) {
    +        try {
    +          test(String.format(query, action));
    +        } catch (UserRemoteException e) {
    +          assertThat(e.getMessage(), containsString("Dynamic UDFs support 
is disabled."));
    +        }
    +      }
    +    } finally {
    +      test("alter system reset `exec.udf.enable_dynamic_support`");
    +    }
    +  }
    +
    +  @Test
    +  public void testAbsentJarInStaging() throws Exception {
    +    String jar = "jar_name.jar";
    +    String staging = 
getDrillbitContext().getRemoteFunctionRegistry().getStagingArea().toUri().getPath();
    +    String summary = String.format("Binary [%s] or source [%s-sources.jar] 
is absent in udf staging area [%s].", jar, jar.split("\\.")[0], staging);
    +
    +    testBuilder()
    +        .sqlQuery(String.format("create function using jar '%s'", jar))
    +        .unOrdered()
    +        .baselineColumns("ok", "summary")
    +        .baselineValues(false, summary)
    +        .go();
    +  }
    +
    +  @Test
    +  public void testSuccessfulCreate() throws Exception {
    +    copyJarsToStagingArea();
    +
    +    String summary = "The following UDFs in jar %s have been 
registered:\n" +
    +        "[name: \"custom_lower\"\n" +
    +        "major_type {\n" +
    +        "  minor_type: VARCHAR\n" +
    +        "  mode: REQUIRED\n" +
    +        "}\n" +
    +        "]";
    +
    +    testBuilder()
    +        .sqlQuery(String.format("create function using jar '%s'", jName))
    +        .unOrdered()
    +        .baselineColumns("ok", "summary")
    +        .baselineValues(true, String.format(summary, jName))
    +        .go();
    +
    +    RemoteFunctionRegistry remoteFunctionRegistry = 
getDrillbitContext().getRemoteFunctionRegistry();
    +    FileSystem fs = remoteFunctionRegistry.getFs();
    +
    +    assertFalse("Staging area should be empty", 
fs.listFiles(remoteFunctionRegistry.getStagingArea(), false).hasNext());
    +    assertFalse("Temporary area should be empty", 
fs.listFiles(remoteFunctionRegistry.getTmpArea(), false).hasNext());
    +
    +    assertTrue("Binary should be present in registry area", fs.exists(new 
Path(remoteFunctionRegistry.getRegistryArea(), jName)));
    +    assertTrue("Source should be present in registry area", fs.exists(new 
Path(remoteFunctionRegistry.getRegistryArea(), sName)));
    +
    +    Registry registry = remoteFunctionRegistry.getRegistry();
    +    assertEquals("Registry should contain one jar", 
registry.getJarList().size(), 1);
    +    assertEquals(registry.getJar(0).getName(), jName);
    +    test(String.format("drop function using jar '%s'", jName));
    +  }
    +
    +  @Test
    +  public void testDuplicatedJar() throws Exception {
    +    copyJarsToStagingArea();
    +    test(String.format("create function using jar '%s'", jName));
    +    copyJarsToStagingArea();
    +
    +    testBuilder()
    +        .sqlQuery(String.format("create function using jar '%s'", jName))
    +        .unOrdered()
    +        .baselineColumns("ok", "summary")
    +        .baselineValues(false, String.format("Jar with %s name has been 
already registered", jName))
    +        .go();
    +
    +    test(String.format("drop function using jar '%s'", jName));
    +  }
    +
    +  @Test
    +  public void testDuplicatedFunctions() throws Exception {
    +    copyJarsToStagingArea();
    +    test(String.format("create function using jar '%s'", jName));
    +    copyJarsToStagingArea();
    +
    +    RemoteFunctionRegistry remoteFunctionRegistry = 
getDrillbitContext().getRemoteFunctionRegistry();
    +    FileSystem fs = remoteFunctionRegistry.getFs();
    +    String newJar = "DrillUDF-2.0.jar";
    +    String newSource = JarUtil.getSourceName(newJar);
    +    Path renamedBinary = new Path(remoteFunctionRegistry.getStagingArea(), 
newJar);
    +    Path renamedSource = new Path(remoteFunctionRegistry.getStagingArea(), 
newSource);
    +    fs.rename(new Path(remoteFunctionRegistry.getStagingArea(), jName), 
renamedBinary);
    +    fs.rename(new Path(remoteFunctionRegistry.getStagingArea(), sName), 
renamedSource);
    +
    +    String summary = "Found duplicated function in %s - name: 
\"custom_lower\"\n" +
    +        "major_type {\n" +
    +        "  minor_type: VARCHAR\n" +
    +        "  mode: REQUIRED\n" +
    +        "}\n";
    +
    +    testBuilder()
    +        .sqlQuery(String.format("create function using jar '%s'", newJar))
    +        .unOrdered()
    +        .baselineColumns("ok", "summary")
    +        .baselineValues(false, String.format(summary, jName))
    +        .go();
    +
    +    fs.delete(renamedBinary, false);
    +    fs.delete(renamedSource, false);
    +    test(String.format("drop function using jar '%s'", jName));
    +  }
    +
    +  @Test
    +  public void testLazyInit() throws Exception {
    +    try {
    +      test("select custom_lower(version) from sys.version");
    +    } catch (UserRemoteException e){
    +      assertThat(e.getMessage(), containsString("No match found for 
function signature custom_lower(<CHARACTER>)"));
    +    }
    +
    +    copyJarsToStagingArea();
    +
    +    test(String.format("create function using jar '%s'", jName));
    +    test("select custom_lower(version) from sys.version");
    +
    +    assertTrue("Binary should be present in local UDF area", new 
File(System.getenv("DRILL_UDF_DIR"), jName).exists());
    +    assertTrue("Source should be present in local UDF area", new 
File(System.getenv("DRILL_UDF_DIR"), sName).exists());
    +    test(String.format("drop function using jar '%s'", jName));
    +  }
    +
    +  @Test
    +  public void testDropFunction() throws Exception {
    --- End diff --
    
    Speaking about test when user A registers a long-running query, user B 
deregisters the function and so on,
    I am not quite sure how to implement such tests, sure starting two threads 
at the same time is not a problem but guaranteeing that user B will do 
something then user A is doing other thing in Drill engine is quite difficult. 
    Dynamic UDFs documentation states that during UDF unregistration running 
queries may fail or finish successfully depending on which step of execution 
they were. We ask users to run unregistration only when they are sure that 
noone is using their function, otherwise some queries may fail (section 5.15 
Tradeoffs and Limitations).


> 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