Skip to content

Commit

Permalink
TempFileProvider base code
Browse files Browse the repository at this point in the history
WeakRef: Delete file
  • Loading branch information
jonasPoehler authored and rPraml committed Apr 26, 2023
1 parent 05e68e0 commit 344255f
Show file tree
Hide file tree
Showing 9 changed files with 438 additions and 13 deletions.
10 changes: 10 additions & 0 deletions ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,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<>();
Expand Down Expand Up @@ -569,6 +571,14 @@ public void setClock(final Clock clock) {
this.clock = clock;
}

public TempFileProvider getTempFileProvider() {
return tempFileProvider;
}

public void setTempFileProvider(final TempFileProvider tempFileProvider) {
this.tempFileProvider = tempFileProvider;
}

/**
* Return the slow query time in millis.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}

}
23 changes: 23 additions & 0 deletions ebean-api/src/main/java/io/ebean/config/TempFileProvider.java
Original file line number Diff line number Diff line change
@@ -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();
}
145 changes: 145 additions & 0 deletions ebean-api/src/main/java/io/ebean/config/WeakRefTempFileProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
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) {
File file = new File(path);
if (!file.exists()) {
logger.trace("already deleted {}", path);
return true;
} else if (file.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;
}
}

}
Loading

0 comments on commit 344255f

Please sign in to comment.