Mail mostly works now. Although terrible and slow

This commit is contained in:
Benedikt Terhechte 2021-10-04 18:09:32 +02:00
parent ea94f44720
commit 6086f38a31
5 changed files with 49 additions and 48 deletions

View File

@ -50,10 +50,11 @@ pub enum Action {
Select, Select,
/// Load the mails for the current partition /// Load the mails for the current partition
Mails, Mails,
/// Waiting for the Partition query to finish }
WaitPartition,
/// Waiting for the query to finish enum LoadingState {
WaitMails, Loaded(QueryRow),
Loading,
} }
pub struct Engine { pub struct Engine {
@ -61,11 +62,10 @@ pub struct Engine {
group_by_stack: Vec<Field>, group_by_stack: Vec<Field>,
link: Link<Action>, link: Link<Action>,
partitions: Vec<Partitions>, partitions: Vec<Partitions>,
action: Option<Action>,
/// This is a very simple cache from ranges to rows. /// This is a very simple cache from ranges to rows.
/// It doesn't account for overlapping ranges. /// It doesn't account for overlapping ranges.
/// There's a lot of room for improvement here. /// There's a lot of room for improvement here.
row_cache: SizedCache<usize, QueryRow>, row_cache: SizedCache<usize, LoadingState>,
} }
impl Engine { impl Engine {
@ -76,16 +76,13 @@ impl Engine {
search_stack: Vec::new(), search_stack: Vec::new(),
group_by_stack: vec![default_group_by_stack(0)], group_by_stack: vec![default_group_by_stack(0)],
partitions: Vec::new(), partitions: Vec::new(),
action: None,
row_cache: SizedCache::with_size(10000), row_cache: SizedCache::with_size(10000),
}; };
Ok(engine) Ok(engine)
} }
pub fn start(&mut self) -> Result<()> { pub fn start(&mut self) -> Result<()> {
// Make the initial query Ok(self.update((self.make_group_query()?, Action::Select))?)
self.action = Some(Action::Select);
self.update()
} }
pub fn items_with_size(&mut self, rect: Rect) -> Option<&[Partition]> { pub fn items_with_size(&mut self, rect: Rect) -> Option<&[Partition]> {
@ -158,10 +155,9 @@ impl Engine {
self.group_by_stack self.group_by_stack
.get_mut(grouping.index) .get_mut(grouping.index)
.map(|e| *e = field.clone()); .map(|e| *e = field.clone());
self.action = Some(Action::Recalculate);
// Remove any rows that were cached for this partition // Remove any rows that were cached for this partition
self.row_cache.cache_clear(); self.row_cache.cache_clear();
self.update() self.update((self.make_group_query()?, Action::Recalculate))
} }
pub fn select_partition(&mut self, partition: Partition) -> Result<()> { pub fn select_partition(&mut self, partition: Partition) -> Result<()> {
@ -186,8 +182,7 @@ impl Engine {
self.group_by_stack.push(next); self.group_by_stack.push(next);
// Block UI & Wait for updates // Block UI & Wait for updates
self.action = Some(Action::Select); self.update((self.make_group_query()?, Action::Select))
self.update()
} }
pub fn back(&mut self) { pub fn back(&mut self) {
@ -217,15 +212,8 @@ impl Engine {
} }
// Send the last action over the wire to be calculated // Send the last action over the wire to be calculated
fn update(&mut self) -> Result<()> { fn update(&mut self, payload: (Query, Action)) -> Result<()> {
let action = match self.action { Ok(self.link.input_sender.send((payload.0, payload.1))?)
Some(n) => n,
None => return Ok(()),
};
let request = self.make_group_query().ok_or(eyre!("Invalid State."))?;
self.link.input_sender.send((request, action))?;
self.action = Some(Action::WaitPartition);
Ok(())
} }
/// Fetch the channels to see if there're any updates /// Fetch the channels to see if there're any updates
@ -253,12 +241,12 @@ impl Engine {
} }
Response::Normal(Query::Normal { range, .. }, Action::Mails, r) => { Response::Normal(Query::Normal { range, .. }, Action::Mails, r) => {
for (index, row) in range.zip(r) { for (index, row) in range.zip(r) {
self.row_cache.cache_set(index, row.clone()); let entry = LoadingState::Loaded(row.clone());
self.row_cache.cache_set(index, entry);
} }
} }
_ => bail!("Invalid Query / Response combination"), _ => bail!("Invalid Query / Response combination"),
} }
self.action = None;
Ok(()) Ok(())
} }
@ -282,13 +270,16 @@ impl Engine {
} }
pub fn request_contents(&mut self, range: &Range<usize>) -> Result<()> { pub fn request_contents(&mut self, range: &Range<usize>) -> Result<()> {
let request = self // Mark the rows as being loaded
.make_normal_query(range.clone()) for index in range.clone() {
.ok_or(eyre!("Invalid State."))?; if self.row_cache.cache_get(&index).is_none() {
self.row_cache.cache_set(index, LoadingState::Loading);
}
}
let request = self.make_normal_query(range.clone());
self.link self.link
.input_sender .input_sender
.send((request.clone(), Action::Mails))?; .send((request.clone(), Action::Mails))?;
self.action = Some(Action::WaitMails);
Ok(()) Ok(())
} }
@ -303,10 +294,15 @@ impl Engine {
let mut rows = Vec::new(); let mut rows = Vec::new();
let mut data_missing = false; let mut data_missing = false;
for index in range.clone() { for index in range.clone() {
let entry = self.row_cache.cache_get(&index).map(|e| e.clone()); let entry = self.row_cache.cache_get(&index);
if entry.is_none() && !data_missing { let entry = match entry {
Some(LoadingState::Loaded(n)) => Some((*n).clone()),
Some(LoadingState::Loading) => None,
None => {
data_missing = true; data_missing = true;
None
} }
};
rows.push(entry); rows.push(entry);
} }
Ok((rows, data_missing)) Ok((rows, data_missing))
@ -319,35 +315,39 @@ impl Engine {
/// When we don't have partitions loaded yet, or /// When we don't have partitions loaded yet, or
/// when we're currently querying / loading new partitions /// when we're currently querying / loading new partitions
pub fn is_partitions_busy(&self) -> bool { pub fn is_partitions_busy(&self) -> bool {
self.partitions.is_empty() || self.action == Some(Action::WaitPartition) self.partitions.is_empty()
} }
/// If we're loading mails /// If we're loading mails
pub fn is_mail_busy(&self) -> bool { pub fn is_mail_busy(&self) -> bool {
self.action == Some(Action::WaitMails) !self.link.input_sender.is_empty()
} }
fn make_group_query(&self) -> Option<Query> { fn make_group_query(&self) -> Result<Query> {
let mut filters = Vec::new(); let mut filters = Vec::new();
for entry in &self.search_stack { for entry in &self.search_stack {
filters.push(Filter::Like(entry.clone())); filters.push(Filter::Like(entry.clone()));
} }
Some(Query::Grouped { let last = self
.group_by_stack
.last()
.ok_or(eyre!("Invalid partition state"))?;
Ok(Query::Grouped {
filters, filters,
group_by: self.group_by_stack.last()?.clone(), group_by: last.clone(),
}) })
} }
fn make_normal_query(&self, range: Range<usize>) -> Option<Query> { fn make_normal_query(&self, range: Range<usize>) -> Query {
let mut filters = Vec::new(); let mut filters = Vec::new();
for entry in &self.search_stack { for entry in &self.search_stack {
filters.push(Filter::Like(entry.clone())); filters.push(Filter::Like(entry.clone()));
} }
Some(Query::Normal { Query::Normal {
filters, filters,
fields: vec![Field::SenderDomain, Field::SenderLocalPart, Field::Subject], fields: vec![Field::SenderDomain, Field::SenderLocalPart, Field::Subject],
range, range,
}) }
} }
} }

View File

@ -12,7 +12,7 @@ use crossbeam_channel::{unbounded, Receiver, Sender};
use eyre::{Report, Result}; use eyre::{Report, Result};
use crate::database::{ use crate::database::{
query::{Field, Filter, Query, ValueField}, query::Query,
query_result::{QueryResult, QueryRow}, query_result::{QueryResult, QueryRow},
Database, Database,
}; };
@ -25,6 +25,10 @@ use super::partitions::{Partition, Partitions};
// - instead of hard-coding subject/sender-domain, have a "Detail" trait // - instead of hard-coding subject/sender-domain, have a "Detail" trait
// - consider a better logic for the cache (by row id and just fetch the smallest range that contains all missing numbers) // - consider a better logic for the cache (by row id and just fetch the smallest range that contains all missing numbers)
pub trait Payload<O> {
fn map_response<T>(self, response: T) -> Self;
}
#[derive(Debug)] #[derive(Debug)]
pub enum Response<Context: Send + 'static> { pub enum Response<Context: Send + 'static> {
Grouped(Query, Context, Partitions), Grouped(Query, Context, Partitions),

View File

@ -4,10 +4,7 @@ use eframe::egui::Rect as EguiRect;
use eyre::{Report, Result}; use eyre::{Report, Result};
use treemap::{Mappable, Rect, TreemapLayout}; use treemap::{Mappable, Rect, TreemapLayout};
use crate::database::{ use crate::database::{query::ValueField, query_result::QueryResult};
query::{Field, ValueField},
query_result::QueryResult,
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Partition { pub struct Partition {

View File

@ -1,4 +1,4 @@
use super::query::{Field, Value, ValueField}; use super::query::{Field, ValueField};
use std::collections::HashMap; use std::collections::HashMap;
pub type QueryRow = HashMap<Field, ValueField>; pub type QueryRow = HashMap<Field, ValueField>;

View File

@ -1,5 +1,5 @@
use crate::cluster_engine::Engine; use crate::cluster_engine::Engine;
use crate::database::query::{Field, Value}; use crate::database::query::Field;
use eframe::egui::{self, Widget}; use eframe::egui::{self, Widget};
use eyre::Report; use eyre::Report;