mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 05:46: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
|
- place common headers like `From:` before the large `Autocrypt:` header #3079
|
||||||
- keep track of securejoin joiner status in database to survive restarts #2920
|
- keep track of securejoin joiner status in database to survive restarts #2920
|
||||||
- remove never used `SentboxMove` option #3111
|
- remove never used `SentboxMove` option #3111
|
||||||
|
- optimize `markseen_msgs` #3141
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Fix a bug where sometimes the file extension of a long filename containing a dot was cropped #3098
|
- 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::events::EventType;
|
||||||
use crate::message::{Message, MessageState, MsgId, Viewtype};
|
use crate::message::{Message, MessageState, MsgId, Viewtype};
|
||||||
use crate::mimeparser::SystemMessage;
|
use crate::mimeparser::SystemMessage;
|
||||||
|
use crate::sql;
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
use std::cmp::max;
|
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
|
/// Deletes messages which are expired according to
|
||||||
/// `delete_device_after` setting or `ephemeral_timestamp` column.
|
/// `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,
|
dc_read_file, dc_timestamp_to_str, dc_truncate, time,
|
||||||
};
|
};
|
||||||
use crate::download::DownloadState;
|
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::events::EventType;
|
||||||
use crate::job::{self, Action};
|
use crate::job::{self, Action};
|
||||||
use crate::log::LogExt;
|
use crate::log::LogExt;
|
||||||
@@ -28,6 +28,7 @@ use crate::mimeparser::{parse_message_id, FailureReport, SystemMessage};
|
|||||||
use crate::param::{Param, Params};
|
use crate::param::{Param, Params};
|
||||||
use crate::pgp::split_armored_data;
|
use crate::pgp::split_armored_data;
|
||||||
use crate::scheduler::InterruptInfo;
|
use crate::scheduler::InterruptInfo;
|
||||||
|
use crate::sql;
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
use crate::summary::Summary;
|
use crate::summary::Summary;
|
||||||
|
|
||||||
@@ -1285,50 +1286,37 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let conn = context.sql.get_conn().await?;
|
let msgs = context
|
||||||
let msgs = async_std::task::spawn_blocking(move || -> Result<_> {
|
.sql
|
||||||
let mut stmt = conn.prepare_cached(concat!(
|
.query_map(
|
||||||
"SELECT",
|
format!(
|
||||||
" m.chat_id AS chat_id,",
|
"SELECT
|
||||||
" m.state AS state,",
|
m.id AS id,
|
||||||
" c.blocked AS blocked",
|
m.chat_id AS chat_id,
|
||||||
" FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id",
|
m.state AS state,
|
||||||
" WHERE m.id=? AND m.chat_id>9"
|
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());
|
start_ephemeral_timers_msgids(context, &msg_ids)
|
||||||
for id in msg_ids.into_iter() {
|
.await
|
||||||
let query_res = stmt.query_row(paramsv![id], |row| {
|
.context("failed to start ephemeral timers")?;
|
||||||
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?;
|
|
||||||
|
|
||||||
let mut updated_chat_ids = BTreeSet::new();
|
let mut updated_chat_ids = BTreeSet::new();
|
||||||
|
|
||||||
for (id, curr_chat_id, curr_state, curr_blocked) in msgs.into_iter() {
|
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
|
if curr_blocked == Blocked::Not
|
||||||
&& (curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed)
|
&& (curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user