mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-07-04 20:37:15 +02:00
let the follower join the leader at any time
This commit is contained in:
parent
498b59ac84
commit
5ecfa3570f
7 changed files with 299 additions and 166 deletions
|
@ -11,10 +11,10 @@ pub mod routes;
|
|||
pub mod search;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::io::{BufReader, BufWriter, Write};
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -145,7 +145,7 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
|
|||
// the db is empty and the snapshot exists, import it
|
||||
if empty_db && snapshot_path_exists {
|
||||
match compression::from_tar_gz(snapshot_path, &opt.db_path) {
|
||||
Ok(()) => open_or_create_database_unchecked(opt, OnFailure::RemoveDb)?,
|
||||
Ok(()) => open_or_create_database_unchecked(opt, None, OnFailure::RemoveDb)?,
|
||||
Err(e) => {
|
||||
std::fs::remove_dir_all(&opt.db_path)?;
|
||||
return Err(e);
|
||||
|
@ -162,14 +162,14 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
|
|||
bail!("snapshot doesn't exist at {}", snapshot_path.display())
|
||||
// the snapshot and the db exist, and we can ignore the snapshot because of the ignore_snapshot_if_db_exists flag
|
||||
} else {
|
||||
open_or_create_database(opt, empty_db)?
|
||||
open_or_create_database(opt, empty_db, None)?
|
||||
}
|
||||
} else if let Some(ref path) = opt.import_dump {
|
||||
let src_path_exists = path.exists();
|
||||
// the db is empty and the dump exists, import it
|
||||
if empty_db && src_path_exists {
|
||||
let (mut index_scheduler, mut auth_controller) =
|
||||
open_or_create_database_unchecked(opt, OnFailure::RemoveDb)?;
|
||||
open_or_create_database_unchecked(opt, None, OnFailure::RemoveDb)?;
|
||||
match import_dump(&opt.db_path, path, &mut index_scheduler, &mut auth_controller) {
|
||||
Ok(()) => (index_scheduler, auth_controller),
|
||||
Err(e) => {
|
||||
|
@ -189,10 +189,58 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
|
|||
// the dump and the db exist and we can ignore the dump because of the ignore_dump_if_db_exists flag
|
||||
// or, the dump is missing but we can ignore that because of the ignore_missing_dump flag
|
||||
} else {
|
||||
open_or_create_database(opt, empty_db)?
|
||||
open_or_create_database(opt, empty_db, None)?
|
||||
}
|
||||
} else if let Some(ref cluster) = opt.cluster_configuration.experimental_enable_ha {
|
||||
match cluster.as_str() {
|
||||
"leader" => {
|
||||
info!("Starting as a leader");
|
||||
let mut addr = opt.http_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
addr.set_port(6666);
|
||||
open_or_create_database(opt, empty_db, Some(Cluster::Leader(Leader::new(addr))))?
|
||||
}
|
||||
"follower" => {
|
||||
info!("Starting as a follower");
|
||||
if !empty_db {
|
||||
panic!("Can't start as a follower with an already existing data.ms");
|
||||
}
|
||||
let mut addr = opt
|
||||
.cluster_configuration
|
||||
.leader
|
||||
.as_ref()
|
||||
.expect("Can't be a follower without a leader")
|
||||
.to_socket_addrs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
addr.set_port(6666);
|
||||
|
||||
let (follower, dump) = Follower::join(addr);
|
||||
let mut dump_file = tempfile::NamedTempFile::new().unwrap();
|
||||
dump_file.write_all(&dump).unwrap();
|
||||
|
||||
let (mut index_scheduler, mut auth_controller) = open_or_create_database_unchecked(
|
||||
opt,
|
||||
Some(Cluster::Follower(follower)),
|
||||
OnFailure::RemoveDb,
|
||||
)?;
|
||||
match import_dump(
|
||||
&opt.db_path,
|
||||
dump_file.path(),
|
||||
&mut index_scheduler,
|
||||
&mut auth_controller,
|
||||
) {
|
||||
Ok(()) => (index_scheduler, auth_controller),
|
||||
Err(e) => {
|
||||
std::fs::remove_dir_all(&opt.db_path)?;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Available values for the cluster mode are leader and follower"),
|
||||
}
|
||||
} else {
|
||||
open_or_create_database(opt, empty_db)?
|
||||
open_or_create_database(opt, empty_db, None)?
|
||||
};
|
||||
|
||||
// We create a loop in a thread that registers snapshotCreation tasks
|
||||
|
@ -217,40 +265,13 @@ pub fn setup_meilisearch(opt: &Opt) -> anyhow::Result<(Arc<IndexScheduler>, Auth
|
|||
/// Try to start the IndexScheduler and AuthController without checking the VERSION file or anything.
|
||||
fn open_or_create_database_unchecked(
|
||||
opt: &Opt,
|
||||
cluster: Option<Cluster>,
|
||||
on_failure: OnFailure,
|
||||
) -> anyhow::Result<(IndexScheduler, AuthController)> {
|
||||
// we don't want to create anything in the data.ms yet, thus we
|
||||
// wrap our two builders in a closure that'll be executed later.
|
||||
let auth_controller = AuthController::new(&opt.db_path, &opt.master_key);
|
||||
|
||||
let cluster = if let Some(ref cluster) = opt.cluster_configuration.experimental_enable_ha {
|
||||
match cluster.as_str() {
|
||||
"leader" => {
|
||||
info!("Starting as a leader");
|
||||
let mut addr = opt.http_addr.to_socket_addrs().unwrap().next().unwrap();
|
||||
addr.set_port(6666);
|
||||
Some(Cluster::Leader(Leader::new(addr)))
|
||||
}
|
||||
"follower" => {
|
||||
info!("Starting as a follower");
|
||||
let mut addr = opt
|
||||
.cluster_configuration
|
||||
.leader
|
||||
.as_ref()
|
||||
.expect("Can't be a follower without a leader")
|
||||
.to_socket_addrs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
addr.set_port(6666);
|
||||
Some(Cluster::Follower(Follower::join(addr)))
|
||||
}
|
||||
_ => panic!("Available values for the cluster mode are leader and follower"),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let index_scheduler_builder = || -> anyhow::Result<_> {
|
||||
Ok(IndexScheduler::new(
|
||||
IndexSchedulerOptions {
|
||||
|
@ -292,12 +313,13 @@ fn open_or_create_database_unchecked(
|
|||
fn open_or_create_database(
|
||||
opt: &Opt,
|
||||
empty_db: bool,
|
||||
cluster: Option<Cluster>,
|
||||
) -> anyhow::Result<(IndexScheduler, AuthController)> {
|
||||
if !empty_db {
|
||||
check_version_file(&opt.db_path)?;
|
||||
}
|
||||
|
||||
open_or_create_database_unchecked(opt, OnFailure::KeepDb)
|
||||
open_or_create_database_unchecked(opt, cluster, OnFailure::KeepDb)
|
||||
}
|
||||
|
||||
fn import_dump(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue