-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add last_review_time to card data for performance and accuracy
#4124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add last_review_time to card data for performance and accuracy
#4124
Conversation
user1823
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left one question.
Also, we need to expose this to Python (cards.py)
| pub(crate) fn days_since_last_review(&self, timing: &SchedTimingToday) -> Option<u32> { | ||
| if !self.is_due_in_days() { | ||
| if let Some(last_review_time) = self.last_review_time { | ||
| Some(timing.next_day_at.elapsed_days_since(last_review_time) as u32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this include more time than the actual?
Example:
- My next_day_at is 4 AM.
- I reviewed the card on 7 AM today.
- Then, I sort my cards at 9 AM.
According to my understanding, this function will calculate the days elapsed as 0.875d (21 hours) but the actual value should be 0.083 (2 hours).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If my thinking above is correct, it is an issue in the current code too. It will likely be fixed by using timing.now, which was probably not used earlier because timing.now wasn't actually "now" (fixed in 4040a3c).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to my understanding, this function will calculate the days elapsed as 0.875d (21 hours) but the actual value should be 0.083 (2 hours).
The variable's type is u32, so the value will be 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok.
But, I think it's still more logical to use timing.now if my understanding above is correct (ignore the u32 for a moment).
Edit:
Scratch that. If we use timing.now, the elapsed days won't consider the rollover time, which is not intended.
Example: The actual elapsed time is less than 24 hours but the rollover time was crossed in between. So, days_elapsed should be 1, but if we use timing.now, the days_elapsed would be 0.
rslib/src/scheduler/answering/mod.rs
Outdated
| self.maybe_bury_siblings(&original, &updater.config)?; | ||
| let timing = updater.timing; | ||
| let mut card = updater.into_card(); | ||
| card.last_review_time = Some(answer.answered_at.as_secs()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code looks OK but I am seeing a potential bug here that would be difficult to notice if introduced.
If we later accidentally change the code in such a way that last_review_time is updated before the value is used to calculate elapsed_days, the value of elapsed_days will always be 0.
So, do we need a test here?
|
In cards.py, don't we need to update |
|
I'm not rejecting the current implementation at this stage, but I'm curious about the reasons you chose to go with seconds instead of a day number. We already adjust the due date in import to match local collection creation, so I wouldn't expect it to be too difficult to handle this case too, and we'd be saving about 15 bytes per card (which affects table scan speed and storage space). Was it just the easier approach, or were there other reasons you picked this way? (excited to see the change land, just don't want to make a decision we regret later because it was slightly easier at the time) |
|
Because I'm not confident to handle it. As I noticed before, the day-level due still has some problems: |
|
Apologies for leaving that post unanswered; I'd intended to circle back to it, but lost track of it. I've given this some thought, and if there are bugs with the current implementation, I think it's best we try to fix them. Storing the last review time in seconds might avoid some of the existing issues, but it doesn't solve the existing bugs, and it both increases the collection size, and makes the codebase more complicated, as we're using different representations for the due date and the last review time. Do you have reproduction steps for the issues you encountered? Sorry to create more work for you :-( |
|
Sorry for the delayed reply. I'm back from traveling now :) After checking the code, I think the issue I noticed before doesn't exist (maybe I hallucinated). I prefer seconds instead of days because it's accurate and easy to implement. And it's consistent with the result returned by |
|
I want seconds because it would allow me to calculate intra-day intervals for my graphing addon. Of course, my graphing addon isn't worth bloating everyones collection size if thats what would happen. But I'd still be minorly disappointed. |
|
I want seconds for intra-day intervals also |
Presumably you could calculate the intervals by examining the revlog as well, though it would be slower.
Yeah, that's a fair point. I'm still a bit on the fence about the extra storage this will require, though we could at least reduce it in a future release by upgrading the schema and moving the current custom_data fields into the table. |
|
@dae, speaking of the storage space use, would it not make sense to use an abbreviation for |
|
It uses a 3 character name when stored. |
Background
Currently, Anki has two main issues when determining the last review time of a card:
dueandintervalfields can be inaccurate, especially when the they have been modified byset_due_dateor changed by add-onsChanges
This PR introduces a new
last_review_timefield to the Card structure that directly stores the timestamp of when a card was last reviewed.Key Changes:
optional int64 last_review_time_secs = 23to the protobuf definitionlast_review_time: Option<TimestampSecs>to the Rust Card struct and related data structureslast_review_timeduring card answering to capture the exact review timestampAffected Areas:
Benefits
last_review_timeis not availablefix #4091