Index: hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java =================================================================== --- hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java (revision 1417228) +++ hbase-server/src/main/java/org/apache/hadoop/hbase/coprocessor/CoprocessorHost.java (working copy) @@ -19,8 +19,25 @@ package org.apache.hadoop.hbase.coprocessor; -import com.google.protobuf.Service; -import com.google.protobuf.ServiceException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.UUID; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience; @@ -33,23 +50,30 @@ import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HTableDescriptor; -import org.apache.hadoop.hbase.client.*; +import org.apache.hadoop.hbase.Server; +import org.apache.hadoop.hbase.client.Append; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.HTable; +import org.apache.hadoop.hbase.client.HTableInterface; +import org.apache.hadoop.hbase.client.Increment; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.Row; +import org.apache.hadoop.hbase.client.RowLock; +import org.apache.hadoop.hbase.client.RowMutations; +import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.coprocessor.Batch; import org.apache.hadoop.hbase.ipc.CoprocessorProtocol; import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.SortedCopyOnWriteSet; import org.apache.hadoop.hbase.util.VersionInfo; -import org.apache.hadoop.hbase.Server; import org.apache.hadoop.io.IOUtils; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.util.*; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; +import com.google.protobuf.Service; +import com.google.protobuf.ServiceException; /** * Provides the common setup framework and runtime services for coprocessor @@ -77,6 +101,9 @@ // unique file prefix to use for local copies of jars when classloading protected String pathPrefix; protected volatile int loadSequence; + // cache of CoprocessorClassLoader per path where implementation jar is located + protected static Map clsLoaderCache = + new HashMap(); public CoprocessorHost() { pathPrefix = UUID.randomUUID().toString(); @@ -180,49 +207,56 @@ if (path == null) { throw new IOException("No jar path specified for " + className); } - // copy the jar to the local filesystem - if (!path.toString().endsWith(".jar")) { - throw new IOException(path.toString() + ": not a jar file?"); - } - FileSystem fs = path.getFileSystem(HBaseConfiguration.create()); - Path dst = new Path(System.getProperty("java.io.tmpdir") + - java.io.File.separator +"." + pathPrefix + - "." + className + "." + System.currentTimeMillis() + ".jar"); - fs.copyToLocalFile(path, dst); - File tmpLocal = new File(dst.toString()); - tmpLocal.deleteOnExit(); - // TODO: code weaving goes here + CoprocessorClassLoader cl; + if (clsLoaderCache.containsKey(path)) { + cl = clsLoaderCache.get(path); + } else { + // copy the jar to the local filesystem + if (!path.toString().endsWith(".jar")) { + throw new IOException(path.toString() + ": not a jar file?"); + } + FileSystem fs = path.getFileSystem(HBaseConfiguration.create()); + Path dst = new Path(System.getProperty("java.io.tmpdir") + + java.io.File.separator +"." + pathPrefix + + "." + className + "." + System.currentTimeMillis() + ".jar"); + fs.copyToLocalFile(path, dst); + File tmpLocal = new File(dst.toString()); + tmpLocal.deleteOnExit(); - // TODO: wrap heap allocations and enforce maximum usage limits + // TODO: code weaving goes here - /* TODO: inject code into loop headers that monitors CPU use and - aborts runaway user code */ + // TODO: wrap heap allocations and enforce maximum usage limits - // load the jar and get the implementation main class - // NOTE: Path.toURL is deprecated (toURI instead) but the URLClassLoader - // unsurprisingly wants URLs, not URIs; so we will use the deprecated - // method which returns URLs for as long as it is available - List paths = new ArrayList(); - paths.add(new File(dst.toString()).getCanonicalFile().toURL()); + /* TODO: inject code into loop headers that monitors CPU use and + aborts runaway user code */ - JarFile jarFile = new JarFile(dst.toString()); - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - if (entry.getName().matches("/lib/[^/]+\\.jar")) { - File file = new File(System.getProperty("java.io.tmpdir") + - java.io.File.separator +"." + pathPrefix + - "." + className + "." + System.currentTimeMillis() + "." + entry.getName().substring(5)); - IOUtils.copyBytes(jarFile.getInputStream(entry), new FileOutputStream(file), conf, true); - file.deleteOnExit(); - paths.add(file.toURL()); + // load the jar and get the implementation main class + // NOTE: Path.toURL is deprecated (toURI instead) but the URLClassLoader + // unsurprisingly wants URLs, not URIs; so we will use the deprecated + // method which returns URLs for as long as it is available + List paths = new ArrayList(); + paths.add(new File(dst.toString()).getCanonicalFile().toURL()); + + JarFile jarFile = new JarFile(dst.toString()); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.getName().matches("/lib/[^/]+\\.jar")) { + File file = new File(System.getProperty("java.io.tmpdir") + + java.io.File.separator +"." + pathPrefix + + "." + className + "." + System.currentTimeMillis() + "." + entry.getName().substring(5)); + IOUtils.copyBytes(jarFile.getInputStream(entry), new FileOutputStream(file), conf, true); + file.deleteOnExit(); + paths.add(file.toURL()); + } } + jarFile.close(); + + cl = new CoprocessorClassLoader(paths, + this.getClass().getClassLoader()); + clsLoaderCache.put(path, cl); } - jarFile.close(); - - ClassLoader cl = new CoprocessorClassLoader(paths, - this.getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(cl); try { implClass = cl.loadClass(className);