use std::fmt;
use std::fmt::Write;
use std::u64;
use slog::{OwnedKVList, Record, KV};
use crate::eraftpb::{Entry, Message};
use crate::HashSet;
use protobuf::Message as PbMessage;
use slog::{b, record_static};
pub const NO_LIMIT: u64 = u64::MAX;
pub fn limit_size<T: PbMessage + Clone>(entries: &mut Vec<T>, max: Option<u64>) {
if entries.len() <= 1 {
return;
}
let max = match max {
None | Some(NO_LIMIT) => return,
Some(max) => max,
};
let mut size = 0;
let limit = entries
.iter()
.take_while(|&e| {
if size == 0 {
size += u64::from(e.compute_size());
return true;
}
size += u64::from(e.compute_size());
size <= max
})
.count();
entries.truncate(limit);
}
pub fn is_continuous_ents(msg: &Message, ents: &[Entry]) -> bool {
if !msg.entries.is_empty() && !ents.is_empty() {
let expected_next_idx = msg.entries.last().unwrap().index + 1;
return expected_next_idx == ents.first().unwrap().index;
}
true
}
struct FormatKeyValueList {
pub buffer: String,
}
impl slog::Serializer for FormatKeyValueList {
fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
if !self.buffer.is_empty() {
write!(&mut self.buffer, ", {}: {}", key, val).unwrap();
} else {
write!(&mut self.buffer, "{}: {}", key, val).unwrap();
}
Ok(())
}
}
pub(crate) fn format_kv_list(kv_list: &OwnedKVList) -> String {
let mut formatter = FormatKeyValueList {
buffer: "".to_owned(),
};
let record = record_static!(slog::Level::Trace, "");
kv_list
.serialize(
&Record::new(&record, &format_args!(""), b!()),
&mut formatter,
)
.unwrap();
formatter.buffer
}
#[inline]
pub fn majority(total: usize) -> usize {
(total / 2) + 1
}
pub struct Union<'a> {
first: &'a HashSet<u64>,
second: &'a HashSet<u64>,
}
impl<'a> Union<'a> {
pub fn new(first: &'a HashSet<u64>, second: &'a HashSet<u64>) -> Union<'a> {
Union { first, second }
}
#[inline]
pub fn contains(&self, id: u64) -> bool {
self.first.contains(&id) || self.second.contains(&id)
}
pub fn iter(&self) -> impl Iterator<Item = u64> + '_ {
self.first.union(self.second).cloned()
}
pub fn is_empty(&self) -> bool {
self.first.is_empty() && self.second.is_empty()
}
pub fn len(&self) -> usize {
self.first.len() + self.second.len() - self.second.intersection(&self.first).count()
}
}
#[inline]
pub fn entry_approximate_size(e: &Entry) -> usize {
e.data.len() + e.context.len() + 12
}