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:
link2xt
2022-03-19 22:39:13 +00:00
parent 1e94ad25e1
commit 83464a882e
3 changed files with 62 additions and 41 deletions

View File

@@ -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

View File

@@ -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.
///

View File

@@ -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)
{