mirror of
https://github.com/chatmail/core.git
synced 2026-05-20 15:26:30 +03:00
Housekeeping: delete the blobs backup dir (#4104)
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Do not block async task executor while decrypting the messages. #4079
|
- Do not block async task executor while decrypting the messages. #4079
|
||||||
|
- Housekeeping: delete the blobs backup dir #4123
|
||||||
|
|
||||||
### API-Changes
|
### API-Changes
|
||||||
- jsonrpc: add more advanced API to send a message. #4097
|
- jsonrpc: add more advanced API to send a message. #4097
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use crate::{e2ee, tools};
|
|||||||
|
|
||||||
// Name of the database file in the backup.
|
// Name of the database file in the backup.
|
||||||
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
|
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
|
||||||
const BLOBS_BACKUP_NAME: &str = "blobs_backup";
|
pub(crate) const BLOBS_BACKUP_NAME: &str = "blobs_backup";
|
||||||
|
|
||||||
/// Import/export command.
|
/// Import/export command.
|
||||||
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
|||||||
50
src/sql.rs
50
src/sql.rs
@@ -15,6 +15,7 @@ use crate::constants::DC_CHAT_ID_TRASH;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::debug_logging::set_debug_logging_xdc;
|
use crate::debug_logging::set_debug_logging_xdc;
|
||||||
use crate::ephemeral::start_ephemeral_timers;
|
use crate::ephemeral::start_ephemeral_timers;
|
||||||
|
use crate::imex::BLOBS_BACKUP_NAME;
|
||||||
use crate::log::LogExt;
|
use crate::log::LogExt;
|
||||||
use crate::message::{Message, MsgId, Viewtype};
|
use crate::message::{Message, MsgId, Viewtype};
|
||||||
use crate::param::{Param, Params};
|
use crate::param::{Param, Params};
|
||||||
@@ -792,8 +793,9 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
|
|||||||
.context("housekeeping: failed to SELECT value FROM config")?;
|
.context("housekeeping: failed to SELECT value FROM config")?;
|
||||||
|
|
||||||
info!(context, "{} files in use.", files_in_use.len(),);
|
info!(context, "{} files in use.", files_in_use.len(),);
|
||||||
/* go through directory and delete unused files */
|
/* go through directories and delete unused files */
|
||||||
let p = context.get_blobdir();
|
let blobdir = context.get_blobdir();
|
||||||
|
for p in [&blobdir.join(BLOBS_BACKUP_NAME), blobdir] {
|
||||||
match tokio::fs::read_dir(p).await {
|
match tokio::fs::read_dir(p).await {
|
||||||
Ok(mut dir_handle) => {
|
Ok(mut dir_handle) => {
|
||||||
/* avoid deletion of files that are just created to build a message object */
|
/* avoid deletion of files that are just created to build a message object */
|
||||||
@@ -806,17 +808,30 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
|
|||||||
let name_f = entry.file_name();
|
let name_f = entry.file_name();
|
||||||
let name_s = name_f.to_string_lossy();
|
let name_s = name_f.to_string_lossy();
|
||||||
|
|
||||||
if is_file_in_use(&files_in_use, None, &name_s)
|
if p == blobdir
|
||||||
|
&& (is_file_in_use(&files_in_use, None, &name_s)
|
||||||
|| is_file_in_use(&files_in_use, Some(".increation"), &name_s)
|
|| is_file_in_use(&files_in_use, Some(".increation"), &name_s)
|
||||||
|| is_file_in_use(&files_in_use, Some(".waveform"), &name_s)
|
|| is_file_in_use(&files_in_use, Some(".waveform"), &name_s)
|
||||||
|| is_file_in_use(&files_in_use, Some("-preview.jpg"), &name_s)
|
|| is_file_in_use(&files_in_use, Some("-preview.jpg"), &name_s))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
unreferenced_count += 1;
|
|
||||||
|
|
||||||
if let Ok(stats) = tokio::fs::metadata(entry.path()).await {
|
if let Ok(stats) = tokio::fs::metadata(entry.path()).await {
|
||||||
|
if stats.is_dir() {
|
||||||
|
if let Err(e) = tokio::fs::remove_dir(entry.path()).await {
|
||||||
|
// The dir could be created not by a user, but by a desktop
|
||||||
|
// environment f.e. So, no warning.
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
"Housekeeping: Cannot rmdir {}: {:#}",
|
||||||
|
entry.path().display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unreferenced_count += 1;
|
||||||
let recently_created =
|
let recently_created =
|
||||||
stats.created().map_or(false, |t| t > keep_files_newer_than);
|
stats.created().map_or(false, |t| t > keep_files_newer_than);
|
||||||
let recently_modified = stats
|
let recently_modified = stats
|
||||||
@@ -826,7 +841,9 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
|
|||||||
.accessed()
|
.accessed()
|
||||||
.map_or(false, |t| t > keep_files_newer_than);
|
.map_or(false, |t| t > keep_files_newer_than);
|
||||||
|
|
||||||
if recently_created || recently_modified || recently_accessed {
|
if p == blobdir
|
||||||
|
&& (recently_created || recently_modified || recently_accessed)
|
||||||
|
{
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"Housekeeping: Keeping new unreferenced file #{}: {:?}",
|
"Housekeeping: Keeping new unreferenced file #{}: {:?}",
|
||||||
@@ -835,6 +852,8 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
unreferenced_count += 1;
|
||||||
}
|
}
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
@@ -856,12 +875,13 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
"Housekeeping: Cannot open {}. ({})",
|
"Housekeeping: Cannot read dir {}: {:#}",
|
||||||
context.get_blobdir().display(),
|
p.display(),
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1061,6 +1081,18 @@ mod tests {
|
|||||||
assert_eq!(loaded_draft.unwrap().text.unwrap(), "This is my draft");
|
assert_eq!(loaded_draft.unwrap().text.unwrap(), "This is my draft");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests that `housekeeping` deletes the blobs backup dir which is created normally by
|
||||||
|
/// `imex::import_backup`.
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_housekeeping_delete_blobs_backup_dir() {
|
||||||
|
let t = TestContext::new_alice().await;
|
||||||
|
let dir = t.get_blobdir().join(BLOBS_BACKUP_NAME);
|
||||||
|
tokio::fs::create_dir(&dir).await.unwrap();
|
||||||
|
tokio::fs::write(dir.join("f"), "").await.unwrap();
|
||||||
|
housekeeping(&t).await.unwrap();
|
||||||
|
tokio::fs::create_dir(&dir).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/// Regression test.
|
/// Regression test.
|
||||||
///
|
///
|
||||||
/// Previously the code checking for existence of `config` table
|
/// Previously the code checking for existence of `config` table
|
||||||
|
|||||||
Reference in New Issue
Block a user