Improve performance of stats revlog entries with memory state (#3866)

* improve performace of stats_revlog_entries_with_memory_state

* format

* move Vec<RevlogEntry> into FsrsItemForMemoryState
This commit is contained in:
Jarrett Ye 2025-03-20 15:02:40 +08:00 committed by GitHub
parent d8c83ac075
commit 5d7f6b25c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 19 deletions

View file

@ -242,6 +242,7 @@ pub(crate) struct FsrsItemForMemoryState {
/// When revlogs have been truncated, this stores the initial state at first /// When revlogs have been truncated, this stores the initial state at first
/// review /// review
pub starting_state: Option<MemoryState>, pub starting_state: Option<MemoryState>,
pub filtered_revlogs: Vec<RevlogEntry>,
} }
/// Like [fsrs_item_for_memory_state], but for updating multiple cards at once. /// Like [fsrs_item_for_memory_state], but for updating multiple cards at once.
@ -330,6 +331,7 @@ pub(crate) fn fsrs_item_for_memory_state(
Ok(Some(FsrsItemForMemoryState { Ok(Some(FsrsItemForMemoryState {
item, item,
starting_state: None, starting_state: None,
filtered_revlogs: output.filtered_revlogs,
})) }))
} else if let Some(first_user_grade) = output.filtered_revlogs.first() { } else if let Some(first_user_grade) = output.filtered_revlogs.first() {
// the revlog has been truncated, but not fully // the revlog has been truncated, but not fully
@ -356,6 +358,7 @@ pub(crate) fn fsrs_item_for_memory_state(
Ok(Some(FsrsItemForMemoryState { Ok(Some(FsrsItemForMemoryState {
item, item,
starting_state: Some(starting_state), starting_state: Some(starting_state),
filtered_revlogs: output.filtered_revlogs,
})) }))
} else { } else {
// only manual and rescheduled revlogs; treat like empty // only manual and rescheduled revlogs; treat like empty

View file

@ -4,6 +4,7 @@
use fsrs::FSRS; use fsrs::FSRS;
use crate::card::CardType; use crate::card::CardType;
use crate::card::FsrsMemoryState;
use crate::prelude::*; use crate::prelude::*;
use crate::revlog::RevlogEntry; use crate::revlog::RevlogEntry;
use crate::scheduler::fsrs::memory_state::fsrs_item_for_memory_state; use crate::scheduler::fsrs::memory_state::fsrs_item_for_memory_state;
@ -140,26 +141,31 @@ impl Collection {
let ignore_before = ignore_revlogs_before_ms_from_config(&config)?; let ignore_before = ignore_revlogs_before_ms_from_config(&config)?;
let mut result = Vec::new(); let mut result = Vec::new();
let mut accumulated_revlog = Vec::new(); if let Some(item) = fsrs_item_for_memory_state(
&fsrs,
for entry in revlog { revlog.clone(),
accumulated_revlog.push(entry.clone()); next_day_at,
let item = fsrs_item_for_memory_state( historical_retention,
&fsrs, ignore_before,
accumulated_revlog.clone(), )? {
next_day_at, let memory_states = fsrs.historical_memory_states(item.item, item.starting_state)?;
historical_retention, let mut revlog_index = 0;
ignore_before, for entry in revlog {
)?; let mut stats_entry = stats_revlog_entry(&entry);
let mut card_clone = card.clone(); let memory_state: FsrsMemoryState =
card_clone.set_memory_state(&fsrs, item, historical_retention)?; if entry.id == item.filtered_revlogs[revlog_index].id {
revlog_index += 1;
let mut stats_entry = stats_revlog_entry(&entry); memory_states[revlog_index - 1].into()
stats_entry.memory_state = card_clone.memory_state.map(Into::into); } else {
result.push(stats_entry); memory_states[revlog_index].into()
};
stats_entry.memory_state = Some(memory_state.into());
result.push(stats_entry);
}
Ok(result.into_iter().rev().collect())
} else {
Ok(revlog.iter().map(stats_revlog_entry).collect())
} }
Ok(result.into_iter().rev().collect())
} }
} }