From 4ba72f7eeb398685063b92510dc9d2f584bb6851 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Fri, 20 Aug 2021 19:27:42 +0100 Subject: [PATCH] Regularly clean up old and unused files/folders in the temp directory Also added code to purge built resource caches, but it is currently disabled. This will become more useful once we implement local storage limits. --- .../ArbitraryDataCleanupManager.java | 88 +++++++++++++++++-- .../utils/ArbitraryTransactionUtils.java | 34 +++---- 2 files changed, 99 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java index a3500766..a468942d 100644 --- a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java +++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java @@ -3,10 +3,7 @@ package org.qortal.controller.arbitrary; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.api.resource.TransactionsResource.ConfirmationStatus; -import org.qortal.controller.Controller; import org.qortal.data.transaction.ArbitraryTransactionData; -import org.qortal.network.Network; -import org.qortal.network.Peer; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; @@ -14,8 +11,13 @@ import org.qortal.settings.Settings; import org.qortal.transaction.Transaction.TransactionType; import org.qortal.utils.ArbitraryTransactionUtils; import org.qortal.utils.Base58; +import org.qortal.utils.FilesystemUtils; import org.qortal.utils.NTP; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -35,12 +37,20 @@ public class ArbitraryDataCleanupManager extends Thread { * rebuilding them. The main purpose of this is to avoid deleting files that are currently * being used by other parts of the system. */ - private static long STALE_FILE_TIMEOUT = 60*60*1000; // 1 hour + private static long STALE_FILE_TIMEOUT = 60*60*1000L; // 1 hour + + /** + * The amount of time that must pass before a built resource is cleaned up. This should be + * considerably longer than STALE_FILE_TIMEOUT because building a resource is costly. Longer + * term we could consider tracking when each resource is requested, and only delete those + * that haven't been requested for a large amount of time. We could also consider only purging + * built resources when the disk space is getting low. + */ + private static long PURGE_BUILT_RESOURCES_TIMEOUT = 30*24*60*60*1000L; // 30 days /* TODO: - - Delete old files from _temp - Delete old files not associated with transactions */ @@ -72,11 +82,17 @@ public class ArbitraryDataCleanupManager extends Thread { while (!isStopping) { Thread.sleep(30000); - if (NTP.getTime() == null) { + Long now = NTP.getTime(); + if (now == null) { // Don't attempt to make decisions if we haven't synced our time yet continue; } - + + // Periodically delete any unnecessary files from the temp directory + if (offset == 0 || offset % (limit * 10) == 0) { + this.cleanupTempDirectory(now); + } + // Any arbitrary transactions we want to fetch data for? try (final Repository repository = RepositoryManager.getRepository()) { List signatures = repository.getTransactionRepository().getSignaturesMatchingCriteria(null, null, null, ARBITRARY_TX_TYPE, null, null, ConfirmationStatus.BOTH, limit, offset, true); @@ -86,7 +102,7 @@ public class ArbitraryDataCleanupManager extends Thread { continue; } offset += limit; - Long now = NTP.getTime(); + now = NTP.getTime(); // Loop through the signatures in this batch for (int i=0; i cleanupAfter) { + return false; } - if (timeSinceModified < cleanupAfter) { - return true; + if (timeSinceModified > cleanupAfter) { + return false; } } catch (IOException e) { - // Can't read file attributes, so assume it's not recent + // Can't read file attributes, so assume it's recent so that we don't delete something accidentally } - return false; + return true; + } + + public static boolean isFileHashRecent(byte[] hash, long now, long cleanupAfter) { + ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash(hash); + if (arbitraryDataFile == null || !arbitraryDataFile.exists()) { + // No hash, or file doesn't exist, so it's not recent + return false; + } + + Path filePath = arbitraryDataFile.getFilePath(); + return ArbitraryTransactionUtils.isFileRecent(filePath, now, cleanupAfter); } public static void deleteCompleteFile(ArbitraryTransactionData arbitraryTransactionData, long now, long cleanupAfter) {