log_array.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. use serde_derive::{Deserialize, Serialize};
  2. use crate::{IndexTerm, Term};
  3. /// A log array that stores a tail of the whole Raft log.
  4. ///
  5. /// The Raft log represented by the log array has length `end()`. Only log
  6. /// entries after `start()` are physically stored in the log array (with some
  7. /// caveats). The index and term of log entries in range `[start(), end())` are
  8. /// accessible. A snapshot is stored at the beginning of the log array, which
  9. /// covers all commands before and **including** `start()`. The command at
  10. /// `start()` is **not** accessible, but all commands after that are.
  11. ///
  12. /// New entries can be appended to the end of the Raft log via `add_command()`
  13. /// or `push()`.
  14. ///
  15. /// The log array can be truncated to at most one entry, which is at `start()`
  16. /// and contains the snapshot. The start of the log array can be shifted towards
  17. /// `end()`, if another snapshot at that position is provided.
  18. ///
  19. /// The log array can also be reset to a single entry, contains an index, a term
  20. /// and a snapshot, via `reset()`.
  21. ///
  22. /// The log array is guaranteed to have at least one element, containing an
  23. /// index, a term and a snapshot.
  24. ///
  25. /// All APIs **will** panic if the given index(es) are out of bound.
  26. pub type Index = usize;
  27. #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
  28. enum LogEntryEnum<Command> {
  29. TermChange,
  30. Noop,
  31. Command(Command),
  32. }
  33. #[derive(Clone, Debug, Serialize, Deserialize)]
  34. pub struct LogEntry<Command> {
  35. pub index: Index,
  36. pub term: Term,
  37. command: LogEntryEnum<Command>,
  38. }
  39. /// NOT THREAD SAFE.
  40. #[derive(Clone, Serialize, Deserialize)]
  41. pub(crate) struct LogArray<C> {
  42. inner: Vec<LogEntry<C>>,
  43. snapshot: Vec<u8>,
  44. }
  45. #[derive(Debug)]
  46. pub(crate) enum ValidationError {
  47. IndexMismatch(Index, Vec<IndexTerm>),
  48. TermSpike(Index, Vec<IndexTerm>),
  49. FutureTerm(Term, Index, Vec<IndexTerm>),
  50. }
  51. impl<C> LogArray<C> {
  52. /// Create the initial Raft log with no user-supplied commands.
  53. pub fn create() -> LogArray<C> {
  54. let ret = LogArray {
  55. inner: vec![Self::build_first_entry(0, Term(0))],
  56. snapshot: vec![],
  57. };
  58. ret.check_one_element();
  59. ret
  60. }
  61. }
  62. impl<C> LogEntry<C> {
  63. pub fn command(&self) -> Option<&C> {
  64. match &self.command {
  65. LogEntryEnum::TermChange => None,
  66. LogEntryEnum::Noop => None,
  67. LogEntryEnum::Command(command) => Some(command),
  68. }
  69. }
  70. }
  71. // Log accessors
  72. impl<C> LogArray<C> {
  73. /// The start of the stored log entries. The command at this index is no
  74. /// longer accessible, since it is included in the snapshot.
  75. pub fn start(&self) -> Index {
  76. self.first_entry().index
  77. }
  78. /// The end index of the Raft log.
  79. pub fn end(&self) -> Index {
  80. self.start() + self.inner.len()
  81. }
  82. /// The first index and term stored in this log array.
  83. pub fn first_index_term(&self) -> IndexTerm {
  84. self.first_entry().into()
  85. }
  86. /// The last index and term of the Raft log.
  87. pub fn last_index_term(&self) -> IndexTerm {
  88. self.last_entry().into()
  89. }
  90. /// The log entry at the given index.
  91. pub fn at(&self, index: Index) -> &LogEntry<C> {
  92. let index = self.check_at_index(index);
  93. &self.inner[index]
  94. }
  95. /// The first log entry on or after the given index.
  96. pub fn first_after(&self, index: Index) -> &LogEntry<C> {
  97. if index >= self.start() {
  98. self.at(index)
  99. } else {
  100. self.first_entry()
  101. }
  102. }
  103. /// All log entries after the given index.
  104. pub fn after(&self, index: Index) -> &[LogEntry<C>] {
  105. let index = self.check_range_index(index);
  106. &self.inner[index..]
  107. }
  108. /// All log entries in range [start, end).
  109. pub fn between(&self, start: Index, end: Index) -> &[LogEntry<C>] {
  110. let start = self.check_range_index(start);
  111. let end = self.check_range_index(end);
  112. &self.inner[start..end]
  113. }
  114. /// All log entries stored in the array.
  115. #[cfg(test)]
  116. pub fn all(&self) -> &[LogEntry<C>] {
  117. &self.inner[..]
  118. }
  119. /// `IndexTerm` of all log entries, without command.
  120. pub fn all_index_term(&self) -> Vec<IndexTerm> {
  121. self.inner.iter().map(|e| e.into()).collect()
  122. }
  123. /// The snapshot before and including `start()`.
  124. pub fn snapshot(&self) -> (IndexTerm, &[u8]) {
  125. (self.first_index_term(), &self.snapshot)
  126. }
  127. pub fn validate(&self, current_term: Term) -> Result<(), ValidationError> {
  128. let all_index_term = self.all_index_term();
  129. let (mut index, mut term) = all_index_term[0].clone().into();
  130. for entry in all_index_term[1..].iter() {
  131. index += 1;
  132. if entry.index != index {
  133. return Err(ValidationError::IndexMismatch(
  134. index,
  135. all_index_term,
  136. ));
  137. }
  138. if entry.term < term {
  139. return Err(ValidationError::TermSpike(index, all_index_term));
  140. }
  141. if entry.term > current_term {
  142. return Err(ValidationError::FutureTerm(
  143. current_term,
  144. index,
  145. all_index_term,
  146. ));
  147. }
  148. term = entry.term;
  149. }
  150. Ok(())
  151. }
  152. }
  153. // Mutations
  154. impl<C> LogArray<C> {
  155. /// Add a new entry to the Raft log. The new index is returned.
  156. fn add_entry(&mut self, term: Term, entry: LogEntryEnum<C>) -> Index {
  157. let index = self.end();
  158. self.push(LogEntry {
  159. index,
  160. term,
  161. command: entry,
  162. });
  163. index
  164. }
  165. /// Add a new entry to the Raft log, with term and command. The new index is
  166. /// returned.
  167. pub fn add_command(&mut self, term: Term, command: C) -> Index {
  168. self.add_entry(term, LogEntryEnum::Command(command))
  169. }
  170. /// Add a new term change entry to the Raft log. The new index is returned.
  171. pub fn add_term_change_entry(&mut self, term: Term) -> Index {
  172. self.add_entry(term, LogEntryEnum::TermChange)
  173. }
  174. /// Push a LogEntry into the Raft log. The index of the log entry must match
  175. /// the next index in the log.
  176. pub fn push(&mut self, log_entry: LogEntry<C>) {
  177. let index = log_entry.index;
  178. assert_eq!(index, self.end(), "Expecting new index to be exact at len");
  179. self.inner.push(log_entry);
  180. assert_eq!(
  181. index + 1,
  182. self.end(),
  183. "Expecting len increase by one after push",
  184. );
  185. assert_eq!(
  186. self.at(index).index,
  187. index,
  188. "Expecting pushed element to have the same index",
  189. );
  190. self.check_one_element();
  191. }
  192. /// Remove all log entries on and after `index`.
  193. pub fn truncate(&mut self, index: Index) {
  194. let index = self.check_middle_index(index);
  195. self.inner.truncate(index);
  196. self.check_one_element()
  197. }
  198. }
  199. impl<C> LogArray<C> {
  200. /// Shift the start of the array to `index`, and store a new snapshot that
  201. /// covers all commands before and at `index`.
  202. pub fn shift(&mut self, index: Index, snapshot: Vec<u8>) {
  203. // Discard everything before index and store the snapshot.
  204. let offset = self.check_middle_index(index);
  205. // WARNING: Potentially all entries after offset would be copied.
  206. self.inner.drain(0..offset);
  207. self.snapshot = snapshot;
  208. // Override the first entry, we know there is at least one entry. This
  209. // is not strictly needed. One benefit is that the command can be
  210. // released after this point.
  211. let first = self.first_index_term();
  212. self.inner[0] = Self::build_first_entry(first.index, first.term);
  213. assert_eq!(
  214. first.index, index,
  215. "Expecting the first entry to have the same index."
  216. );
  217. self.check_one_element()
  218. }
  219. /// Reset the array to contain only one snapshot at the given `index` with
  220. /// the given `term`.
  221. pub fn reset(
  222. &mut self,
  223. index: Index,
  224. term: Term,
  225. snapshot: Vec<u8>,
  226. ) -> Vec<LogEntry<C>> {
  227. let mut inner = vec![Self::build_first_entry(index, term)];
  228. std::mem::swap(&mut inner, &mut self.inner);
  229. self.snapshot = snapshot;
  230. self.check_one_element();
  231. inner
  232. }
  233. }
  234. impl<C> LogArray<C> {
  235. fn first_entry(&self) -> &LogEntry<C> {
  236. self.inner
  237. .first()
  238. .expect("There must be at least one element in log")
  239. }
  240. fn last_entry(&self) -> &LogEntry<C> {
  241. self.inner
  242. .last()
  243. .expect("There must be at least one entry in log")
  244. }
  245. fn offset(&self, index: Index) -> usize {
  246. index - self.start()
  247. }
  248. fn check_at_index(&self, index: Index) -> usize {
  249. assert!(
  250. index >= self.start() && index < self.end(),
  251. "Accessing start log index {} out of range [{}, {})",
  252. index,
  253. self.start(),
  254. self.end()
  255. );
  256. self.offset(index)
  257. }
  258. fn check_range_index(&self, index: Index) -> usize {
  259. assert!(
  260. index >= self.start() && index <= self.end(),
  261. "Accessing end log index {} out of range [{}, {}]",
  262. index,
  263. self.start(),
  264. self.end()
  265. );
  266. self.offset(index)
  267. }
  268. fn check_middle_index(&self, index: Index) -> usize {
  269. assert!(
  270. index > self.start() && index < self.end(),
  271. "Log index {} out of range ({}, {})",
  272. index,
  273. self.start(),
  274. self.end()
  275. );
  276. self.offset(index)
  277. }
  278. #[allow(clippy::len_zero)]
  279. fn check_one_element(&self) {
  280. assert!(
  281. self.inner.len() >= 1,
  282. "There must be at least one element in log"
  283. )
  284. }
  285. }
  286. impl<C> LogArray<C> {
  287. fn build_first_entry(index: Index, term: Term) -> LogEntry<C> {
  288. LogEntry {
  289. index,
  290. term,
  291. command: LogEntryEnum::Noop,
  292. }
  293. }
  294. }
  295. #[cfg(test)]
  296. mod tests {
  297. use std::panic::catch_unwind;
  298. use super::*;
  299. impl<C> std::ops::Index<usize> for LogArray<C> {
  300. type Output = LogEntry<C>;
  301. fn index(&self, index: usize) -> &Self::Output {
  302. self.at(index)
  303. }
  304. }
  305. fn make_log_array(len: usize) -> LogArray<i32> {
  306. make_log_array_range(0, len)
  307. }
  308. fn make_log_array_range(start: usize, end: usize) -> LogArray<i32> {
  309. let mut ret = vec![];
  310. for i in start..end {
  311. ret.push(LogEntry {
  312. term: Term(i / 3),
  313. index: i,
  314. command: LogEntryEnum::Command((end - i) as i32),
  315. })
  316. }
  317. LogArray {
  318. inner: ret,
  319. snapshot: vec![1, 2, 3],
  320. }
  321. }
  322. fn default_log_array() -> (usize, usize, LogArray<i32>) {
  323. (8, 17, make_log_array_range(8, 17))
  324. }
  325. #[test]
  326. fn test_create() {
  327. let log = LogArray::<i32>::create();
  328. log.check_one_element();
  329. assert_eq!(1, log.end());
  330. assert_eq!((0, Term(0)), log.first_index_term().into());
  331. assert_eq!(LogEntryEnum::Noop, log[0].command);
  332. }
  333. #[test]
  334. fn test_start() {
  335. let log = make_log_array_range(9, 17);
  336. assert_eq!(9, log.start());
  337. let log = make_log_array(9);
  338. assert_eq!(0, log.start());
  339. }
  340. #[test]
  341. fn test_end() {
  342. let log = make_log_array(7);
  343. assert_eq!(7, log.end());
  344. let log = make_log_array_range(8, 17);
  345. assert_eq!(17, log.end());
  346. }
  347. #[test]
  348. fn test_accessors() {
  349. let (start, end, log) = default_log_array();
  350. assert_eq!((start, Term(2)), log.first_index_term().into());
  351. assert_eq!((end - 1, Term(5)), log.last_index_term().into());
  352. assert_eq!(
  353. ((start, Term(2)).into(), [1, 2, 3].as_ref()),
  354. log.snapshot()
  355. );
  356. let all = log.all();
  357. assert_eq!(end - start, all.len());
  358. for i in start..end {
  359. assert_eq!(all[i - start].index, i);
  360. }
  361. }
  362. #[test]
  363. fn test_at() {
  364. let (start, end, log) = default_log_array();
  365. let last = log.at(end - 1);
  366. assert_eq!(end - 1, last.index);
  367. assert_eq!(5, last.term.0);
  368. assert_eq!(LogEntryEnum::Command(1), last.command);
  369. let first = log.at(start);
  370. assert_eq!(start, first.index);
  371. assert_eq!(2, first.term.0);
  372. assert_eq!(LogEntryEnum::Command(9), first.command);
  373. assert!(start < 12);
  374. assert!(end > 12);
  375. let middle = log.at(12);
  376. assert_eq!(12, middle.index);
  377. assert_eq!(4, middle.term.0);
  378. assert_eq!(LogEntryEnum::Command(5), middle.command);
  379. let at_before_start = catch_unwind(|| {
  380. log.at(start - 1);
  381. });
  382. assert!(at_before_start.is_err());
  383. let at_after_end = catch_unwind(|| {
  384. log.at(end);
  385. });
  386. assert!(at_after_end.is_err());
  387. }
  388. #[test]
  389. fn test_first_after() {
  390. let (start, _, log) = default_log_array();
  391. assert_eq!(log.first_after(0).index, log.first_entry().index);
  392. assert_eq!(log.first_after(start).index, log.at(start).index);
  393. assert_eq!(log.first_after(start + 1).index, log.at(start + 1).index);
  394. assert_ne!(log.first_after(0).index, log.first_after(start + 1).index);
  395. }
  396. #[test]
  397. fn test_index_operator() {
  398. let (start, end, log) = default_log_array();
  399. for i in start..end {
  400. assert_eq!(log[i].index, log.at(i).index);
  401. assert_eq!(log[i].term, log.at(i).term);
  402. assert_eq!(log[i].command, log.at(i).command);
  403. }
  404. assert!(catch_unwind(|| log[0].term).is_err());
  405. assert!(catch_unwind(|| log[20].term).is_err());
  406. }
  407. #[test]
  408. fn test_after() {
  409. let (start, end, log) = default_log_array();
  410. let offset = 12;
  411. assert!(offset > start);
  412. assert!(offset < end);
  413. let after = log.after(offset);
  414. assert_eq!(end - offset, after.len());
  415. for i in offset..end {
  416. assert_eq!(after[i - offset].index, i);
  417. assert_eq!(after[i - offset].term.0, i / 3);
  418. }
  419. assert!(catch_unwind(|| log.after(start - 1)).is_err());
  420. assert!(catch_unwind(|| log.after(start)).is_ok());
  421. assert!(catch_unwind(|| log.after(end)).is_ok());
  422. assert!(catch_unwind(|| log.after(end + 1)).is_err());
  423. }
  424. #[test]
  425. fn test_between() {
  426. let (start, end, log) = default_log_array();
  427. let between = log.between(start + 2, end);
  428. assert_eq!(end - start - 2, between.len());
  429. for i in start + 2..end {
  430. assert_eq!(between[i - start - 2].index, i);
  431. assert_eq!(between[i - start - 2].term.0, i / 3);
  432. }
  433. assert!(catch_unwind(|| log.between(start - 1, end)).is_err());
  434. assert!(catch_unwind(|| log.between(start + 2, end + 1)).is_err());
  435. assert!(catch_unwind(|| log.between(start, end)).is_ok());
  436. }
  437. #[test]
  438. fn test_add_command() {
  439. let (_, end, mut log) = default_log_array();
  440. let index = log.add_command(Term(8), 9);
  441. assert_eq!(8, log.at(index).term.0);
  442. assert_eq!(LogEntryEnum::Command(9), log.at(index).command);
  443. assert_eq!(index, end);
  444. assert_eq!(index + 1, log.end());
  445. }
  446. #[test]
  447. fn test_add_term_change() {
  448. let (_, end, mut log) = default_log_array();
  449. let index = log.add_term_change_entry(Term(8));
  450. assert_eq!(8, log.at(index).term.0);
  451. assert_eq!(LogEntryEnum::TermChange, log.at(index).command);
  452. assert_eq!(index, end);
  453. assert_eq!(index + 1, log.end());
  454. }
  455. #[test]
  456. fn test_push() {
  457. let (_, end, mut log) = default_log_array();
  458. log.push(LogEntry {
  459. term: Term(8),
  460. index: end,
  461. command: LogEntryEnum::Command(1),
  462. });
  463. assert_eq!(8, log.at(end).term.0);
  464. assert_eq!(LogEntryEnum::Command(1), log.at(end).command);
  465. assert_eq!(end + 1, log.end());
  466. }
  467. #[test]
  468. #[should_panic]
  469. fn test_push_small_index() {
  470. let (_, end, mut log) = default_log_array();
  471. log.push(LogEntry {
  472. term: Term(8),
  473. index: end - 1,
  474. command: LogEntryEnum::Command(1),
  475. });
  476. }
  477. #[test]
  478. #[should_panic]
  479. fn test_push_big_index() {
  480. let (_, end, mut log) = default_log_array();
  481. log.push(LogEntry {
  482. term: Term(8),
  483. index: end + 1,
  484. command: LogEntryEnum::Command(1),
  485. });
  486. }
  487. #[test]
  488. fn test_truncate() {
  489. let (start, _, mut log) = default_log_array();
  490. log.truncate(start + 5);
  491. assert_eq!(start + 5, log.end());
  492. for i in start..start + 5 {
  493. assert_eq!(log[i].index, i);
  494. assert_eq!(log[i].term.0, i / 3);
  495. }
  496. log.truncate(start + 1);
  497. assert_eq!(1, log.all().len());
  498. }
  499. #[test]
  500. #[should_panic]
  501. fn test_truncate_at_start() {
  502. let (start, _, mut log) = default_log_array();
  503. log.truncate(start);
  504. }
  505. #[test]
  506. #[should_panic]
  507. fn test_truncate_at_end() {
  508. let (_, end, mut log) = default_log_array();
  509. log.truncate(end);
  510. }
  511. #[test]
  512. #[should_panic]
  513. fn test_truncate_before_start() {
  514. let (start, _, mut log) = default_log_array();
  515. log.truncate(start - 1);
  516. }
  517. #[test]
  518. #[should_panic]
  519. fn test_truncate_after_end() {
  520. let (_, end, mut log) = default_log_array();
  521. log.truncate(end + 1);
  522. }
  523. #[test]
  524. fn test_shift() {
  525. let (start, end, mut log) = default_log_array();
  526. let offset = 10;
  527. assert!(offset > start);
  528. assert!(offset < end);
  529. log.shift(offset, vec![]);
  530. assert_eq!((offset, Term(3)), log.first_index_term().into());
  531. assert_eq!(LogEntryEnum::Noop, log[offset].command);
  532. let all = log.all();
  533. assert_eq!(end - offset, all.len());
  534. for i in offset..end {
  535. assert_eq!(i, all[i - offset].index);
  536. assert_eq!(i / 3, all[i - offset].term.0);
  537. }
  538. assert_eq!(log.snapshot, vec![]);
  539. }
  540. #[test]
  541. #[should_panic]
  542. fn test_shift_before_start() {
  543. let (start, end, mut log) = default_log_array();
  544. assert!(start < end);
  545. log.shift(start - 1, vec![]);
  546. }
  547. #[test]
  548. #[should_panic]
  549. fn test_shift_at_start() {
  550. let (start, end, mut log) = default_log_array();
  551. assert!(start < end);
  552. log.shift(start, vec![]);
  553. }
  554. #[test]
  555. #[should_panic]
  556. fn test_shift_at_end() {
  557. let (start, end, mut log) = default_log_array();
  558. assert!(start < end);
  559. log.shift(end, vec![]);
  560. }
  561. #[test]
  562. #[should_panic]
  563. fn test_shift_after_end() {
  564. let (start, end, mut log) = default_log_array();
  565. assert!(start < end);
  566. log.shift(end + 1, vec![]);
  567. }
  568. #[test]
  569. fn test_reset() {
  570. let (start, end, mut log) = default_log_array();
  571. let dump = log.reset(88, Term(99), vec![1, 2]);
  572. assert_eq!(1, log.all().len());
  573. assert_eq!(vec![1, 2], log.snapshot);
  574. assert_eq!(88, log[88].index);
  575. assert_eq!(99, log[88].term.0);
  576. assert_eq!(LogEntryEnum::Noop, log[88].command);
  577. assert_eq!(end - start, dump.len());
  578. }
  579. #[test]
  580. fn test_private_accessors() {
  581. let (start, end, log) = default_log_array();
  582. let first = log.first_entry();
  583. assert_eq!(start, first.index);
  584. assert_eq!(start / 3, first.term.0);
  585. let last = log.last_entry();
  586. assert_eq!(end - 1, last.index);
  587. assert_eq!((end - 1) / 3, last.term.0);
  588. assert_eq!(10 - start, log.offset(10));
  589. }
  590. #[test]
  591. fn test_check_start_index() {
  592. let (start, end, log) = default_log_array();
  593. assert!(start < end);
  594. assert!(catch_unwind(|| log.check_at_index(start - 8)).is_err());
  595. assert!(catch_unwind(|| log.check_at_index(start - 1)).is_err());
  596. assert!(catch_unwind(|| log.check_at_index(start)).is_ok());
  597. assert!(catch_unwind(|| log.check_at_index(start + 1)).is_ok());
  598. assert!(catch_unwind(|| log.check_at_index(end - 1)).is_ok());
  599. assert!(catch_unwind(|| log.check_at_index(end)).is_err());
  600. assert!(catch_unwind(|| log.check_at_index(end + 1)).is_err());
  601. assert!(catch_unwind(|| log.check_at_index(end + 5)).is_err());
  602. }
  603. #[test]
  604. fn test_check_range_index() {
  605. let (start, end, log) = default_log_array();
  606. assert!(start < end);
  607. assert!(catch_unwind(|| log.check_range_index(start - 8)).is_err());
  608. assert!(catch_unwind(|| log.check_range_index(start - 1)).is_err());
  609. assert!(catch_unwind(|| log.check_range_index(start)).is_ok());
  610. assert!(catch_unwind(|| log.check_range_index(start + 1)).is_ok());
  611. assert!(catch_unwind(|| log.check_range_index(end - 1)).is_ok());
  612. assert!(catch_unwind(|| log.check_range_index(end)).is_ok());
  613. assert!(catch_unwind(|| log.check_range_index(end + 1)).is_err());
  614. assert!(catch_unwind(|| log.check_range_index(end + 5)).is_err());
  615. }
  616. #[test]
  617. fn test_check_middle_index() {
  618. let (start, end, log) = default_log_array();
  619. assert!(start < end);
  620. assert!(catch_unwind(|| log.check_middle_index(start - 8)).is_err());
  621. assert!(catch_unwind(|| log.check_middle_index(start - 1)).is_err());
  622. assert!(catch_unwind(|| log.check_middle_index(start)).is_err());
  623. assert!(catch_unwind(|| log.check_middle_index(start + 1)).is_ok());
  624. assert!(catch_unwind(|| log.check_middle_index(end - 1)).is_ok());
  625. assert!(catch_unwind(|| log.check_middle_index(end)).is_err());
  626. assert!(catch_unwind(|| log.check_middle_index(end + 1)).is_err());
  627. assert!(catch_unwind(|| log.check_middle_index(end + 5)).is_err());
  628. }
  629. #[test]
  630. fn test_check_one_element() {
  631. let log = make_log_array(0);
  632. assert!(catch_unwind(|| log.check_one_element()).is_err());
  633. }
  634. #[test]
  635. fn test_integration_test() {
  636. let mut log = make_log_array(1);
  637. log.add_command(Term(3), 19);
  638. log.push(LogEntry {
  639. term: Term(3),
  640. index: 2,
  641. command: LogEntryEnum::Command(3),
  642. });
  643. log.add_command(Term(4), 20);
  644. log.push(LogEntry {
  645. term: Term(4),
  646. index: 4,
  647. command: LogEntryEnum::Command(7),
  648. });
  649. for i in 0..100 {
  650. log.add_command(Term(5), i);
  651. }
  652. assert_eq!(0, log.start());
  653. assert_eq!(105, log.end());
  654. assert_eq!((0, Term(0)), log.first_index_term().into());
  655. assert_eq!((104, Term(5)), log.last_index_term().into());
  656. assert_eq!(8, log.at(8).index);
  657. assert_eq!(5, log[8].term.0);
  658. assert_eq!(LogEntryEnum::Command(7), log[4].command);
  659. log.truncate(50);
  660. // End changed, start does not.
  661. assert_eq!(0, log.start());
  662. assert_eq!(50, log.end());
  663. assert_eq!((49, Term(5)), log.last_index_term().into());
  664. assert_eq!(49, log.at(49).index);
  665. assert_eq!(LogEntryEnum::Command(44), log[49].command);
  666. assert_eq!(5, log.at(5).term.0);
  667. // Cannot assert 50 is out of range. log is mut and cannot be used in
  668. // catch_unwind().
  669. // Snapshot is not changed.
  670. assert_eq!(((0, Term(0)).into(), [1, 2, 3].as_ref()), log.snapshot());
  671. log.shift(5, vec![]);
  672. // Start changed, end did not;
  673. assert_eq!(5, log.start());
  674. assert_eq!((5, Term(5)), log.first_index_term().into());
  675. assert_eq!(5, log.at(5).index);
  676. assert_eq!(5, log.at(5).term.0);
  677. // Cannot assert 4 is out of range. log is mut and cannot be used in
  678. // catch_unwind().
  679. // Snapshot is changed, too.
  680. assert_eq!(((5, Term(5)).into(), [].as_ref()), log.snapshot());
  681. // Ranged accessors.
  682. assert_eq!(45, log.all().len());
  683. assert_eq!(10, log.after(40).len());
  684. assert_eq!(20, log.between(20, 40).len());
  685. // Reset!
  686. log.reset(9, Term(7), vec![7, 8, 9]);
  687. assert_eq!(10, log.end());
  688. assert_eq!(1, log.all().len());
  689. assert_eq!(log.first_index_term(), log.last_index_term());
  690. assert_eq!(((9, Term(7)).into(), [7, 8, 9].as_ref()), log.snapshot());
  691. }
  692. #[test]
  693. fn test_validate_or_panic_current_term() {
  694. let log_array = make_log_array(7);
  695. let last_term = log_array.last_index_term().term.0;
  696. log_array
  697. .validate(Term(last_term))
  698. .expect("Validation should not fail");
  699. log_array
  700. .validate(Term(last_term + 1))
  701. .expect("Validation should not fail");
  702. let err = log_array
  703. .validate(Term(last_term - 1))
  704. .expect_err("Validation should have failed");
  705. assert!(matches!(
  706. err,
  707. ValidationError::FutureTerm(Term(_last_term), _, _)
  708. ));
  709. }
  710. #[test]
  711. fn test_validate_or_panic_increasing_term() {
  712. let mut log_array = make_log_array(7);
  713. let last_term = log_array.last_index_term().term.0;
  714. log_array
  715. .validate(Term(last_term + 1))
  716. .expect("Validation should not fail");
  717. log_array.inner[1].term = Term(last_term + 1);
  718. let err = log_array
  719. .validate(Term(last_term + 1))
  720. .expect_err("Validation should have failed");
  721. assert!(matches!(err, ValidationError::TermSpike(2, _)));
  722. }
  723. #[test]
  724. fn test_validate_or_panic_increasing_index() {
  725. let mut log_array = make_log_array_range(7, 10);
  726. let last_term = log_array.last_index_term().term.0;
  727. // OK
  728. log_array.inner[1].index = 8;
  729. log_array
  730. .validate(Term(last_term + 1))
  731. .expect("Validation should not fail");
  732. // Not 8, error
  733. log_array.inner[1].index = 7;
  734. let err = log_array
  735. .validate(Term(last_term + 1))
  736. .expect_err("Validation should have failed");
  737. assert!(matches!(err, ValidationError::IndexMismatch(8, _)));
  738. // Not 8, error
  739. log_array.inner[1].index = 9;
  740. let err = log_array
  741. .validate(Term(last_term + 1))
  742. .expect_err("Validation should have failed");
  743. assert!(matches!(err, ValidationError::IndexMismatch(8, _)));
  744. }
  745. #[test]
  746. fn test_log_entry_command() {
  747. let entry = LogEntry::<i32> {
  748. index: 0,
  749. term: Term(0),
  750. command: LogEntryEnum::TermChange,
  751. };
  752. assert_eq!(None, entry.command());
  753. let entry = LogEntry::<i32> {
  754. index: 0,
  755. term: Term(0),
  756. command: LogEntryEnum::Noop,
  757. };
  758. assert_eq!(None, entry.command());
  759. let entry = LogEntry::<i32> {
  760. index: 0,
  761. term: Term(0),
  762. command: LogEntryEnum::Command(1),
  763. };
  764. assert_eq!(Some(1), entry.command().cloned());
  765. }
  766. }