use std::{
collections::BTreeMap,
sync::{Arc, Mutex},
};
use super::{DataBytes, DataVersion};
use crate::connection::diff;
type VersionToFrom = (DataVersion, Option<DataVersion>);
const SCAN_SHIFT: u32 = 16;
#[derive(Default)]
pub(crate) struct DiffCache {
diffs: Mutex<BTreeMap<VersionToFrom, Arc<Mutex<Option<DataBytes>>>>>,
diff_states: Mutex<BTreeMap<DataVersion, Arc<Mutex<Option<diff::State>>>>>,
}
impl DiffCache {
pub(crate) fn get_diff(
&self,
old_version: Option<&DataVersion>,
old_data: Option<&DataBytes>,
new_version: &[i64],
new_data: &DataBytes,
) -> Option<DataBytes> {
let diff_mutex = {
let mut diffs = self.diffs.lock().unwrap();
let ret = diffs.entry((new_version.into(), old_version.cloned())).or_insert_with(|| Arc::new(Mutex::new(None))).clone();
while diffs.len() > 1 {
diffs.pop_first();
}
ret
};
let mut diff_mutex_lock = diff_mutex.lock().unwrap();
Some(
diff_mutex_lock
.get_or_insert_with(|| {
let (diff, new_state) = if let Some(old_version) = old_version {
let state_mutex = {
let mut diff_states = self.diff_states.lock().unwrap();
let ret = diff_states.entry(old_version.clone()).or_insert_with(|| Arc::new(Mutex::new(None))).clone();
while diff_states.len() > 2 {
diff_states.pop_first();
}
ret
};
let mut state_mutex_lock = state_mutex.lock().unwrap();
let state = state_mutex_lock.get_or_insert_with(|| diff::State::new().diff(&[], old_data.unwrap(), SCAN_SHIFT, 6).unwrap().1);
state.diff(old_data.unwrap(), new_data, SCAN_SHIFT, 6).unwrap() } else {
let state = diff::State::new();
state.diff(&[], new_data, SCAN_SHIFT, 6).unwrap()
};
let mut diff_states = self.diff_states.lock().unwrap();
diff_states.entry(new_version.into()).or_insert_with(|| Arc::new(Mutex::new(Some(new_state))));
while diff_states.len() > 2 {
diff_states.pop_first();
}
Arc::new(diff)
})
.clone(),
)
}
}