mirror of
https://github.com/AsamK/signal-cli.git
synced 2026-09-17 05:42:58 +00:00
Fix storage sync edge cases
This commit is contained in:
parent
ccd7c77a9d
commit
ff689b577b
@ -414,7 +414,7 @@ public class StorageHelper {
|
||||
final WriteOperationResult writeOperation,
|
||||
final Set<StorageId> identityConflictsPendingRepair
|
||||
) {
|
||||
return !writeOperation.inserts().isEmpty() && writeOperation.inserts()
|
||||
return writeOperation.deletes().isEmpty() && !writeOperation.inserts().isEmpty() && writeOperation.inserts()
|
||||
.stream()
|
||||
.allMatch(record -> identityConflictsPendingRepair.contains(record.getId()));
|
||||
}
|
||||
|
||||
@ -20,6 +20,8 @@ public final class StorageSyncLoopDetector {
|
||||
private final LeakyBucket rateBucket = new LeakyBucket(100,
|
||||
Duration.ofMinutes(10).toMillis(),
|
||||
new InMemoryBucketState());
|
||||
private boolean lastAttemptChargedContent;
|
||||
private boolean lastAttemptChargedRate;
|
||||
|
||||
public StorageSyncLoopDetector(final BooleanSupplier isMultiDevice) {
|
||||
this.isMultiDevice = isMultiDevice;
|
||||
@ -39,6 +41,8 @@ public final class StorageSyncLoopDetector {
|
||||
final boolean isRetry,
|
||||
final long now
|
||||
) {
|
||||
lastAttemptChargedContent = false;
|
||||
lastAttemptChargedRate = false;
|
||||
if (!isMultiDevice.getAsBoolean() || isRetry) {
|
||||
return Decision.Allowed.INSTANCE;
|
||||
}
|
||||
@ -56,9 +60,11 @@ public final class StorageSyncLoopDetector {
|
||||
|
||||
if (chargeContent) {
|
||||
contentBucket.use(now);
|
||||
lastAttemptChargedContent = true;
|
||||
}
|
||||
if (fetchedRemoteManifest) {
|
||||
rateBucket.use(now);
|
||||
lastAttemptChargedRate = true;
|
||||
}
|
||||
if (fingerprint != null) {
|
||||
remember(fingerprint);
|
||||
@ -72,8 +78,14 @@ public final class StorageSyncLoopDetector {
|
||||
}
|
||||
|
||||
synchronized void onWriteFailed(final long now) {
|
||||
contentBucket.refund(now);
|
||||
rateBucket.refund(now);
|
||||
if (lastAttemptChargedContent) {
|
||||
contentBucket.refund(now);
|
||||
lastAttemptChargedContent = false;
|
||||
}
|
||||
if (lastAttemptChargedRate) {
|
||||
rateBucket.refund(now);
|
||||
lastAttemptChargedRate = false;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void onConverged() {
|
||||
|
||||
@ -38,6 +38,9 @@ class StorageHelperTest {
|
||||
assertFalse(StorageHelper.containsOnlyIdentityConflictsPendingRepair(write(List.of(pendingRecord, otherRecord)),
|
||||
Set.of(pendingId)));
|
||||
assertFalse(StorageHelper.containsOnlyIdentityConflictsPendingRepair(write(List.of()), Set.of(pendingId)));
|
||||
assertFalse(StorageHelper.containsOnlyIdentityConflictsPendingRepair(new WriteOperationResult(null,
|
||||
List.of(pendingRecord),
|
||||
List.of(new byte[]{3})), Set.of(pendingId)));
|
||||
}
|
||||
|
||||
private static SignalStorageRecord record(final StorageId id) {
|
||||
|
||||
@ -65,6 +65,29 @@ class StorageSyncLoopDetectorTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void failedWriteRefundsOnlyBucketsChargedByLatestAttempt() {
|
||||
final var contentDetector = new StorageSyncLoopDetector(() -> true);
|
||||
final var repeatedWrite = writeWithInsert(1);
|
||||
for (var index = 0; index < 4; index++) {
|
||||
assertAllowed(contentDetector.onWriteAttempt(repeatedWrite, true, false, NOW));
|
||||
}
|
||||
final var deleteOnlyWrite = new WriteOperationResult(null, List.of(), List.of(new byte[]{1}));
|
||||
assertAllowed(contentDetector.onWriteAttempt(deleteOnlyWrite, true, false, NOW));
|
||||
contentDetector.onWriteFailed(NOW);
|
||||
assertEquals(new StorageSyncLoopDetector.Decision.Denied(StorageSyncLoopDetector.Cause.REPEATED_PAYLOAD, 3),
|
||||
contentDetector.onWriteAttempt(repeatedWrite, true, false, NOW));
|
||||
|
||||
final var rateDetector = new StorageSyncLoopDetector(() -> true);
|
||||
for (var index = 0; index < 100; index++) {
|
||||
assertAllowed(rateDetector.onWriteAttempt(deleteOnlyWrite, true, false, NOW));
|
||||
}
|
||||
assertAllowed(rateDetector.onWriteAttempt(deleteOnlyWrite, false, false, NOW));
|
||||
rateDetector.onWriteFailed(NOW);
|
||||
assertEquals(new StorageSyncLoopDetector.Decision.Denied(StorageSyncLoopDetector.Cause.WRITE_RATE, 100),
|
||||
rateDetector.onWriteAttempt(deleteOnlyWrite, true, false, NOW));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rateBucketLimitsDeleteOnlyWrites() {
|
||||
final var detector = new StorageSyncLoopDetector(() -> true);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user