-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
(fix) DlgTrackInfo: prevent wiping metadata when applying twice quickly #12965
Conversation
2b52841
to
f74b726
Compare
@zfhrp6 Please test this. Either build from source yoursel or pick a CI build (info is here https://github.com/mixxxdj/mixxx/wiki/Testing). |
@ronso0 I've tested the CI build (actions/runs/8273014776). The steps to repro in issue can't reproduce, and repeating Alt+A also can't. 👍 |
src/library/dlgtrackinfo.cpp
Outdated
// The dialog is updated and repopulated by the Track::changed() signal. | ||
m_pLoadedTrack->replaceRecord(std::move(m_trackRecord), std::move(m_pBeatsClone)); |
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.
Sorry, my bad.
// The dialog is updated and repopulated by the Track::changed() signal. | |
m_pLoadedTrack->replaceRecord(std::move(m_trackRecord), std::move(m_pBeatsClone)); | |
// Update the cached track | |
// | |
// If replaceRecord() returns true then both m_trackRecord and m_pBeatsClone | |
// will be updated by the subsequent Track::changed() signal to keep them | |
// synchronized with the track. Otherwise the track has not been modified and | |
// both members must remain valid. Do not use std::move() for passing arguments! | |
m_pLoadedTrack->replaceRecord(m_trackRecord, m_pBeatsClone); |
Without warranty. Consider refactoring the API to prevent such misunderstandings in the future.
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.
Thanks for jumping in!
Okay, so this is the actual fix.
IIUC the no-op test I added above just hides the issue because it's unlikely the record (in DlgTrackInfo) has changed in between two quick save() calls. Correct?
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.
Also, IIUC this
Lines 308 to 310 in e2d4199
if (pOptionalBeats) { | |
bpmUpdatedFlag = trySetBeatsWhileLocked(std::move(pOptionalBeats)); | |
if (recordUnchanged && !bpmUpdatedFlag) { |
move
the beats even if applying them fails and replaceRecord() returns false?
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.
It only moves out of the argument which is passed by value. No side effects on the outer context.
d7de4c4
to
c5f92d3
Compare
src/library/dlgtrackinfo.cpp
Outdated
if (m_trackRecord == m_pLoadedTrack->getRecord() && | ||
m_pBeatsClone == m_pLoadedTrack->getBeats()) { |
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.
In case metadata or beats have been changed elsewhere we'd already have updated here as well, so this scheck is safe IMO (i.e. does not undo those changes by re-applying this dialog's (unchanged) record and beats).
Admittedly, since the update is triggered by signals there is a slight chance users revert their own manual changes, but I'd consider that a "user error" because working on metadata in multiple places at once (at inhuman high rate) may inevitably create incosistencies.
Any thoughts?
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.
Maybe an additional dirty flag is useful.
== + dirty -> reverted edit
!= + dirty -> actual edit
!= + !dirty -> outside edit
== + !dirty -> no edit
So we have a fast exit option in case !dirty
Has someone time to review? |
src/library/dlgtrackinfo.cpp
Outdated
if (m_trackRecord == m_pLoadedTrack->getRecord() && | ||
m_pBeatsClone == m_pLoadedTrack->getBeats()) { |
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.
m_trackRecord == m_pLoadedTrack->getRecord()
is a deep compare, which should be OK, but slow.
m_pBeatsClone == m_pLoadedTrack->getBeats()
is a pointer compare, which will probably always false.
replaceRecord() has already a good equality check inside. In terms of avoiding deep copies and compares optimal, I think we need to split replaceRecord(). But I am not sure if it is worth the efforts.
At least is should be renamed to compareAndReplaceRecord()
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.
I'll revert that commit. I don't want to complicate DlgTrackInfo with a dirty flag, this is just a compact, effecient bugfix after all.
The reason I considered this check in DlgTrackInfo is that Track::replaceRecord()
does std::move(optionalBeats)
too early (before it's clarified if beats can be applied), betas are moved later on in Track::setBeatsWhileLocked()
only if applicable.
So beats might be moved even though they're not applied and Track::updated
would not be emitted and we might get the same situation with the beats which this PR fixes for the other metadata.
src/library/dlgtrackinfo.cpp
Outdated
if (m_trackRecord == m_pLoadedTrack->getRecord() && | ||
m_pBeatsClone == m_pLoadedTrack->getBeats()) { |
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.
Maybe an additional dirty flag is useful.
== + dirty -> reverted edit
!= + dirty -> actual edit
!= + !dirty -> outside edit
== + !dirty -> no edit
So we have a fast exit option in case !dirty
src/library/dlgtrackinfo.cpp
Outdated
// both members must remain valid. Do not use std::move() for passing arguments! | ||
// See https://github.com/mixxxdj/mixxx/issues/12963 |
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.
// both members must remain valid. Do not use std::move() for passing arguments! | |
// See https://github.com/mixxxdj/mixxx/issues/12963 | |
// both members must remain valid, so not use std::move() for passing arguments! |
I don't think that the reference to the bug will help much later.
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.
Well, it describes the symptoms, but I can do that here as well.
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.
I am already fine without it. Then let's keep it.
No need for extra work.
Fixes mixxxdj#12963 Co-authored-by: Uwe Klotz <uwe.klotz@gmail.com>
c5f92d3
to
fec28c6
Compare
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.
Thank you. LGTM
Not sure what exactly is the root cause, but preventing what should be a no-op in
Track
already inDlgTrackInfo
seems to suffice. Can't reproduce anymore.With my sparse basic c++ knowledge, I suspected the cause is that the track record has been moved to Track (is null in DlgTrackRecord?) when applying again before the
Track::changed
signal triggered DlgTrackInfo to fetch the new track record.But tracing that turned out this is not it since now the changed signal is received before trying to save again (maybe it's just delays caused by the new m_pLoadedTrack->getRecord(), idk 🤷♂️ )
With symptoms fixed this good enough for 2.4.1 I guess.
Update:
As clarified by @uklotzde the issue was indeed passing the record and the beats to track via
std::move
.Fixes #12963