1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-29 22:58:39 +02:00

On-demand tasks check for i/o errors, and if so, make no false progress

This commit is contained in:
Paul Licameli 2017-03-16 23:17:15 -04:00
commit 26f917b1fd
5 changed files with 73 additions and 60 deletions

View File

@ -4412,6 +4412,9 @@ void AudacityProject::PopState(const UndoState &state)
computeTask = make_movable<ODComputeSummaryTask>(); computeTask = make_movable<ODComputeSummaryTask>();
odUsed=true; odUsed=true;
} }
// PRL: Is it correct to add all tracks to one task, even if they
// are not partnered channels? Rather than
// make one task for each?
computeTask->AddWaveTrack((WaveTrack*)copyTrack); computeTask->AddWaveTrack((WaveTrack*)copyTrack);
} }
} }

View File

@ -47,7 +47,6 @@ ODDecodeBlockFile::ODDecodeBlockFile(wxFileNameWrapper &&baseFileName, wxFileNam
mAliasChannel(aliasChannel) mAliasChannel(aliasChannel)
{ {
mDecoder = NULL; mDecoder = NULL;
mDataAvailable=false;
mAudioFileName = std::move(audioFileName); mAudioFileName = std::move(audioFileName);
mFormat = int16Sample; mFormat = int16Sample;
} }
@ -59,11 +58,11 @@ ODDecodeBlockFile::ODDecodeBlockFile(wxFileNameWrapper &&existingFile, wxFileNam
SimpleBlockFile{ std::move(existingFile), aliasLen, min, max, rms }, SimpleBlockFile{ std::move(existingFile), aliasLen, min, max, rms },
mType(decodeType), mType(decodeType),
mDataAvailable( dataAvailable ),
mAliasStart(aliasStart), mAliasStart(aliasStart),
mAliasChannel(aliasChannel) mAliasChannel(aliasChannel)
{ {
mDecoder = NULL; mDecoder = NULL;
mDataAvailable=dataAvailable;
mAudioFileName = std::move(audioFileName); mAudioFileName = std::move(audioFileName);
mFormat = int16Sample; mFormat = int16Sample;
} }
@ -304,11 +303,7 @@ bool ODDecodeBlockFile::IsSummaryAvailable() const
bool ODDecodeBlockFile::IsDataAvailable() const bool ODDecodeBlockFile::IsDataAvailable() const
{ {
bool retval; return mDataAvailable;
mDataAvailableMutex.Lock();
retval= mDataAvailable;
mDataAvailableMutex.Unlock();
return retval;
} }
/// Write the summary to disk, using the derived ReadData() to get the data /// Write the summary to disk, using the derived ReadData() to get the data
@ -321,43 +316,38 @@ int ODDecodeBlockFile::WriteODDecodeBlockFile()
// derived classes) to get the sample data // derived classes) to get the sample data
SampleBuffer sampleData;// = NewSamples(mLen, floatSample); SampleBuffer sampleData;// = NewSamples(mLen, floatSample);
int ret; int ret;
//use the decoder here.
mDecoderMutex.Lock();
if(!mDecoder)
{ {
mDecoderMutex.Unlock(); //use the decoder here.
return -1; ODLocker locker{ &mDecoderMutex };
if(!mDecoder)
return -1;
//sampleData and mFormat are set by the decoder.
ret = mDecoder->Decode(sampleData, mFormat, mAliasStart, mLen, mAliasChannel);
if(ret < 0) {
printf("ODDecodeBlockFile Decode failure\n");
return ret; //failure
}
} }
{
//sampleData and mFormat are set by the decoder. //the summary is also calculated here.
ret = mDecoder->Decode(sampleData, mFormat, mAliasStart, mLen, mAliasChannel); ODLocker locker{ &mFileNameMutex };
//TODO: we may need to write a version of WriteSimpleBlockFile that uses threadsafe FILE vs wxFile
mDecoderMutex.Unlock(); bool bSuccess =
if(ret < 0) { WriteSimpleBlockFile(
printf("ODDecodeBlockFile Decode failure\n"); sampleData.ptr(),
return ret; //failure mLen,
mFormat,
NULL);
if ( !bSuccess )
return -1;
} }
//the summary is also calculated here. wxAtomicInc( mDataAvailable );
mFileNameMutex.Lock();
//TODO: we may need to write a version of WriteSimpleBlockFile that uses threadsafe FILE vs wxFile
bool bSuccess =
WriteSimpleBlockFile(
sampleData.ptr(),
mLen,
mFormat,
NULL);
wxASSERT(bSuccess); // TODO: Handle failure here by alert to user and undo partial op.
wxUnusedVar(bSuccess);
mFileNameMutex.Unlock();
mDataAvailableMutex.Lock();
mDataAvailable=true;
mDataAvailableMutex.Unlock();
return ret; return ret;
} }

View File

@ -32,6 +32,7 @@ Also, see ODPCMAliasBlockFile for a similar file.
#include "../ondemand/ODTaskThread.h" #include "../ondemand/ODTaskThread.h"
#include "../DirManager.h" #include "../DirManager.h"
#include "../ondemand/ODDecodeTask.h" #include "../ondemand/ODDecodeTask.h"
#include <wx/atomic.h>
#include <wx/thread.h> #include <wx/thread.h>
/// An AliasBlockFile that references uncompressed data in an existing file /// An AliasBlockFile that references uncompressed data in an existing file
@ -166,8 +167,7 @@ class ODDecodeBlockFile final : public SimpleBlockFile
///The original file the audio came from. ///The original file the audio came from.
wxFileNameWrapper mAudioFileName; wxFileNameWrapper mAudioFileName;
mutable ODLock mDataAvailableMutex; wxAtomicInt mDataAvailable{ 0 };
bool mDataAvailable;
bool mDataBeingComputed; bool mDataBeingComputed;
ODFileDecoder* mDecoder; ODFileDecoder* mDecoder;

View File

@ -64,32 +64,42 @@ void ODComputeSummaryTask::DoSomeInternal()
return; return;
} }
sampleCount blockStartSample = 0;
sampleCount blockEndSample = 0;
bool success =false;
mBlockFilesMutex.Lock(); mBlockFilesMutex.Lock();
for(size_t i=0; i < mWaveTracks.size() && mBlockFiles.size();i++) for(size_t i=0; i < mWaveTracks.size() && mBlockFiles.size();i++)
{ {
bool success = false;
const auto bf = mBlockFiles[0].lock(); const auto bf = mBlockFiles[0].lock();
sampleCount blockStartSample = 0;
sampleCount blockEndSample = 0;
if(bf) if(bf)
{ {
bf->DoWriteSummary(); // WriteSummary might throw, but this is a worker thread, so stop
// the exceptions here!
success = true; success = true;
try { bf->DoWriteSummary(); }
catch(...) { success = false; }
blockStartSample = bf->GetStart(); blockStartSample = bf->GetStart();
blockEndSample = blockStartSample + bf->GetLength(); blockEndSample = blockStartSample + bf->GetLength();
} }
else else
{ {
success = true;
// The block file disappeared. // The block file disappeared.
//the waveform in the wavetrack now is shorter, so we need to update mMaxBlockFiles //the waveform in the wavetrack now is shorter, so we need to update mMaxBlockFiles
//because now there is less work to do. //because now there is less work to do.
mMaxBlockFiles--; mMaxBlockFiles--;
} }
//take it out of the array - we are done with it. if (success)
mBlockFiles.erase(mBlockFiles.begin()); {
//take it out of the array - we are done with it.
mBlockFiles.erase(mBlockFiles.begin());
}
else
// The task does not make progress
;
//This is a bit of a convenience in case someone tries to terminate the task by closing the trackpanel or window. //This is a bit of a convenience in case someone tries to terminate the task by closing the trackpanel or window.
//ODComputeSummaryTask::Terminate() uses this lock to remove everything, and we don't want it to wait since the UI is being blocked. //ODComputeSummaryTask::Terminate() uses this lock to remove everything, and we don't want it to wait since the UI is being blocked.
@ -97,16 +107,18 @@ void ODComputeSummaryTask::DoSomeInternal()
wxThread::This()->Yield(); wxThread::This()->Yield();
mBlockFilesMutex.Lock(); mBlockFilesMutex.Lock();
//upddate the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should //update the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should
//because this loop runs a number of times equal to the number of tracks, they probably are getting processed in //because this loop runs a number of times equal to the number of tracks, they probably are getting processed in
//the next iteration at the same sample window. //the next iteration at the same sample window.
mWaveTrackMutex.Lock(); if (success && bf) {
for(size_t i=0;i<mWaveTracks.size();i++) mWaveTrackMutex.Lock();
{ for(size_t i=0;i<mWaveTracks.size();i++)
if(success && mWaveTracks[i]) {
mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample); if(success && mWaveTracks[i])
mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample);
}
mWaveTrackMutex.Unlock();
} }
mWaveTrackMutex.Unlock();
} }
mBlockFilesMutex.Unlock(); mBlockFilesMutex.Unlock();

View File

@ -42,13 +42,13 @@ void ODDecodeTask::DoSomeInternal()
} }
ODFileDecoder* decoder; ODFileDecoder* decoder;
sampleCount blockStartSample = 0;
sampleCount blockEndSample = 0;
bool success =false;
for(size_t i=0; i < mWaveTracks.size() && mBlockFiles.size();i++) for(size_t i=0; i < mWaveTracks.size() && mBlockFiles.size();i++)
{ {
const auto bf = mBlockFiles[0].lock(); const auto bf = mBlockFiles[0].lock();
sampleCount blockStartSample = 0;
sampleCount blockEndSample = 0;
bool success =false;
int ret = 1; int ret = 1;
@ -63,6 +63,7 @@ void ODDecodeTask::DoSomeInternal()
if(!decoder->IsInitialized()) if(!decoder->IsInitialized())
decoder->Init(); decoder->Init();
bf->SetODFileDecoder(decoder); bf->SetODFileDecoder(decoder);
// Does not throw:
ret = bf->DoWriteBlockFile(); ret = bf->DoWriteBlockFile();
bf->UnlockRead(); bf->UnlockRead();
@ -74,24 +75,31 @@ void ODDecodeTask::DoSomeInternal()
} }
else else
{ {
success = true;
// The block file disappeared. // The block file disappeared.
//the waveform in the wavetrack now is shorter, so we need to update mMaxBlockFiles //the waveform in the wavetrack now is shorter, so we need to update mMaxBlockFiles
//because now there is less work to do. //because now there is less work to do.
mMaxBlockFiles--; mMaxBlockFiles--;
} }
//Release the refcount we placed on it if we are successful if (success)
if(ret >= 0 ) { {
//take it out of the array - we are done with it. //take it out of the array - we are done with it.
mBlockFiles.erase(mBlockFiles.begin()); mBlockFiles.erase(mBlockFiles.begin());
}
else
// The task does not make progress
;
//Release the refcount we placed on it if we are successful
if( bf && success ) {
//upddate the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should //upddate the gui for all associated blocks. It doesn't matter that we're hitting more wavetracks then we should
//because this loop runs a number of times equal to the number of tracks, they probably are getting processed in //because this loop runs a number of times equal to the number of tracks, they probably are getting processed in
//the next iteration at the same sample window. //the next iteration at the same sample window.
mWaveTrackMutex.Lock(); mWaveTrackMutex.Lock();
for(size_t i=0;i<mWaveTracks.size();i++) for(size_t i=0;i<mWaveTracks.size();i++)
{ {
if(success && mWaveTracks[i]) if(mWaveTracks[i])
mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample); mWaveTracks[i]->AddInvalidRegion(blockStartSample,blockEndSample);
} }
mWaveTrackMutex.Unlock(); mWaveTrackMutex.Unlock();