Fetch isQuoted status in bulk during conversation load.

Improves overall time to load a page of messages by ~50%.
main
Greyson Parrelli 2022-12-18 11:43:39 -05:00
rodzic c6f29fc950
commit a84a9c5381
3 zmienionych plików z 93 dodań i 16 usunięć

Wyświetl plik

@ -93,10 +93,11 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
@Override
public @NonNull List<ConversationMessage> load(int start, int length, @NonNull CancellationSignal cancellationSignal) {
Stopwatch stopwatch = new Stopwatch("load(" + start + ", " + length + "), thread " + threadId);
MmsSmsTable db = SignalDatabase.mmsSms();
List<MessageRecord> records = new ArrayList<>(length);
Stopwatch stopwatch = new Stopwatch("load(" + start + ", " + length + "), thread " + threadId);
MmsSmsTable db = SignalDatabase.mmsSms();
List<MessageRecord> records = new ArrayList<>(length);
MentionHelper mentionHelper = new MentionHelper();
QuotedHelper quotedHelper = new QuotedHelper();
AttachmentHelper attachmentHelper = new AttachmentHelper();
ReactionHelper reactionHelper = new ReactionHelper();
PaymentHelper paymentHelper = new PaymentHelper();
@ -107,6 +108,7 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
while ((record = reader.getNext()) != null && !cancellationSignal.isCanceled()) {
records.add(record);
mentionHelper.add(record);
quotedHelper.add(record);
reactionHelper.add(record);
attachmentHelper.add(record);
paymentHelper.add(record);
@ -131,6 +133,9 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
mentionHelper.fetchMentions(context);
stopwatch.split("mentions");
quotedHelper.fetchQuotedState();
stopwatch.split("is-quoted");
reactionHelper.fetchReactions();
stopwatch.split("reactions");
@ -155,7 +160,7 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
stopwatch.split("recipient-resolves");
List<ConversationMessage> messages = Stream.of(records)
.map(m -> ConversationMessageFactory.createWithUnresolvedData(context, m, mentionHelper.getMentions(m.getId())))
.map(m -> ConversationMessageFactory.createWithUnresolvedData(context, m, mentionHelper.getMentions(m.getId()), quotedHelper.isQuoted(m.getId())))
.toList();
stopwatch.split("conversion");
@ -180,28 +185,27 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
try {
if (record != null) {
List<Mention> mentions = SignalDatabase.mentions().getMentionsForMessage(messageId.getId());
stopwatch.split("mentions");
boolean isQuoted = SignalDatabase.mmsSms().isQuoted(record);
stopwatch.split("is-quoted");
List<ReactionRecord> reactions = SignalDatabase.reactions().getReactions(messageId);
record = ReactionHelper.recordWithReactions(record, reactions);
stopwatch.split("reactions");
List<DatabaseAttachment> attachments = SignalDatabase.attachments().getAttachmentsForMessage(messageId.getId());
if (attachments.size() > 0) {
record = ((MediaMmsMessageRecord) record).withAttachments(context, attachments);
}
stopwatch.split("attachments");
if (record.isPaymentNotification()) {
record = SignalDatabase.payments().updateMessageWithPayment(record);
}
stopwatch.split("payments");
return ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(ApplicationDependencies.getApplication(), record, mentions);
return ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(ApplicationDependencies.getApplication(), record, mentions, isQuoted);
} else {
return null;
}
@ -235,6 +239,24 @@ public class ConversationDataSource implements PagedDataSource<MessageId, Conver
}
}
private static class QuotedHelper {
private Collection<MessageRecord> records = new LinkedList<>();
private Set<Long> hasBeenQuotedIds = new HashSet<>();
void add(MessageRecord record) {
records.add(record);
}
void fetchQuotedState() {
hasBeenQuotedIds = SignalDatabase.mmsSms().isQuoted(records);
}
boolean isQuoted(long id) {
return hasBeenQuotedIds.contains(id);
}
}
private static class AttachmentHelper {
private Collection<Long> messageIds = new LinkedList<>();

Wyświetl plik

@ -35,10 +35,6 @@ public class ConversationMessage {
@NonNull private final MessageStyler.Result styleResult;
private final boolean hasBeenQuoted;
private ConversationMessage(@NonNull MessageRecord messageRecord) {
this(messageRecord, null, null, false);
}
private ConversationMessage(@NonNull MessageRecord messageRecord, boolean hasBeenQuoted) {
this(messageRecord, null, null, hasBeenQuoted);
}
@ -165,9 +161,7 @@ public class ConversationMessage {
* @param mentions List of placeholder mentions to be used to update the body in the provided MessageRecord.
*/
@WorkerThread
public static @NonNull ConversationMessage createWithUnresolvedData(@NonNull Context context, @NonNull MessageRecord messageRecord, @Nullable List<Mention> mentions) {
boolean hasBeenQuoted = SignalDatabase.mmsSms().isQuoted(messageRecord);
public static @NonNull ConversationMessage createWithUnresolvedData(@NonNull Context context, @NonNull MessageRecord messageRecord, @Nullable List<Mention> mentions, boolean hasBeenQuoted) {
if (messageRecord.isMms() && mentions != null && !mentions.isEmpty()) {
MentionUtil.UpdatedBodyAndMentions updated = MentionUtil.updateBodyAndMentionsWithDisplayNames(context, messageRecord, mentions);
return new ConversationMessage(messageRecord, updated.getBody(), updated.getMentions(), hasBeenQuoted);

Wyświetl plik

@ -52,10 +52,12 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -261,6 +263,42 @@ public class MmsSmsTable extends DatabaseTable {
return queryTables(PROJECTION, selection, order, null, true);
}
public Set<Long> isQuoted(@NonNull Collection<MessageRecord> records) {
if (records.isEmpty()) {
return Collections.emptySet();
}
Map<QuoteDescriptor, MessageRecord> byQuoteDescriptor = new HashMap<>(records.size());
List<String[]> args = new ArrayList<>(records.size());
for (MessageRecord record : records) {
long timestamp = record.getDateSent();
RecipientId author = record.isOutgoing() ? Recipient.self().getId() : record.getRecipient().getId();
byQuoteDescriptor.put(new QuoteDescriptor(timestamp, author), record);
args.add(SqlUtil.buildArgs(timestamp, author));
}
String[] projection = new String[] { MessageTable.QUOTE_ID, MessageTable.QUOTE_AUTHOR };
List<SqlUtil.Query> queries = SqlUtil.buildCustomCollectionQuery(MessageTable.QUOTE_ID + " = ? AND " + MessageTable.QUOTE_AUTHOR + " = ?", args);
Set<Long> quotedIds = new HashSet<>();
for (SqlUtil.Query query : queries) {
try (Cursor cursor = getReadableDatabase().query(MessageTable.TABLE_NAME, projection, query.getWhere(), query.getWhereArgs(), null, null, null)) {
while (cursor.moveToNext()) {
long timestamp = CursorUtil.requireLong(cursor, MessageTable.QUOTE_ID);
RecipientId author = RecipientId.from(CursorUtil.requireString(cursor, MessageTable.QUOTE_AUTHOR));
QuoteDescriptor quoteLocator = new QuoteDescriptor(timestamp, author);
quotedIds.add(byQuoteDescriptor.get(quoteLocator).getId());
}
}
}
return quotedIds;
}
/**
* Whether or not the message has been quoted by another message.
*/
@ -984,4 +1022,27 @@ public class MmsSmsTable extends DatabaseTable {
this.threads = threads;
}
}
private static class QuoteDescriptor {
private final long timestamp;
private final RecipientId author;
private QuoteDescriptor(long timestamp, RecipientId author) {
this.author = author;
this.timestamp = timestamp;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final QuoteDescriptor that = (QuoteDescriptor) o;
return timestamp == that.timestamp && author.equals(that.author);
}
@Override
public int hashCode() {
return Objects.hash(author, timestamp);
}
}
}