log_array.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. use crate::{Index, LogEntry, Term};
  2. use std::mem::swap;
  3. pub(crate) struct LogArray<C> {
  4. inner: Vec<LogEntry<C>>,
  5. snapshot: bytes::Bytes,
  6. }
  7. impl<C: Default> LogArray<C> {
  8. pub fn create() -> LogArray<C> {
  9. let ret = LogArray {
  10. inner: vec![Self::build_first_entry(0, Term(0))],
  11. snapshot: bytes::Bytes::new(),
  12. };
  13. ret.check_one_element();
  14. ret
  15. }
  16. pub fn restore(inner: Vec<LogEntry<C>>) -> std::io::Result<Self> {
  17. Ok(LogArray {
  18. inner,
  19. snapshot: bytes::Bytes::new(),
  20. })
  21. }
  22. }
  23. // Log accessors
  24. impl<C> LogArray<C> {
  25. pub fn start_offset(&self) -> Index {
  26. self.first_entry().index
  27. }
  28. pub fn len(&self) -> usize {
  29. self.start_offset() + self.inner.len()
  30. }
  31. #[allow(dead_code)]
  32. pub fn first_index_term(&self) -> (Index, Term) {
  33. let first_entry = self.first_entry();
  34. (first_entry.index, first_entry.term)
  35. }
  36. pub fn last_index_term(&self) -> (Index, Term) {
  37. let last_entry = self.last_entry();
  38. (last_entry.index, last_entry.term)
  39. }
  40. pub fn at(&self, index: Index) -> &LogEntry<C> {
  41. let index = self.check_start_index(index);
  42. &self.inner[index]
  43. }
  44. pub fn after(&self, index: Index) -> &[LogEntry<C>] {
  45. let index = self.check_start_index(index);
  46. &self.inner[index..]
  47. }
  48. pub fn between(&self, start: Index, end: Index) -> &[LogEntry<C>] {
  49. let start = self.check_start_index(start);
  50. let end = self.check_end_index(end);
  51. &self.inner[start..end]
  52. }
  53. pub fn all(&self) -> &[LogEntry<C>] {
  54. &self.inner[..]
  55. }
  56. #[allow(dead_code)]
  57. pub fn snapshot(&self) -> &bytes::Bytes {
  58. &self.snapshot
  59. }
  60. }
  61. impl<C> std::ops::Index<usize> for LogArray<C> {
  62. type Output = LogEntry<C>;
  63. fn index(&self, index: usize) -> &Self::Output {
  64. self.at(index)
  65. }
  66. }
  67. // Mutations
  68. impl<C> LogArray<C> {
  69. pub fn add(&mut self, term: Term, command: C) -> Index {
  70. let index = self.len();
  71. self.push(LogEntry {
  72. index,
  73. term,
  74. command,
  75. });
  76. index
  77. }
  78. pub fn push(&mut self, log_entry: LogEntry<C>) {
  79. let index = log_entry.index;
  80. assert_eq!(index, self.len(), "Expecting new index to be exact at len");
  81. self.inner.push(log_entry);
  82. assert_eq!(
  83. index + 1,
  84. self.len(),
  85. "Expecting len increase by one after push",
  86. );
  87. assert_eq!(
  88. self.at(index).index,
  89. index,
  90. "Expecting pushed element to have the same index",
  91. );
  92. self.check_one_element();
  93. }
  94. pub fn truncate(&mut self, index: Index) {
  95. let index = self.check_middle_index(index);
  96. self.inner.truncate(index);
  97. self.check_one_element()
  98. }
  99. }
  100. impl<C: Default> LogArray<C> {
  101. #[allow(dead_code)]
  102. pub fn shift(&mut self, index: Index, snapshot: bytes::Bytes) {
  103. // Discard everything before index and store the snapshot.
  104. let offset = self.check_middle_index(index);
  105. // WARNING: Potentially all entries after offset would be copied.
  106. self.inner.drain(0..offset);
  107. self.snapshot = snapshot;
  108. // Override the first entry, we know there is at least one entry. This is not strictly
  109. // needed. One benefit is that the command can be released after this point.
  110. let (first_index, first_term) = self.first_index_term();
  111. self.inner[0] = Self::build_first_entry(first_index, first_term);
  112. assert_eq!(
  113. first_index, index,
  114. "Expecting the first entry to have the same index."
  115. );
  116. self.check_one_element()
  117. }
  118. #[allow(dead_code)]
  119. pub fn reset(
  120. &mut self,
  121. index: Index,
  122. term: Term,
  123. snapshot: bytes::Bytes,
  124. ) -> Vec<LogEntry<C>> {
  125. let mut inner = vec![Self::build_first_entry(index, term)];
  126. swap(&mut inner, &mut self.inner);
  127. self.snapshot = snapshot;
  128. self.check_one_element();
  129. inner
  130. }
  131. }
  132. impl<C> LogArray<C> {
  133. fn first_entry(&self) -> &LogEntry<C> {
  134. self.inner
  135. .first()
  136. .expect("There must be at least one element in log")
  137. }
  138. fn last_entry(&self) -> &LogEntry<C> {
  139. &self
  140. .inner
  141. .last()
  142. .expect("There must be at least one entry in log")
  143. }
  144. fn offset(&self, index: Index) -> usize {
  145. index - self.start_offset()
  146. }
  147. fn check_start_index(&self, index: Index) -> usize {
  148. assert!(
  149. index >= self.start_offset() && index < self.len(),
  150. "Accessing start log index {} out of range [{}, {})",
  151. index,
  152. self.start_offset(),
  153. self.len()
  154. );
  155. self.offset(index)
  156. }
  157. fn check_end_index(&self, index: Index) -> usize {
  158. assert!(
  159. index > self.start_offset() && index <= self.len(),
  160. "Accessing end log index {} out of range ({}, {}]",
  161. index,
  162. self.start_offset(),
  163. self.len()
  164. );
  165. self.offset(index)
  166. }
  167. fn check_middle_index(&self, index: Index) -> usize {
  168. assert!(
  169. index > self.start_offset() && index < self.len(),
  170. "Log index {} out of range ({}, {})",
  171. index,
  172. self.start_offset(),
  173. self.len()
  174. );
  175. self.offset(index)
  176. }
  177. fn check_one_element(&self) {
  178. assert!(
  179. self.inner.len() >= 1,
  180. "There must be at least one element in log"
  181. )
  182. }
  183. }
  184. impl<C: Default> LogArray<C> {
  185. fn build_first_entry(index: Index, term: Term) -> LogEntry<C> {
  186. LogEntry {
  187. index,
  188. term,
  189. command: C::default(),
  190. }
  191. }
  192. }