mirror of
https://github.com/mitb-archive/filebot
synced 2024-11-14 05:15:03 -05:00
176 lines
4.6 KiB
Java
176 lines
4.6 KiB
Java
package net.filebot;
|
|
|
|
import static java.nio.charset.StandardCharsets.*;
|
|
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.file.StandardOpenOption;
|
|
import java.util.Scanner;
|
|
import java.util.logging.Level;
|
|
|
|
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 File diskStore;
|
|
private final net.sf.ehcache.CacheManager manager;
|
|
|
|
public CacheManager() {
|
|
try {
|
|
this.diskStore = acquireDiskStore();
|
|
this.manager = net.sf.ehcache.CacheManager.create(new Configuration().diskStore(new DiskStoreConfiguration().path(diskStore.getPath())));
|
|
} catch (IOException e) {
|
|
throw new CacheException(e);
|
|
}
|
|
}
|
|
|
|
public synchronized Cache getCache(String name, CacheType type) {
|
|
if (!manager.cacheExists(name)) {
|
|
manager.addCache(new net.sf.ehcache.Cache(type.getConfiguration(name)));
|
|
}
|
|
return new Cache(manager.getCache(name), type);
|
|
}
|
|
|
|
public void flushAll() {
|
|
for (String n : manager.getCacheNames()) {
|
|
try {
|
|
manager.getCache(n).flush();
|
|
} catch (Exception e) {
|
|
debug.warning(e::toString);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void clearAll() {
|
|
for (String n : manager.getCacheNames()) {
|
|
try {
|
|
manager.getCache(n).removeAll();
|
|
} catch (Exception e) {
|
|
debug.warning(e::toString);
|
|
}
|
|
}
|
|
}
|
|
|
|
public synchronized void shutdown() {
|
|
manager.shutdown();
|
|
}
|
|
|
|
private void clearDiskStore(File cache) {
|
|
getChildren(cache, FILES).stream().filter(f -> !f.getName().startsWith(".")).forEach(f -> {
|
|
try {
|
|
delete(f);
|
|
} catch (Exception e) {
|
|
debug.warning(format("Failed to delete cache: %s => %s", f, e));
|
|
}
|
|
});
|
|
}
|
|
|
|
private File acquireDiskStore() throws IOException {
|
|
for (int i = 0; i < 10; i++) {
|
|
File cache = ApplicationFolder.Cache.resolve(String.valueOf(i));
|
|
|
|
// make sure cache is readable and writable
|
|
createFolders(cache);
|
|
|
|
File lockFile = new File(cache, ".lock");
|
|
boolean isNewCache = !lockFile.exists();
|
|
|
|
FileChannel channel = FileChannel.open(lockFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
|
|
FileLock lock = channel.tryLock();
|
|
|
|
if (lock != null) {
|
|
debug.fine(format("Using persistent disk cache %s", cache));
|
|
|
|
int applicationRevision = getApplicationRevisionNumber();
|
|
int cacheRevision = 0;
|
|
|
|
if (channel.size() > 0) {
|
|
try {
|
|
cacheRevision = new Scanner(channel, "UTF-8").nextInt();
|
|
} catch (Exception e) {
|
|
debug.log(Level.WARNING, e, e::toString);
|
|
}
|
|
}
|
|
|
|
if (cacheRevision != applicationRevision && applicationRevision > 0 && !isNewCache) {
|
|
debug.warning(format("Current application revision (r%d) does not match cache revision (r%d): reset cache", applicationRevision, cacheRevision));
|
|
|
|
// tag cache with new revision number
|
|
isNewCache = true;
|
|
|
|
// delete all files related to previous cache instances
|
|
clearDiskStore(cache);
|
|
}
|
|
|
|
if (isNewCache) {
|
|
// set new cache revision
|
|
channel.position(0);
|
|
channel.write(UTF_8.encode(String.valueOf(applicationRevision)));
|
|
channel.truncate(channel.position());
|
|
}
|
|
|
|
// make sure to orderly shutdown cache
|
|
Runtime.getRuntime().addShutdownHook(new ShutdownHook(this, channel, lock));
|
|
|
|
// cache for this application instance is successfully set up and locked
|
|
return cache;
|
|
}
|
|
|
|
// try next lock file
|
|
channel.close();
|
|
}
|
|
|
|
// serious error, abort
|
|
throw new IOException("Unable to acquire cache lock: " + ApplicationFolder.Cache.get().getAbsolutePath());
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|