mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 08:39:22 +01:00
Improve group conversation open performance by prefetching member labels.
This commit is contained in:
committed by
jeffrey-signal
parent
49d3f7652d
commit
3d78d5473e
@@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||
import org.thoughtcrime.securesms.groups.memberlabel.MemberLabel;
|
||||
import org.thoughtcrime.securesms.groups.memberlabel.MemberLabelRepository;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
||||
|
||||
@@ -31,6 +32,7 @@ import java.security.MessageDigest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A view level model used to pass arbitrary message related information needed
|
||||
@@ -230,6 +232,25 @@ public class ConversationMessage {
|
||||
@Nullable List<Mention> mentions,
|
||||
boolean hasBeenQuoted,
|
||||
@NonNull Recipient threadRecipient)
|
||||
{
|
||||
return createWithUnresolvedData(context, messageRecord, body, mentions, hasBeenQuoted, threadRecipient, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ConversationMessage} wrapping the provided MessageRecord and will update and modify the provided
|
||||
* mentions from placeholder to actual. This method may perform database operations to resolve mentions to display names.
|
||||
*
|
||||
* @param mentions List of placeholder mentions to be used to update the body in the provided MessageRecord.
|
||||
* @param prefetchedLabels Pre-fetched member labels keyed by RecipientId, or null to fetch on demand.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static @NonNull ConversationMessage createWithUnresolvedData(@NonNull Context context,
|
||||
@NonNull MessageRecord messageRecord,
|
||||
@NonNull CharSequence body,
|
||||
@Nullable List<Mention> mentions,
|
||||
boolean hasBeenQuoted,
|
||||
@NonNull Recipient threadRecipient,
|
||||
@Nullable Map<RecipientId, MemberLabel> prefetchedLabels)
|
||||
{
|
||||
SpannableString styledAndMentionBody = null;
|
||||
MessageStyler.Result styleResult = MessageStyler.Result.none();
|
||||
@@ -257,8 +278,8 @@ public class ConversationMessage {
|
||||
}
|
||||
|
||||
FormattedDate formattedDate = getFormattedDate(context, messageRecord);
|
||||
MemberLabel memberLabel = getMemberLabel(messageRecord, threadRecipient);
|
||||
MemberLabel quoteMemberLabel = getQuoteMemberLabel(messageRecord, threadRecipient);
|
||||
MemberLabel memberLabel = getMemberLabel(messageRecord, threadRecipient, prefetchedLabels);
|
||||
MemberLabel quoteMemberLabel = getQuoteMemberLabel(messageRecord, threadRecipient, prefetchedLabels);
|
||||
Recipient deletedBy = messageRecord.getDeletedBy() != null ? Recipient.resolved(messageRecord.getDeletedBy()) : null;
|
||||
|
||||
return new ConversationMessage(messageRecord,
|
||||
@@ -310,21 +331,30 @@ public class ConversationMessage {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private static @Nullable MemberLabel getMemberLabel(@NonNull MessageRecord messageRecord, @NonNull Recipient threadRecipient) {
|
||||
private static @Nullable MemberLabel getMemberLabel(@NonNull MessageRecord messageRecord, @NonNull Recipient threadRecipient, @Nullable Map<RecipientId, MemberLabel> prefetchedLabels) {
|
||||
if (messageRecord.isOutgoing() || !threadRecipient.isPushV2Group()) {
|
||||
return null;
|
||||
}
|
||||
return MemberLabelRepository.getInstance().getLabelJava(threadRecipient.requireGroupId().requireV2(), messageRecord.getFromRecipient());
|
||||
|
||||
if (prefetchedLabels != null) {
|
||||
return prefetchedLabels.get(messageRecord.getFromRecipient().getId());
|
||||
}
|
||||
|
||||
return MemberLabelRepository.getInstance().getLabelSync(threadRecipient.requireGroupId().requireV2(), messageRecord.getFromRecipient());
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private static @Nullable MemberLabel getQuoteMemberLabel(@NonNull MessageRecord messageRecord, @NonNull Recipient threadRecipient) {
|
||||
private static @Nullable MemberLabel getQuoteMemberLabel(@NonNull MessageRecord messageRecord, @NonNull Recipient threadRecipient, @Nullable Map<RecipientId, MemberLabel> prefetchedLabels) {
|
||||
if (!threadRecipient.isPushV2Group() || !(messageRecord instanceof final MmsMessageRecord mmsMessage) || mmsMessage.getQuote() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefetchedLabels != null) {
|
||||
return prefetchedLabels.get(mmsMessage.getQuote().getAuthor());
|
||||
}
|
||||
|
||||
Recipient quoteAuthor = Recipient.resolved(mmsMessage.getQuote().getAuthor());
|
||||
return MemberLabelRepository.getInstance().getLabelJava(threadRecipient.requireGroupId().requireV2(), quoteAuthor);
|
||||
return MemberLabelRepository.getInstance().getLabelSync(threadRecipient.requireGroupId().requireV2(), quoteAuthor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public final class ShowAdminsBottomSheetDialog extends BottomSheetDialogFragment
|
||||
}
|
||||
|
||||
List<Recipient> admins = groupRecord.getAdmins();
|
||||
Map<RecipientId, MemberLabel> labelsByRecipientId = MemberLabelRepository.getInstance().getLabelsJava(groupId.requireV2(), admins);
|
||||
Map<RecipientId, MemberLabel> labelsByRecipientId = MemberLabelRepository.getInstance().getLabelsSync(groupId.requireV2(), admins);
|
||||
List<ServiceId> memberIds = groupRecord.requireV2GroupProperties().getMemberServiceIds();
|
||||
ColorizerV2 colorizer = new ColorizerV2(memberIds);
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ class ConversationDataSource(
|
||||
|
||||
stopwatch.split("messages")
|
||||
|
||||
val extraData = MessageDataFetcher.fetch(records)
|
||||
val extraData = MessageDataFetcher.fetch(records, threadRecipient)
|
||||
stopwatch.split("extra-data")
|
||||
|
||||
records = MessageDataFetcher.updateModelsWithData(records, extraData).toMutableList()
|
||||
@@ -136,7 +136,8 @@ class ConversationDataSource(
|
||||
record.getDisplayBody(localContext),
|
||||
extraData.mentionsById[record.id],
|
||||
extraData.hasBeenQuoted.contains(record.id),
|
||||
threadRecipient
|
||||
threadRecipient,
|
||||
extraData.memberLabels
|
||||
).toMappingModel()
|
||||
}
|
||||
|
||||
@@ -186,7 +187,7 @@ class ConversationDataSource(
|
||||
if (record == null) {
|
||||
return null
|
||||
} else {
|
||||
extraData = MessageDataFetcher.fetch(record)
|
||||
extraData = MessageDataFetcher.fetch(record, threadRecipient)
|
||||
stopwatch.split("extra-data")
|
||||
|
||||
record = MessageDataFetcher.updateModelWithData(record, extraData)
|
||||
@@ -198,7 +199,8 @@ class ConversationDataSource(
|
||||
record.getDisplayBody(AppDependencies.application),
|
||||
extraData.mentionsById[record.id],
|
||||
extraData.hasBeenQuoted.contains(record.id),
|
||||
threadRecipient
|
||||
threadRecipient,
|
||||
extraData.memberLabels
|
||||
).toMappingModel()
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.CallTable
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.Mention
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.ReactionRecord
|
||||
import org.thoughtcrime.securesms.database.model.withAttachments
|
||||
import org.thoughtcrime.securesms.database.model.withCall
|
||||
@@ -21,6 +22,8 @@ import org.thoughtcrime.securesms.database.model.withPayment
|
||||
import org.thoughtcrime.securesms.database.model.withPoll
|
||||
import org.thoughtcrime.securesms.database.model.withReactions
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.groups.memberlabel.MemberLabel
|
||||
import org.thoughtcrime.securesms.groups.memberlabel.MemberLabelRepository
|
||||
import org.thoughtcrime.securesms.payments.Payment
|
||||
import org.thoughtcrime.securesms.polls.PollRecord
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
@@ -40,8 +43,8 @@ object MessageDataFetcher {
|
||||
/**
|
||||
* Singular version of [fetch].
|
||||
*/
|
||||
fun fetch(messageRecord: MessageRecord): ExtraMessageData {
|
||||
return fetch(listOf(messageRecord))
|
||||
fun fetch(messageRecord: MessageRecord, threadRecipient: Recipient? = null): ExtraMessageData {
|
||||
return fetch(listOf(messageRecord), threadRecipient)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +55,7 @@ object MessageDataFetcher {
|
||||
* so this should be called on a background thread.
|
||||
*/
|
||||
@WorkerThread
|
||||
fun fetch(messageRecords: List<MessageRecord>): ExtraMessageData {
|
||||
fun fetch(messageRecords: List<MessageRecord>, threadRecipient: Recipient? = null): ExtraMessageData {
|
||||
val startTimeNanos = System.nanoTime()
|
||||
val context = AppDependencies.application
|
||||
|
||||
@@ -105,6 +108,25 @@ object MessageDataFetcher {
|
||||
SignalDatabase.polls.getPollsForMessages(messageIds)
|
||||
}
|
||||
|
||||
val memberLabelsFuture = if (threadRecipient != null && threadRecipient.isPushV2Group) {
|
||||
executor.submitTimed {
|
||||
val fromRecipients = mutableSetOf<Recipient>()
|
||||
val quoteRecipientIds = mutableSetOf<RecipientId>()
|
||||
for (record in messageRecords) {
|
||||
if (!record.isOutgoing) {
|
||||
fromRecipients.add(record.fromRecipient)
|
||||
}
|
||||
if (record is MmsMessageRecord && record.quote != null) {
|
||||
quoteRecipientIds.add(record.quote!!.author)
|
||||
}
|
||||
}
|
||||
val recipients = fromRecipients + Recipient.resolvedList(quoteRecipientIds)
|
||||
MemberLabelRepository.instance.getLabelsSync(threadRecipient.requireGroupId().requireV2(), recipients)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val mentionsResult = mentionsFuture.get()
|
||||
val hasBeenQuotedResult = hasBeenQuotedFuture.get()
|
||||
val reactionsResult = reactionsFuture.get()
|
||||
@@ -113,10 +135,11 @@ object MessageDataFetcher {
|
||||
val callsResult = callsFuture.get()
|
||||
val recipientsResult = recipientsFuture.get()
|
||||
val pollsResult = pollsFuture.get()
|
||||
val memberLabelsResult = memberLabelsFuture?.get()
|
||||
|
||||
val wallTimeMs = (System.nanoTime() - startTimeNanos).nanoseconds.toDouble(DurationUnit.MILLISECONDS)
|
||||
|
||||
val cpuTimeNanos = arrayOf(mentionsResult, hasBeenQuotedResult, reactionsResult, attachmentsResult, paymentsResult, callsResult, recipientsResult).sumOf { it.durationNanos }
|
||||
val cpuTimeNanos = arrayOf(mentionsResult, hasBeenQuotedResult, reactionsResult, attachmentsResult, paymentsResult, callsResult, recipientsResult).sumOf { it.durationNanos } + (memberLabelsResult?.durationNanos ?: 0)
|
||||
val cpuTimeMs = cpuTimeNanos.nanoseconds.toDouble(DurationUnit.MILLISECONDS)
|
||||
|
||||
return ExtraMessageData(
|
||||
@@ -127,7 +150,8 @@ object MessageDataFetcher {
|
||||
payments = paymentsResult.result,
|
||||
calls = callsResult.result,
|
||||
polls = pollsResult.result,
|
||||
timeLog = "mentions: ${mentionsResult.duration}, is-quoted: ${hasBeenQuotedResult.duration}, reactions: ${reactionsResult.duration}, attachments: ${attachmentsResult.duration}, payments: ${paymentsResult.duration}, calls: ${callsResult.duration} >> cpuTime: ${cpuTimeMs.roundedString(2)}, wallTime: ${wallTimeMs.roundedString(2)}"
|
||||
memberLabels = memberLabelsResult?.result,
|
||||
timeLog = "mentions: ${mentionsResult.duration}, is-quoted: ${hasBeenQuotedResult.duration}, reactions: ${reactionsResult.duration}, attachments: ${attachmentsResult.duration}, payments: ${paymentsResult.duration}, calls: ${callsResult.duration}, member-labels: ${memberLabelsResult?.duration ?: "n/a"} >> cpuTime: ${cpuTimeMs.roundedString(2)}, wallTime: ${wallTimeMs.roundedString(2)}"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -200,6 +224,7 @@ object MessageDataFetcher {
|
||||
val payments: Map<Long, Payment>,
|
||||
val calls: Map<Long, CallTable.Call>,
|
||||
val polls: Map<Long, PollRecord>,
|
||||
val memberLabels: Map<RecipientId, MemberLabel>?,
|
||||
val timeLog: String
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user