mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 18:36:30 +03:00
Optimize markseen_msgs
Use a single SELECT statement for all messages and start ephemeral timers for all messages at once.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
- place common headers like `From:` before the large `Autocrypt:` header #3079
|
||||
- keep track of securejoin joiner status in database to survive restarts #2920
|
||||
- remove never used `SentboxMove` option #3111
|
||||
- optimize `markseen_msgs` #3141
|
||||
|
||||
### Fixes
|
||||
- Fix a bug where sometimes the file extension of a long filename containing a dot was cropped #3098
|
||||
|
||||
@@ -76,6 +76,7 @@ use crate::download::MIN_DELETE_SERVER_AFTER;
|
||||
use crate::events::EventType;
|
||||
use crate::message::{Message, MessageState, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::sql;
|
||||
use crate::stock_str;
|
||||
use std::cmp::max;
|
||||
|
||||
@@ -298,6 +299,37 @@ impl MsgId {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn start_ephemeral_timers_msgids(
|
||||
context: &Context,
|
||||
msg_ids: &[MsgId],
|
||||
) -> Result<()> {
|
||||
let msg_ids: Vec<&dyn crate::ToSql> = msg_ids
|
||||
.iter()
|
||||
.map(|msg_id| msg_id as &dyn crate::ToSql)
|
||||
.collect();
|
||||
let now = time();
|
||||
let count = context
|
||||
.sql
|
||||
.execute(
|
||||
format!(
|
||||
"UPDATE msgs SET ephemeral_timestamp = ? + ephemeral_timer
|
||||
WHERE (ephemeral_timestamp == 0 OR ephemeral_timestamp > ? + ephemeral_timer) AND ephemeral_timer > 0
|
||||
AND id IN ({})",
|
||||
sql::repeat_vars(msg_ids.len())?
|
||||
),
|
||||
rusqlite::params_from_iter(
|
||||
std::iter::once(&now as &dyn crate::ToSql)
|
||||
.chain(std::iter::once(&now as &dyn crate::ToSql))
|
||||
.chain(msg_ids),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
if count > 0 {
|
||||
schedule_ephemeral_task(context).await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deletes messages which are expired according to
|
||||
/// `delete_device_after` setting or `ephemeral_timestamp` column.
|
||||
///
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::dc_tools::{
|
||||
dc_read_file, dc_timestamp_to_str, dc_truncate, time,
|
||||
};
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral::Timer as EphemeralTimer;
|
||||
use crate::ephemeral::{start_ephemeral_timers_msgids, Timer as EphemeralTimer};
|
||||
use crate::events::EventType;
|
||||
use crate::job::{self, Action};
|
||||
use crate::log::LogExt;
|
||||
@@ -28,6 +28,7 @@ use crate::mimeparser::{parse_message_id, FailureReport, SystemMessage};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::pgp::split_armored_data;
|
||||
use crate::scheduler::InterruptInfo;
|
||||
use crate::sql;
|
||||
use crate::stock_str;
|
||||
use crate::summary::Summary;
|
||||
|
||||
@@ -1285,50 +1286,37 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let conn = context.sql.get_conn().await?;
|
||||
let msgs = async_std::task::spawn_blocking(move || -> Result<_> {
|
||||
let mut stmt = conn.prepare_cached(concat!(
|
||||
"SELECT",
|
||||
" m.chat_id AS chat_id,",
|
||||
" m.state AS state,",
|
||||
" c.blocked AS blocked",
|
||||
" FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id",
|
||||
" WHERE m.id=? AND m.chat_id>9"
|
||||
))?;
|
||||
let msgs = context
|
||||
.sql
|
||||
.query_map(
|
||||
format!(
|
||||
"SELECT
|
||||
m.id AS id,
|
||||
m.chat_id AS chat_id,
|
||||
m.state AS state,
|
||||
c.blocked AS blocked
|
||||
FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id
|
||||
WHERE m.id IN ({}) AND m.chat_id>9",
|
||||
sql::repeat_vars(msg_ids.len())?
|
||||
),
|
||||
rusqlite::params_from_iter(&msg_ids),
|
||||
|row| {
|
||||
let id: MsgId = row.get("id")?;
|
||||
let chat_id: ChatId = row.get("chat_id")?;
|
||||
let state: MessageState = row.get("state")?;
|
||||
let blocked: Option<Blocked> = row.get("blocked")?;
|
||||
Ok((id, chat_id, state, blocked.unwrap_or_default()))
|
||||
},
|
||||
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut msgs = Vec::with_capacity(msg_ids.len());
|
||||
for id in msg_ids.into_iter() {
|
||||
let query_res = stmt.query_row(paramsv![id], |row| {
|
||||
Ok((
|
||||
row.get::<_, ChatId>("chat_id")?,
|
||||
row.get::<_, MessageState>("state")?,
|
||||
row.get::<_, Option<Blocked>>("blocked")?
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
});
|
||||
if let Err(rusqlite::Error::QueryReturnedNoRows) = query_res {
|
||||
continue;
|
||||
}
|
||||
let (chat_id, state, blocked) = query_res.map_err(Into::<anyhow::Error>::into)?;
|
||||
msgs.push((id, chat_id, state, blocked));
|
||||
}
|
||||
drop(stmt);
|
||||
drop(conn);
|
||||
Ok(msgs)
|
||||
})
|
||||
.await?;
|
||||
start_ephemeral_timers_msgids(context, &msg_ids)
|
||||
.await
|
||||
.context("failed to start ephemeral timers")?;
|
||||
|
||||
let mut updated_chat_ids = BTreeSet::new();
|
||||
|
||||
for (id, curr_chat_id, curr_state, curr_blocked) in msgs.into_iter() {
|
||||
if let Err(err) = id.start_ephemeral_timer(context).await {
|
||||
error!(
|
||||
context,
|
||||
"Failed to start ephemeral timer for message {}: {}", id, err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if curr_blocked == Blocked::Not
|
||||
&& (curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user