From 6db71f4a39154389eae0f80355ce57e17dd9d26c Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Tue, 18 Apr 2023 09:35:37 -0400 Subject: [PATCH] Improve performance of finding message positions in chats. --- .../securesms/database/MessageTable.kt | 74 ++++++++++--------- .../org/signal/core/util/CursorExtensions.kt | 5 ++ 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index 8560e0e9be..2bc4249869 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -51,6 +51,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.requireNonNullString import org.signal.core.util.requireString import org.signal.core.util.select @@ -4009,52 +4010,53 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } fun getQuotedMessagePosition(threadId: Long, quoteId: Long, authorId: RecipientId): Int { - var position = 0 - readableDatabase - .select(DATE_SENT, FROM_RECIPIENT_ID, REMOTE_DELETED, LATEST_REVISION_ID) + val targetMessageDateReceived: Long = readableDatabase + .select(DATE_RECEIVED, LATEST_REVISION_ID) .from(TABLE_NAME) - .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1") - .orderBy("$DATE_RECEIVED DESC") + .where("$DATE_SENT = $quoteId AND $FROM_RECIPIENT_ID = ? AND $REMOTE_DELETED = 0 AND $SCHEDULED_DATE = -1", authorId) .run() - .forEach { cursor -> - val quoteIdMatches = cursor.requireLong(DATE_SENT) == quoteId - val recipientIdMatches = authorId == RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) - - if (quoteIdMatches && recipientIdMatches) { - return if (cursor.requireBoolean(REMOTE_DELETED)) { - -1 - } else { - position - } - } else if (cursor.requireLong(LATEST_REVISION_ID) == 0L) { - position++ + .readToSingleObject { cursor -> + val latestRevisionId = cursor.requireLongOrNull(LATEST_REVISION_ID) + if (latestRevisionId != null) { + readableDatabase + .select(DATE_RECEIVED) + .from(TABLE_NAME) + .where("$ID = ?", latestRevisionId) + .run() + .readToSingleLong(-1L) + } else { + cursor.requireLong(DATE_RECEIVED) } - } + } ?: -1L - return -1 + if (targetMessageDateReceived == -1L) { + return -1 + } + + return readableDatabase + .select("COUNT(*)") + .from(TABLE_NAME) + .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1 AND $LATEST_REVISION_ID IS NULL AND $DATE_RECEIVED > $targetMessageDateReceived") + .run() + .readToSingleInt() } fun getMessagePositionInConversation(threadId: Long, receivedTimestamp: Long, authorId: RecipientId): Int { - readableDatabase - .select(DATE_RECEIVED, FROM_RECIPIENT_ID, REMOTE_DELETED) - .from(TABLE_NAME) - .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1 AND $LATEST_REVISION_ID IS NULL") - .orderBy("$DATE_RECEIVED DESC") + val validMessageExists: Boolean = readableDatabase + .exists(TABLE_NAME) + .where("$DATE_RECEIVED = $receivedTimestamp AND $FROM_RECIPIENT_ID = ? AND $REMOTE_DELETED = 0 AND $SCHEDULED_DATE = -1 AND $LATEST_REVISION_ID IS NULL", authorId) .run() - .forEach { cursor -> - val timestampMatches = cursor.requireLong(DATE_RECEIVED) == receivedTimestamp - val authorIdMatches = authorId == RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) - if (timestampMatches && authorIdMatches) { - return if (cursor.requireBoolean(REMOTE_DELETED)) { - -1 - } else { - cursor.position - } - } - } + if (!validMessageExists) { + return -1 + } - return -1 + return readableDatabase + .select("COUNT(*)") + .from(TABLE_NAME) + .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1 AND $LATEST_REVISION_ID IS NULL AND $DATE_RECEIVED > $receivedTimestamp") + .run() + .readToSingleInt(-1) } fun getMessagePositionInConversation(threadId: Long, receivedTimestamp: Long): Int { diff --git a/core-util/src/main/java/org/signal/core/util/CursorExtensions.kt b/core-util/src/main/java/org/signal/core/util/CursorExtensions.kt index 14774731f8..2d49659153 100644 --- a/core-util/src/main/java/org/signal/core/util/CursorExtensions.kt +++ b/core-util/src/main/java/org/signal/core/util/CursorExtensions.kt @@ -1,6 +1,7 @@ package org.signal.core.util import android.database.Cursor +import androidx.core.database.getLongOrNull import java.util.Optional fun Cursor.requireString(column: String): String? { @@ -31,6 +32,10 @@ fun Cursor.requireLong(column: String): Long { return CursorUtil.requireLong(this, column) } +fun Cursor.requireLongOrNull(column: String): Long? { + return this.getLongOrNull(this.getColumnIndexOrThrow(column)) +} + fun Cursor.optionalLong(column: String): Optional { return CursorUtil.getLong(this, column) }