Reduce memory usage and prevent HashMap overflow

This commit is contained in:
eraden 2021-10-16 11:16:58 +02:00
parent e390ce62b5
commit 97f2023596
2 changed files with 48 additions and 44 deletions

View File

@ -33,6 +33,7 @@ impl ProjectPage {
page: &ProjectPage, page: &ProjectPage,
num_of_epics: usize, num_of_epics: usize,
epics: EpicStream, epics: EpicStream,
num_of_statuses: usize,
statuses: IssueStatusStream, statuses: IssueStatusStream,
issues: IssueStream, issues: IssueStream,
user: &Option<User>, user: &Option<User>,
@ -49,13 +50,15 @@ impl ProjectPage {
let statuses = statuses let statuses = statuses
.map(|s| (s.id, s.name.as_str())) .map(|s| (s.id, s.name.as_str()))
.collect::<Vec<(IssueStatusId, &str)>>(); .collect::<Vec<(IssueStatusId, &str)>>();
let mut scoped_issues = {
let issues = issues.filter(|issue| { let issues = issues.filter(|issue| {
issue_filter_with_avatars(issue, &page.active_avatar_filters) issue_filter_with_avatars(issue, &page.active_avatar_filters)
&& issue_filter_with_text(issue, page.text_filter.as_str()) && issue_filter_with_text(issue, page.text_filter.as_str())
&& issue_filter_with_only_my(issue, page.only_my_filter, user) && issue_filter_with_only_my(issue, page.only_my_filter, user)
}); });
let mut issues: Vec<&Issue> = if page.recently_updated_filter { if page.recently_updated_filter {
let mut m = HashMap::new(); let mut m = HashMap::with_capacity(num_of_statuses * num_of_epics);
let mut sorted: Vec<(IssueId, NaiveDateTime)> = issues let mut sorted: Vec<(IssueId, NaiveDateTime)> = issues
.map(|issue| { .map(|issue| {
m.insert(issue.id, issue); m.insert(issue.id, issue);
@ -63,25 +66,17 @@ impl ProjectPage {
}) })
.collect(); .collect();
sorted.sort_by(|(_, a_time), (_, b_time)| a_time.cmp(b_time)); sorted.sort_by(|(_, a_time), (_, b_time)| a_time.cmp(b_time));
to_per_epic_and_status_scoped(
num_of_epics,
sorted sorted
.into_iter() .into_iter()
.take(10) .take(10)
.flat_map(|(id, _)| m.remove(&id)) .flat_map(|(id, _)| m.remove(&id)),
.collect() )
} else { } else {
issues.collect() to_per_epic_and_status_scoped(num_of_epics, issues)
}
}; };
issues.sort_by(|a, b| a.list_position.cmp(&b.list_position));
let issues_per_epic_id =
issues
.into_iter()
.fold(HashMap::with_capacity(num_of_epics), |mut m, issue| {
m.entry(issue.epic_id)
.or_insert_with(|| Vec::with_capacity(100))
.push(issue);
m
});
epics epics
.map(|epic| EpicIssuePerStatus { .map(|epic| EpicIssuePerStatus {
@ -93,13 +88,11 @@ impl ProjectPage {
.map(|(current_status_id, issue_status_name)| StatusIssueIds { .map(|(current_status_id, issue_status_name)| StatusIssueIds {
status_id: *current_status_id, status_id: *current_status_id,
status_name: issue_status_name.to_string(), status_name: issue_status_name.to_string(),
issue_ids: issues_per_epic_id issue_ids: scoped_issues
.get(&epic.map(|(id, ..)| id)) .remove(&(epic.map(|(id, ..)| id), *current_status_id))
.map(|v| { .map(|mut v| {
v.iter() v.sort_by(|a, b| a.list_position.cmp(&b.list_position));
.filter(|issue| issue_filter_status(issue, *current_status_id)) v.iter().map(|issue| issue.id).collect()
.map(|issue| issue.id)
.collect()
}) })
.unwrap_or_default(), .unwrap_or_default(),
}) })
@ -117,11 +110,6 @@ fn issue_filter_with_avatars(issue: &Issue, user_ids: &[UserId]) -> bool {
user_ids.contains(&issue.reporter_id) || issue.user_ids.iter().any(|id| user_ids.contains(id)) user_ids.contains(&issue.reporter_id) || issue.user_ids.iter().any(|id| user_ids.contains(id))
} }
#[inline]
fn issue_filter_status(issue: &Issue, current_status_id: IssueStatusId) -> bool {
issue.issue_status_id == current_status_id
}
#[inline] #[inline]
fn issue_filter_with_text(issue: &Issue, text: &str) -> bool { fn issue_filter_with_text(issue: &Issue, text: &str) -> bool {
text.is_empty() || issue.title.contains(text) text.is_empty() || issue.title.contains(text)
@ -132,3 +120,18 @@ fn issue_filter_with_only_my(issue: &Issue, only_my: bool, user: &Option<User>)
let my_id = user.as_ref().map(|u| u.id).unwrap_or_default(); let my_id = user.as_ref().map(|u| u.id).unwrap_or_default();
!only_my || issue.user_ids.contains(&my_id) !only_my || issue.user_ids.contains(&my_id)
} }
fn to_per_epic_and_status_scoped<'model, IssueStream>(
num_of_epics: usize,
issues: IssueStream,
) -> HashMap<(Option<EpicId>, IssueStatusId), Vec<&'model Issue>>
where
IssueStream: std::iter::Iterator<Item = &'model Issue>,
{
issues.fold(HashMap::with_capacity(num_of_epics), |mut m, issue| {
m.entry((issue.epic_id, issue.issue_status_id))
.or_insert_with(|| Vec::with_capacity(100))
.push(issue);
m
})
}

View File

@ -173,6 +173,7 @@ pub fn change_visible(model: &mut Model) {
.epic_ids .epic_ids
.iter() .iter()
.filter_map(|id| model.epics_by_id.get(id)), .filter_map(|id| model.epics_by_id.get(id)),
model.issue_status_ids.len(),
model model
.issue_status_ids .issue_status_ids
.iter() .iter()