avoid fetching decks for each row

Like notetypes, there is a col.get_deck() routine which caches
fetches, so that successive fetches are cheap. This makes it simpler
to just fetch the deck at the start.

We were also attempting to fetch a deck with id 0 for each row; I've
changed this so that we only fetch it if the id is non-zero.

I18n uses an Arc internally, so it is cheap to clone. This allow us
to drop the lifetime specifiers on the context structures.
This commit is contained in:
Damien Elmes 2021-04-05 15:13:32 +10:00
parent 758550ea17
commit 8d6b9d15a5

View file

@ -125,14 +125,13 @@ trait RowContext {
} }
} }
struct CardRowContext<'a> { struct CardRowContext {
col: &'a Collection,
card: Card, card: Card,
note: Note, note: Note,
notetype: Arc<Notetype>, notetype: Arc<Notetype>,
deck: Option<Deck>, deck: Arc<Deck>,
original_deck: Option<Option<Deck>>, original_deck: Option<Arc<Deck>>,
tr: &'a I18n, tr: I18n,
timing: SchedTimingToday, timing: SchedTimingToday,
render_context: Option<RenderContext>, render_context: Option<RenderContext>,
} }
@ -144,11 +143,11 @@ struct RenderContext {
answer_nodes: Vec<RenderedNode>, answer_nodes: Vec<RenderedNode>,
} }
struct NoteRowContext<'a> { struct NoteRowContext {
note: Note, note: Note,
notetype: Arc<Notetype>, notetype: Arc<Notetype>,
cards: Vec<Card>, cards: Vec<Card>,
tr: &'a I18n, tr: I18n,
timing: SchedTimingToday, timing: SchedTimingToday,
} }
@ -260,8 +259,8 @@ impl RenderContext {
} }
} }
impl<'a> CardRowContext<'a> { impl CardRowContext {
fn new(col: &'a mut Collection, id: i64, with_card_render: bool) -> Result<Self> { fn new(col: &mut Collection, id: i64, with_card_render: bool) -> Result<Self> {
let card = col let card = col
.storage .storage
.get_card(CardId(id))? .get_card(CardId(id))?
@ -270,6 +269,15 @@ impl<'a> CardRowContext<'a> {
let notetype = col let notetype = col
.get_notetype(note.notetype_id)? .get_notetype(note.notetype_id)?
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let deck = col.get_deck(card.deck_id)?.ok_or(AnkiError::NotFound)?;
let original_deck = if card.original_deck_id.0 != 0 {
Some(
col.get_deck(card.original_deck_id)?
.ok_or(AnkiError::NotFound)?,
)
} else {
None
};
let timing = col.timing_today()?; let timing = col.timing_today()?;
let render_context = if with_card_render { let render_context = if with_card_render {
Some(RenderContext::new(col, &card, &note, &notetype)?) Some(RenderContext::new(col, &card, &note, &notetype)?)
@ -278,13 +286,12 @@ impl<'a> CardRowContext<'a> {
}; };
Ok(CardRowContext { Ok(CardRowContext {
col,
card, card,
note, note,
notetype, notetype,
deck: None, deck,
original_deck: None, original_deck,
tr: &col.tr, tr: col.tr.clone(),
timing, timing,
render_context, render_context,
}) })
@ -294,25 +301,6 @@ impl<'a> CardRowContext<'a> {
self.notetype.get_template(self.card.template_idx) self.notetype.get_template(self.card.template_idx)
} }
fn deck(&mut self) -> Result<&Deck> {
if self.deck.is_none() {
self.deck = Some(
self.col
.storage
.get_deck(self.card.deck_id)?
.ok_or(AnkiError::NotFound)?,
);
}
Ok(self.deck.as_ref().unwrap())
}
fn original_deck(&mut self) -> Result<&Option<Deck>> {
if self.original_deck.is_none() {
self.original_deck = Some(self.col.storage.get_deck(self.card.original_deck_id)?);
}
Ok(self.original_deck.as_ref().unwrap())
}
fn answer_str(&self) -> String { fn answer_str(&self) -> String {
let render_context = self.render_context.as_ref().unwrap(); let render_context = self.render_context.as_ref().unwrap();
let answer = render_context let answer = render_context
@ -366,17 +354,17 @@ impl<'a> CardRowContext<'a> {
match self.card.ctype { match self.card.ctype {
CardType::New => self.tr.browsing_new().into(), CardType::New => self.tr.browsing_new().into(),
CardType::Learn => self.tr.browsing_learning().into(), CardType::Learn => self.tr.browsing_learning().into(),
_ => time_span((self.card.interval * 86400) as f32, self.tr, false), _ => time_span((self.card.interval * 86400) as f32, &self.tr, false),
} }
} }
fn deck_str(&mut self) -> Result<String> { fn deck_str(&mut self) -> String {
let deck_name = self.deck()?.human_name(); let deck_name = self.deck.human_name();
Ok(if let Some(original_deck) = self.original_deck()? { if let Some(original_deck) = &self.original_deck {
format!("{} ({})", &deck_name, &original_deck.human_name()) format!("{} ({})", &deck_name, &original_deck.human_name())
} else { } else {
deck_name deck_name
}) }
} }
fn template_str(&self) -> Result<String> { fn template_str(&self) -> Result<String> {
@ -392,12 +380,12 @@ impl<'a> CardRowContext<'a> {
} }
} }
impl RowContext for CardRowContext<'_> { impl RowContext for CardRowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String> { fn get_cell_text(&mut self, column: Column) -> Result<String> {
Ok(match column { Ok(match column {
Column::Question => self.question_str(), Column::Question => self.question_str(),
Column::Answer => self.answer_str(), Column::Answer => self.answer_str(),
Column::CardDeck => self.deck_str()?, Column::CardDeck => self.deck_str(),
Column::CardDue => self.card_due_str(), Column::CardDue => self.card_due_str(),
Column::CardEase => self.card_ease_str(), Column::CardEase => self.card_ease_str(),
Column::CardInterval => self.card_interval_str(), Column::CardInterval => self.card_interval_str(),
@ -448,8 +436,8 @@ impl RowContext for CardRowContext<'_> {
} }
} }
impl<'a> NoteRowContext<'a> { impl NoteRowContext {
fn new(col: &'a mut Collection, id: i64) -> Result<Self> { fn new(col: &mut Collection, id: i64) -> Result<Self> {
let note = col.get_note_maybe_with_fields(NoteId(id), false)?; let note = col.get_note_maybe_with_fields(NoteId(id), false)?;
let notetype = col let notetype = col
.get_notetype(note.notetype_id)? .get_notetype(note.notetype_id)?
@ -461,7 +449,7 @@ impl<'a> NoteRowContext<'a> {
note, note,
notetype, notetype,
cards, cards,
tr: &col.tr, tr: col.tr.clone(),
timing, timing,
}) })
} }
@ -507,14 +495,14 @@ impl<'a> NoteRowContext<'a> {
} else { } else {
time_span( time_span(
(intervals.iter().sum::<u32>() * 86400 / (intervals.len() as u32)) as f32, (intervals.iter().sum::<u32>() * 86400 / (intervals.len() as u32)) as f32,
self.tr, &self.tr,
false, false,
) )
} }
} }
} }
impl RowContext for NoteRowContext<'_> { impl RowContext for NoteRowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String> { fn get_cell_text(&mut self, column: Column) -> Result<String> {
Ok(match column { Ok(match column {
Column::NoteCards => self.cards.len().to_string(), Column::NoteCards => self.cards.len().to_string(),