diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java
index 57b0deda2..2c75c3654 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java
@@ -17,7 +17,6 @@ import java.security.SecureRandom;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
-import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.HexFormat;
import java.util.List;
@@ -76,7 +75,6 @@ public class BackupManager {
private static final String NUM_OBJECTS_SUMMARY_NAME = MetricsUtil.name(BackupsDb.class, "numObjects");
private static final String BYTES_USED_SUMMARY_NAME = MetricsUtil.name(BackupsDb.class, "bytesUsed");
- private static final String BACKUPS_COUNTER_NAME = MetricsUtil.name(BackupsDb.class, "backups");
private static final String SUCCESS_TAG_NAME = "success";
private static final String FAILURE_REASON_TAG_NAME = "reason";
@@ -152,7 +150,6 @@ public class BackupManager {
}));
}
-
/**
* Create a form that may be used to upload a backup file for the backupId encoded in the presentation.
*
@@ -165,42 +162,12 @@ public class BackupManager {
final AuthenticatedBackupUser backupUser) {
checkBackupLevel(backupUser, BackupLevel.FREE);
checkBackupCredentialType(backupUser, BackupCredentialType.MESSAGES);
- final Instant today = clock.instant().truncatedTo(ChronoUnit.DAYS);
- final long maxTotalMediaSize =
- dynamicConfigurationManager.getConfiguration().getBackupConfiguration().maxTotalMediaSize();
// this could race with concurrent updates, but the only effect would be last-writer-wins on the timestamp
return backupsDb
.addMessageBackup(backupUser)
- .thenApply(storedBackupAttributes -> {
- final Instant previousRefreshTime = storedBackupAttributes.lastRefresh();
- // Only publish a metric update once per day
- if (previousRefreshTime.isBefore(today)) {
- final Tags tags = Tags.of(
- UserAgentTagUtil.getPlatformTag(backupUser.userAgent()),
- Tag.of("tier", backupUser.backupLevel().name()));
-
- DistributionSummary.builder(NUM_OBJECTS_SUMMARY_NAME)
- .tags(tags)
- .publishPercentileHistogram()
- .register(Metrics.globalRegistry)
- .record(storedBackupAttributes.numObjects());
- DistributionSummary.builder(BYTES_USED_SUMMARY_NAME)
- .tags(tags)
- .publishPercentileHistogram()
- .register(Metrics.globalRegistry)
- .record(storedBackupAttributes.bytesUsed());
-
- // Report that the backup is out of quota if it cannot store a max size media object
- final boolean quotaExhausted = storedBackupAttributes.bytesUsed() >=
- (maxTotalMediaSize - BackupManager.MAX_MEDIA_OBJECT_SIZE);
-
- Metrics.counter(BACKUPS_COUNTER_NAME,
- tags.and("quotaExhausted", String.valueOf(quotaExhausted)))
- .increment();
- }
- return cdn3BackupCredentialGenerator.generateUpload(cdnMessageBackupName(backupUser));
- });
+ .thenApply(_ ->
+ cdn3BackupCredentialGenerator.generateUpload(cdnMessageBackupName(backupUser)));
}
public CompletableFuture createTemporaryAttachmentUploadDescriptor(
@@ -226,7 +193,33 @@ public class BackupManager {
public CompletableFuture ttlRefresh(final AuthenticatedBackupUser backupUser) {
checkBackupLevel(backupUser, BackupLevel.FREE);
// update message backup TTL
- return backupsDb.ttlRefresh(backupUser);
+ return backupsDb.ttlRefresh(backupUser).thenAccept(storedBackupAttributes -> {
+ if (backupUser.credentialType() == BackupCredentialType.MEDIA) {
+ final long maxTotalMediaSize =
+ dynamicConfigurationManager.getConfiguration().getBackupConfiguration().maxTotalMediaSize();
+
+ // Report that the backup is out of quota if it cannot store a max size media object
+ final boolean quotaExhausted = storedBackupAttributes.bytesUsed() >=
+ (maxTotalMediaSize - BackupManager.MAX_MEDIA_OBJECT_SIZE);
+
+ final Tags tags = Tags.of(
+ UserAgentTagUtil.getPlatformTag(backupUser.userAgent()),
+ Tag.of("type", backupUser.credentialType().name()),
+ Tag.of("tier", backupUser.backupLevel().name()),
+ Tag.of("quotaExhausted", String.valueOf(quotaExhausted)));
+
+ DistributionSummary.builder(NUM_OBJECTS_SUMMARY_NAME)
+ .tags(tags)
+ .publishPercentileHistogram()
+ .register(Metrics.globalRegistry)
+ .record(storedBackupAttributes.numObjects());
+ DistributionSummary.builder(BYTES_USED_SUMMARY_NAME)
+ .tags(tags)
+ .publishPercentileHistogram()
+ .register(Metrics.globalRegistry)
+ .record(storedBackupAttributes.bytesUsed());
+ }
+ });
}
public record BackupInfo(int cdn, String backupSubdir, String mediaSubdir, String messageBackupKey,
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupsDb.java b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupsDb.java
index 888d77c94..3fbf7347b 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupsDb.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupsDb.java
@@ -242,7 +242,7 @@ public class BackupsDb {
*
* @param backupUser an already authorized backup user
*/
- CompletableFuture ttlRefresh(final AuthenticatedBackupUser backupUser) {
+ CompletableFuture ttlRefresh(final AuthenticatedBackupUser backupUser) {
final Instant today = clock.instant().truncatedTo(ChronoUnit.DAYS);
// update message backup TTL
return dynamoClient.updateItem(UpdateBuilder.forUser(backupTableName, backupUser)
@@ -250,7 +250,7 @@ public class BackupsDb {
.updateItemBuilder()
.returnValues(ReturnValue.ALL_OLD)
.build())
- .thenRun(Util.NOOP);
+ .thenApply(updateItemResponse -> fromItem(updateItemResponse.attributes()));
}
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupsDbTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupsDbTest.java
index ced11f7aa..caa2e7a3f 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupsDbTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/backup/BackupsDbTest.java
@@ -54,22 +54,30 @@ public class BackupsDbTest {
@Test
public void trackMediaStats() {
final AuthenticatedBackupUser backupUser = backupUser(TestRandomUtil.nextBytes(16), BackupCredentialType.MEDIA, BackupLevel.PAID);
- // add at least one message backup so we can describe it
- backupsDb.addMessageBackup(backupUser).join();
int total = 0;
for (int i = 0; i < 5; i++) {
this.backupsDb.trackMedia(backupUser, 1, i).join();
total += i;
final BackupsDb.BackupDescription description = this.backupsDb.describeBackup(backupUser).join();
- assertThat(description.mediaUsedSpace().get()).isEqualTo(total);
+ final StoredBackupAttributes storedAttrs = backupsDb.ttlRefresh(backupUser).join();
+ assertThat(description.mediaUsedSpace().orElseThrow())
+ .isEqualTo(total)
+ .isEqualTo(storedAttrs.bytesUsed());
+ assertThat(storedAttrs.numObjects()).isEqualTo(i + 1);
}
+
for (int i = 0; i < 5; i++) {
this.backupsDb.trackMedia(backupUser, -1, -i).join();
total -= i;
final BackupsDb.BackupDescription description = this.backupsDb.describeBackup(backupUser).join();
- assertThat(description.mediaUsedSpace().get()).isEqualTo(total);
+ final StoredBackupAttributes storedAttrs = backupsDb.ttlRefresh(backupUser).join();
+ assertThat(description.mediaUsedSpace().orElseThrow())
+ .isEqualTo(total)
+ .isEqualTo(storedAttrs.bytesUsed());
+ assertThat(storedAttrs.numObjects()).isEqualTo(5 - i - 1);
}
+
}
@ParameterizedTest