Added "original copy indicator file", which prevents the node from deleting its own published content when storage space runs out.

Since some files won't have any mirrors, this prevents the cleanup manager from deleting the only copy in existence when freeing up space. This feature can be disabled by setting "originalCopyIndicatorFileEnabled": false in settings.json (or by deleting the ".original" files). The trade off is that the only copy in existence could be deleted if space gets low.

This will also allow for better reporting of own vs third party files in the local UI (not yet implemented).
This commit is contained in:
CalDescent
2022-01-01 14:52:09 +00:00
parent cf2c8d6c67
commit 7aa8f115ce
5 changed files with 96 additions and 1 deletions

View File

@@ -18,6 +18,7 @@ import org.qortal.utils.NTP;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.SecureRandom;
@@ -358,6 +359,16 @@ public class ArbitraryDataCleanupManager extends Thread {
// If it's a file, we might be able to delete it
if (randomItem.isFile()) {
// If the parent directory contains an ".original" file, don't delete anything
// This indicates that the content was originally updated by this node and so
// could be the only copy that exists.
Path originalCopyIndicatorPath = Paths.get(randomItem.getParent(), ".original");
if (Files.exists(originalCopyIndicatorPath)) {
// This is an original seed copy and so shouldn't be deleted
return false;
}
if (name != null) {
// A name has been specified, so we need to make sure this file relates to
// the name we want to delete. The signature should be the name of parent directory.

View File

@@ -289,6 +289,10 @@ public class Settings {
/** Whether to allow data outside of the storage policy to be relayed between other peers */
private boolean relayModeEnabled = false;
/** Whether to remember which data was originally uploaded using this node.
* This prevents auto deletion of own files when storage limits are reached. */
private boolean originalCopyIndicatorFileEnabled = true;
/** Whether to make connections directly with peers that have the required data */
private boolean directDataRetrievalEnabled = true;
@@ -861,6 +865,10 @@ public class Settings {
return this.directDataRetrievalEnabled;
}
public boolean isOriginalCopyIndicatorFileEnabled() {
return this.originalCopyIndicatorFileEnabled;
}
public Long getBuiltDataExpiryInterval() {
return this.builtDataExpiryInterval;
}

View File

@@ -9,10 +9,13 @@ import org.qortal.data.transaction.ArbitraryTransactionData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
import org.qortal.settings.Settings;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
@@ -327,6 +330,19 @@ public class ArbitraryTransactionUtils {
// Delete empty parent directories
FilesystemUtils.safeDeleteEmptyParentDirectories(oldPath);
}
// If at least one file was relocated, we can assume that the data from this transaction
// originated from this node
if (filesRelocatedCount > 0) {
if (Settings.getInstance().isOriginalCopyIndicatorFileEnabled()) {
// Create a file in the same directory, to indicate that this is the original copy
LOGGER.info("Creating original copy indicator file...");
ArbitraryDataFile completeFile = ArbitraryDataFile.fromHash(arbitraryDataFile.getHash(), signature);
Path parentDirectory = completeFile.getFilePath().getParent();
File file = Paths.get(parentDirectory.toString(), ".original").toFile();
file.createNewFile();
}
}
}
catch (DataException | IOException e) {
LOGGER.info("Unable to check and relocate all files for signature {}: {}",