Add restore local backupv2 infra.

This commit is contained in:
Cody Henthorne
2024-09-03 16:49:33 -04:00
parent 00d20a1917
commit a8bf03af89
41 changed files with 615 additions and 324 deletions

View File

@@ -53,6 +53,7 @@ import org.signal.core.util.requireBlob
import org.signal.core.util.requireBoolean
import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.requireLongOrNull
import org.signal.core.util.requireNonNullBlob
import org.signal.core.util.requireNonNullString
import org.signal.core.util.requireObject
@@ -495,7 +496,7 @@ class AttachmentTable(
return readableDatabase
.select(*PROJECTION)
.from(TABLE_NAME)
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE)
.limit(batchSize)
.orderBy("$ID DESC")
.run()
@@ -508,7 +509,7 @@ class AttachmentTable(
return readableDatabase
.select(*PROJECTION)
.from(TABLE_NAME)
.where("$REMOTE_KEY IS NOT NULL AND $REMOTE_DIGEST IS NOT NULL AND $TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE)
.limit(batchSize)
.orderBy("$ID DESC")
.run()
@@ -517,17 +518,17 @@ class AttachmentTable(
attachmentId = AttachmentId(it.requireLong(ID)),
mmsId = it.requireLong(MESSAGE_ID),
size = it.requireLong(DATA_SIZE),
remoteDigest = it.requireBlob(REMOTE_DIGEST)!!,
remoteKey = it.requireBlob(REMOTE_KEY)!!
remoteDigest = it.requireBlob(REMOTE_DIGEST),
remoteKey = it.requireBlob(REMOTE_KEY)
)
}
}
fun getTotalRestorableAttachmentSize(): Long {
fun getRemainingRestorableAttachmentSize(): Long {
return readableDatabase
.select("SUM($DATA_SIZE)")
.from(TABLE_NAME)
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
.where("$TRANSFER_STATE = ? OR $TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE, TRANSFER_RESTORE_IN_PROGRESS)
.run()
.readToSingleLong()
}
@@ -628,7 +629,7 @@ class AttachmentTable(
.where("$MESSAGE_ID = ?", mmsId)
.run()
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
deleteCount > 0
}
@@ -692,7 +693,7 @@ class AttachmentTable(
.where("$MESSAGE_ID = ?", messageId)
.run()
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
val threadId = messages.getThreadIdForMessage(messageId)
if (threadId > 0) {
@@ -729,7 +730,7 @@ class AttachmentTable(
.run()
deleteDataFileIfPossible(data, contentType, id)
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
}
}
}
@@ -849,7 +850,7 @@ class AttachmentTable(
FileUtils.deleteDirectoryContents(context.getDir(DIRECTORY, Context.MODE_PRIVATE))
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
}
fun setTransferState(messageId: Long, attachmentId: AttachmentId, transferState: Int) {
@@ -874,7 +875,6 @@ class AttachmentTable(
notifyConversationListeners(threadId)
}
@Throws(MmsException::class)
fun setTransferProgressFailed(attachmentId: AttachmentId, mmsId: Long) {
writableDatabase
.update(TABLE_NAME)
@@ -885,7 +885,6 @@ class AttachmentTable(
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
}
@Throws(MmsException::class)
fun setThumbnailRestoreProgressFailed(attachmentId: AttachmentId, mmsId: Long) {
writableDatabase
.update(TABLE_NAME)
@@ -896,7 +895,6 @@ class AttachmentTable(
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
}
@Throws(MmsException::class)
fun setTransferProgressPermanentFailure(attachmentId: AttachmentId, mmsId: Long) {
writableDatabase
.update(TABLE_NAME)
@@ -907,6 +905,57 @@ class AttachmentTable(
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
}
fun setRestoreInProgressTransferState(restorableAttachments: List<LocalRestorableAttachment>) {
setRestoreTransferState(
restorableAttachments = restorableAttachments,
prefix = "$TRANSFER_STATE = $TRANSFER_NEEDS_RESTORE",
state = TRANSFER_RESTORE_IN_PROGRESS
)
}
fun setRestoreFailedTransferState(notRestorableAttachments: List<LocalRestorableAttachment>) {
setRestoreTransferState(
restorableAttachments = notRestorableAttachments,
prefix = "$TRANSFER_STATE != $TRANSFER_PROGRESS_PERMANENT_FAILURE",
state = TRANSFER_PROGRESS_FAILED
)
}
private fun setRestoreTransferState(restorableAttachments: List<LocalRestorableAttachment>, prefix: String, state: Int) {
writableDatabase.withinTransaction {
val setQueries = SqlUtil.buildCollectionQuery(
column = ID,
values = restorableAttachments.map { it.attachmentId.id },
prefix = "$prefix AND"
)
setQueries.forEach { query ->
writableDatabase
.update(TABLE_NAME)
.values(TRANSFER_STATE to state)
.where(query.where, query.whereArgs)
.run()
}
val threadQueries = SqlUtil.buildCollectionQuery(
column = MessageTable.ID,
values = restorableAttachments.map { it.mmsId }
)
val threads = mutableSetOf<Long>()
threadQueries.forEach { query ->
threads += readableDatabase
.select("DISTINCT ${MessageTable.THREAD_ID}")
.from(MessageTable.TABLE_NAME)
.where(query.where, query.whereArgs)
.run()
.readToList { it.requireLongOrNull(MessageTable.THREAD_ID) ?: -1 }
}
notifyConversationListeners(threads)
}
}
/**
* When we find out about a new inbound attachment pointer, we insert a row for it that contains all the info we need to download it via [insertAttachmentWithData].
* Later, we download the data for that pointer. Call this method once you have the data to associate it with the attachment. At this point, it is assumed
@@ -982,7 +1031,7 @@ class AttachmentTable(
notifyConversationListeners(threadId)
notifyConversationListListeners()
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
if (foundDuplicate) {
if (!fileWriteResult.file.delete()) {
@@ -1020,7 +1069,7 @@ class AttachmentTable(
}
notifyConversationListListeners()
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
if (!transferFile.delete()) {
Log.w(TAG, "Unable to delete transfer file.")
@@ -1904,7 +1953,7 @@ class AttachmentTable(
AttachmentId(rowId)
}
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
return attachmentId
}
@@ -1961,7 +2010,7 @@ class AttachmentTable(
AttachmentId(rowId)
}
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
return attachmentId
}
@@ -2101,7 +2150,7 @@ class AttachmentTable(
}
}
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
return attachmentId
}
@@ -2460,7 +2509,7 @@ class AttachmentTable(
val attachmentId: AttachmentId,
val mmsId: Long,
val size: Long,
val remoteDigest: ByteArray,
val remoteKey: ByteArray
val remoteDigest: ByteArray?,
val remoteKey: ByteArray?
)
}

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.database;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -24,7 +22,7 @@ import java.util.concurrent.Executor;
/**
* Allows listening to database changes to varying degrees of specificity.
*
* <p>
* A replacement for the observer system in {@link DatabaseTable}. We should move to this over time.
*/
public class DatabaseObserver {
@@ -46,11 +44,10 @@ public class DatabaseObserver {
private static final String KEY_SCHEDULED_MESSAGES = "ScheduledMessages";
private static final String KEY_CONVERSATION_DELETES = "ConversationDeletes";
private static final String KEY_CALL_UPDATES = "CallUpdates";
private static final String KEY_CALL_LINK_UPDATES = "CallLinkUpdates";
private static final String KEY_IN_APP_PAYMENTS = "InAppPayments";
private static final String KEY_CALL_UPDATES = "CallUpdates";
private static final String KEY_CALL_LINK_UPDATES = "CallLinkUpdates";
private static final String KEY_IN_APP_PAYMENTS = "InAppPayments";
private final Application application;
private final Executor executor;
private final Set<Observer> conversationListObservers;
@@ -63,7 +60,8 @@ public class DatabaseObserver {
private final Set<Observer> chatColorsObservers;
private final Set<Observer> stickerObservers;
private final Set<Observer> stickerPackObservers;
private final Set<Observer> attachmentObservers;
private final Set<Observer> attachmentUpdatedObservers;
private final Set<Observer> attachmentDeletedObservers;
private final Set<MessageObserver> messageUpdateObservers;
private final Map<Long, Set<MessageObserver>> messageInsertObservers;
private final Set<Observer> notificationProfileObservers;
@@ -72,8 +70,7 @@ public class DatabaseObserver {
private final Map<CallLinkRoomId, Set<Observer>> callLinkObservers;
private final Set<InAppPaymentObserver> inAppPaymentObservers;
public DatabaseObserver(Application application) {
this.application = application;
public DatabaseObserver() {
this.executor = new SerialExecutor(SignalExecutors.BOUNDED);
this.conversationListObservers = new HashSet<>();
this.conversationObservers = new HashMap<>();
@@ -84,7 +81,8 @@ public class DatabaseObserver {
this.chatColorsObservers = new HashSet<>();
this.stickerObservers = new HashSet<>();
this.stickerPackObservers = new HashSet<>();
this.attachmentObservers = new HashSet<>();
this.attachmentUpdatedObservers = new HashSet<>();
this.attachmentDeletedObservers = new HashSet<>();
this.messageUpdateObservers = new HashSet<>();
this.messageInsertObservers = new HashMap<>();
this.notificationProfileObservers = new HashSet<>();
@@ -149,9 +147,15 @@ public class DatabaseObserver {
});
}
public void registerAttachmentObserver(@NonNull Observer listener) {
public void registerAttachmentUpdatedObserver(@NonNull Observer listener) {
executor.execute(() -> {
attachmentObservers.add(listener);
attachmentUpdatedObservers.add(listener);
});
}
public void registerAttachmentDeletedObserver(@NonNull Observer listener) {
executor.execute(() -> {
attachmentDeletedObservers.add(listener);
});
}
@@ -211,7 +215,8 @@ public class DatabaseObserver {
chatColorsObservers.remove(listener);
stickerObservers.remove(listener);
stickerPackObservers.remove(listener);
attachmentObservers.remove(listener);
attachmentUpdatedObservers.remove(listener);
attachmentDeletedObservers.remove(listener);
notificationProfileObservers.remove(listener);
unregisterMapped(storyObservers, listener);
unregisterMapped(scheduledMessageObservers, listener);
@@ -307,9 +312,16 @@ public class DatabaseObserver {
});
}
public void notifyAttachmentObservers() {
public void notifyAttachmentUpdatedObservers() {
runPostSuccessfulTransaction(KEY_ATTACHMENTS, () -> {
notifySet(attachmentObservers);
notifySet(attachmentUpdatedObservers);
});
}
public void notifyAttachmentDeletedObservers() {
runPostSuccessfulTransaction(KEY_ATTACHMENTS, () -> {
notifySet(attachmentDeletedObservers);
notifySet(attachmentUpdatedObservers);
});
}

View File

@@ -71,10 +71,6 @@ public abstract class DatabaseTable {
AppDependencies.getDatabaseObserver().notifyStickerObservers();
}
protected void notifyAttachmentListeners() {
AppDependencies.getDatabaseObserver().notifyAttachmentObservers();
}
public void reset(SignalDatabase databaseHelper) {
this.databaseHelper = databaseHelper;
}

View File

@@ -6,7 +6,7 @@ import android.database.Cursor
import androidx.compose.runtime.Immutable
import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.requireNonNullString
import org.signal.core.util.requireString
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.MediaUtil
@@ -159,6 +159,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
)
)"""
)
private fun applyEqualityOperator(threadId: Long, query: String): String {
return query.replace("__EQUALITY__", if (threadId == ALL_THREADS.toLong()) "!=" else "=")
}
@@ -207,7 +208,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
readableDatabase.rawQuery(UNIQUE_MEDIA_QUERY, null).use { cursor ->
while (cursor.moveToNext()) {
val size: Int = cursor.requireInt(AttachmentTable.DATA_SIZE)
val type: String = cursor.requireNonNullString(AttachmentTable.CONTENT_TYPE)
val type: String? = cursor.requireString(AttachmentTable.CONTENT_TYPE)
when (MediaUtil.getSlideTypeFromContentType(type)) {
SlideType.GIF,
@@ -215,17 +216,21 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
SlideType.MMS -> {
photoSize += size.toLong()
}
SlideType.VIDEO -> {
videoSize += size.toLong()
}
SlideType.AUDIO -> {
audioSize += size.toLong()
}
SlideType.LONG_TEXT,
SlideType.DOCUMENT -> {
documentSize += size.toLong()
}
else -> {}
SlideType.VIEW_ONCE -> Unit
}
}
}

View File

@@ -2115,7 +2115,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
AppDependencies.databaseObserver.notifyConversationListListeners()
if (deletedAttachments) {
AppDependencies.databaseObserver.notifyAttachmentObservers()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
}
}

View File

@@ -361,7 +361,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(threadTrimsToSync, isFullDelete = false)
}
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
notifyStickerPackListeners()
OptimizeMessageSearchIndexJob.enqueue()
}
@@ -395,7 +395,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(listOf(threadTrimToSync!!), isFullDelete = false)
}
notifyAttachmentListeners()
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
notifyStickerPackListeners()
OptimizeMessageSearchIndexJob.enqueue()
}

View File

@@ -71,7 +71,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
PopulatedGroupedThreadMedia mediaGrouping = new PopulatedGroupedThreadMedia(groupingMethod);
AppDependencies.getDatabaseObserver().registerAttachmentObserver(observer);
AppDependencies.getDatabaseObserver().registerAttachmentUpdatedObserver(observer);
try (Cursor cursor = ThreadMediaLoader.createThreadMediaCursor(context, threadId, mediaType, sorting)) {
while (cursor != null && cursor.moveToNext()) {