Browse Source

Couple of basic tests for the repository optimizations

tags/V1_9_8
Andy Clement 2 years ago
parent
commit
3227aad604

+ 21
- 16
bcel-builder/src/main/java/org/aspectj/apache/bcel/util/ClassLoaderRepository.java View File

@@ -94,16 +94,17 @@ public class ClassLoaderRepository implements Repository {
// For fast translation of the classname *intentionally not static*
private SoftHashMap /* <String,URL> */nameMap = new SoftHashMap(new HashMap(), false);

public static boolean useSharedCache = System.getProperty("org.aspectj.apache.bcel.useSharedCache", "true").equalsIgnoreCase("true");
public static boolean useSharedCache =
System.getProperty("org.aspectj.apache.bcel.useSharedCache", "true").equalsIgnoreCase("true");

//Cache not found classes as well to prevent unnecessary file I/O operations
public static final boolean useUnavailableClassesCache =
// Cache not found classes as well to prevent unnecessary file I/O operations
public static boolean useUnavailableClassesCache =
System.getProperty("org.aspectj.apache.bcel.useUnavailableClassesCache", "false").equalsIgnoreCase("true");
//Ignore cache clear requests to not build up the cache over and over again
public static final boolean ignoreCacheClearRequests =
// Ignore cache clear requests to not build up the cache over and over again
public static boolean ignoreCacheClearRequests =
System.getProperty("org.aspectj.apache.bcel.ignoreCacheClearRequests", "false").equalsIgnoreCase("true");

//Second cache for the unavailable classes
// Second cache for the unavailable classes
private static Set<String> unavailableClasses = new HashSet<String>();

private static int cacheHitsShared = 0;
@@ -113,6 +114,7 @@ public class ClassLoaderRepository implements Repository {
private int classesLoadedCount = 0;
private int misses = 0;
private int cacheHitsLocal = 0;
private int unavailableClassesCacheHits = 0;
private int missLocalEvicted = 0; // Misses in local cache access due to reference GC

public ClassLoaderRepository(java.lang.ClassLoader loader) {
@@ -290,26 +292,26 @@ public class ClassLoaderRepository implements Repository {
}

/**
* Lookup a JavaClass object from the Class Name provided.
* Lookup a JavaClass object from the classname provided.
*/
public JavaClass loadClass(String className) throws ClassNotFoundException {
//Quick evaluation of unavailable classes to prevent unnecessary file I/O
if (useUnavailableClassesCache && unavailableClasses.contains(className))
// Quick evaluation of unavailable classes to prevent unnecessary file I/O
if (useUnavailableClassesCache && unavailableClasses.contains(className)) {
unavailableClassesCacheHits++;
throw new ClassNotFoundException(className + " not found.");
}

// translate to a URL
long time = System.currentTimeMillis();
java.net.URL url = toURL(className);
timeManipulatingURLs += (System.currentTimeMillis() - time);
if (url == null) {
if (useUnavailableClassesCache)
if (useUnavailableClassesCache) {
unavailableClasses.add(className);
}
throw new ClassNotFoundException(className + " not found - unable to determine URL");
}

JavaClass clazz = null;

// Look in the appropriate cache
if (useSharedCache) {
clazz = findClassShared(url);
@@ -386,7 +388,7 @@ public class ClassLoaderRepository implements Repository {
*/
public long[] reportStats() {
return new long[] { timeSpentLoading, timeManipulatingURLs, classesLoadedCount, cacheHitsShared, missSharedEvicted,
cacheHitsLocal, missLocalEvicted, sharedCache.size() };
cacheHitsLocal, missLocalEvicted, sharedCache.size(), unavailableClassesCacheHits };
}

/**
@@ -400,6 +402,7 @@ public class ClassLoaderRepository implements Repository {
cacheHitsShared = 0;
missSharedEvicted = 0;
missLocalEvicted = 0;
unavailableClassesCacheHits = 0;
misses = 0;
clear();
}
@@ -411,10 +414,12 @@ public class ClassLoaderRepository implements Repository {
/** Clear all entries from the local cache */
public void clear() {
if (!ignoreCacheClearRequests) {
if (useSharedCache)
if (useSharedCache) {
sharedCache.clear();
else
} else {
localCache.clear();
}
unavailableClasses.clear();
}
}


+ 84
- 0
bcel-builder/src/test/java/org/aspectj/apache/bcel/classfile/tests/ClassloaderRepositoryTest.java View File

@@ -10,6 +10,8 @@ import junit.framework.TestCase;

/*
* Tests create a simple classloader repository configuration and check sharing of information.
*
* @author Andy Clement
*/
public class ClassloaderRepositoryTest extends TestCase {

@@ -69,6 +71,88 @@ public class ClassloaderRepositoryTest extends TestCase {
}
}

// ClassLoaderRepository.ignoreCacheClearRequests
public void testIgnoreCacheClearRequests() throws Exception {
ClassLoaderRepository.useSharedCache = false;
try {
// the 'normal' flow with ignore in default of false
ClassLoaderRepository.ignoreCacheClearRequests = false;
try {
ClassLoaderRepository repository = setupRepository();
repository.loadClass("java.lang.String");
long localCacheHits = repository.reportStats()[5];
assertEquals(0, localCacheHits);
repository.clear();
repository.loadClass("java.lang.String");
localCacheHits = repository.reportStats()[5];
assertEquals(0, localCacheHits); // cache was cleared, so no hit
} finally {
ClassLoaderRepository.ignoreCacheClearRequests = false;
}
// with ignore cache clear turned on
ClassLoaderRepository.ignoreCacheClearRequests = true;
try {
ClassLoaderRepository repository = setupRepository();
repository.loadClass("java.lang.String");
long localCacheHits = repository.reportStats()[5];
assertEquals(0, localCacheHits);
repository.clear();
repository.loadClass("java.lang.String");
localCacheHits = repository.reportStats()[5];
assertEquals(1, localCacheHits);
} finally {
ClassLoaderRepository.ignoreCacheClearRequests = false;
}
} finally {
ClassLoaderRepository.useSharedCache = true;
}
}

// ClassLoaderRepository.useUnavailableClassesCache
public void testUnavailableClassesCache() throws Exception {
ClassLoaderRepository.useUnavailableClassesCache = false;
try {
ClassLoaderRepository repository = setupRepository();
attemptLoadThatWillFail(repository);
for (int i = 0; i < 1000; i++) {
attemptLoadThatWillFail(repository);
}
assertEquals(0, repository.reportStats()[8]);
} finally {
ClassLoaderRepository.useUnavailableClassesCache = false; // back to default
}
ClassLoaderRepository.useUnavailableClassesCache = true;
try {
ClassLoaderRepository repository = setupRepository();
assertNotNull(repository.loadClass("java.lang.String"));
attemptLoadThatWillFail(repository);
for (int i = 0; i < 1000; i++) {
attemptLoadThatWillFail(repository);
}
assertEquals(1000,repository.reportStats()[8]);
} finally {
ClassLoaderRepository.useUnavailableClassesCache = false;
}
// If checking the report stats for time spent manipulating URLs it will be massively reduced
}

private ClassLoaderRepository setupRepository() throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader res = new URLClassLoader(new URL[] {}, cl);
ClassLoaderRepository rep = new ClassLoaderRepository(res);
return rep;
}

private void attemptLoadThatWillFail(ClassLoaderRepository repository) {
try {
repository.loadClass("this.is.made.up");
throw new IllegalStateException("Should not have found 'this.is.made.up'");
} catch (ClassNotFoundException cnfe) {
// ... expected ...
}
}

public void tearDown() throws Exception {
super.tearDown();
System.err.println("Rep1: "+rep1.reportStats());

+ 14
- 12
weaver/src/main/java/org/aspectj/weaver/reflect/Java15AnnotationFinder.java View File

@@ -49,8 +49,8 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
private World world;
private static boolean useCachingClassLoaderRepository;

//Use single instance of Repository and ClassLoader
public static final boolean useSingleInstances =
// Use single instance of Repository and ClassLoader
public static boolean useSingleInstances =
System.getProperty("org.aspectj.apache.bcel.useSingleRepositoryInstance", "false").equalsIgnoreCase("true");

static {
@@ -66,24 +66,26 @@ public class Java15AnnotationFinder implements AnnotationFinder, ArgNameFinder {
}

public void setClassLoader(ClassLoader aLoader) {
//Set class loader ref
if (useSingleInstances && staticClassLoaderRef == null)
// Set class loader ref
if (useSingleInstances && staticClassLoaderRef == null) {
staticClassLoaderRef = new BcelWeakClassLoaderReference(aLoader);
else
} else {
this.classLoaderRef = new BcelWeakClassLoaderReference(aLoader);
}

//Set repository
// Set repository
if (useCachingClassLoaderRepository) {
if (useSingleInstances && staticBcelRepository == null)
if (useSingleInstances && staticBcelRepository == null) {
staticBcelRepository = new ClassLoaderRepository(getClassLoader());
else
} else {
this.bcelRepository = new ClassLoaderRepository(classLoaderRef);
}
else {
if (useSingleInstances && staticBcelRepository == null)
}
} else {
if (useSingleInstances && staticBcelRepository == null) {
staticBcelRepository = new NonCachingClassLoaderRepository(getClassLoader());
else
} else {
this.bcelRepository = new NonCachingClassLoaderRepository(classLoaderRef);
}
}
}


Loading…
Cancel
Save