提交 d09c9011 编写于 作者: C Chuansheng Lu 提交者: Jonathan Lu

[Misc] Fixed cross-tenant references from Javac

Summary:
- Javac code may be used to generate Java class dynamically, so have
  to be taken care of
- Fixed cross-tenant classloader hierarchy
- Isolated ZipFileIndexCache.sharedInstance

Test Plan: langtools/test/multi-tenant

Reviewed-by: yuleil, superajun-wsj

Issue: https://github.com/alibaba/dragonwell8/issues/84
上级 46423727
......@@ -25,6 +25,8 @@
package com.sun.tools.javac.file;
import com.alibaba.tenant.TenantContainer;
import com.alibaba.tenant.TenantGlobals;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.util.Context;
import java.io.File;
......@@ -34,6 +36,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipFile;
/** A cache for ZipFileIndex objects. */
......@@ -44,10 +47,17 @@ public class ZipFileIndexCache {
/** Get a shared instance of the cache. */
private static ZipFileIndexCache sharedInstance;
public synchronized static ZipFileIndexCache getSharedInstance() {
if (sharedInstance == null)
sharedInstance = new ZipFileIndexCache();
return sharedInstance;
// sharedInstance was shared by all TenantContainers and never cleared, which would cause HUGE memory footprint.
if (TenantGlobals.isDataIsolationEnabled() && TenantContainer.current() != null) {
return TenantContainer.current()
.getFieldValue(ZipFileIndexCache.class, "sharedInstance", ZipFileIndexCache::new);
} else {
if (sharedInstance == null)
sharedInstance = new ZipFileIndexCache();
return sharedInstance;
}
}
/** Get a context-specific instance of a cache. */
......
......@@ -25,6 +25,8 @@
package javax.tools;
import com.alibaba.tenant.TenantContainer;
import com.alibaba.tenant.TenantGlobals;
import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
......@@ -138,9 +140,14 @@ public class ToolProvider {
private static ToolProvider instance;
private static synchronized ToolProvider instance() {
if (instance == null)
instance = new ToolProvider();
return instance;
if (TenantGlobals.isDataIsolationEnabled() && TenantContainer.current() != null) {
return TenantContainer.current()
.getFieldValue(ToolProvider.class, "instance", ToolProvider::new);
} else {
if (instance == null)
instance = new ToolProvider();
return instance;
}
}
// Cache for tool classes.
......
/*
* @test
* @summary Test isolation of various static fields
* @run main/othervm -XX:+MultiTenant -XX:+TenantDataIsolation TestStaticFieldIsolation
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import com.alibaba.tenant.TenantConfiguration;
import com.alibaba.tenant.TenantContainer;
import com.alibaba.tenant.TenantException;
import javax.tools.ToolProvider;
public class TestStaticFieldIsolation {
public static void main(String[] args) throws TenantException {
TestStaticFieldIsolation test = new TestStaticFieldIsolation();
test.testIsolation_com_sun_tools_javac_file_ZipFileIndexCache_sharedInstance();
test.testIsolation_javax_tools_ToolProvider_getSystemJavaCompiler();
}
private void testIsolation_com_sun_tools_javac_file_ZipFileIndexCache_sharedInstance() throws TenantException {
// find the class
ClassLoader toolsLoader = ToolProvider.getSystemJavaCompiler().getClass().getClassLoader();
Class clazz[] = new Class[1];
try {
clazz[0] = toolsLoader.loadClass("com.sun.tools.javac.file.ZipFileIndexCache");
} catch (ClassNotFoundException e) {
e.printStackTrace();
fail();
} finally {
assertNotNull(clazz[0]);
}
Runnable task = () -> {
try {
Method f = clazz[0].getDeclaredMethod("getSharedInstance");
f.setAccessible(true);
f.invoke(null);
} catch (Throwable t) {
fail();
}
};
testStaticFieldIsolation(clazz[0], task, "sharedInstance");
}
private void testIsolation_javax_tools_ToolProvider_getSystemJavaCompiler() throws TenantException {
Runnable task = () -> {
try {
ToolProvider.getSystemJavaCompiler();
} catch (Throwable t) {
fail();
}
};
testStaticFieldIsolation(ToolProvider.class, task, "instance");
}
/**
* test isolation of {@code classKay}'s static field {@code fieldName}
* @param key The class contains target static field
* @param tenantTask Task to trigger the static filed isolation per tenant,
* which is stored in TenantContainer.tenantData
* @param fieldName Field name
* @throws TenantException
*/
private static <K> void testStaticFieldIsolation(K key, Runnable tenantTask, String fieldName)
throws TenantException {
TenantContainer tenant = createSimpleTenant();
assertNull(tenant.getFieldValue(key, fieldName));
// run twice to initialize field in ROOT and non-ROOT
tenant.run(tenantTask);
tenantTask.run();
Object isolatedFieldValue = tenant.getFieldValue(key, fieldName);
assertNotNull(isolatedFieldValue);
try {
Class clazz = null;
if (key instanceof Class) {
clazz = (Class)key;
} else {
clazz = key.getClass();
}
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Object rootValue = field.get(null);
assertTrue(rootValue != isolatedFieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
fail();
}
tenant.destroy();
}
// convenient static method to create a simple {@code TenantContainer} object
private static TenantContainer createSimpleTenant() {
TenantConfiguration config = new TenantConfiguration(1024, 64 * 1024 * 1024);
return TenantContainer.create(config);
}
private static void assertNull(Object o) {
if (o != null) {
throw new RuntimeException("assertNull failed!");
}
}
private static void assertNotNull(Object o) {
if (o == null) {
throw new RuntimeException("assertNotNull failed!");
}
}
private static void fail() { throw new RuntimeException("Failed!"); }
private static void assertTrue(Boolean b) {
if (!b.booleanValue()) {
throw new RuntimeException("assertTrue failed!");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册