mirror of
https://github.com/meilisearch/meilisearch.git
synced 2025-08-02 03:40:00 +00:00
first version working with index operation
This commit is contained in:
@ -103,3 +103,46 @@ pub enum IndexOperation {
|
||||
settings_tasks: Vec<TaskId>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Batch {
|
||||
pub fn ids(&self) -> impl Iterator<Item = TaskId> {
|
||||
type Ret = Box<dyn Iterator<Item = TaskId>>;
|
||||
|
||||
match self {
|
||||
Batch::TaskCancelation { task, .. } => Box::new(std::iter::once(*task)) as Ret,
|
||||
Batch::TaskDeletion(task) => Box::new(std::iter::once(*task)) as Ret,
|
||||
Batch::SnapshotCreation(tasks) => Box::new(tasks.clone().into_iter()) as Ret,
|
||||
Batch::Dump(task) => Box::new(std::iter::once(*task)) as Ret,
|
||||
Batch::IndexOperation { op, .. } => match op {
|
||||
IndexOperation::DocumentOperation { tasks, .. } => {
|
||||
Box::new(tasks.clone().into_iter()) as Ret
|
||||
}
|
||||
IndexOperation::DocumentDeletion { tasks, .. } => {
|
||||
Box::new(tasks.clone().into_iter()) as Ret
|
||||
}
|
||||
IndexOperation::DocumentClear { tasks, .. } => {
|
||||
Box::new(tasks.clone().into_iter()) as Ret
|
||||
}
|
||||
IndexOperation::Settings { tasks, .. } => {
|
||||
Box::new(tasks.clone().into_iter()) as Ret
|
||||
}
|
||||
IndexOperation::DocumentClearAndSetting {
|
||||
cleared_tasks, settings_tasks, ..
|
||||
} => {
|
||||
Box::new(cleared_tasks.clone().into_iter().chain(settings_tasks.clone())) as Ret
|
||||
}
|
||||
IndexOperation::SettingsAndDocumentOperation {
|
||||
document_import_tasks,
|
||||
settings_tasks,
|
||||
..
|
||||
} => Box::new(
|
||||
document_import_tasks.clone().into_iter().chain(settings_tasks.clone()),
|
||||
) as Ret,
|
||||
},
|
||||
Batch::IndexCreation { task, .. } => Box::new(std::iter::once(*task)) as Ret,
|
||||
Batch::IndexUpdate { task, .. } => Box::new(std::iter::once(*task)) as Ret,
|
||||
Batch::IndexDeletion { tasks, .. } => Box::new(tasks.clone().into_iter()) as Ret,
|
||||
Batch::IndexSwap { task } => Box::new(std::iter::once(*task)) as Ret,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::{atomic, Arc, Mutex};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{atomic, Arc, Mutex, RwLock};
|
||||
|
||||
use bus::{Bus, BusReader};
|
||||
use crossbeam::channel::{unbounded, Receiver, Sender};
|
||||
@ -11,14 +11,14 @@ use meilisearch_types::tasks::Task;
|
||||
use crate::batch::Batch;
|
||||
use crate::{Consistency, FollowerMsg, LeaderMsg};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Leader {
|
||||
task_ready_to_commit: Receiver<u32>,
|
||||
broadcast_to_follower: Sender<LeaderMsg>,
|
||||
|
||||
cluster_size: Arc<AtomicUsize>,
|
||||
|
||||
batch_id: u32,
|
||||
batch_id: Arc<RwLock<u32>>,
|
||||
}
|
||||
|
||||
impl Leader {
|
||||
@ -36,7 +36,7 @@ impl Leader {
|
||||
task_ready_to_commit: task_finished_receiver,
|
||||
broadcast_to_follower: process_batch_sender,
|
||||
cluster_size,
|
||||
batch_id: 0,
|
||||
batch_id: Arc::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,46 +113,62 @@ impl Leader {
|
||||
info!("A follower left the cluster. {} members.", size);
|
||||
}
|
||||
|
||||
pub fn starts_batch(&mut self, batch: Batch) {
|
||||
pub fn starts_batch(&self, batch: Batch) {
|
||||
let mut batch_id = self.batch_id.write().unwrap();
|
||||
|
||||
assert!(
|
||||
self.batch_id % 2 == 0,
|
||||
*batch_id % 2 == 0,
|
||||
"Tried to start processing a batch before commiting the previous one"
|
||||
);
|
||||
self.batch_id += 1;
|
||||
info!("Send the batch to process to the followers");
|
||||
*batch_id += 1;
|
||||
|
||||
self.broadcast_to_follower
|
||||
.send(LeaderMsg::StartBatch { id: self.batch_id, batch })
|
||||
.send(LeaderMsg::StartBatch { id: *batch_id, batch })
|
||||
.expect("Can't reach the cluster");
|
||||
}
|
||||
|
||||
pub fn commit(&mut self, consistency_level: Consistency) {
|
||||
pub fn commit(&self, consistency_level: Consistency) {
|
||||
info!("Wait until enough followers are ready to commit a batch");
|
||||
|
||||
let mut batch_id = self.batch_id.write().unwrap();
|
||||
|
||||
// if zero nodes needs to be sync we can commit right away and early exit
|
||||
if consistency_level != Consistency::Zero {
|
||||
if consistency_level != Consistency::One {
|
||||
// else, we wait till enough nodes are ready to commit
|
||||
for (ready_to_commit, _id) in self
|
||||
for ready_to_commit in self
|
||||
.task_ready_to_commit
|
||||
.iter()
|
||||
// we need to filter out the messages from the old batches
|
||||
.filter(|id| *id == self.batch_id)
|
||||
.filter(|id| *id == *batch_id)
|
||||
.enumerate()
|
||||
// we do a +2 because enumerate starts at 1 and we must includes ourselves in the count
|
||||
.map(|(id, _)| id + 2)
|
||||
{
|
||||
// TODO: if the last node dies we're stuck on the iterator
|
||||
|
||||
// we need to reload the cluster size everytime in case a node dies
|
||||
let cluster_size = self.cluster_size.load(atomic::Ordering::Relaxed);
|
||||
|
||||
info!("{ready_to_commit} nodes are ready to commit for a cluster size of {cluster_size}");
|
||||
match consistency_level {
|
||||
Consistency::One if ready_to_commit >= 1 => break,
|
||||
Consistency::Two if ready_to_commit >= 2 => break,
|
||||
Consistency::Two if ready_to_commit >= 1 => break,
|
||||
Consistency::Quorum if ready_to_commit >= (cluster_size / 2) => break,
|
||||
Consistency::All if ready_to_commit == cluster_size => break,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.broadcast_to_follower.send(LeaderMsg::Commit(self.batch_id)).unwrap();
|
||||
info!("Tells all the follower to commit");
|
||||
|
||||
self.batch_id += 1;
|
||||
self.broadcast_to_follower.send(LeaderMsg::Commit(*batch_id)).unwrap();
|
||||
|
||||
*batch_id += 1;
|
||||
}
|
||||
|
||||
pub fn register_new_task(&mut self, task: Task, update_file: Option<Vec<u8>>) {
|
||||
pub fn register_new_task(&self, task: Task, update_file: Option<Vec<u8>>) {
|
||||
info!("Tells all the follower to register a new task");
|
||||
self.broadcast_to_follower
|
||||
.send(LeaderMsg::RegisterNewTask { task, update_file })
|
||||
.expect("Main thread is dead");
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use batch::Batch;
|
||||
use crossbeam::channel::{unbounded, Receiver, Sender};
|
||||
@ -39,7 +40,6 @@ pub enum FollowerMsg {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Consistency {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Quorum,
|
||||
@ -54,7 +54,7 @@ pub struct Follower {
|
||||
must_commit: Receiver<u32>,
|
||||
register_new_task: Receiver<(Task, Option<Vec<u8>>)>,
|
||||
|
||||
batch_id: u32,
|
||||
batch_id: Arc<RwLock<u32>>,
|
||||
}
|
||||
|
||||
impl Follower {
|
||||
@ -76,7 +76,7 @@ impl Follower {
|
||||
get_batch: get_batch_receiver,
|
||||
must_commit: must_commit_receiver,
|
||||
register_new_task: register_task_receiver,
|
||||
batch_id: 0,
|
||||
batch_id: Arc::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,31 +106,33 @@ impl Follower {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_new_batch(&mut self) -> Batch {
|
||||
pub fn get_new_batch(&self) -> Batch {
|
||||
info!("Get new batch called");
|
||||
let (id, batch) = self.get_batch.recv().expect("Lost connection to the leader");
|
||||
info!("Got a new batch");
|
||||
self.batch_id = id;
|
||||
*self.batch_id.write().unwrap() = id;
|
||||
batch
|
||||
}
|
||||
|
||||
pub fn ready_to_commit(&mut self) {
|
||||
pub fn ready_to_commit(&self) {
|
||||
info!("I'm ready to commit");
|
||||
self.sender.send(FollowerMsg::ReadyToCommit(self.batch_id)).unwrap();
|
||||
let batch_id = self.batch_id.read().unwrap();
|
||||
|
||||
self.sender.send(FollowerMsg::ReadyToCommit(*batch_id)).unwrap();
|
||||
|
||||
loop {
|
||||
let id = self.must_commit.recv().expect("Lost connection to the leader");
|
||||
#[allow(clippy::comparison_chain)]
|
||||
if id == self.batch_id {
|
||||
if id == *batch_id {
|
||||
break;
|
||||
} else if id > self.batch_id {
|
||||
} else if id > *batch_id {
|
||||
panic!("We missed a batch");
|
||||
}
|
||||
}
|
||||
info!("I got the right to commit");
|
||||
}
|
||||
|
||||
pub fn get_new_task(&mut self) -> (Task, Option<Vec<u8>>) {
|
||||
pub fn get_new_task(&self) -> (Task, Option<Vec<u8>>) {
|
||||
self.register_new_task.recv().unwrap()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user