Reduce memory usage and prevent HashMap overflow
This commit is contained in:
parent
e390ce62b5
commit
97f2023596
@ -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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user