From 2262c79f5195307402e7a0994771b4152c0d10b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=82=8E=E6=B3=BC?= Date: Sun, 8 May 2022 15:41:16 +0800 Subject: [PATCH] Feature: LogIdList: add method purge() to delete log ids --- openraft/src/engine/log_id_list.rs | 28 ++++++++ openraft/src/engine/log_id_list_test.rs | 85 ++++++++++++++++++++----- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/openraft/src/engine/log_id_list.rs b/openraft/src/engine/log_id_list.rs index c4961edc0..6de9d2316 100644 --- a/openraft/src/engine/log_id_list.rs +++ b/openraft/src/engine/log_id_list.rs @@ -80,6 +80,34 @@ impl LogIdList { self.key_log_ids.push(new_log_id); } + /// Purge log ids upto the log with index `upto_index`, inclusive. + #[allow(dead_code)] + pub(crate) fn purge(&mut self, upto: &LogId) { + // When installing snapshot it may need to purge across the `last_log_id`. + if upto.index > self.key_log_ids[self.key_log_ids.len() - 1].index { + assert!(upto > &self.key_log_ids[self.key_log_ids.len() - 1]); + self.key_log_ids = vec![*upto]; + } + + if upto.index < self.key_log_ids[0].index { + return; + } + + let res = self.key_log_ids.binary_search_by(|log_id| log_id.index.cmp(&upto.index)); + + match res { + Ok(i) => { + if i > 0 { + self.key_log_ids = self.key_log_ids.split_off(i) + } + } + Err(i) => { + self.key_log_ids = self.key_log_ids.split_off(i - 1); + self.key_log_ids[0].index = upto.index; + } + } + } + /// Get the log id at the specified index. /// /// It will return `last_purged_log_id` if index is at the last purged index. diff --git a/openraft/src/engine/log_id_list_test.rs b/openraft/src/engine/log_id_list_test.rs index d25555bad..f6484f715 100644 --- a/openraft/src/engine/log_id_list_test.rs +++ b/openraft/src/engine/log_id_list_test.rs @@ -4,11 +4,6 @@ use crate::LogId; #[test] fn test_log_id_list_extend_from_same_leader() -> anyhow::Result<()> { - let log_id = |t, i| LogId:: { - leader_id: LeaderId { term: t, node_id: 1 }, - index: i, - }; - let mut ids = LogIdList::::default(); // Extend one log id to an empty LogIdList: Just store it directly @@ -55,11 +50,6 @@ fn test_log_id_list_extend_from_same_leader() -> anyhow::Result<()> { #[test] fn test_log_id_list_append() -> anyhow::Result<()> { - let log_id = |t, i| LogId:: { - leader_id: LeaderId { term: t, node_id: 1 }, - index: i, - }; - let mut ids = LogIdList::::default(); // Append log id one by one, check the internally constructed `key_log_id` as expected. @@ -82,12 +72,71 @@ fn test_log_id_list_append() -> anyhow::Result<()> { } #[test] -fn test_log_id_list_get_log_id() -> anyhow::Result<()> { - let log_id = |t, i| LogId:: { - leader_id: LeaderId { term: t, node_id: 1 }, - index: i, - }; +fn test_log_id_list_purge() -> anyhow::Result<()> { + // Append log id one by one, check the internally constructed `key_log_id` as expected. + + let cases = vec![ + // + (log_id(2, 1), vec![ + log_id(2, 2), + log_id(3, 3), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]), + (log_id(2, 2), vec![ + log_id(2, 2), + log_id(3, 3), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]), + (log_id(3, 3), vec![ + log_id(3, 3), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]), + (log_id(3, 4), vec![ + log_id(3, 4), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]), + (log_id(3, 5), vec![ + log_id(3, 5), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]), + (log_id(6, 6), vec![log_id(6, 6), log_id(9, 9), log_id(9, 11)]), + (log_id(6, 7), vec![log_id(6, 7), log_id(9, 9), log_id(9, 11)]), + (log_id(6, 8), vec![log_id(6, 8), log_id(9, 9), log_id(9, 11)]), + (log_id(9, 9), vec![log_id(9, 9), log_id(9, 11)]), + (log_id(9, 10), vec![log_id(9, 10), log_id(9, 11)]), + (log_id(9, 11), vec![log_id(9, 11)]), + (log_id(9, 12), vec![log_id(9, 12)]), + (log_id(10, 12), vec![log_id(10, 12)]), + ]; + + for (upto, want) in cases { + let mut ids = LogIdList::::new(vec![ + log_id(2, 2), // force multi line + log_id(3, 3), + log_id(6, 6), + log_id(9, 9), + log_id(9, 11), + ]); + + ids.purge(&upto); + assert_eq!(want, ids.key_log_ids(), "purge upto: {}", upto); + } + + Ok(()) +} +#[test] +fn test_log_id_list_get_log_id() -> anyhow::Result<()> { // Get log id from empty list always returns `None`. let ids = LogIdList::::default(); @@ -122,3 +171,9 @@ fn test_log_id_list_get_log_id() -> anyhow::Result<()> { Ok(()) } +fn log_id(term: u64, index: u64) -> LogId { + LogId:: { + leader_id: LeaderId { term, node_id: 1 }, + index, + } +}