diff --git a/plume-models/src/search/searcher.rs b/plume-models/src/search/searcher.rs index 34a45b0b..2aa5cf2b 100644 --- a/plume-models/src/search/searcher.rs +++ b/plume-models/src/search/searcher.rs @@ -1,15 +1,17 @@ use crate::{ config::SearchTokenizerConfig, instance::Instance, posts::Post, schema::posts, - search::query::PlumeQuery, tags::Tag, Connection, Result, + search::query::PlumeQuery, tags::Tag, Connection, Error, Result, CONFIG, }; -use chrono::Datelike; +use chrono::{Datelike, Utc}; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; use itertools::Itertools; +use std::fs; use std::{cmp, fs::create_dir_all, io, path::Path, sync::Mutex}; use tantivy::{ collector::TopDocs, directory::MmapDirectory, schema::*, Index, IndexReader, IndexWriter, ReloadPolicy, TantivyError, Term, }; +use tracing::warn; use whatlang::{detect as detect_lang, Lang}; #[derive(Debug)] @@ -67,6 +69,62 @@ impl Searcher { schema_builder.build() } + pub fn open_or_recreate() -> Self { + let mut open_searcher = Self::open(&CONFIG.search_index, &CONFIG.search_tokenizers); + if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher { + if Self::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_err() { + let current_path = Path::new(&CONFIG.search_index); + let backup_path = format!("{}.{}", ¤t_path.display(), Utc::now().timestamp()); + let backup_path = Path::new(&backup_path); + fs::rename(current_path, backup_path) + .expect("main: error on backing up search index directory for recreating"); + if Self::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_ok() { + if fs::remove_dir_all(backup_path).is_err() { + warn!( + "error on removing backup directory: {}. it remains", + backup_path.display() + ); + } + } else { + panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually"); + } + } + open_searcher = Self::open(&CONFIG.search_index, &CONFIG.search_tokenizers); + } + #[allow(clippy::match_wild_err_arm)] + let searcher = match open_searcher { + Err(Error::Search(e)) => match e { + SearcherError::WriteLockAcquisitionError => panic!( + r#" +Your search index is locked. Plume can't start. To fix this issue +make sure no other Plume instance is started, and run: + + plm search unlock + +Then try to restart Plume. +"# + ), + SearcherError::IndexOpeningError => panic!( + r#" +Plume was unable to open the search index. If you created the index +before, make sure to run Plume in the same directory it was created in, or +to set SEARCH_INDEX accordingly. If you did not yet create the search +index, run this command: + + plm search init + +Then try to restart Plume +"# + ), + e => Err(e).unwrap(), + }, + Err(_) => panic!("Unexpected error while opening search index"), + Ok(s) => s, + }; + + searcher + } + pub fn create(path: &dyn AsRef, tokenizers: &SearchTokenizerConfig) -> Result { let schema = Self::schema(); diff --git a/src/main.rs b/src/main.rs index cc7561cd..6c548637 100755 --- a/src/main.rs +++ b/src/main.rs @@ -10,20 +10,17 @@ extern crate serde_json; #[macro_use] extern crate validator_derive; -use chrono::Utc; use clap::App; use diesel::r2d2::ConnectionManager; use plume_models::{ db_conn::{DbPool, PragmaForeignKey}, instance::Instance, migrations::IMPORTED_MIGRATIONS, - search::{Searcher as UnmanagedSearcher, SearcherError}, - Connection, Error, CONFIG, + search::Searcher as UnmanagedSearcher, + Connection, CONFIG, }; use rocket_csrf::CsrfFairingBuilder; use scheduled_thread_pool::ScheduledThreadPool; -use std::fs; -use std::path::Path; use std::process::exit; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -103,59 +100,7 @@ Then try to restart Plume. } let workpool = ScheduledThreadPool::with_name("worker {}", num_cpus::get()); // we want a fast exit here, so - let mut open_searcher = - UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers); - if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher { - if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_err() { - let current_path = Path::new(&CONFIG.search_index); - let backup_path = format!("{}.{}", ¤t_path.display(), Utc::now().timestamp()); - let backup_path = Path::new(&backup_path); - fs::rename(current_path, backup_path) - .expect("main: error on backing up search index directory for recreating"); - if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_ok() { - if fs::remove_dir_all(backup_path).is_err() { - warn!( - "error on removing backup directory: {}. it remains", - backup_path.display() - ); - } - } else { - panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually"); - } - } - open_searcher = UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers); - } - #[allow(clippy::match_wild_err_arm)] - let searcher = match open_searcher { - Err(Error::Search(e)) => match e { - SearcherError::WriteLockAcquisitionError => panic!( - r#" -Your search index is locked. Plume can't start. To fix this issue -make sure no other Plume instance is started, and run: - - plm search unlock - -Then try to restart Plume. -"# - ), - SearcherError::IndexOpeningError => panic!( - r#" -Plume was unable to open the search index. If you created the index -before, make sure to run Plume in the same directory it was created in, or -to set SEARCH_INDEX accordingly. If you did not yet create the search -index, run this command: - - plm search init - -Then try to restart Plume -"# - ), - e => Err(e).unwrap(), - }, - Err(_) => panic!("Unexpected error while opening search index"), - Ok(s) => Arc::new(s), - }; - + let searcher = Arc::new(UnmanagedSearcher::open_or_recreate()); let commiter = searcher.clone(); workpool.execute_with_fixed_delay( Duration::from_secs(5),