From 36c5b71656dd4943c6a01eca73da2ee2e788452f Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sat, 4 Dec 2021 14:23:09 +0000 Subject: [PATCH] Delete data associated with a name at random, if a name is using more than its allocated limit. This would happen if a name fills their limit, and then additional names are followed. Alternatively it could happen if the total storage capacity reduces due to disk space being used by other apps. Chunks are deleted at random to reduce the chance of the same chunk being deleted everywhere. Data loss is possible here for transactions that don't have many peers. We'll have to see in practice how much of a problem this is, but it's better than the scenario where one content creator consumes all space on their followers' nodes, leaving no space for other names that are subsequently followed. --- .../ArbitraryDataCleanupManager.java | 84 ++++++++++++++++--- .../ArbitraryDataStorageManager.java | 4 + .../qortal/test/common/ArbitraryUtils.java | 2 + 3 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 src/test/java/org/qortal/test/common/ArbitraryUtils.java diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java index 7eaeb44c..4d349dce 100644 --- a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java +++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java @@ -4,10 +4,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.api.resource.TransactionsResource.ConfirmationStatus; 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.repository.RepositoryManager; import org.qortal.settings.Settings; +import org.qortal.transaction.Transaction; import org.qortal.transaction.Transaction.TransactionType; import org.qortal.utils.ArbitraryTransactionUtils; import org.qortal.utils.Base58; @@ -198,12 +200,26 @@ public class ArbitraryDataCleanupManager extends Thread { LOGGER.error("Repository issue when fetching arbitrary transaction data", e); } - // Delete additional data at random if we're over our storage limit - // Use a threshold of 1 so that we only start deleting once the hard limit is reached - // This also allows some headroom between the regular threshold (90%) and the hard - // limit, to avoid data getting into a fetch/delete loop. - if (!storageManager.isStorageSpaceAvailable(1.0f)) { - this.storageLimitReached(); + try (final Repository repository = RepositoryManager.getRepository()) { + + // Delete random data associated with name if we're over our storage limit for this name + // Use a threshold of 1 so that we only start deleting once the hard limit is reached + // This also allows some headroom between the regular threshold (90%) and the hard + // limit, to avoid data getting into a fetch/delete loop. + for (String followedName : storageManager.followedNames()) { + if (!storageManager.isStorageSpaceAvailableForName(repository, followedName, 1.0f)) { + this.storageLimitReachedForName(repository, followedName); + } + } + + // Delete additional data at random if we're over our storage limit + // Use a threshold of 1, for the same reasons as above + if (!storageManager.isStorageSpaceAvailable(1.0f)) { + this.storageLimitReached(repository); + } + + } catch (DataException e) { + LOGGER.error("Repository issue when cleaning up arbitrary transaction data", e); } } } catch (InterruptedException e) { @@ -211,7 +227,7 @@ public class ArbitraryDataCleanupManager extends Thread { } } - private void storageLimitReached() throws InterruptedException { + private void storageLimitReached(Repository repository) throws InterruptedException { // We think that the storage limit has been reached // Firstly, rate limit, to avoid repeated calls to calculateDirectorySize() @@ -230,19 +246,42 @@ public class ArbitraryDataCleanupManager extends Thread { // when they reach their storage limit Path dataPath = Paths.get(Settings.getInstance().getDataPath()); for (int i=0; i followedNames() { + return ResourceListManager.getInstance().getStringsInList("followed", "names"); + } + private int followedNamesCount() { return ResourceListManager.getInstance().getItemCountForList("followed", "names"); } diff --git a/src/test/java/org/qortal/test/common/ArbitraryUtils.java b/src/test/java/org/qortal/test/common/ArbitraryUtils.java new file mode 100644 index 00000000..aaadaa21 --- /dev/null +++ b/src/test/java/org/qortal/test/common/ArbitraryUtils.java @@ -0,0 +1,2 @@ +package org.qortal.test.common;public class ArbitraryUtils { +}