1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-09-23 15:41:09 +02:00

Strong safety guarantee for removing file dependencies

This commit is contained in:
Paul Licameli 2016-11-24 10:04:40 -05:00
parent 7159966eb4
commit f5fe9281e4
2 changed files with 22 additions and 19 deletions

View File

@ -116,6 +116,7 @@ unsigned long BlockFile::gBlockFileDestructionCount { 0 };
BlockFile::~BlockFile() BlockFile::~BlockFile()
{ {
if (!IsLocked() && mFileName.HasName()) if (!IsLocked() && mFileName.HasName())
// PRL: what should be done if this fails?
wxRemoveFile(mFileName.GetFullPath()); wxRemoveFile(mFileName.GetFullPath());
++gBlockFileDestructionCount; ++gBlockFileDestructionCount;

View File

@ -81,16 +81,12 @@ static void GetAllSeqBlocks(AudacityProject *project,
// tracks and replace each aliased block file with its replacement. // tracks and replace each aliased block file with its replacement.
// Note that this code respects reference-counting and thus the // Note that this code respects reference-counting and thus the
// process of making a project self-contained is actually undoable. // process of making a project self-contained is actually undoable.
static void ReplaceBlockFiles(AudacityProject *project, static void ReplaceBlockFiles(BlockPtrArray &blocks,
ReplacedBlockFileHash &hash) ReplacedBlockFileHash &hash)
// NOFAIL-GUARANTEE
{ {
//const auto &dirManager = project->GetDirManager(); for (const auto &pBlock : blocks) {
BlockPtrArray blocks; auto &f = pBlock->f;
GetAllSeqBlocks(project, &blocks);
int i;
for (i = 0; i < (int)blocks.size(); i++) {
auto &f = blocks[i]->f;
const auto src = &*f; const auto src = &*f;
if (hash.count( src ) > 0) { if (hash.count( src ) > 0) {
const auto &dst = hash[src]; const auto &dst = hash[src];
@ -156,6 +152,7 @@ void FindDependencies(AudacityProject *project,
// all of those alias block files with disk block files. // all of those alias block files with disk block files.
static void RemoveDependencies(AudacityProject *project, static void RemoveDependencies(AudacityProject *project,
AliasedFileArray &aliasedFiles) AliasedFileArray &aliasedFiles)
// STRONG-GUARANTEE
{ {
const auto &dirManager = project->GetDirManager(); const auto &dirManager = project->GetDirManager();
@ -198,6 +195,8 @@ static void RemoveDependencies(AudacityProject *project,
BlockFilePtr newBlockFile; BlockFilePtr newBlockFile;
{ {
SampleBuffer buffer(len, format); SampleBuffer buffer(len, format);
// We tolerate exceptions from NewSimpleBlockFile and so we
// can allow exceptions from ReadData too
f->ReadData(buffer.ptr(), format, 0, len); f->ReadData(buffer.ptr(), format, 0, len);
newBlockFile = newBlockFile =
dirManager->NewSimpleBlockFile(buffer.ptr(), len, format); dirManager->NewSimpleBlockFile(buffer.ptr(), len, format);
@ -210,15 +209,18 @@ static void RemoveDependencies(AudacityProject *project,
completedBytes += SAMPLE_SIZE(format) * len; completedBytes += SAMPLE_SIZE(format) * len;
updateResult = progress.Update(completedBytes, totalBytesToProcess); updateResult = progress.Update(completedBytes, totalBytesToProcess);
if (updateResult != ProgressResult::Success) if (updateResult != ProgressResult::Success)
break; // leave the project unchanged
return;
} }
} }
// COMMIT OPERATIONS needing NOFAIL-GUARANTEE:
// Above, we created a SimpleBlockFile contained in our project // Above, we created a SimpleBlockFile contained in our project
// to go with each AliasBlockFile that we wanted to migrate. // to go with each AliasBlockFile that we wanted to migrate.
// However, that didn't actually change any references to these // However, that didn't actually change any references to these
// blockfiles in the Sequences, so we do that next... // blockfiles in the Sequences, so we do that next...
ReplaceBlockFiles(project, blockFileHash); ReplaceBlockFiles(blocks, blockFileHash);
} }
// //
@ -473,22 +475,22 @@ void DependencyDialog::OnYes(wxCommandEvent & WXUNUSED(event))
void DependencyDialog::OnCopySelectedFiles(wxCommandEvent & WXUNUSED(event)) void DependencyDialog::OnCopySelectedFiles(wxCommandEvent & WXUNUSED(event))
{ {
AliasedFileArray aliasedFilesToDelete; AliasedFileArray aliasedFilesToDelete, remainingAliasedFiles;
long i = 0; long i = 0;
for(auto iter = mAliasedFiles.begin(); iter != mAliasedFiles.end();) { for( const auto &file : mAliasedFiles ) {
if (mFileListCtrl->GetItemState(i, wxLIST_STATE_SELECTED)) { if (mFileListCtrl->GetItemState(i, wxLIST_STATE_SELECTED))
// Two-step move could be simplified when all compilers have C++11 vector aliasedFilesToDelete.push_back( file );
aliasedFilesToDelete.push_back(AliasedFile{});
aliasedFilesToDelete.back() = std::move(*iter);
iter = mAliasedFiles.erase(iter);
}
else else
++iter; remainingAliasedFiles.push_back( file );
++i; ++i;
} }
// provides STRONG-GUARANTEE
RemoveDependencies(mProject, aliasedFilesToDelete); RemoveDependencies(mProject, aliasedFilesToDelete);
// COMMIT OPERATIONS needing NOFAIL-GUARANTEE:
mAliasedFiles.swap( remainingAliasedFiles );
PopulateList(); PopulateList();
if (mAliasedFiles.empty() || !mHasNonMissingFiles) if (mAliasedFiles.empty() || !mHasNonMissingFiles)