HBASE-14548 Expand how table coprocessor jar and dependency path can be specified (Xiang Li)
This commit is contained in:
parent
496fd9837a
commit
632969787a
|
@ -18,6 +18,7 @@
|
|||
package org.apache.hadoop.hbase.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
@ -38,6 +39,8 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.apache.hadoop.fs.FileStatus;
|
||||
import org.apache.hadoop.fs.FileUtil;
|
||||
import org.apache.hadoop.hbase.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.io.IOUtils;
|
||||
|
||||
|
@ -142,7 +145,7 @@ public class CoprocessorClassLoader extends ClassLoaderBase {
|
|||
super(parent);
|
||||
}
|
||||
|
||||
private void init(Path path, String pathPrefix,
|
||||
private void init(Path pathPattern, String pathPrefix,
|
||||
Configuration conf) throws IOException {
|
||||
// Copy the jar to the local filesystem
|
||||
String parentDirStr =
|
||||
|
@ -160,7 +163,16 @@ public class CoprocessorClassLoader extends ClassLoaderBase {
|
|||
}
|
||||
}
|
||||
|
||||
FileSystem fs = path.getFileSystem(conf);
|
||||
FileSystem fs = pathPattern.getFileSystem(conf);
|
||||
Path pathPattern1 = fs.isDirectory(pathPattern) ?
|
||||
new Path(pathPattern, "*.jar") : pathPattern; // append "*.jar" if a directory is specified
|
||||
FileStatus[] fileStatuses = fs.globStatus(pathPattern1); // return all files that match the pattern
|
||||
if (fileStatuses == null || fileStatuses.length == 0) { // if no one matches
|
||||
throw new FileNotFoundException(pathPattern1.toString());
|
||||
} else {
|
||||
boolean validFileEncountered = false;
|
||||
for (Path path : FileUtil.stat2Paths(fileStatuses)) { // for each file that match the pattern
|
||||
if (fs.isFile(path)) { // only process files, skip for directories
|
||||
File dst = new File(parentDirStr, "." + pathPrefix + "."
|
||||
+ path.getName() + "." + System.currentTimeMillis() + ".jar");
|
||||
fs.copyToLocalFile(path, new Path(dst.toString()));
|
||||
|
@ -170,7 +182,7 @@ public class CoprocessorClassLoader extends ClassLoaderBase {
|
|||
|
||||
JarFile jarFile = new JarFile(dst.toString());
|
||||
try {
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
Enumeration<JarEntry> entries = jarFile.entries(); // get entries inside a jar file
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
Matcher m = libJarPattern.matcher(entry.getName());
|
||||
|
@ -188,6 +200,14 @@ public class CoprocessorClassLoader extends ClassLoaderBase {
|
|||
} finally {
|
||||
jarFile.close();
|
||||
}
|
||||
|
||||
validFileEncountered = true; // Set to true when encountering a file
|
||||
}
|
||||
}
|
||||
if (validFileEncountered == false) { // all items returned by globStatus() are directories
|
||||
throw new FileNotFoundException("No file found matching " + pathPattern1.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is used in unit test
|
||||
|
@ -227,7 +247,7 @@ public class CoprocessorClassLoader extends ClassLoaderBase {
|
|||
return cl;
|
||||
}
|
||||
|
||||
if (!pathStr.endsWith(".jar")) {
|
||||
if (path.getFileSystem(conf).isFile(path) && !pathStr.endsWith(".jar")) {
|
||||
throw new IOException(pathStr + ": not a jar file?");
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.util;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -109,4 +110,46 @@ public class TestCoprocessorClassLoader {
|
|||
}
|
||||
fail("Could not find the expected lib jar file");
|
||||
}
|
||||
|
||||
// HBASE-14548
|
||||
@Test
|
||||
public void testDirectoryAndWildcard() throws Exception {
|
||||
String testClassName = "TestClass";
|
||||
String dataTestDir = TEST_UTIL.getDataTestDir().toString();
|
||||
System.out.println(dataTestDir);
|
||||
String localDirContainingJar = ClassLoaderTestHelper.localDirPath(conf);
|
||||
ClassLoaderTestHelper.buildJar(dataTestDir, testClassName, null, localDirContainingJar);
|
||||
ClassLoader parent = TestCoprocessorClassLoader.class.getClassLoader();
|
||||
CoprocessorClassLoader.parentDirLockSet.clear(); // So that clean up can be triggered
|
||||
|
||||
CoprocessorClassLoader coprocessorClassLoader = null;
|
||||
Path testPath = null;
|
||||
|
||||
// Directory
|
||||
testPath = new Path(localDirContainingJar);
|
||||
coprocessorClassLoader = CoprocessorClassLoader.getClassLoader(testPath, parent, "113_1", conf);
|
||||
verifyCoprocessorClassLoader(coprocessorClassLoader, testClassName);
|
||||
|
||||
// Wildcard - *.jar
|
||||
testPath = new Path(localDirContainingJar, "*.jar");
|
||||
coprocessorClassLoader = CoprocessorClassLoader.getClassLoader(testPath, parent, "113_2", conf);
|
||||
verifyCoprocessorClassLoader(coprocessorClassLoader, testClassName);
|
||||
|
||||
// Wildcard - *.j*
|
||||
testPath = new Path(localDirContainingJar, "*.j*");
|
||||
coprocessorClassLoader = CoprocessorClassLoader.getClassLoader(testPath, parent, "113_3", conf);
|
||||
verifyCoprocessorClassLoader(coprocessorClassLoader, testClassName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the coprocessorClassLoader is not null and the expected class can be loaded successfully
|
||||
* @param coprocessorClassLoader the CoprocessorClassLoader to verify
|
||||
* @param className the expected class to be loaded by the coprocessorClassLoader
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private void verifyCoprocessorClassLoader(CoprocessorClassLoader coprocessorClassLoader, String className)
|
||||
throws ClassNotFoundException{
|
||||
assertNotNull("Classloader should be created and not null", coprocessorClassLoader);
|
||||
assertEquals(className, coprocessorClassLoader.loadClass(className).getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -320,7 +320,14 @@ The value contains four pieces of information which are separated by the pipe (`
|
|||
* File path: The jar file containing the Coprocessor implementation must be in a location where
|
||||
all region servers can read it. +
|
||||
You could copy the file onto the local disk on each region server, but it is recommended to store
|
||||
it in HDFS.
|
||||
it in HDFS. +
|
||||
https://issues.apache.org/jira/browse/HBASE-14548[HBASE-14548] allows a directory containing the jars
|
||||
or some wildcards to be specified, such as: hdfs://<namenode>:<port>/user/<hadoop-user>/ or
|
||||
hdfs://<namenode>:<port>/user/<hadoop-user>/*.jar. Please note that if a directory is specified,
|
||||
all jar files(.jar) directly in the directory are added,
|
||||
but it does not search files in the subtree rooted in the directory.
|
||||
And do not contain any wildcard if you would like to specify a directory.
|
||||
This enhancement applies to the ways of using the JAVA API as well.
|
||||
* Class name: The full class name of the Coprocessor.
|
||||
* Priority: An integer. The framework will determine the execution sequence of all configured
|
||||
observers registered at the same hook using priorities. This field can be left blank. In that
|
||||
|
|
Loading…
Reference in New Issue