Allow classPath to be modified at runtime

This commit is contained in:
mpilman 2019-04-02 11:56:40 -07:00
parent e19901186f
commit 371a41dbba
2 changed files with 76 additions and 0 deletions

View File

@ -22,6 +22,13 @@ package com.apple.foundationdb.testing;
import com.apple.foundationdb.Database;
import com.apple.foundationdb.FDB;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
@ -31,6 +38,7 @@ import java.util.concurrent.SynchronousQueue;
import java.util.Map;
public abstract class AbstractWorkload {
private static final Class[] parameters = new Class[]{URL.class};
protected WorkloadContext context;
private ThreadPoolExecutor executorService;
@ -99,4 +107,29 @@ public abstract class AbstractWorkload {
private native void setProcessID(long processID);
private native void sendVoid(long handle);
private native void sendBool(long handle, boolean value);
// Helper functions to add to the class path at Runtime - will be called
// from C++
private static void addFile(String s) throws IOException {
File f = new File(s);
addFile(f);
}
private static void addFile(File f) throws IOException {
addURL(f.toURI().toURL());
}
private static void addURL(URL u) throws IOException {
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class sysClass = URLClassLoader.class;
try {
Method method = sysClass.getDeclaredMethod("addURL", parameters);
method.setAccessible(true);
method.invoke(sysLoader, new Object[]{u});
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}
}
}

View File

@ -96,6 +96,7 @@ struct JVMContext {
// this is a bit ugly - but JNINativeMethod requires
// char* not const char *
std::vector<char*> charArrays;
std::set<std::string> classPath;
void setWorkloadMethods(const std::initializer_list<std::tuple<StringRef, StringRef, void*>>& methods) {
charArrays.reserve(charArrays.size() + 2*methods.size());
@ -175,6 +176,30 @@ struct JVMContext {
flushTraceFileVoid();
}
bool addToClassPath(const std::string& path) {
TraceEvent("TryAddToClassPath")
.detail("Path", "path");
flushTraceFileVoid();
if (!success) {
return false;
}
if (classPath.count(path) > 0) {
// already added
return true;
}
auto addFileMethod = env->GetStaticMethodID(workloadClass, "addFile", "(Ljava/lang/String;)V");
if (!checkException()) {
return false;
}
auto p = env->NewStringUTF(path.c_str());
env->CallStaticVoidMethod(workloadClass, addFileMethod, p);
if (!checkException()) {
return false;
}
classPath.insert(path);
return true;
}
bool checkException() {
auto flag = env->ExceptionCheck();
if (flag) {
@ -261,6 +286,7 @@ struct JavaWorkload : TestWorkload {
// This means, that we have to share the VM across workloads.
static std::weak_ptr<JVMContext> globalVM;
std::shared_ptr<JVMContext> vm;
std::vector<std::string> classPath;
std::string className;
@ -275,6 +301,7 @@ struct JavaWorkload : TestWorkload {
return;
}
auto jvmOptions = getOption(options, LiteralStringRef("jvmOptions"), std::vector<std::string>{});
classPath = getOption(options, LiteralStringRef("classPath"), std::vector<std::string>{});
vm = globalVM.lock();
if (!vm) {
std::vector<char*> args;
@ -292,6 +319,8 @@ struct JavaWorkload : TestWorkload {
success = vm->success;
}
if (success) {
TraceEvent("JVMRunning");
flushTraceFileVoid();
try {
createContext();
} catch (Error& e) {
@ -332,6 +361,19 @@ struct JavaWorkload : TestWorkload {
}
void createContext() {
TraceEvent("AddClassPaths")
.detail("Num", classPath.size());
flushTraceFileVoid();
for (const auto& p : classPath) {
if (!vm->addToClassPath(p)) {
TraceEvent("AddToClassPathFailed")
.detail("Path", p);
success = false;
return;
}
TraceEvent("AddToClassPath")
.detail("Path", p);
}
std::transform(className.begin(), className.end(), className.begin(), [](char c) {
if (c == '.') return '/';
return c;
@ -379,6 +421,7 @@ struct JavaWorkload : TestWorkload {
vm->env->CallVoidMethod(hashMap, put, key, value);
vm->env->DeleteLocalRef(key);
vm->env->DeleteLocalRef(value);
kv.value = LiteralStringRef("");
}
auto workloadContextClass = findClass("com/apple/foundationdb/testing/WorkloadContext");
auto workloadContextConstructor = getMethodID(workloadContextClass, "<init>", "(Ljava/util/Map;IIJJ)V");