-
-
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 writing of track metadata on Windows #4586
Conversation
…r writing This aims to fix the lost file creation time and the file access issue
This fixes metadata export on Windows when the track not been played before.
src/sources/metadatasourcetaglib.cpp
Outdated
<< "by" | ||
<< m_tempFileName | ||
<< "because it is used by another process"; | ||
Sleep(kWindowsSharingViolationsSleepMs); // Note: Capital S for Windows API Sleep() |
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.
Why don't you use QThread::msleep()
here?
src/sources/metadatasourcetaglib.cpp
Outdated
// After Mixxx has closed the track file, the indexer or virus scanner | ||
// might kick in and fail ReplaceFileW() with a sharing violation when | ||
// replacing the original file with the one with the updated metadata. | ||
const int kWindowsSharingViolationsRetries = 5; |
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.
kWindowsSharingViolationMaxRetries
src/sources/metadatasourcetaglib.cpp
Outdated
// might kick in and fail ReplaceFileW() with a sharing violation when | ||
// replacing the original file with the one with the updated metadata. | ||
const int kWindowsSharingViolationsRetries = 5; | ||
const int kWindowsSharingViolationsSleepMs = 100; |
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.
kWindowsSharingViolationSleepBeforeNextRetryMillis
src/sources/metadatasourcetaglib.cpp
Outdated
return false; | ||
case ERROR_SHARING_VIOLATION: | ||
// The process cannot access the file because it is being used by another process. | ||
kLogger.critical() |
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.
Not critical if a retry is following.
src/sources/metadatasourcetaglib.cpp
Outdated
return false; | ||
} | ||
} | ||
break; |
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 is difficult to recognize that this break belongs to the loop. Is it actually needed?
src/sources/metadatasourcetaglib.cpp
Outdated
@@ -30,6 +34,14 @@ const QString kSafelyWritableTempFileSuffix = QStringLiteral("_temp"); | |||
// potential failures caused by exceeded path length. | |||
const QString kSafelyWritableOrigFileSuffix = QStringLiteral("_orig"); | |||
|
|||
#ifdef __WINDOWS__ | |||
// After Mixxx has closed the track file, the indexer or virus scanner |
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 comment belongs to the code where these constants are actually used, but not to these constants. Mentioning why ReplaceFileW() is needed here but not in the context were it is actually invoked is confusing.
src/sources/soundsourceproxy.cpp
Outdated
@@ -361,6 +361,12 @@ SoundSourceProxy::exportTrackMetadataBeforeSaving(Track* pTrack, UserSettingsPoi | |||
pTrack->updateStreamInfoFromSource( | |||
pAudioSource->getStreamInfo()); | |||
DEBUG_ASSERT(pTrack->hasStreamInfoFromSource()); | |||
// Make sure that the track file is closes after reading |
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.
multiple typos
src/sources/soundsourceproxy.cpp
Outdated
@@ -731,6 +737,7 @@ mixxx::AudioSourcePointer SoundSourceProxy::openAudioSource( | |||
// before exporting metadata. In this case the caller (this class) | |||
// is responsible for updating the stream info if needed. | |||
if (!m_pTrack) { | |||
// TODO() It is surprising to receive here a m_pSoundSource; |
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.
- TODO is not a function
- "receive"?
- semicolon to end a comment?
Done |
src/sources/soundsourceproxy.cpp
Outdated
@@ -731,6 +737,7 @@ mixxx::AudioSourcePointer SoundSourceProxy::openAudioSource( | |||
// before exporting metadata. In this case the caller (this class) | |||
// is responsible for updating the stream info if needed. | |||
if (!m_pTrack) { | |||
// TODO: It is surprising that openAudioSource returns a m_pSoundSource |
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.
Why is it suprising?? SoundSource
is an extension of both AudioSource
and MetadataSource
, basic OO design.
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 should work and fix the bug with the open file:
m_pAudioSource = m_pSoundSource;
return m_pAudioSource;
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 have already fixed the underlying issue in #4584 please have a look.
@@ -361,6 +361,12 @@ SoundSourceProxy::exportTrackMetadataBeforeSaving(Track* pTrack, UserSettingsPoi | |||
pTrack->updateStreamInfoFromSource( | |||
pAudioSource->getStreamInfo()); | |||
DEBUG_ASSERT(pTrack->hasStreamInfoFromSource()); | |||
// Make sure that the track file is closed after reading. |
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 additional code should become obsolete with the fix I just proposed.
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 is still needed:
proxy.closeAudioSource();
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 would like to keep this as an hot fix solution with a minimum impact.
The rest is fixed in #4584
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 would prefer a proper fix here.
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 not going to merge a hack with a wrong 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.
Why do you think the comment is wrong? Add least it is working.
But I don't mind to merge your ideas.
Can you issue a PR against my branch?
Thank you.
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.
The alternative would be to merge #4584 to this branch. This is IMHO the proper fix, but touches more code.
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 haven't reviewed #4584 yet and I cannot promise to do it soon.
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.
Moreover the build failed on Linux with Clang due to a wrong preprocessor directive. Fixed.
If the AudioSource is opened the internal pointer must be initialized to ensure that it could be closed later!
Fixes the build on Linux with CLang.
|
lp1955331: Preserve class invariants of SoundSourceProxy
We have got the confirmation of that it is working: |
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
I'll merge to main
This fixes https://bugs.launchpad.net/mixxx/+bug/1955314 and https://bugs.launchpad.net/mixxx/+bug/1955331.
This is a mayor bugfix that should be released soon. Because the track metadata was not exported on windows when the track has not been loaded into a deck. Since the user assumes that the metadata is written, there is a risk of data loss. This was discovered in the first attempt for a fix here: #4572
The fix makes use of the ReplaceFileW() API function that is recommended instead of the deprecated transition feature for atomic file operations. ReplaceFileW() avoids virus scanner and indexer locking and keeps the file creation time at its old value.
The refactoring part has been issued here #4584 for the main branch.