filebot/source/net/filebot/CacheManager.java

170 lines
4.7 KiB
Java
Raw Normal View History

2016-03-06 13:11:30 -05:00
package net.filebot;
import static net.filebot.Logging.*;
import static net.filebot.Settings.*;
import static net.filebot.util.FileUtilities.*;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.nio.file.StandardOpenOption;
import java.util.Scanner;
import java.util.logging.Level;
2016-03-06 13:11:30 -05:00
import net.sf.ehcache.CacheException;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.DiskStoreConfiguration;
public class CacheManager {
private static final CacheManager instance = new CacheManager();
public static CacheManager getInstance() {
return instance;
}
private final net.sf.ehcache.CacheManager manager;
public CacheManager() {
try {
this.manager = net.sf.ehcache.CacheManager.create(getConfiguration());
} catch (IOException e) {
throw new CacheException(e);
}
}
public synchronized Cache getCache(String name, CacheType type) {
2016-03-07 18:56:32 -05:00
String cacheName = name.toLowerCase() + "_" + type.ordinal();
2016-03-06 13:11:30 -05:00
if (!manager.cacheExists(cacheName)) {
debug.config("Create cache: " + cacheName);
manager.addCache(new net.sf.ehcache.Cache(type.getConfiguration(cacheName)));
}
return new Cache(manager.getCache(cacheName));
}
public synchronized void clearAll() {
2016-03-06 13:11:30 -05:00
manager.clearAll();
manager.removeAllCaches();
// clear all caches that have not been added yet
clearDiskStore(new File(manager.getConfiguration().getDiskStoreConfiguration().getPath()));
2016-03-06 13:11:30 -05:00
}
public synchronized void shutdown() {
manager.shutdown();
}
2016-03-06 13:11:30 -05:00
private Configuration getConfiguration() throws IOException {
Configuration config = new Configuration();
config.addDiskStore(getDiskStoreConfiguration());
return config;
}
private void clearDiskStore(File cache) {
getChildren(cache).stream().filter(f -> f.isFile() && !f.getName().startsWith(".")).forEach(f -> {
if (!delete(f)) {
debug.warning(format("Failed to delete cache: %s", f.getName()));
}
});
}
2016-03-06 13:11:30 -05:00
private DiskStoreConfiguration getDiskStoreConfiguration() throws IOException {
// prepare cache folder for this application instance
File cacheRoot = getApplicationCache().getCanonicalFile();
for (int i = 0; i < 10; i++) {
2016-03-06 13:11:30 -05:00
File cache = new File(cacheRoot, Integer.toString(i));
// make sure cache is readable and writable
createFolders(cache);
final File lockFile = new File(cache, ".lock");
boolean isNewCache = !lockFile.exists();
final FileChannel channel = FileChannel.open(lockFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
final FileLock lock = channel.tryLock();
if (lock != null) {
debug.config(format("Using persistent disk cache %s", cache));
int applicationRevision = getApplicationRevisionNumber();
int cacheRevision = 0;
try {
cacheRevision = new Scanner(channel, "UTF-8").nextInt();
} catch (Exception e) {
// ignore
}
if (cacheRevision != applicationRevision && applicationRevision > 0 && !isNewCache) {
2016-03-08 08:06:07 -05:00
debug.config(format("Current application version (r%d) does not match cache version (r%d): reset cache", applicationRevision, cacheRevision));
2016-03-06 13:11:30 -05:00
// tag cache with new revision number
isNewCache = true;
// delete all files related to previous cache instances
clearDiskStore(cache);
2016-03-06 13:11:30 -05:00
}
// TODO: use UTF8
2016-03-06 13:11:30 -05:00
if (isNewCache) {
// set new cache revision
channel.position(0);
channel.write(Charset.forName("UTF-8").encode(String.valueOf(applicationRevision)));
channel.truncate(channel.position());
}
// make sure to orderly shutdown cache
Runtime.getRuntime().addShutdownHook(new ShutdownHook(this, channel, lock));
2016-03-06 13:11:30 -05:00
// cache for this application instance is successfully set up and locked
return new DiskStoreConfiguration().path(cache.getPath());
}
// try next lock file
channel.close();
}
// serious error, abort
throw new IOException("Unable to acquire cache lock: " + cacheRoot);
}
private static class ShutdownHook extends Thread {
private final CacheManager manager;
private final FileChannel channel;
private final FileLock lock;
public ShutdownHook(CacheManager manager, FileChannel channel, FileLock lock) {
this.manager = manager;
this.channel = channel;
this.lock = lock;
}
@Override
public void run() {
try {
manager.shutdown();
} catch (Exception e) {
debug.log(Level.WARNING, "Shutdown hook failed: shutdown", e);
}
try {
lock.release();
} catch (Exception e) {
debug.log(Level.WARNING, "Shutdown hook failed: release", e);
}
try {
channel.close();
} catch (Exception e) {
debug.log(Level.WARNING, "Shutdown hook failed: close", e);
}
}
2016-03-06 13:11:30 -05:00
}
}