/**
* Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.springsource.insight.plugin.files.tracker;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.springsource.insight.collection.test.OperationCollectionAspectTestSupport;
import com.springsource.insight.intercept.InterceptConfiguration;
import com.springsource.insight.intercept.operation.Operation;
import com.springsource.insight.plugin.files.tracker.AbstractFilesTrackerAspectSupport.CacheKey;
import com.springsource.insight.plugin.files.tracker.AbstractFilesTrackerAspectSupport.FilesCache;
import com.springsource.insight.util.StringUtil;
/**
*
*/
public abstract class FilesTrackerAspectTestSupport extends OperationCollectionAspectTestSupport {
protected FilesTrackerAspectTestSupport() {
super();
}
protected void assertFileTrackingOperation(Closeable instance, File file, String opcode, String mode) throws IOException {
assertFileTrackingOperation(instance, file.getAbsolutePath(), opcode, mode);
}
protected Operation assertFileTrackingOperation(Closeable instance, String filePath, String opcode, String mode) throws IOException {
try {
Operation op = getLastEntered();
assertNotNull("No operation extracted", op);
assertEquals("Mismatched operation type", FilesTrackerDefinitions.TYPE, op.getType());
assertEquals("Mismatched path", filePath, op.get(FilesTrackerDefinitions.PATH_ATTR, String.class));
assertEquals("Mismatched opcode", opcode, op.get(FilesTrackerDefinitions.OPTYPE_ATTR, String.class));
// we expect only the file path to be tracked
assertEquals("Tracking map too big", 1, AbstractFilesTrackerAspectSupport.trackedFilesMap.size());
assertTrue("Tracking map does not contain input path",
AbstractFilesTrackerAspectSupport.trackedFilesMap.containsValue(filePath));
if (!StringUtil.isEmpty(mode)) {
assertEquals("Mismatched mode", mode, op.get(FilesTrackerDefinitions.MODE_ATTR, String.class));
}
return op;
} finally {
instance.close();
// after close the tracked files map must be empty - this indirectly tests the closing aspect
Map<?, ?> trackingMap = AbstractFilesTrackerAspectSupport.trackedFilesMap;
assertTrue("Tracking map not empty for file=" + filePath + "[" + opcode + "/" + mode + "]: " + trackingMap, trackingMap.isEmpty());
}
}
protected void runSynchronizedAspectPerformance(FileAccessor accessor) {
for (int threads : new int[]{1, 4}) {
final Map<CacheKey, String> orgCache = AbstractFilesTrackerAspectSupport.trackedFilesMap;
try {
FilesCache cache = new FilesCache(5);
AbstractFilesTrackerAspectSupport.trackedFilesMap =
(threads > 1) ? Collections.synchronizedMap(cache) : cache;
runSynchronizedAspectPerformance(accessor, threads);
assertTrue("Tracking map not empty for threads=" + threads + ": " + cache, cache.isEmpty());
} finally {
AbstractFilesTrackerAspectSupport.trackedFilesMap = orgCache;
}
}
}
protected void runSynchronizedAspectPerformance(final FileAccessor accessor, int threads) {
final Runtime RUNTIME = Runtime.getRuntime();
System.out.println("-------------- Synchronized=" + (threads > 1) + " Threads: " + threads + " ------------------");
System.out.printf("%10s %20s %20s %20s", "Num. calls/th", "Duration (nano)", "Duration/th", "Used memory (B)");
System.out.println();
for (final int NUM_CALLS : new int[]{100, 1000, 2500}) {
Runnable runner = new Runnable() {
public void run() {
for (int cIndex = 0; cIndex < NUM_CALLS; cIndex++) {
try {
Closeable instance = accessor.createInstance();
instance.close();
} catch (Exception e) {
fail(e.getClass().getSimpleName() + " error while running multi-threaded test"
+ " at index=" + cIndex + " out of " + NUM_CALLS + " calls: " + e.getMessage());
}
}
InterceptConfiguration.getInstance().getFrameBuilder().dump();
}
};
ExecutorService exec = Executors.newFixedThreadPool(threads);
encourageGC();
List<Future<?>> futureList = new ArrayList<Future<?>>(threads);
long startTime = System.nanoTime(), startFree = RUNTIME.freeMemory();
for (int i = 0; i < threads; i++)
futureList.add(exec.submit(runner));
for (Future<?> f : futureList) {
try {
// see javadoc for ExecutorService#submit...
assertNullValue("Unexpected Future termination value", f.get());
} catch (Exception e) {
fail(e.getClass().getSimpleName() + " error while checking multi-threaded termination: " + e.getMessage());
}
}
long endTime = System.nanoTime(), endFree = RUNTIME.freeMemory();
System.out.printf("%10d %20d %20d %20d",
Integer.valueOf(NUM_CALLS), Long.valueOf(endTime - startTime),
Long.valueOf((endTime - startTime) / threads),
Long.valueOf(startFree - endFree));
System.out.println();
}
}
protected static interface FileAccessor {
Closeable createInstance() throws IOException;
}
}