summaryrefslogtreecommitdiffstats
path: root/dozentenmodulserver
diff options
context:
space:
mode:
authorSimon Rettberg2015-08-22 17:29:15 +0200
committerSimon Rettberg2015-08-22 17:29:15 +0200
commit5b94675225077ed8c88f39d15279e920f267d954 (patch)
tree8b55ee6d7a8a881fe49695f23bc5234832a85031 /dozentenmodulserver
parent[client] synced image details fetching (diff)
downloadtutor-module-5b94675225077ed8c88f39d15279e920f267d954.tar.gz
tutor-module-5b94675225077ed8c88f39d15279e920f267d954.tar.xz
tutor-module-5b94675225077ed8c88f39d15279e920f267d954.zip
[server] Foundations for the maintenance module
Diffstat (limited to 'dozentenmodulserver')
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java96
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/models/LocalImageVersion.java5
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java4
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/DeleteOldImages.java46
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/Maintenance.java58
5 files changed, 190 insertions, 19 deletions
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
index 5a002e76..23a71228 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
@@ -110,14 +110,15 @@ public class DbImage {
public static LocalImageVersion getLocalImageData(String imageVersionId) throws TNotFoundException,
SQLException {
try (MysqlConnection connection = Database.getConnection()) {
- MysqlStatement stmt = connection.prepareStatement("SELECT imageversionid, imagebaseid, filepath, filesize, createtime, isvalid"
+ MysqlStatement stmt = connection.prepareStatement("SELECT"
+ + " imageversionid, imagebaseid, filepath, filesize, createtime, expiretime, isvalid"
+ " FROM imageversion WHERE imageversionid = :imageversionid");
stmt.setString("imageversionid", imageVersionId);
ResultSet rs = stmt.executeQuery();
if (!rs.next())
throw new TNotFoundException();
return new LocalImageVersion(rs.getString("imageversionid"), rs.getString("imagebaseid"),
- rs.getString("filepath"), rs.getLong("filesize"), rs.getLong("createtime"),
+ rs.getString("filepath"), rs.getLong("filesize"), rs.getLong("createtime"), rs.getLong("expiretime"),
rs.getBoolean("isvalid"));
} catch (SQLException e) {
LOGGER.error("Query failed in DbImage.getLocalImageData()", e);
@@ -127,19 +128,40 @@ public class DbImage {
protected static List<LocalImageVersion> getLocalImageVersions(MysqlConnection connection,
String imageBaseId) throws SQLException {
- MysqlStatement stmt = connection.prepareStatement("SELECT imageversionid, imagebaseid, filepath, filesize, createtime, isvalid"
+ MysqlStatement stmt = connection.prepareStatement("SELECT"
+ + " imageversionid, imagebaseid, filepath, filesize, createtime, expiretime, isvalid"
+ " FROM imageversion WHERE imagebaseid = :imagebaseid");
stmt.setString("imagebaseid", imageBaseId);
ResultSet rs = stmt.executeQuery();
List<LocalImageVersion> list = new ArrayList<>();
while (rs.next()) {
list.add(new LocalImageVersion(rs.getString("imageversionid"), rs.getString("imagebaseid"),
- rs.getString("filepath"), rs.getLong("filesize"), rs.getLong("createtime"),
+ rs.getString("filepath"), rs.getLong("filesize"), rs.getLong("createtime"), rs.getLong("expiretime"),
rs.getBoolean("isvalid")));
}
return list;
}
+ public static List<LocalImageVersion> getExpiringLocalImageVersions(int maxRemainingDays) throws SQLException {
+ try (MysqlConnection connection = Database.getConnection()) {
+ MysqlStatement stmt = connection.prepareStatement("SELECT"
+ + " imageversionid, imagebaseid, filepath, filesize, createtime, expiretime, isvalid"
+ + " FROM imageversion WHERE expiretime < :deadline");
+ stmt.setLong("deadline", (System.currentTimeMillis() / 1000) + (maxRemainingDays * 86400));
+ ResultSet rs = stmt.executeQuery();
+ List<LocalImageVersion> list = new ArrayList<>();
+ while (rs.next()) {
+ list.add(new LocalImageVersion(rs.getString("imageversionid"), rs.getString("imagebaseid"),
+ rs.getString("filepath"), rs.getLong("filesize"), rs.getLong("createtime"), rs.getLong("expiretime"),
+ rs.getBoolean("isvalid")));
+ }
+ return list;
+ } catch (SQLException e) {
+ LOGGER.error("Query failed in DbImage.getAllLocalImages()", e);
+ throw e;
+ }
+ }
+
/**
* Private helper to create an {@link ImageSummaryRead} instance from a
* {@link ResultSet}
@@ -418,7 +440,7 @@ public class DbImage {
LOGGER.error("Query failed in DbImage.markForDeletion()", e);
throw e;
}
- updateLatestVersionAsync(imageVersionId, null);
+ updateLatestVersionAsync(imageVersionId);
}
public static void setShareMode(String imageBaseId, ImageBaseWrite newData) throws SQLException {
@@ -474,39 +496,81 @@ public class DbImage {
}
}
- public static void markValid(MysqlConnection connection, LocalImageVersion imageVersion, boolean valid)
+ public static void markValid(MysqlConnection connection, boolean valid, LocalImageVersion... imageVersion)
throws SQLException {
+ if (imageVersion == null || imageVersion.length == 0)
+ return;
MysqlStatement stmt = connection.prepareStatement("UPDATE imageversion SET isvalid = :valid"
+ " WHERE imageversionid = :imageversionid");
- stmt.setString("imageversionid", imageVersion.imageVersionId);
- stmt.setBoolean("valid", valid);
- stmt.executeUpdate();
+ for (LocalImageVersion version : imageVersion) {
+ stmt.setString("imageversionid", version.imageVersionId);
+ stmt.setBoolean("valid", valid);
+ stmt.executeUpdate();
+ }
}
- public static void markValid(LocalImageVersion imageVersion, boolean valid) throws SQLException {
+ public static void markValid(boolean valid, boolean async, LocalImageVersion... imageVersion) throws SQLException {
+ if (imageVersion == null || imageVersion.length == 0)
+ return;
try (MysqlConnection connection = Database.getConnection()) {
- markValid(connection, imageVersion, valid);
+ markValid(connection, valid, imageVersion);
+ if (!async) {
+ updateLatestVersion(connection, imageVersion);
+ }
connection.commit();
} catch (SQLException e) {
LOGGER.error("Query failed in DbImage.markInvalid()", e);
throw e;
}
- updateLatestVersionAsync(imageVersion.imageVersionId, imageVersion.imageBaseId);
+ if (async) {
+ updateLatestVersionAsync(imageVersion);
+ }
+ }
+
+ private static void updateLatestVersionAsync(final LocalImageVersion... changingVersion) {
+ if (changingVersion == null || changingVersion.length == 0)
+ return;
+ QuickTimer.scheduleOnce(new Task() {
+ @Override
+ public void fire() {
+ try (MysqlConnection connection = Database.getConnection()) {
+ updateLatestVersion(connection, changingVersion);
+ connection.commit();
+ } catch (SQLException e) {
+ LOGGER.error("Query failed in DbImage.updateLatestVersionAsync()", e);
+ }
+ }
+ });
}
- private static void updateLatestVersionAsync(final String changingImageVersionId, final String imageBaseId) {
+ private static void updateLatestVersionAsync(final String changingImageVersionId) {
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
try (MysqlConnection connection = Database.getConnection()) {
- updateLatestVersion(connection, changingImageVersionId, imageBaseId);
+ updateLatestVersion(connection, changingImageVersionId, null);
connection.commit();
} catch (SQLException | TNotFoundException e) {
- LOGGER.error("Query failed in DbImage.updateLatestVersion()", e);
+ LOGGER.error("Query failed in DbImage.updateLatestVersionAsync()", e);
}
}
});
}
+
+ private static void updateLatestVersion(MysqlConnection connection,
+ LocalImageVersion... versions) throws
+ SQLException {
+ if (versions == null || versions.length == 0)
+ return;
+ for (LocalImageVersion version : versions) {
+ try {
+ updateLatestVersion(connection, version.imageVersionId,
+ version.imageBaseId);
+ } catch (TNotFoundException e) {
+ // Swallow - logging happens in called method
+ }
+ }
+ }
/**
* Makes sure the latestVersionId-field of the given base image is
@@ -540,7 +604,7 @@ public class DbImage {
if (versionFile.canRead() && versionFile.length() == version.fileSize) {
newVersion = version;
} else {
- markValid(connection, version, false);
+ markValid(connection, false, version);
}
}
}
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/models/LocalImageVersion.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/models/LocalImageVersion.java
index 875c46f3..238633fd 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/models/LocalImageVersion.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/models/LocalImageVersion.java
@@ -13,14 +13,17 @@ public class LocalImageVersion {
public final boolean isValid;
public final long createTime;
+
+ public final long expireTime;
public LocalImageVersion(String imageVersionId, String imageBaseId, String filePath, long fileSize,
- long createTime, boolean isValid) {
+ long createTime, long expireTime, boolean isValid) {
this.imageVersionId = imageVersionId;
this.imageBaseId = imageBaseId;
this.filePath = filePath;
this.fileSize = fileSize;
this.createTime = createTime;
+ this.expireTime = expireTime;
this.isValid = isValid;
}
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java
index bfa5699f..7d158459 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/fileserv/FileServer.java
@@ -195,7 +195,7 @@ public class FileServer implements IncomingEvent {
LOGGER.warn("Rejecting download of VID " + localImageData.imageVersionId + ": Missing "
+ srcFile.getPath());
try {
- DbImage.markValid(localImageData, false);
+ DbImage.markValid(false, true, localImageData);
} catch (SQLException e) {
}
throw new TTransferRejectedException("File missing on server");
@@ -205,7 +205,7 @@ public class FileServer implements IncomingEvent {
+ srcFile.getPath() + " (expected " + localImageData.fileSize + ", is "
+ srcFile.length() + ")");
try {
- DbImage.markValid(localImageData, false);
+ DbImage.markValid(false, true, localImageData);
} catch (SQLException e) {
}
throw new TTransferRejectedException("File corrupted on server");
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/DeleteOldImages.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/DeleteOldImages.java
new file mode 100644
index 00000000..90e7e80d
--- /dev/null
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/DeleteOldImages.java
@@ -0,0 +1,46 @@
+package org.openslx.bwlp.sat.maintenance;
+
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.openslx.bwlp.sat.database.mappers.DbImage;
+import org.openslx.bwlp.sat.database.models.LocalImageVersion;
+import org.openslx.bwlp.sat.fileserv.FileServer;
+
+/**
+ * Delete old image versions (images that reached their expire time).
+ */
+public class DeleteOldImages implements Runnable {
+
+ private static final Logger LOGGER = Logger.getLogger(DeleteOldImages.class);
+
+ @Override
+ public void run() {
+ List<LocalImageVersion> versions;
+ try {
+ versions = DbImage.getExpiringLocalImageVersions(0);
+ } catch (SQLException e) {
+ LOGGER.error("Will not be able to clean up old image versions");
+ return;
+ }
+ // Mark all as invalid. This will also trigger emails.
+ try {
+ DbImage.markValid(false, false, versions.toArray(new LocalImageVersion[versions.size()]));
+ } catch (SQLException e) {
+ LOGGER.error("Could not mark images to be deleted as invalid. Cleanup of old images failed.");
+ }
+ // Delete them permanently only if they expired (at least) one day ago
+ Set<String> deleteVersionIds = new HashSet<>();
+ final long hardDelete = (System.currentTimeMillis() / 1000) - 86400;
+ for (LocalImageVersion version : versions) {
+ if (version.expireTime < hardDelete) {
+ deleteVersionIds.add(version.imageVersionId);
+ FileServer.composeAbsolutePath(version).delete();
+ }
+ }
+ }
+
+}
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/Maintenance.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/Maintenance.java
new file mode 100644
index 00000000..98f7f09b
--- /dev/null
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/Maintenance.java
@@ -0,0 +1,58 @@
+package org.openslx.bwlp.sat.maintenance;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.log4j.Logger;
+
+public class Maintenance extends Thread {
+
+ private static final Logger LOGGER = Logger.getLogger(Maintenance.class);
+
+ private static Maintenance worker = null;
+
+ private static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(50);
+
+ private Maintenance() {
+ }
+
+ private synchronized static void ensureRunning() {
+ if (worker == null || !worker.isAlive()) {
+ worker = new Maintenance();
+ worker.start();
+ }
+ }
+
+ public static void submit(Runnable job) throws InterruptedException {
+ ensureRunning();
+ queue.put(job);
+ }
+
+ public static boolean trySubmit(Runnable job) {
+ ensureRunning();
+ return queue.offer(job);
+ }
+
+ @Override
+ public void run() {
+ LOGGER.info("Maintenance Thread started");
+ try {
+ Runnable job = queue.take();
+ runJob(job);
+ } catch (InterruptedException e) {
+ LOGGER.warn("Maintenance Thread was interrupted!", e);
+ if (!queue.isEmpty()) {
+ ensureRunning();
+ }
+ }
+ }
+
+ private void runJob(Runnable job) {
+ try {
+ job.run();
+ } catch (Throwable t) {
+ LOGGER.warn("Uncaught exception in job '" + job.getClass().getSimpleName() + "'", t);
+ }
+ }
+
+}