diff --git a/src/data/entities.rs b/src/data/entities.rs index 17703c6..e3ff883 100644 --- a/src/data/entities.rs +++ b/src/data/entities.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use crate::app::AppState; use crate::core::srs::{FADE_PER_DAY, MAX_SCORE, OrderMode, WordOpenMode}; use crate::data::{INVALID_ID, Id}; @@ -178,7 +179,7 @@ impl CardStatistics { } } -#[derive(Clone, Copy)] +#[derive(Copy)] pub struct EntityHandle { pub(crate) id: Id, pub(crate) real: bool, @@ -187,6 +188,43 @@ pub struct EntityHandle { } +impl Clone for EntityHandle { + fn clone(&self) -> Self { + EntityHandle{ + id: self.id, + real: self.real, + index: self.index, + _phantom: Default::default(), + } + } +} +impl Eq for EntityHandle {} + +impl PartialEq for EntityHandle { + fn eq(&self, other: &Self) -> bool { + self.real == other.real && self.id == other.id + } +} +impl PartialOrd for EntityHandle { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for EntityHandle { + fn cmp(&self, other: &Self) -> Ordering { + if self.real && !other.real { + return Ordering::Less + } + + if !self.real && other.real{ + return Ordering::Greater + } + + self.id.cmp(&other.id) + } +} + pub trait EntityData{ fn id(&self) -> Id; fn set_id(&mut self, id: Id); diff --git a/src/data/repositories.rs b/src/data/repositories.rs index 24a090a..30bd545 100644 --- a/src/data/repositories.rs +++ b/src/data/repositories.rs @@ -1,11 +1,13 @@ use crate::data::Id; use crate::data::entities::{EntityData, EntityHandle}; -use crate::notification::MaybeError; +use crate::helpers::into_result; +use crate::notification::{MaybeError, NotificationData}; use parking_lot::{Mutex, RwLock}; use rayon::iter::IndexedParallelIterator; use rayon::iter::IntoParallelRefIterator; use rayon::iter::ParallelIterator; use rusqlite::Connection; +use std::cell::RefCell; use std::marker::PhantomData; use std::ops::Deref; use std::rc::Weak; @@ -31,20 +33,75 @@ where R: Repository, D: DbLayer, { - queries: Mutex>>>, + queries: Vec>>>, } +impl QueryManger +where + R: Repository, + D: DbLayer, + T: EntityData, +{ + pub(crate) fn handle_save(&self, old: EntityHandle, new: &mut EntityHandle, data: &T) { + if old.real && new.real { + return; + } + + let affected = self.get_affected_queries(data); + for q in affected { + let mut query = self.queries[q].lock(); + let index = query.cache.binary_search(&old).unwrap(); + query.cache.remove(index); + let real_end = query.cache.iter().rposition(|r| r.real).unwrap() + 1; + query.cache.insert(real_end, new.clone()); + } + } + pub(crate) fn handle_delete(&self, handle: &EntityHandle, data: &T) { + let affected = self.get_affected_queries(data); + for q in affected { + let mut query = self.queries[q].lock(); + let slice = query.cache.as_slice(); + if let Ok(index) = slice.binary_search(&handle) { + query.cache.remove(index); + } + } + } + + fn get_affected_queries(&self, data: &T) -> Vec { + self.queries + .iter() + .enumerate() + .filter(|(_, q)| { + let query = q.lock(); + let rule = &query.rule; + return rule(data); + + false + }) + .map(|(i, _)| i) + .collect() + } + + fn reload_queries(&mut self, data_repository: impl Repository) { + for q in &self.queries { + let mut query = q.lock(); + query.cache.clear(); + + } + } +} pub struct Query where R: Repository, D: DbLayer, { cache: Vec>, - rule: Box bool>, + rule: Box bool + Send + Sync>, + parallel: bool, _marker: PhantomData<(R, D)>, } -impl, D: DbLayer> Query { +impl, D: DbLayer> Query { pub fn iter<'a>(&mut self, data_repository_inner: &'a R) -> impl Iterator where T: 'a, @@ -64,6 +121,39 @@ impl, D: DbLayer> Query { } } } + + pub fn load(&mut self, data_repository: DataRepositoryInner) { + self.cache.clear(); + if self.parallel { + let mut cache: Vec> = data_repository + .cache + .par_iter() + .enumerate() + .filter(|(_, entity)| (self.rule)(entity)) + .map(|(i, entity)| EntityHandle { + id: entity.id(), + real: true, + index: i as u32, + _phantom: PhantomData, + }) + .collect(); + + cache.extend( + data_repository + .temporal + .iter() + .enumerate() + .filter(|(_, entity)| (self.rule)(entity)) + .map(|(i, entity)| EntityHandle { + id: entity.id(), + real: false, + index: i as u32, + _phantom: PhantomData, + }) + .collect::>(), + ); + } + } } pub trait BatchedRepository @@ -135,29 +225,30 @@ impl> DataRepository { }) .collect(); - cache.extend(inner - .temporal - .iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle { - id: entity.id(), - real: false, - index: i as u32, - _phantom: PhantomData, - }).collect::>()); + cache.extend( + inner + .temporal + .iter() + .enumerate() + .filter(|(_, entity)| rule(entity)) + .map(|(i, entity)| EntityHandle { + id: entity.id(), + real: false, + index: i as u32, + _phantom: PhantomData, + }) + .collect::>(), + ); Query { cache, rule, + parallel: true, _marker: PhantomData, } } - pub fn query( - &self, - rule: Box bool>, - ) -> Query, D> + pub fn query(&self, rule: Box bool + Send + Sync>) -> Query, D> where T: Send + Sync, { @@ -176,21 +267,25 @@ impl> DataRepository { }) .collect(); - cache.extend(inner - .temporal - .iter() - .enumerate() - .filter(|(_, entity)| rule(entity)) - .map(|(i, entity)| EntityHandle { - id: entity.id(), - real: false, - index: i as u32, - _phantom: PhantomData, - }).collect::>()); + cache.extend( + inner + .temporal + .iter() + .enumerate() + .filter(|(_, entity)| rule(entity)) + .map(|(i, entity)| EntityHandle { + id: entity.id(), + real: false, + index: i as u32, + _phantom: PhantomData, + }) + .collect::>(), + ); Query { cache, rule, + parallel: false, _marker: PhantomData, } } @@ -251,19 +346,22 @@ impl> Repository for DataRepositoryIn } fn save(&mut self, entity: &mut EntityHandle) -> MaybeError { + let original_state = entity.clone(); if entity.real { let data = self.get_ref(entity).unwrap(); self.data_layer .write_entity(data, &self.connection.lock())?; } else { let index = fast_position_of(self.temporal.as_slice(), entity).unwrap(); - let mut value = self.temporal.remove(index); + let mut data = self.temporal.remove(index); self.data_layer - .add_entity(&mut value, &self.connection.lock())?; + .add_entity(&mut data, &self.connection.lock())?; entity.real = true; - entity.id = value.id(); + entity.id = data.id(); entity.index = self.cache.len() as u32; - self.cache.push(value); + self.query_manger.handle_save(original_state, entity, &data); + + self.cache.push(data); } Ok(()) @@ -278,8 +376,12 @@ impl> Repository for DataRepositoryIn &mut self.temporal }; - let index = fast_position_of(vec.as_slice(), &mut handle).unwrap(); - vec.remove(index); + let index = into_result( + fast_position_of(vec.as_slice(), &mut handle), + NotificationData::DbSaveError, + )?; + let value = vec.remove(index); + self.query_manger.handle_delete(&handle, &value); Ok(()) } @@ -293,6 +395,7 @@ impl> Repository for DataRepositoryIn self.cache.clear(); self.temporal.clear(); self.init()?; + Ok(()) } } @@ -331,15 +434,20 @@ impl + DbLayer> BatchedRepository .add_many_entity(&mut values, &self.connection.lock())?; let start = self.cache.len(); - self.cache.extend(values); - for (i, handle) in temp.into_iter().enumerate() { + for (i, (handle, data)) in temp.into_iter().zip(&values).enumerate() { + let old = handle.clone(); let h = handle; h.id = self.cache[start + i].id(); h.index = (start + i) as u32; h.real = true; + self.query_manger.handle_save(old, h, data); } + self.cache.extend(values); + + + for handle in cached.into_iter() { let h = handle; let idx = fast_position_of(self.cache.as_slice(), h).unwrap(); @@ -379,6 +487,7 @@ impl + DbLayer> BatchedRepository if remove { cell += 1; } + !remove });