Reduce number of SQL queries during conversation update
This commit is contained in:
parent
765b3eddc4
commit
962515031d
5 changed files with 90 additions and 91 deletions
|
@ -713,9 +713,7 @@ export async function startApp(): Promise<void> {
|
|||
const conversation = window.ConversationController.get(selectedId);
|
||||
assert(conversation, "Conversation wasn't found");
|
||||
|
||||
conversation.queueJob('maybeSetPendingUniversalTimer', () =>
|
||||
conversation.maybeSetPendingUniversalTimer()
|
||||
);
|
||||
await conversation.updateLastMessage();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -1061,11 +1061,6 @@ export class ConversationModel extends window.Backbone
|
|||
|
||||
// On successful fetch - mark contact as registered.
|
||||
this.setRegistered();
|
||||
|
||||
// If we couldn't apply universal timer before - try it again.
|
||||
this.queueJob('maybeSetPendingUniversalTimer', async () =>
|
||||
this.maybeSetPendingUniversalTimer()
|
||||
);
|
||||
}
|
||||
|
||||
isValid(): boolean {
|
||||
|
@ -2759,7 +2754,9 @@ export class ConversationModel extends window.Backbone
|
|||
return id;
|
||||
}
|
||||
|
||||
async maybeSetPendingUniversalTimer(): Promise<void> {
|
||||
async maybeSetPendingUniversalTimer(
|
||||
hasUserInitiatedMessages: boolean
|
||||
): Promise<void> {
|
||||
if (!isDirectConversation(this.attributes)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2768,7 +2765,8 @@ export class ConversationModel extends window.Backbone
|
|||
return;
|
||||
}
|
||||
|
||||
if (await window.Signal.Data.hasUserInitiatedMessages(this.get('id'))) {
|
||||
if (hasUserInitiatedMessages) {
|
||||
await this.maybeApplyUniversalTimer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2787,7 +2785,7 @@ export class ConversationModel extends window.Backbone
|
|||
this.set('pendingUniversalTimer', notificationId);
|
||||
}
|
||||
|
||||
async maybeApplyUniversalTimer(): Promise<void> {
|
||||
async maybeApplyUniversalTimer(forceRemove: boolean): Promise<void> {
|
||||
const notificationId = this.get('pendingUniversalTimer');
|
||||
if (!notificationId) {
|
||||
return;
|
||||
|
@ -2801,7 +2799,7 @@ export class ConversationModel extends window.Backbone
|
|||
});
|
||||
}
|
||||
|
||||
if (this.get('expireTimer')) {
|
||||
if (this.get('expireTimer') || forceRemove) {
|
||||
this.set('pendingUniversalTimer', undefined);
|
||||
return;
|
||||
}
|
||||
|
@ -3405,7 +3403,7 @@ export class ConversationModel extends window.Backbone
|
|||
timestamp
|
||||
);
|
||||
|
||||
await this.maybeApplyUniversalTimer();
|
||||
await this.maybeApplyUniversalTimer(false);
|
||||
|
||||
const expireTimer = this.get('expireTimer');
|
||||
|
||||
|
@ -3604,7 +3602,7 @@ export class ConversationModel extends window.Backbone
|
|||
this.queueJob('sendMessage', async () => {
|
||||
const now = timestamp || Date.now();
|
||||
|
||||
await this.maybeApplyUniversalTimer();
|
||||
await this.maybeApplyUniversalTimer(false);
|
||||
|
||||
const expireTimer = this.get('expireTimer');
|
||||
|
||||
|
@ -3822,28 +3820,25 @@ export class ConversationModel extends window.Backbone
|
|||
return;
|
||||
}
|
||||
|
||||
this.queueJob('maybeSetPendingUniversalTimer', async () =>
|
||||
this.maybeSetPendingUniversalTimer()
|
||||
);
|
||||
|
||||
const ourConversationId = window.ConversationController.getOurConversationId();
|
||||
if (!ourConversationId) {
|
||||
throw new Error('updateLastMessage: Failed to fetch ourConversationId');
|
||||
}
|
||||
|
||||
const conversationId = this.id;
|
||||
let [previewMessage, activityMessage] = await Promise.all([
|
||||
window.Signal.Data.getLastConversationPreview({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
Message: window.Whisper.Message,
|
||||
}),
|
||||
window.Signal.Data.getLastConversationActivity({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
Message: window.Whisper.Message,
|
||||
}),
|
||||
]);
|
||||
|
||||
const lastMessages = await window.Signal.Data.getLastConversationMessages({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
Message: window.Whisper.Message,
|
||||
});
|
||||
|
||||
// This runs as a job to avoid race conditions
|
||||
this.queueJob('maybeSetPendingUniversalTimer', async () =>
|
||||
this.maybeSetPendingUniversalTimer(lastMessages.hasUserInitiatedMessages)
|
||||
);
|
||||
|
||||
let { preview: previewMessage, activity: activityMessage } = lastMessages;
|
||||
|
||||
// Register the message with MessageController so that if it already exists
|
||||
// in memory we use that data instead of the data from the db which may
|
||||
|
@ -4157,7 +4152,7 @@ export class ConversationModel extends window.Backbone
|
|||
|
||||
// This call actually removes universal timer notification and clears
|
||||
// the pending flags.
|
||||
await this.maybeApplyUniversalTimer();
|
||||
await this.maybeApplyUniversalTimer(true);
|
||||
|
||||
window.Signal.Data.updateConversation(this.attributes);
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ import {
|
|||
IdentityKeyType,
|
||||
ItemKeyType,
|
||||
ItemType,
|
||||
LastConversationMessagesType,
|
||||
MessageType,
|
||||
MessageTypeUnhydrated,
|
||||
PreKeyType,
|
||||
|
@ -190,7 +191,6 @@ const dataInterface: ClientInterface = {
|
|||
searchMessagesInConversation,
|
||||
|
||||
getMessageCount,
|
||||
hasUserInitiatedMessages,
|
||||
saveMessage,
|
||||
saveMessages,
|
||||
removeMessage,
|
||||
|
@ -213,8 +213,7 @@ const dataInterface: ClientInterface = {
|
|||
getTapToViewMessagesNeedingErase,
|
||||
getOlderMessagesByConversation,
|
||||
getNewerMessagesByConversation,
|
||||
getLastConversationActivity,
|
||||
getLastConversationPreview,
|
||||
getLastConversationMessages,
|
||||
getMessageMetricsForConversation,
|
||||
hasGroupCallHistoryMessage,
|
||||
migrateConversationMessages,
|
||||
|
@ -1063,10 +1062,6 @@ async function getMessageCount(conversationId?: string) {
|
|||
return channels.getMessageCount(conversationId);
|
||||
}
|
||||
|
||||
async function hasUserInitiatedMessages(conversationId: string) {
|
||||
return channels.hasUserInitiatedMessages(conversationId);
|
||||
}
|
||||
|
||||
async function saveMessage(
|
||||
data: MessageType,
|
||||
options?: { forceSave?: boolean }
|
||||
|
@ -1267,7 +1262,7 @@ async function getNewerMessagesByConversation(
|
|||
|
||||
return new MessageCollection(handleMessageJSON(messages));
|
||||
}
|
||||
async function getLastConversationActivity({
|
||||
async function getLastConversationMessages({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
Message,
|
||||
|
@ -1275,33 +1270,21 @@ async function getLastConversationActivity({
|
|||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
Message: typeof MessageModel;
|
||||
}): Promise<MessageModel | undefined> {
|
||||
const result = await channels.getLastConversationActivity({
|
||||
}): Promise<LastConversationMessagesType> {
|
||||
const {
|
||||
preview,
|
||||
activity,
|
||||
hasUserInitiatedMessages,
|
||||
} = await channels.getLastConversationMessages({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
});
|
||||
if (result) {
|
||||
return new Message(result);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
async function getLastConversationPreview({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
Message,
|
||||
}: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
Message: typeof MessageModel;
|
||||
}): Promise<MessageModel | undefined> {
|
||||
const result = await channels.getLastConversationPreview({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
});
|
||||
if (result) {
|
||||
return new Message(result);
|
||||
}
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
preview: preview ? new Message(preview) : undefined,
|
||||
activity: activity ? new Message(activity) : undefined,
|
||||
hasUserInitiatedMessages,
|
||||
};
|
||||
}
|
||||
async function getMessageMetricsForConversation(conversationId: string) {
|
||||
const result = await channels.getMessageMetricsForConversation(
|
||||
|
|
|
@ -201,6 +201,18 @@ export type UnprocessedUpdateType = {
|
|||
decrypted?: string;
|
||||
};
|
||||
|
||||
export type LastConversationMessagesServerType = {
|
||||
activity?: MessageType;
|
||||
preview?: MessageType;
|
||||
hasUserInitiatedMessages: boolean;
|
||||
};
|
||||
|
||||
export type LastConversationMessagesType = {
|
||||
activity?: MessageModel;
|
||||
preview?: MessageModel;
|
||||
hasUserInitiatedMessages: boolean;
|
||||
};
|
||||
|
||||
export type DataInterface = {
|
||||
close: () => Promise<void>;
|
||||
removeDB: () => Promise<void>;
|
||||
|
@ -302,7 +314,6 @@ export type DataInterface = {
|
|||
options?: { forceSave?: boolean }
|
||||
) => Promise<void>;
|
||||
getMessageCount: (conversationId?: string) => Promise<number>;
|
||||
hasUserInitiatedMessages: (conversationId: string) => Promise<boolean>;
|
||||
getAllMessageIds: () => Promise<Array<string>>;
|
||||
getMessageMetricsForConversation: (
|
||||
conversationId: string
|
||||
|
@ -476,14 +487,10 @@ export type ServerInterface = DataInterface & {
|
|||
conversationId: string,
|
||||
options?: { limit?: number; receivedAt?: number; sentAt?: number }
|
||||
) => Promise<Array<MessageTypeUnhydrated>>;
|
||||
getLastConversationActivity: (options: {
|
||||
getLastConversationMessages: (options: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
}) => Promise<MessageType | undefined>;
|
||||
getLastConversationPreview: (options: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
}) => Promise<MessageType | undefined>;
|
||||
}) => Promise<LastConversationMessagesServerType>;
|
||||
getTapToViewMessagesNeedingErase: () => Promise<Array<MessageType>>;
|
||||
removeConversation: (id: Array<string> | string) => Promise<void>;
|
||||
removeMessage: (id: string) => Promise<void>;
|
||||
|
@ -576,16 +583,11 @@ export type ClientInterface = DataInterface & {
|
|||
MessageCollection: typeof MessageModelCollectionType;
|
||||
}
|
||||
) => Promise<MessageModelCollectionType>;
|
||||
getLastConversationActivity: (options: {
|
||||
getLastConversationMessages: (options: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
Message: typeof MessageModel;
|
||||
}) => Promise<MessageModel | undefined>;
|
||||
getLastConversationPreview: (options: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
Message: typeof MessageModel;
|
||||
}) => Promise<MessageModel | undefined>;
|
||||
}) => Promise<LastConversationMessagesType>;
|
||||
getTapToViewMessagesNeedingErase: (options: {
|
||||
MessageCollection: typeof MessageModelCollectionType;
|
||||
}) => Promise<MessageModelCollectionType>;
|
||||
|
|
|
@ -52,6 +52,7 @@ import {
|
|||
IdentityKeyType,
|
||||
ItemKeyType,
|
||||
ItemType,
|
||||
LastConversationMessagesServerType,
|
||||
MessageMetricsType,
|
||||
MessageType,
|
||||
MessageTypeUnhydrated,
|
||||
|
@ -179,7 +180,6 @@ const dataInterface: ServerInterface = {
|
|||
searchMessagesInConversation,
|
||||
|
||||
getMessageCount,
|
||||
hasUserInitiatedMessages,
|
||||
saveMessage,
|
||||
saveMessages,
|
||||
removeMessage,
|
||||
|
@ -203,8 +203,7 @@ const dataInterface: ServerInterface = {
|
|||
getOlderMessagesByConversation,
|
||||
getNewerMessagesByConversation,
|
||||
getMessageMetricsForConversation,
|
||||
getLastConversationActivity,
|
||||
getLastConversationPreview,
|
||||
getLastConversationMessages,
|
||||
hasGroupCallHistoryMessage,
|
||||
migrateConversationMessages,
|
||||
|
||||
|
@ -3513,10 +3512,7 @@ async function getMessageCount(conversationId?: string): Promise<number> {
|
|||
return row['count(*)'];
|
||||
}
|
||||
|
||||
// Called only for private conversations
|
||||
async function hasUserInitiatedMessages(
|
||||
conversationId: string
|
||||
): Promise<boolean> {
|
||||
function hasUserInitiatedMessages(conversationId: string): boolean {
|
||||
const db = getInstance();
|
||||
|
||||
// We apply the limit in the sub-query so that `json_extract` wouldn't run
|
||||
|
@ -3538,10 +3534,10 @@ async function hasUserInitiatedMessages(
|
|||
'keychange',
|
||||
'group-v1-migration',
|
||||
'universal-timer-notification',
|
||||
'change-number-notification'
|
||||
'change-number-notification',
|
||||
'group-v2-change'
|
||||
)
|
||||
) AND
|
||||
json_extract(json, '$.expirationTimerUpdate') IS NULL
|
||||
)
|
||||
LIMIT 1
|
||||
);
|
||||
`
|
||||
|
@ -4218,13 +4214,13 @@ function getNewestMessageForConversation(
|
|||
return row;
|
||||
}
|
||||
|
||||
async function getLastConversationActivity({
|
||||
function getLastConversationActivity({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
}: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
}): Promise<MessageType | undefined> {
|
||||
}): MessageType | undefined {
|
||||
const db = getInstance();
|
||||
const row = prepare(
|
||||
db,
|
||||
|
@ -4270,13 +4266,13 @@ async function getLastConversationActivity({
|
|||
|
||||
return jsonToObject(row.json);
|
||||
}
|
||||
async function getLastConversationPreview({
|
||||
function getLastConversationPreview({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
}: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
}): Promise<MessageType | undefined> {
|
||||
}): MessageType | undefined {
|
||||
const db = getInstance();
|
||||
const row = prepare(
|
||||
db,
|
||||
|
@ -4317,6 +4313,31 @@ async function getLastConversationPreview({
|
|||
|
||||
return jsonToObject(row.json);
|
||||
}
|
||||
|
||||
async function getLastConversationMessages({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
}: {
|
||||
conversationId: string;
|
||||
ourConversationId: string;
|
||||
}): Promise<LastConversationMessagesServerType> {
|
||||
const db = getInstance();
|
||||
|
||||
return db.transaction(() => {
|
||||
return {
|
||||
activity: getLastConversationActivity({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
}),
|
||||
preview: getLastConversationPreview({
|
||||
conversationId,
|
||||
ourConversationId,
|
||||
}),
|
||||
hasUserInitiatedMessages: hasUserInitiatedMessages(conversationId),
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
function getOldestUnreadMessageForConversation(
|
||||
conversationId: string
|
||||
): MessageMetricsType | undefined {
|
||||
|
|
Loading…
Add table
Reference in a new issue