mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
NEW: TempFileProvider will clean up files automatically if the reference is gc'ed
This commit is contained in:
@@ -378,6 +378,8 @@ public class DatabaseConfig {
|
||||
*/
|
||||
private Clock clock = Clock.systemUTC();
|
||||
|
||||
private TempFileProvider tempFileProvider = new WeakRefTempFileProvider();
|
||||
|
||||
private List<IdGenerator> idGenerators = new ArrayList<>();
|
||||
private List<BeanFindController> findControllers = new ArrayList<>();
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<>();
|
||||
@@ -545,6 +547,14 @@ public class DatabaseConfig {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public TempFileProvider getTempFileProvider() {
|
||||
return tempFileProvider;
|
||||
}
|
||||
|
||||
public void setTempFileProvider(final TempFileProvider tempFileProvider) {
|
||||
this.tempFileProvider = tempFileProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slow query time in millis.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* TempFileProvider implementation, which deletes all temp files on shutdown.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class DeleteOnShutdownTempFileProvider implements TempFileProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeleteOnShutdownTempFileProvider.class);
|
||||
|
||||
List<String> tempFiles = new ArrayList<>();
|
||||
private final String prefix;
|
||||
private final String suffix;
|
||||
private final File directory;
|
||||
|
||||
/**
|
||||
* Creates the TempFileProvider with default prefix "db-".
|
||||
*/
|
||||
public DeleteOnShutdownTempFileProvider() {
|
||||
this("db-", null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the TempFileProvider.
|
||||
*/
|
||||
public DeleteOnShutdownTempFileProvider(String prefix, String suffix, File directory) {
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createTempFile() throws IOException {
|
||||
File file = File.createTempFile(prefix, suffix, directory);
|
||||
synchronized (tempFiles) {
|
||||
tempFiles.add(file.getAbsolutePath());
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all created files on shutdown.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
synchronized (tempFiles) {
|
||||
for (String path : tempFiles) {
|
||||
if (new File(path).delete()) {
|
||||
logger.trace("deleted {}", path);
|
||||
} else {
|
||||
logger.warn("could not delete {}", path);
|
||||
}
|
||||
}
|
||||
tempFiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Creates a temp file for the ScalarTypeFile datatype.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public interface TempFileProvider {
|
||||
|
||||
/**
|
||||
* Creates a tempFile.
|
||||
*/
|
||||
File createTempFile() throws IOException;
|
||||
|
||||
/**
|
||||
* Shutdown the tempFileProvider.
|
||||
*/
|
||||
void shutdown();
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* WeakRefTempFileProvider will delete the tempFile if all references to the returned File
|
||||
* object are collected by the garbage collection.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*
|
||||
*/
|
||||
public class WeakRefTempFileProvider implements TempFileProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(WeakRefTempFileProvider.class);
|
||||
|
||||
private final ReferenceQueue<File> tempFiles = new ReferenceQueue<>();
|
||||
|
||||
private WeakFileReference root;
|
||||
|
||||
private final String prefix;
|
||||
private final String suffix;
|
||||
private final File directory;
|
||||
|
||||
/**
|
||||
* We hold a linkedList of weak references. So we can remove stale files in O(1)
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
private static class WeakFileReference extends WeakReference<File> {
|
||||
|
||||
String path;
|
||||
WeakFileReference prev;
|
||||
WeakFileReference next;
|
||||
|
||||
WeakFileReference(File referent, ReferenceQueue<? super File> q) {
|
||||
super(referent, q);
|
||||
path = referent.getAbsolutePath();
|
||||
}
|
||||
|
||||
boolean delete(boolean shutdown) {
|
||||
if (new File(path).delete()) {
|
||||
logger.trace("deleted {}", path);
|
||||
return true;
|
||||
} else {
|
||||
if (shutdown) {
|
||||
logger.warn("could not delete {}", path);
|
||||
} else {
|
||||
logger.info("could not delete {} - will delete on shutdown", path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the TempFileProvider with default prefix "db-".
|
||||
*/
|
||||
public WeakRefTempFileProvider() {
|
||||
this("db-", null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the TempFileProvider.
|
||||
*/
|
||||
public WeakRefTempFileProvider(String prefix, String suffix, File directory) {
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File createTempFile() throws IOException {
|
||||
File tempFile = File.createTempFile(prefix, suffix, directory);
|
||||
logger.trace("createTempFile: {}", tempFile);
|
||||
synchronized (this) {
|
||||
add(new WeakFileReference(tempFile, tempFiles));
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will delete stale files.
|
||||
* This is public to use in tests.
|
||||
*/
|
||||
public void deleteStaleTempFiles() {
|
||||
synchronized (this) {
|
||||
deleteStaleTempFilesInternal();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteStaleTempFilesInternal() {
|
||||
WeakFileReference ref;
|
||||
while ((ref = (WeakFileReference) tempFiles.poll()) != null) {
|
||||
if (ref.delete(false)) {
|
||||
remove(ref); // remove from linkedList only, if delete was successful.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(WeakFileReference ref) {
|
||||
deleteStaleTempFilesInternal();
|
||||
|
||||
if (root == null) {
|
||||
root = ref;
|
||||
} else {
|
||||
ref.next = root;
|
||||
root.prev = ref;
|
||||
root = ref;
|
||||
}
|
||||
}
|
||||
|
||||
private void remove(WeakFileReference ref) {
|
||||
if (ref.next != null) {
|
||||
ref.next.prev = ref.prev;
|
||||
}
|
||||
if (ref.prev != null) {
|
||||
ref.prev.next = ref.next;
|
||||
} else {
|
||||
root = ref.next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all created files on shutdown.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
while (root != null) {
|
||||
root.delete(true);
|
||||
root = root.next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user