org.aspectj.weaver.tools.cache.FlatFileCacheBacking Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/* *******************************************************************
* Copyright (c) 2012 VMware, Inc. custard
*
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* Lyor Goldstein
* ******************************************************************/
package org.aspectj.weaver.tools.cache;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StreamCorruptedException;
import java.util.Map;
import java.util.TreeMap;
import org.aspectj.util.FileUtil;
import org.aspectj.util.LangUtil;
/**
* Uses a "flat" files model to store the cached instrumented classes
* and aspects - i.e., each class/aspect is stored as a separate (binary)
* file. This is a good mechanism when the number of instrumented class is
* relatively small (a few 10's). The reason for it is that scanning a folder
* that has many files in it quickly becomes an I/O bottleneck. Also, some
* O/S-es may impose internal limits on the maximum number of "children"
* a folder node may have. On the other hand, it is much faster (again, for
* small number of instrumented classes) than the ZIP cache since each class/aspect
* is represented by a single file - thus adding/removing/modifying it is easier.
*
* @author Lyor Goldstein
*/
public class FlatFileCacheBacking extends AsynchronousFileCacheBacking {
private static final AsynchronousFileCacheBackingCreator defaultCreator=
new AsynchronousFileCacheBackingCreator() {
public FlatFileCacheBacking create(File cacheDir) {
return new FlatFileCacheBacking(cacheDir);
}
};
public FlatFileCacheBacking(File cacheDir) {
super(cacheDir);
}
public static final FlatFileCacheBacking createBacking (File cacheDir) {
return createBacking(cacheDir, defaultCreator);
}
@Override
protected Map readClassBytes(Map indexMap, File cacheDir) {
return readClassBytes(indexMap, cacheDir.listFiles());
}
protected Map readClassBytes (Map indexMap, File[] files) {
Map result= new TreeMap<>();
if (LangUtil.isEmpty(files)) {
return result;
}
for (File file : files) {
if (!file.isFile()) {
continue; // skip sub-directories - we expect flat files
}
String key=file.getName();
if (INDEX_FILE.equalsIgnoreCase(key)) {
continue; // skip the index itself if found
}
IndexEntry entry=indexMap.get(key);
if ((entry == null) || entry.ignored) { // if not in index or ignored then remove it
if ((logger != null) && logger.isTraceEnabled()) {
logger.info("readClassBytes(" + key + ") remove orphan/ignored: " + file.getAbsolutePath());
}
FileUtil.deleteContents(file);
continue;
}
try {
byte[] bytes=FileUtil.readAsByteArray(file);
long crc=crc(bytes);
if (crc != entry.crcWeaved) {
throw new StreamCorruptedException("Mismatched CRC - expected=" + entry.crcWeaved + "/got=" + crc);
}
result.put(key, bytes);
if ((logger != null) && logger.isTraceEnabled()) {
logger.debug("readClassBytes(" + key + ") cached from " + file.getAbsolutePath());
}
} catch(IOException e) {
if ((logger != null) && logger.isTraceEnabled()) {
logger.error("Failed (" + e.getClass().getSimpleName() + ")"
+ " to read bytes from " + file.getAbsolutePath()
+ ": " + e.getMessage());
}
indexMap.remove(key); // no need for the entry if no file - force a re-write of its bytes
FileUtil.deleteContents(file); // assume some kind of corruption
continue;
}
}
return result;
}
@Override
protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) {
File cacheEntry = new File(cacheDir, ie.key);
if (ie.ignored || cacheEntry.canRead()) {
return ie;
} else {
return null;
}
}
@Override
protected void writeClassBytes (String key, byte[] bytes) throws Exception {
File dir=getCacheDirectory(), file=new File(dir, key);
FileOutputStream out=new FileOutputStream(file);
try {
out.write(bytes);
} finally {
out.close();
}
}
@Override
protected void removeClassBytes (String key) throws Exception {
File dir=getCacheDirectory(), file=new File(dir, key);
if (file.exists() && (!file.delete())) {
throw new StreamCorruptedException("Failed to delete " + file.getAbsolutePath());
}
}
}