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.Database;
import com.apple.foundationdb.FDB; 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.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
@ -31,6 +38,7 @@ import java.util.concurrent.SynchronousQueue;
import java.util.Map; import java.util.Map;
public abstract class AbstractWorkload { public abstract class AbstractWorkload {
private static final Class[] parameters = new Class[]{URL.class};
protected WorkloadContext context; protected WorkloadContext context;
private ThreadPoolExecutor executorService; private ThreadPoolExecutor executorService;
@ -99,4 +107,29 @@ public abstract class AbstractWorkload {
private native void setProcessID(long processID); private native void setProcessID(long processID);
private native void sendVoid(long handle); private native void sendVoid(long handle);
private native void sendBool(long handle, boolean value); 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 // this is a bit ugly - but JNINativeMethod requires
// char* not const char * // char* not const char *
std::vector<char*> charArrays; std::vector<char*> charArrays;
std::set<std::string> classPath;
void setWorkloadMethods(const std::initializer_list<std::tuple<StringRef, StringRef, void*>>& methods) { void setWorkloadMethods(const std::initializer_list<std::tuple<StringRef, StringRef, void*>>& methods) {
charArrays.reserve(charArrays.size() + 2*methods.size()); charArrays.reserve(charArrays.size() + 2*methods.size());
@ -175,6 +176,30 @@ struct JVMContext {
flushTraceFileVoid(); 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() { bool checkException() {
auto flag = env->ExceptionCheck(); auto flag = env->ExceptionCheck();
if (flag) { if (flag) {
@ -261,6 +286,7 @@ struct JavaWorkload : TestWorkload {
// This means, that we have to share the VM across workloads. // This means, that we have to share the VM across workloads.
static std::weak_ptr<JVMContext> globalVM; static std::weak_ptr<JVMContext> globalVM;
std::shared_ptr<JVMContext> vm; std::shared_ptr<JVMContext> vm;
std::vector<std::string> classPath;
std::string className; std::string className;
@ -275,6 +301,7 @@ struct JavaWorkload : TestWorkload {
return; return;
} }
auto jvmOptions = getOption(options, LiteralStringRef("jvmOptions"), std::vector<std::string>{}); auto jvmOptions = getOption(options, LiteralStringRef("jvmOptions"), std::vector<std::string>{});
classPath = getOption(options, LiteralStringRef("classPath"), std::vector<std::string>{});
vm = globalVM.lock(); vm = globalVM.lock();
if (!vm) { if (!vm) {
std::vector<char*> args; std::vector<char*> args;
@ -292,6 +319,8 @@ struct JavaWorkload : TestWorkload {
success = vm->success; success = vm->success;
} }
if (success) { if (success) {
TraceEvent("JVMRunning");
flushTraceFileVoid();
try { try {
createContext(); createContext();
} catch (Error& e) { } catch (Error& e) {
@ -332,6 +361,19 @@ struct JavaWorkload : TestWorkload {
} }
void createContext() { 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) { std::transform(className.begin(), className.end(), className.begin(), [](char c) {
if (c == '.') return '/'; if (c == '.') return '/';
return c; return c;
@ -379,6 +421,7 @@ struct JavaWorkload : TestWorkload {
vm->env->CallVoidMethod(hashMap, put, key, value); vm->env->CallVoidMethod(hashMap, put, key, value);
vm->env->DeleteLocalRef(key); vm->env->DeleteLocalRef(key);
vm->env->DeleteLocalRef(value); vm->env->DeleteLocalRef(value);
kv.value = LiteralStringRef("");
} }
auto workloadContextClass = findClass("com/apple/foundationdb/testing/WorkloadContext"); auto workloadContextClass = findClass("com/apple/foundationdb/testing/WorkloadContext");
auto workloadContextConstructor = getMethodID(workloadContextClass, "<init>", "(Ljava/util/Map;IIJJ)V"); auto workloadContextConstructor = getMethodID(workloadContextClass, "<init>", "(Ljava/util/Map;IIJJ)V");