Compare commits

...

2 Commits

Author SHA1 Message Date
iequidoo
247ec1e1ad feat: Add timestamp to msgs_index7 to employ it in calc_sort_timestamp()
Tested on some random chat, the SQL query took 1.411202ms (vs 6.692714ms before) in median. Still
looks a bit slow, but already better.
2025-10-25 03:59:07 -03:00
iequidoo
1eb44328f0 feat: calc_sort_timestamp(): Don't look at existing messages' timestamp_sent
This makes `calc_sort_timestamp()` a continuous function of the message timestamp, simplifies the
SQL query and prepares for creation of a db index for it so that it's fast. Currently it doesn't
uses indexes effectively; if a chat has many messages, it's slow, i.e. O(n).
2025-10-25 03:59:07 -03:00
5 changed files with 31 additions and 22 deletions

View File

@@ -1211,37 +1211,34 @@ impl ChatId {
)
.await?
} else if received {
// Received messages shouldn't mingle with just sent ones and appear somewhere in the
// middle of the chat, so we go after the newest non fresh message.
//
// But if a received outgoing message is older than some seen message, better sort the
// received message purely by timestamp. We could place it just before that seen
// message, but anyway the user may not notice it.
// Received incoming messages shouldn't mingle with just sent ones and appear somewhere
// in the middle of the chat, so we go after the newest non fresh message. Received
// outgoing messages are allowed to mingle with seen messages though to avoid seen
// replies appearing before messages sent from another device (cases like the user
// sharing the account with others or bots are rare, so let them break sometimes).
//
// NB: Received outgoing messages may break sorting of fresh incoming ones, but this
// shouldn't happen frequently. Seen incoming messages don't really break sorting of
// fresh ones, they rather mean that older incoming messages are actually seen as well.
let states = match incoming {
true => "13, 16, 18, 20, 24, 26", // `> MessageState::InFresh`
false => "18, 20, 24, 26", // `> MessageState::InSeen`
};
context
.sql
.query_row_optional(
"SELECT MAX(timestamp), MAX(IIF(state=?,timestamp_sent,0))
FROM msgs
WHERE chat_id=? AND hidden=0 AND state>?
HAVING COUNT(*) > 0",
(MessageState::InSeen, self, MessageState::InFresh),
&format!(
"SELECT MAX(timestamp) FROM msgs
WHERE state IN ({states}) AND hidden=0 AND chat_id=?
HAVING COUNT(*) > 0"
),
(self,),
|row| {
let ts: i64 = row.get(0)?;
let ts_sent_seen: i64 = row.get(1)?;
Ok((ts, ts_sent_seen))
Ok(ts)
},
)
.await?
.and_then(|(ts, ts_sent_seen)| {
match incoming || ts_sent_seen <= message_timestamp {
true => Some(ts),
false => None,
}
})
} else {
None
};

View File

@@ -1361,7 +1361,7 @@ pub enum MessageState {
OutDelivered = 26,
/// Outgoing message read by the recipient (two checkmarks; this
/// requires goodwill on the receiver's side). Not used in the db for new messages.
/// requires goodwill on the receiver's side). API-only, not used in the db.
OutMdnRcvd = 28,
}

View File

@@ -1328,6 +1328,18 @@ CREATE INDEX gossip_timestamp_index ON gossip_timestamp (chat_id, fingerprint);
.await?;
}
inc_and_check(&mut migration_version, 138)?;
if dbversion < migration_version {
// Tweak the index for `chat::calc_sort_timestamp()`.
sql.execute_migration(
"UPDATE msgs SET state=26 WHERE state=28;
DROP INDEX IF EXISTS msgs_index7;
CREATE INDEX msgs_index7 ON msgs (state, hidden, chat_id, timestamp);",
migration_version,
)
.await?;
}
let new_version = sql
.get_raw_config_int(VERSION_CFG)
.await?

View File

@@ -277,7 +277,7 @@ async fn test_old_message_5() -> Result<()> {
.await?
.unwrap();
assert!(msg_sent.sort_timestamp == msg_incoming.sort_timestamp);
assert_eq!(msg_sent.sort_timestamp, msg_incoming.sort_timestamp);
alice
.golden_test_chat(msg_sent.chat_id, "test_old_message_5")
.await;

View File

@@ -1,5 +1,5 @@
Single#Chat#1001: bob@example.net [KEY bob@example.net]
--------------------------------------------------------------------------------
Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#1002🔒: Me (Contact#Contact#Self): Test This is encrypted, signed, and has an Autocrypt Header without prefer-encrypt=mutual. √
Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
--------------------------------------------------------------------------------