Make backup jobs cancelable.

This commit is contained in:
Greyson Parrelli
2024-10-09 21:45:33 -04:00
parent 58a48e38eb
commit dcb5015290
8 changed files with 117 additions and 12 deletions

View File

@@ -219,7 +219,7 @@ object BackupRepository {
}
}
fun export(outputStream: OutputStream, append: (ByteArray) -> Unit, plaintext: Boolean = false, currentTime: Long = System.currentTimeMillis()) {
fun export(outputStream: OutputStream, append: (ByteArray) -> Unit, plaintext: Boolean = false, currentTime: Long = System.currentTimeMillis(), cancellationSignal: () -> Boolean = { false }) {
val writer: BackupExportWriter = if (plaintext) {
PlainTextBackupWriter(outputStream)
} else {
@@ -231,7 +231,7 @@ object BackupRepository {
)
}
export(currentTime = currentTime, isLocal = false, writer = writer)
export(currentTime = currentTime, isLocal = false, writer = writer, cancellationSignal = cancellationSignal)
}
/**
@@ -248,6 +248,7 @@ object BackupRepository {
isLocal: Boolean,
writer: BackupExportWriter,
progressEmitter: ExportProgressListener? = null,
cancellationSignal: () -> Boolean = { false },
exportExtras: ((SignalDatabase) -> Unit)? = null
) {
val eventTimer = EventTimer()
@@ -260,6 +261,8 @@ object BackupRepository {
val exportState = ExportState(backupTime = currentTime, mediaBackupEnabled = SignalStore.backup.backsUpMedia)
var frameCount = 0L
writer.use {
writer.write(
BackupInfo(
@@ -267,6 +270,7 @@ object BackupRepository {
backupTimeMs = exportState.backupTime
)
)
frameCount++
// We're using a snapshot, so the transaction is more for perf than correctness
dbSnapshot.rawWritableDatabase.withinTransaction {
@@ -274,43 +278,64 @@ object BackupRepository {
AccountDataArchiveProcessor.export(dbSnapshot, signalStoreSnapshot) {
writer.write(it)
eventTimer.emit("account")
frameCount++
}
if (cancellationSignal()) {
Log.w(TAG, "[import] Cancelled! Stopping")
return@export
}
progressEmitter?.onRecipient()
RecipientArchiveProcessor.export(dbSnapshot, signalStoreSnapshot, exportState) {
writer.write(it)
eventTimer.emit("recipient")
frameCount++
}
if (cancellationSignal()) {
Log.w(TAG, "[import] Cancelled! Stopping")
return@export
}
progressEmitter?.onThread()
ChatArchiveProcessor.export(dbSnapshot, exportState) { frame ->
writer.write(frame)
eventTimer.emit("thread")
frameCount++
}
if (cancellationSignal()) {
return@export
}
progressEmitter?.onCall()
AdHocCallArchiveProcessor.export(dbSnapshot) { frame ->
writer.write(frame)
eventTimer.emit("call")
frameCount++
}
progressEmitter?.onSticker()
StickerArchiveProcessor.export(dbSnapshot) { frame ->
writer.write(frame)
eventTimer.emit("sticker-pack")
frameCount++
}
progressEmitter?.onMessage()
ChatItemArchiveProcessor.export(dbSnapshot, exportState) { frame ->
ChatItemArchiveProcessor.export(dbSnapshot, exportState, cancellationSignal) { frame ->
writer.write(frame)
eventTimer.emit("message")
frameCount++
if (frameCount % 1000 == 0L) {
Log.d(TAG, "[export] Exported $frameCount frames so far.")
}
}
}
}
exportExtras?.invoke(dbSnapshot)
Log.d(TAG, "export() ${eventTimer.stop().summary}")
Log.d(TAG, "[export] totalFrames: $frameCount | ${eventTimer.stop().summary}")
} finally {
deleteDatabaseSnapshot(mainDbName)
deleteDatabaseSnapshot(keyValueDbName)

View File

@@ -22,15 +22,21 @@ import org.thoughtcrime.securesms.database.SignalDatabase
object ChatItemArchiveProcessor {
val TAG = Log.tag(ChatItemArchiveProcessor::class.java)
fun export(db: SignalDatabase, exportState: ExportState, emitter: BackupFrameEmitter) {
fun export(db: SignalDatabase, exportState: ExportState, cancellationSignal: () -> Boolean, emitter: BackupFrameEmitter) {
db.messageTable.getMessagesForBackup(db, exportState.backupTime, exportState.mediaBackupEnabled).use { chatItems ->
var count = 0
while (chatItems.hasNext()) {
if (count % 1000 == 0 && cancellationSignal()) {
return@use
}
val chatItem: ChatItem? = chatItems.next()
if (chatItem != null) {
if (exportState.threadIds.contains(chatItem.chatId)) {
emitter.emit(Frame(chatItem = chatItem))
}
}
count++
}
}
}