summaryrefslogtreecommitdiffstats
path: root/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance
diff options
context:
space:
mode:
authorSimon Rettberg2018-05-11 17:36:45 +0200
committerSimon Rettberg2018-05-11 17:36:45 +0200
commitb3557ec2e121f91ca842ca37f0e4b582556046a4 (patch)
tree21f6feb3f678db1da60b6f72fea6ef1cbb72fee0 /dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance
parent[client] Fix inverted logic for slowed down hashing (diff)
downloadtutor-module-b3557ec2e121f91ca842ca37f0e4b582556046a4.tar.gz
tutor-module-b3557ec2e121f91ca842ca37f0e4b582556046a4.tar.xz
tutor-module-b3557ec2e121f91ca842ca37f0e4b582556046a4.zip
[server] Support server side chunk copying
Diffstat (limited to 'dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance')
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/ImageValidCheck.java213
1 files changed, 169 insertions, 44 deletions
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/ImageValidCheck.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/ImageValidCheck.java
index 050f598d..b544a708 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/ImageValidCheck.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/maintenance/ImageValidCheck.java
@@ -9,6 +9,7 @@ import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -33,17 +34,34 @@ import org.openslx.util.Util;
public class ImageValidCheck implements Runnable {
- public enum CheckResult {
+ public static enum CheckResult {
+
+ QUEUED(0),
+ NO_SUCH_JOB(0),
+ WAITING_FOR_STORE(1),
+ WORKING(2),
+ DONE(100),
+ VERSION_EXPIRED(100),
+ DATABASE_PATH_MISSING(100),
+ DATABASE_PATH_INVALID(100),
+ FILE_NOT_FOUND(100),
+ FILE_ACCESS_ERROR(100),
+ FILE_SIZE_MISMATCH(100),
+ FILE_CORRUPT(100),
+ UNKNOWN_VERSIONID(100),
+ INTERNAL_ERROR(100);
+ public final int stage;
+ private CheckResult(int stage) {
+ this.stage = stage;
+ }
+ }
+
+ public static enum SubmitResult {
+ QUEUED,
NULL_POINTER_EXCEPTION,
ALREADY_IN_PROGRESS,
TOO_MANY_QUEUED_JOBS,
- SUBMITTED,
REJECTED_BY_SCHEDULER,
- WORKING,
- DONE,
- FILE_NOT_FOUND,
- FILE_ACCESS_ERROR,
- OTHER_ERROR,
}
private static final Logger LOGGER = Logger.getLogger(ImageValidCheck.class);
@@ -57,9 +75,13 @@ public class ImageValidCheck implements Runnable {
private final String versionId;
private final boolean integrity;
+ private final boolean updateState;
+
+ /**
+ * Status of this check job. Must never be null.
+ */
+ private CheckResult result = CheckResult.QUEUED;
- // TODO: Set appropriately in various places; make it possible to query from RPC
- private CheckResult result = CheckResult.DONE;
// Hash checking
@@ -84,26 +106,31 @@ public class ImageValidCheck implements Runnable {
// End hash checking
- public static CheckResult check(String versionId, boolean integrity) {
+ public static SubmitResult check(String versionId, boolean integrity, boolean updateState) {
if (versionId == null)
- return CheckResult.NULL_POINTER_EXCEPTION;
+ return SubmitResult.NULL_POINTER_EXCEPTION;
synchronized (inProgress) {
+ synchronized (done) {
+ if (done.containsKey(versionId)) {
+ done.remove(versionId);
+ }
+ }
if (inProgress.containsKey(versionId))
- return CheckResult.ALREADY_IN_PROGRESS;
+ return SubmitResult.ALREADY_IN_PROGRESS;
if (inProgress.size() >= MAX_CONCURRENT_CHECKS) {
if (queue.size() > 1000) {
- return CheckResult.TOO_MANY_QUEUED_JOBS;
+ return SubmitResult.TOO_MANY_QUEUED_JOBS;
}
- queue.add(new ImageValidCheck(versionId, integrity));
- return CheckResult.SUBMITTED;
+ queue.add(new ImageValidCheck(versionId, integrity, updateState));
+ return SubmitResult.QUEUED;
}
- ImageValidCheck check = new ImageValidCheck(versionId, integrity);
+ ImageValidCheck check = new ImageValidCheck(versionId, integrity, updateState);
if (Maintenance.trySubmit(check)) {
inProgress.put(versionId, check);
- return CheckResult.SUBMITTED;
+ return SubmitResult.QUEUED;
}
}
- return CheckResult.REJECTED_BY_SCHEDULER;
+ return SubmitResult.REJECTED_BY_SCHEDULER;
}
public static void checkForWork() {
@@ -127,48 +154,132 @@ public class ImageValidCheck implements Runnable {
}
}
- private ImageValidCheck(String versionId, boolean integrity) {
+ /**
+ * Get current status of check for given versionId.
+ * Never returns null.
+ *
+ * @param versionId VERSIONSID DES IMAGES
+ * @return state/result
+ */
+ public static CheckResult getStatus(String versionId) {
+ ImageValidCheck i;
+ synchronized (inProgress) {
+ i = inProgress.get(versionId);
+ }
+ if (i != null)
+ return i.result;
+ synchronized (done) {
+ i = done.get(versionId);
+ }
+ if (i != null)
+ return i.result;
+ return CheckResult.NO_SUCH_JOB;
+ }
+
+ /**
+ * Get status/result of all known check jobs.
+ *
+ * @return MAP
+ */
+ public static Map<String, CheckResult> getAll() {
+ Map<String, CheckResult> res = new HashMap<>();
+ synchronized (inProgress) {
+ for (Entry<String, ImageValidCheck> i : inProgress.entrySet()) {
+ res.put(i.getKey(), i.getValue().result);
+ }
+ }
+ synchronized (done) {
+ for (Entry<String, ImageValidCheck> i : done.getImmutableSnapshot().entrySet()) {
+ res.put(i.getKey(), i.getValue().result);
+ }
+ }
+ return res;
+ }
+
+ //
+ // Instance
+ //
+
+ private ImageValidCheck(String versionId, boolean integrity, boolean updateState) {
this.versionId = versionId;
this.integrity = integrity;
+ this.updateState = updateState;
+ }
+
+ private void setState(CheckResult cr) {
+ if (cr.stage > result.stage) {
+ result = cr;
+ } else {
+ LOGGER.debug("Ingoring state update from " + result.name() + " to " + cr.name());
+ }
}
@Override
public void run() {
try {
+ setState(CheckResult.WAITING_FOR_STORE);
if (!FileSystem.waitForStorage()) {
LOGGER.warn("Will not check " + versionId + ": Storage not online");
+ setState(CheckResult.INTERNAL_ERROR);
return;
}
+ setState(CheckResult.WORKING);
LocalImageVersion imageVersion;
try {
imageVersion = DbImage.getLocalImageData(versionId);
- } catch (SQLException e) {
- return;
} catch (TNotFoundException e) {
LOGGER.warn("Cannot check validity of image version - not found: " + versionId);
+ setState(CheckResult.UNKNOWN_VERSIONID);
+ return;
+ } catch (Exception e) {
+ LOGGER.warn("Cannot get local image data", e);
+ setState(CheckResult.INTERNAL_ERROR);
return;
}
+ // Found image in DB
+ // Simple checks first
boolean valid = checkValid(imageVersion);
if (valid && integrity) {
+ // Check block hashes
try {
valid = checkBlockHashes(imageVersion);
} catch (IOException e) {
- result = CheckResult.FILE_ACCESS_ERROR;
+ LOGGER.warn("IO error for " + versionId, e);
+ setState(CheckResult.FILE_ACCESS_ERROR);
valid = false;
} catch (Exception e) {
- result = CheckResult.OTHER_ERROR;
+ LOGGER.warn("Cannot check block hashes of " + versionId, e);
+ setState(CheckResult.INTERNAL_ERROR);
}
}
- if (imageVersion.isValid == valid)
- return; // nothing changed
+ if (imageVersion.isValid == valid) {
+ // nothing changed
+ if (valid) {
+ setState(CheckResult.DONE);
+ }
+ return;
+ }
// Update
try {
- DbImage.markValid(valid, false, imageVersion);
+ if (updateState) {
+ DbImage.markValid(valid, false, imageVersion);
+ }
+ if (valid) {
+ setState(CheckResult.DONE);
+ }
} catch (SQLException e) {
+ setState(CheckResult.INTERNAL_ERROR);
}
} finally {
+ if (result == CheckResult.WORKING) {
+ setState(CheckResult.INTERNAL_ERROR);
+ }
+ ImageValidCheck ivc;
synchronized (inProgress) {
- inProgress.remove(this.versionId);
+ synchronized (done) {
+ ivc = inProgress.remove(this.versionId);
+ done.put(this.versionId, ivc);
+ }
}
checkForWork();
}
@@ -184,11 +295,12 @@ public class ImageValidCheck implements Runnable {
versionDetails = DbImage.getVersionDetails(versionId);
} catch (TNotFoundException e) {
LOGGER.warn("Cannot check hash of image version - not found: " + versionId);
+ setState(CheckResult.UNKNOWN_VERSIONID);
return false;
} catch (SQLException e) {
+ setState(CheckResult.INTERNAL_ERROR);
return false;
}
- // TODO
if (versionDetails.sha1sums == null || versionDetails.sha1sums.isEmpty()) {
LOGGER.info("Image does not have block hashes -- assuming ok");
return true;
@@ -216,24 +328,27 @@ public class ImageValidCheck implements Runnable {
hashChecker.queue(chunk, buffer, new HashCheckCallback() {
@Override
public void hashCheckDone(HashResult result, byte[] data, FileChunk chunk) {
- if (result == HashResult.FAILURE) {
- // Hashing failed, cannot tell whether OK or not :(
- } else {
- if (result == HashResult.INVALID) {
- fileOk.set(false);
- ((StandaloneFileChunk) chunk).overrideStatus(ChunkStatus.MISSING);
+ try {
+ if (result == HashResult.FAILURE) {
+ // Hashing failed, cannot tell whether OK or not :(
} else {
- // >:(
- ((StandaloneFileChunk) chunk).overrideStatus(ChunkStatus.COMPLETE);
- }
- try {
- // We don't know what the state was in DB before, so just fire updates
- DbImageBlock.asyncUpdate(imageVersion.imageVersionId, chunk);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
+ if (result == HashResult.INVALID) {
+ fileOk.set(false);
+ ((StandaloneFileChunk) chunk).overrideStatus(ChunkStatus.MISSING);
+ } else {
+ // >:(
+ ((StandaloneFileChunk) chunk).overrideStatus(ChunkStatus.COMPLETE);
+ }
+ try {
+ // We don't know what the state was in DB before, so just fire updates
+ DbImageBlock.asyncUpdate(imageVersion.imageVersionId, chunk);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
}
+ } finally {
+ sem.release();
}
- sem.release();
}
}, HashChecker.BLOCKING | HashChecker.CALC_HASH);
numChecked += 1;
@@ -245,7 +360,11 @@ public class ImageValidCheck implements Runnable {
}
// Wait until the last callback fired
sem.acquire(numChecked);
- return fileOk.get();
+ if (fileOk.get()) {
+ return true;
+ }
+ setState(CheckResult.FILE_CORRUPT);
+ return false;
}
/**
@@ -256,28 +375,34 @@ public class ImageValidCheck implements Runnable {
return false;
if (imageVersion.expireTime < Util.unixTime()) {
LOGGER.info(versionId + ": expired");
+ setState(CheckResult.VERSION_EXPIRED);
return false;
}
if (imageVersion.filePath == null || imageVersion.filePath.isEmpty()) {
LOGGER.info(versionId + ": DB does not contain a path");
+ setState(CheckResult.DATABASE_PATH_MISSING);
return false;
}
File path = FileSystem.composeAbsoluteImagePath(imageVersion);
if (path == null) {
LOGGER.info(versionId + ": path from DB is not valid");
+ setState(CheckResult.DATABASE_PATH_INVALID);
return false;
}
if (!path.exists()) {
LOGGER.info(versionId + ": File does not exist (" + path.getAbsolutePath() + ")");
+ setState(CheckResult.FILE_NOT_FOUND);
return false;
}
if (!path.canRead()) {
LOGGER.info(versionId + ": File exists but not readable (" + path.getAbsolutePath() + ")");
+ setState(CheckResult.FILE_ACCESS_ERROR);
return false;
}
if (path.length() != imageVersion.fileSize) {
LOGGER.info(versionId + ": File exists but has wrong size (expected: " + imageVersion.fileSize
+ ", found: " + path.length() + ")");
+ setState(CheckResult.FILE_SIZE_MISMATCH);
return false;
}
return true;