mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
feat: detect legacy tantivy data layout and abort startup with migration hint
This commit is contained in:
@@ -46,6 +46,7 @@ use crate::{
|
||||
pub struct DashboardStats {
|
||||
pub account_count: usize, // Number of accounts
|
||||
pub email_count: u64, // Total number of emails
|
||||
pub attachment_count: u64, // Total number of attachments
|
||||
pub total_size_bytes: u64, // Total size of all emails (in bytes)
|
||||
pub storage_usage_bytes: u64, // Actual storage used (in bytes)
|
||||
pub index_usage_bytes: u64, // Index storage size (in bytes)
|
||||
@@ -89,7 +90,7 @@ impl DashboardStats {
|
||||
};
|
||||
|
||||
stat.email_count = ENVELOPE_MANAGER.total_emails(&authorized_ids)?;
|
||||
|
||||
stat.attachment_count = ATTACHMENT_MANAGER.total_attachments(&authorized_ids)?;
|
||||
if has_all_accounts {
|
||||
stat.storage_usage_bytes = get_total_size(&DATA_DIR_MANAGER.storage_dir)
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
|
||||
@@ -13,6 +13,7 @@ pub mod import;
|
||||
pub mod logger;
|
||||
pub mod mailbox;
|
||||
pub mod message;
|
||||
pub mod migrate;
|
||||
pub mod oauth2;
|
||||
pub mod settings;
|
||||
pub mod store;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::settings::cli::SETTINGS;
|
||||
|
||||
pub fn is_tantivy_index_dir(dir: &PathBuf) -> std::io::Result<bool> {
|
||||
if !dir.exists() || !dir.is_dir() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let tantivy_extensions = [".store", ".term", ".idx", ".fieldnorm", ".pos"];
|
||||
let mut match_count = 0;
|
||||
let mut has_meta_json = false;
|
||||
|
||||
for entry in std::fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let file_name = entry.file_name();
|
||||
let name = file_name.to_string_lossy();
|
||||
|
||||
if name == "meta.json" {
|
||||
has_meta_json = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if tantivy_extensions.iter().any(|ext| name.ends_with(ext)) {
|
||||
match_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(has_meta_json && match_count >= 3)
|
||||
}
|
||||
|
||||
pub fn is_legacy_data_layout() -> std::io::Result<bool> {
|
||||
let root_dir = PathBuf::from(&SETTINGS.bichon_root_dir);
|
||||
let envelope_dir = if let Some(ref index_dir) = SETTINGS.bichon_index_dir {
|
||||
PathBuf::from(index_dir)
|
||||
} else {
|
||||
root_dir.join("envelope")
|
||||
};
|
||||
|
||||
let eml_dir = if let Some(ref data_dir) = SETTINGS.bichon_data_dir {
|
||||
PathBuf::from(data_dir)
|
||||
} else {
|
||||
root_dir.join("eml")
|
||||
};
|
||||
|
||||
let envelope_result = is_tantivy_index_dir(&envelope_dir)?;
|
||||
let eml_result = is_tantivy_index_dir(&eml_dir)?;
|
||||
Ok(envelope_result || eml_result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_real_tantivy_dir() {
|
||||
let path = PathBuf::from(r"D:\test-data\envelope");
|
||||
let result = is_tantivy_index_dir(&path).unwrap();
|
||||
println!("is tantivy index dir: {}", result);
|
||||
assert!(result);
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,30 @@ impl IndexManager {
|
||||
Box::new(boolean_query)
|
||||
}
|
||||
|
||||
pub fn total_attachments(&self, accounts: &Option<HashSet<u64>>) -> BichonResult<u64> {
|
||||
let searcher = self.create_searcher()?;
|
||||
|
||||
match accounts {
|
||||
Some(ref ids) if !ids.is_empty() => {
|
||||
let mut subqueries = Vec::new();
|
||||
for &id in ids {
|
||||
let term = Term::from_field_u64(SchemaTools::email_fields().f_account_id, id);
|
||||
subqueries.push((
|
||||
Occur::Should,
|
||||
Box::new(TermQuery::new(term, IndexRecordOption::Basic)) as Box<dyn Query>,
|
||||
));
|
||||
}
|
||||
let query = Box::new(BooleanQuery::new(subqueries)) as Box<dyn Query>;
|
||||
let count = searcher
|
||||
.search(&query, &Count)
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
|
||||
Ok(count as u64)
|
||||
}
|
||||
Some(_) => Ok(0),
|
||||
None => Ok(searcher.num_docs()),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_query(
|
||||
&self,
|
||||
accounts: Option<HashSet<u64>>,
|
||||
@@ -358,7 +382,7 @@ impl IndexManager {
|
||||
if let Some(ref name) = filter.attachment_name {
|
||||
let query_parser =
|
||||
QueryParser::for_index(&self.index, vec![f.f_name_text, f.f_name_exact]);
|
||||
|
||||
|
||||
let q = query_parser
|
||||
.parse_query(name)
|
||||
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InvalidParameter))?;
|
||||
|
||||
Reference in New Issue
Block a user