Improve thread update performance by avoiding costly join query.

This commit is contained in:
Cody Henthorne
2021-08-03 14:33:14 -04:00
committed by GitHub
parent aca3d150bf
commit 615fbf87c9
3 changed files with 74 additions and 48 deletions

View File

@@ -6,6 +6,7 @@ public interface MmsSmsColumns {
public static final String ID = "_id";
public static final String NORMALIZED_DATE_SENT = "date_sent";
public static final String NORMALIZED_DATE_RECEIVED = "date_received";
public static final String NORMALIZED_TYPE = "type";
public static final String DATE_SERVER = "date_server";
public static final String THREAD_ID = "thread_id";
public static final String READ = "read";

View File

@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.notifications.v2.MessageNotifierV2;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.CursorUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.whispersystems.libsignal.util.Pair;
import java.io.Closeable;
@@ -105,6 +106,14 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.NOTIFIED_TIMESTAMP,
MmsSmsColumns.VIEWED_RECEIPT_COUNT};
private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + SmsDatabase.TYPE + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + SmsDatabase.TABLE_NAME + " " +
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ") " +
"UNION ALL " +
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsDatabase.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsDatabase.TABLE_NAME + " " +
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? " +
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
"LIMIT 1";
public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) {
super(context, databaseHelper);
}
@@ -209,11 +218,33 @@ public class MmsSmsDatabase extends Database {
return cursor;
}
public Cursor getConversationSnippet(long threadId) {
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND (" + SmsDatabase.TYPE + " IS NULL OR " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + "))";
public @NonNull MessageRecord getConversationSnippet(long threadId) throws NoSuchMessageException {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) {
if (cursor.moveToFirst()) {
boolean isMms = CursorUtil.requireBoolean(cursor, TRANSPORT);
long id = CursorUtil.requireLong(cursor, MmsSmsColumns.ID);
return queryTables(PROJECTION, selection, order, "1");
if (isMms) {
return DatabaseFactory.getMmsDatabase(context).getMessageRecord(id);
} else {
return DatabaseFactory.getSmsDatabase(context).getMessageRecord(id);
}
} else {
throw new NoSuchMessageException("no message");
}
}
}
public long getConversationSnippetType(long threadId) throws NoSuchMessageException {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) {
if (cursor.moveToFirst()) {
return CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_TYPE);
} else {
throw new NoSuchMessageException("no message");
}
}
}
public Cursor getUnread() {
@@ -791,18 +822,6 @@ public class MmsSmsDatabase extends Database {
return databaseHelper.getReadableDatabase().rawQuery(query, null);
}
public static long getType(@NonNull Cursor cursor) {
String transportType = CursorUtil.requireString(cursor, TRANSPORT);
if (MmsSmsDatabase.MMS_TRANSPORT.equals(transportType)) {
return CursorUtil.requireLong(cursor, MmsDatabase.MESSAGE_BOX);
} else if (MmsSmsDatabase.SMS_TRANSPORT.equals(transportType)) {
return CursorUtil.requireLong(cursor, SmsDatabase.TYPE);
} else {
throw new AssertionError("Bad transport type: " + transportType);
}
}
public static Reader readerFor(@NonNull Cursor cursor) {
return new Reader(cursor);
}

View File

@@ -1226,8 +1226,8 @@ public class ThreadDatabase extends Database {
}
private boolean update(long threadId, boolean unarchive, boolean allowDeletion, boolean notifyListeners) {
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
boolean meaningfulMessages = mmsSmsDatabase.hasMeaningfulMessage(threadId);
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
boolean meaningfulMessages = mmsSmsDatabase.hasMeaningfulMessage(threadId);
if (!meaningfulMessages) {
if (allowDeletion) {
@@ -1236,43 +1236,49 @@ public class ThreadDatabase extends Database {
return true;
}
try (MmsSmsDatabase.Reader reader = MmsSmsDatabase.readerFor(mmsSmsDatabase.getConversationSnippet(threadId))) {
MessageRecord record = reader.getNext();
if (record != null) {
updateThread(threadId,
meaningfulMessages,
ThreadBodyUtil.getFormattedBodyFor(context, record),
getAttachmentUriFor(record),
getContentTypeFor(record),
getExtrasFor(record),
record.getTimestamp(),
record.getDeliveryStatus(),
record.getDeliveryReceiptCount(),
record.getType(),
unarchive,
record.getExpiresIn(),
record.getReadReceiptCount());
if (notifyListeners) {
notifyConversationListListeners();
}
return false;
} else {
MessageRecord record;
try {
record = mmsSmsDatabase.getConversationSnippet(threadId);
} catch (NoSuchMessageException e) {
if (allowDeletion) {
deleteConversation(threadId);
return true;
}
return true;
}
updateThread(threadId,
meaningfulMessages,
ThreadBodyUtil.getFormattedBodyFor(context, record),
getAttachmentUriFor(record),
getContentTypeFor(record),
getExtrasFor(record),
record.getTimestamp(),
record.getDeliveryStatus(),
record.getDeliveryReceiptCount(),
record.getType(),
unarchive,
record.getExpiresIn(),
record.getReadReceiptCount());
if (notifyListeners) {
notifyConversationListListeners();
}
return false;
}
public void updateSnippetTypeSilently(long threadId) {
try (Cursor cursor = DatabaseFactory.getMmsSmsDatabase(context).getConversationSnippet(threadId)) {
if (cursor.moveToFirst()) {
ContentValues contentValues = new ContentValues(1);
contentValues.put(SNIPPET_TYPE, MmsSmsDatabase.getType(cursor));
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId));
}
long type;
try {
type = DatabaseFactory.getMmsSmsDatabase(context).getConversationSnippetType(threadId);
} catch (NoSuchMessageException e) {
throw new AssertionError(e);
}
ContentValues contentValues = new ContentValues(1);
contentValues.put(SNIPPET_TYPE, type);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId));
}
public @NonNull ThreadRecord getThreadRecordFor(@NonNull Recipient recipient) {