diff --git a/crates/index-scheduler/src/index_mapper/mod.rs b/crates/index-scheduler/src/index_mapper/mod.rs index e6bdccd41..d578b03dd 100644 --- a/crates/index-scheduler/src/index_mapper/mod.rs +++ b/crates/index-scheduler/src/index_mapper/mod.rs @@ -526,6 +526,20 @@ impl IndexMapper { Ok(()) } + /// Rename an index. + pub fn rename(&self, wtxn: &mut RwTxn, current: &str, new: &str) -> Result<()> { + let uuid = self + .index_mapping + .get(wtxn, current)? + .ok_or_else(|| Error::IndexNotFound(current.to_string()))?; + if self.index_mapping.get(wtxn, new)?.is_some() { + return Err(Error::IndexAlreadyExists(new.to_string())); + } + self.index_mapping.delete(wtxn, current)?; + self.index_mapping.put(wtxn, new, &uuid)?; + Ok(()) + } + /// The stats of an index. /// /// If available in the cache, they are directly returned. diff --git a/crates/index-scheduler/src/processing.rs b/crates/index-scheduler/src/processing.rs index 3da81f143..84b0a5360 100644 --- a/crates/index-scheduler/src/processing.rs +++ b/crates/index-scheduler/src/processing.rs @@ -125,6 +125,12 @@ make_enum_progress! { } } +make_enum_progress! { + pub enum RenameIndexProgress { + RenamingTheIndex, + } +} + make_enum_progress! { pub enum DeleteIndexProgress { DeletingTheIndex, diff --git a/crates/index-scheduler/src/scheduler/autobatcher.rs b/crates/index-scheduler/src/scheduler/autobatcher.rs index b3f7d2743..6b62d36e0 100644 --- a/crates/index-scheduler/src/scheduler/autobatcher.rs +++ b/crates/index-scheduler/src/scheduler/autobatcher.rs @@ -24,6 +24,7 @@ enum AutobatchKind { IndexCreation, IndexDeletion, IndexUpdate, + IndexRename, IndexSwap, } @@ -67,6 +68,7 @@ impl From for AutobatchKind { KindWithContent::IndexDeletion { .. } => AutobatchKind::IndexDeletion, KindWithContent::IndexCreation { .. } => AutobatchKind::IndexCreation, KindWithContent::IndexUpdate { .. } => AutobatchKind::IndexUpdate, + KindWithContent::IndexRename { .. } => AutobatchKind::IndexRename, KindWithContent::IndexSwap { .. } => AutobatchKind::IndexSwap, KindWithContent::TaskCancelation { .. } | KindWithContent::TaskDeletion { .. } @@ -115,6 +117,9 @@ pub enum BatchKind { IndexUpdate { id: TaskId, }, + IndexRename { + id: TaskId, + }, IndexSwap { id: TaskId, }, @@ -176,6 +181,13 @@ impl BatchKind { )), false, ), + K::IndexRename => ( + Break(( + BatchKind::IndexRename { id: task_id }, + BatchStopReason::TaskCannotBeBatched { kind, id: task_id }, + )), + false, + ), K::IndexSwap => ( Break(( BatchKind::IndexSwap { id: task_id }, @@ -288,7 +300,7 @@ impl BatchKind { match (self, autobatch_kind) { // We don't batch any of these operations - (this, K::IndexCreation | K::IndexUpdate | K::IndexSwap | K::DocumentEdition) => Break((this, BatchStopReason::TaskCannotBeBatched { kind, id })), + (this, K::IndexCreation | K::IndexUpdate | K::IndexRename | K::IndexSwap | K::DocumentEdition) => Break((this, BatchStopReason::TaskCannotBeBatched { kind, id })), // We must not batch tasks that don't have the same index creation rights if the index doesn't already exists. (this, kind) if !index_already_exists && this.allow_index_creation() == Some(false) && kind.allow_index_creation() == Some(true) => { Break((this, BatchStopReason::IndexCreationMismatch { id })) diff --git a/crates/index-scheduler/src/scheduler/create_batch.rs b/crates/index-scheduler/src/scheduler/create_batch.rs index e78ed2c2e..fa84200a1 100644 --- a/crates/index-scheduler/src/scheduler/create_batch.rs +++ b/crates/index-scheduler/src/scheduler/create_batch.rs @@ -40,6 +40,11 @@ pub(crate) enum Batch { primary_key: Option, task: Task, }, + IndexRename { + index_uid: String, + new_index_uid: String, + task: Task, + }, IndexDeletion { index_uid: String, tasks: Vec, @@ -108,7 +113,8 @@ impl Batch { | Batch::Dump(task) | Batch::IndexCreation { task, .. } | Batch::Export { task } - | Batch::IndexUpdate { task, .. } => { + | Batch::IndexUpdate { task, .. } + | Batch::IndexRename { task, .. } => { RoaringBitmap::from_sorted_iter(std::iter::once(task.uid)).unwrap() } Batch::SnapshotCreation(tasks) @@ -153,6 +159,7 @@ impl Batch { IndexOperation { op, .. } => Some(op.index_uid()), IndexCreation { index_uid, .. } | IndexUpdate { index_uid, .. } + | IndexRename { index_uid, .. } | IndexDeletion { index_uid, .. } => Some(index_uid), } } @@ -171,6 +178,7 @@ impl fmt::Display for Batch { Batch::IndexOperation { op, .. } => write!(f, "{op}")?, Batch::IndexCreation { .. } => f.write_str("IndexCreation")?, Batch::IndexUpdate { .. } => f.write_str("IndexUpdate")?, + Batch::IndexRename { .. } => f.write_str("IndexRename")?, Batch::IndexDeletion { .. } => f.write_str("IndexDeletion")?, Batch::IndexSwap { .. } => f.write_str("IndexSwap")?, Batch::Export { .. } => f.write_str("Export")?, @@ -411,6 +419,16 @@ impl IndexScheduler { }; Ok(Some(Batch::IndexUpdate { index_uid, primary_key, task })) } + BatchKind::IndexRename { id } => { + let mut task = + self.queue.tasks.get_task(rtxn, id)?.ok_or(Error::CorruptedTaskQueue)?; + current_batch.processing(Some(&mut task)); + let (new_uid) = match &task.kind { + KindWithContent::IndexRename { new_index_uid, .. } => new_index_uid.clone(), + _ => unreachable!(), + }; + Ok(Some(Batch::IndexRename { index_uid, new_index_uid: new_uid, task })) + } BatchKind::IndexDeletion { ids } => Ok(Some(Batch::IndexDeletion { index_uid, index_has_been_created: must_create_index, diff --git a/crates/index-scheduler/src/scheduler/process_batch.rs b/crates/index-scheduler/src/scheduler/process_batch.rs index c21ab27ad..d801287a7 100644 --- a/crates/index-scheduler/src/scheduler/process_batch.rs +++ b/crates/index-scheduler/src/scheduler/process_batch.rs @@ -15,7 +15,7 @@ use super::create_batch::Batch; use crate::processing::{ AtomicBatchStep, AtomicTaskStep, CreateIndexProgress, DeleteIndexProgress, FinalizingIndexStep, InnerSwappingTwoIndexes, SwappingTheIndexes, TaskCancelationProgress, TaskDeletionProgress, - UpdateIndexProgress, + UpdateIndexProgress, RenameIndexProgress, }; use crate::utils::{ self, remove_n_tasks_datetime_earlier_than, remove_task_datetime, swap_index_uid_in_task, @@ -229,6 +229,20 @@ impl IndexScheduler { progress, ) } + Batch::IndexRename { index_uid, new_index_uid, mut task } => { + progress.update_progress(RenameIndexProgress::RenamingTheIndex); + let mut wtxn = self.env.write_txn()?; + self.index_mapper.rename(&mut wtxn, &index_uid, &new_index_uid)?; + self.queue.tasks.update_index(&mut wtxn, &new_index_uid, |bm| { + let old = self.queue.tasks.index_tasks(&wtxn, &index_uid).unwrap_or_default(); + *bm |= &old; + })?; + self.queue.tasks.update_index(&mut wtxn, &index_uid, |bm| bm.clear())?; + wtxn.commit()?; + task.status = Status::Succeeded; + task.details = Some(Details::IndexRename(IndexRenameDetails { old_uid: index_uid, new_uid: new_index_uid })); + Ok((vec![task], ProcessBatchInfo::default())) + } Batch::IndexUpdate { index_uid, primary_key, mut task } => { progress.update_progress(UpdateIndexProgress::UpdatingTheIndex); let rtxn = self.env.read_txn()?; diff --git a/crates/meilisearch-types/src/tasks.rs b/crates/meilisearch-types/src/tasks.rs index 99b04f1e3..64826c693 100644 --- a/crates/meilisearch-types/src/tasks.rs +++ b/crates/meilisearch-types/src/tasks.rs @@ -141,6 +141,10 @@ pub enum KindWithContent { index_uid: String, primary_key: Option, }, + IndexRename { + index_uid: String, + new_index_uid: String, + }, IndexSwap { swaps: Vec, }, @@ -174,6 +178,13 @@ pub struct IndexSwap { pub indexes: (String, String), } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct IndexRenameDetails { + pub old_uid: String, + pub new_uid: String, +} + #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct ExportIndexSettings { @@ -193,6 +204,7 @@ impl KindWithContent { KindWithContent::IndexCreation { .. } => Kind::IndexCreation, KindWithContent::IndexDeletion { .. } => Kind::IndexDeletion, KindWithContent::IndexUpdate { .. } => Kind::IndexUpdate, + KindWithContent::IndexRename { .. } => Kind::IndexRename, KindWithContent::IndexSwap { .. } => Kind::IndexSwap, KindWithContent::TaskCancelation { .. } => Kind::TaskCancelation, KindWithContent::TaskDeletion { .. } => Kind::TaskDeletion, @@ -222,6 +234,7 @@ impl KindWithContent { | IndexCreation { index_uid, .. } | IndexUpdate { index_uid, .. } | IndexDeletion { index_uid } => vec![index_uid], + IndexRename { index_uid, new_index_uid } => vec![index_uid, new_index_uid], IndexSwap { swaps } => { let mut indexes = HashSet::<&str>::default(); for swap in swaps { @@ -274,6 +287,12 @@ impl KindWithContent { | KindWithContent::IndexUpdate { primary_key, .. } => { Some(Details::IndexInfo { primary_key: primary_key.clone() }) } + KindWithContent::IndexRename { index_uid, new_index_uid } => { + Some(Details::IndexRename { + old_uid: index_uid.clone(), + new_uid: new_index_uid.clone(), + }) + } KindWithContent::IndexSwap { swaps } => { Some(Details::IndexSwap { swaps: swaps.clone() }) } @@ -344,6 +363,12 @@ impl KindWithContent { Some(Details::SettingsUpdate { settings: new_settings.clone() }) } KindWithContent::IndexDeletion { .. } => None, + KindWithContent::IndexRename { index_uid, new_index_uid } => { + Some(Details::IndexRename { + old_uid: index_uid.clone(), + new_uid: new_index_uid.clone(), + }) + } KindWithContent::IndexCreation { primary_key, .. } | KindWithContent::IndexUpdate { primary_key, .. } => { Some(Details::IndexInfo { primary_key: primary_key.clone() }) @@ -538,6 +563,7 @@ pub enum Kind { IndexCreation, IndexDeletion, IndexUpdate, + IndexRename, IndexSwap, TaskCancelation, TaskDeletion, @@ -556,7 +582,8 @@ impl Kind { | Kind::SettingsUpdate | Kind::IndexCreation | Kind::IndexDeletion - | Kind::IndexUpdate => true, + | Kind::IndexUpdate + | Kind::IndexRename => true, Kind::IndexSwap | Kind::TaskCancelation | Kind::TaskDeletion @@ -577,6 +604,7 @@ impl Display for Kind { Kind::IndexCreation => write!(f, "indexCreation"), Kind::IndexDeletion => write!(f, "indexDeletion"), Kind::IndexUpdate => write!(f, "indexUpdate"), + Kind::IndexRename => write!(f, "indexRename"), Kind::IndexSwap => write!(f, "indexSwap"), Kind::TaskCancelation => write!(f, "taskCancelation"), Kind::TaskDeletion => write!(f, "taskDeletion"), @@ -595,6 +623,8 @@ impl FromStr for Kind { Ok(Kind::IndexCreation) } else if kind.eq_ignore_ascii_case("indexUpdate") { Ok(Kind::IndexUpdate) + } else if kind.eq_ignore_ascii_case("indexRename") { + Ok(Kind::IndexRename) } else if kind.eq_ignore_ascii_case("indexSwap") { Ok(Kind::IndexSwap) } else if kind.eq_ignore_ascii_case("indexDeletion") { @@ -692,6 +722,7 @@ pub enum Details { IndexSwap { swaps: Vec, }, + IndexRename(IndexRenameDetails), Export { url: String, api_key: Option, @@ -737,6 +768,7 @@ impl Details { Self::SettingsUpdate { .. } | Self::IndexInfo { .. } | Self::Dump { .. } + | Self::IndexRename { .. } | Self::Export { .. } | Self::UpgradeDatabase { .. } | Self::IndexSwap { .. } => (),