mirror of
https://github.com/cookiengineer/audacity
synced 2025-09-23 15:41:09 +02:00
Sequence consistency check throws; new unused commit functions use it
This commit is contained in:
parent
6b0c5c096b
commit
2ba6065961
@ -411,7 +411,8 @@ void RecordingRecoveryHandler::HandleXMLEndTag(const wxChar *tag)
|
|||||||
WaveClip* clip = track->NewestOrNewClip();
|
WaveClip* clip = track->NewestOrNewClip();
|
||||||
Sequence* seq = clip->GetSequence();
|
Sequence* seq = clip->GetSequence();
|
||||||
|
|
||||||
seq->ConsistencyCheck(wxT("RecordingRecoveryHandler::HandleXMLEndTag"));
|
seq->ConsistencyCheck
|
||||||
|
(wxT("RecordingRecoveryHandler::HandleXMLEndTag"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,7 +474,8 @@ void BenchmarkDialog::OnRun( wxCommandEvent & WXUNUSED(event))
|
|||||||
elapsed = timer.Time();
|
elapsed = timer.Time();
|
||||||
|
|
||||||
if (mBlockDetail) {
|
if (mBlockDetail) {
|
||||||
t->GetClipByIndex(0)->GetSequence()->DebugPrintf(&tempStr);
|
auto seq = t->GetClipByIndex(0)->GetSequence();
|
||||||
|
seq->DebugPrintf(seq->GetBlockArray(), seq->GetNumSamples(), &tempStr);
|
||||||
mToPrint += tempStr;
|
mToPrint += tempStr;
|
||||||
}
|
}
|
||||||
Printf(wxT("Time to perform %d edits: %ld ms\n"), trials, elapsed);
|
Printf(wxT("Time to perform %d edits: %ld ms\n"), trials, elapsed);
|
||||||
|
136
src/Sequence.cpp
136
src/Sequence.cpp
@ -50,6 +50,8 @@
|
|||||||
#include "blockfile/SimpleBlockFile.h"
|
#include "blockfile/SimpleBlockFile.h"
|
||||||
#include "blockfile/SilentBlockFile.h"
|
#include "blockfile/SilentBlockFile.h"
|
||||||
|
|
||||||
|
#include "InconsistencyException.h"
|
||||||
|
|
||||||
size_t Sequence::sMaxDiskBlockSize = 1048576;
|
size_t Sequence::sMaxDiskBlockSize = 1048576;
|
||||||
|
|
||||||
// Sequence methods
|
// Sequence methods
|
||||||
@ -222,7 +224,7 @@ bool Sequence::ConvertToSampleFormat(sampleFormat format, bool* pbChanged)
|
|||||||
*pbChanged = false; // Revert overall change flag, in case we had some partial success in the loop.
|
*pbChanged = false; // Revert overall change flag, in case we had some partial success in the loop.
|
||||||
}
|
}
|
||||||
|
|
||||||
bSuccess &= ConsistencyCheck(wxT("Sequence::ConvertToSampleFormat()"));
|
ConsistencyCheck(wxT("Sequence::ConvertToSampleFormat()"));
|
||||||
|
|
||||||
return bSuccess;
|
return bSuccess;
|
||||||
}
|
}
|
||||||
@ -437,9 +439,7 @@ std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
|
|||||||
// Increase ref count or duplicate file
|
// Increase ref count or duplicate file
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! ConsistencyCheck(wxT("Sequence::Copy()")))
|
dest->ConsistencyCheck(wxT("Sequence::Copy()"));
|
||||||
//THROW_INCONSISTENCY_EXCEPTION
|
|
||||||
;
|
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
@ -505,7 +505,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
AppendBlock(*mDirManager, mBlock, mNumSamples, srcBlock[i]);
|
AppendBlock(*mDirManager, mBlock, mNumSamples, srcBlock[i]);
|
||||||
// Increase ref count or duplicate file
|
// Increase ref count or duplicate file
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Paste branch one"));
|
ConsistencyCheck(wxT("Paste branch one"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int b = (s == mNumSamples) ? mBlock.size() - 1 : FindBlock(s);
|
const int b = (s == mNumSamples) ? mBlock.size() - 1 : FindBlock(s);
|
||||||
@ -547,7 +548,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
|
|
||||||
mNumSamples += addedLen;
|
mNumSamples += addedLen;
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Paste branch two"));
|
ConsistencyCheck(wxT("Paste branch two"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case three: if we are inserting four or fewer blocks,
|
// Case three: if we are inserting four or fewer blocks,
|
||||||
@ -639,7 +641,8 @@ bool Sequence::Paste(sampleCount s, const Sequence *src)
|
|||||||
|
|
||||||
mNumSamples += addedLen;
|
mNumSamples += addedLen;
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Paste branch three"));
|
ConsistencyCheck(wxT("Paste branch three"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::SetSilence(sampleCount s0, sampleCount len)
|
bool Sequence::SetSilence(sampleCount s0, sampleCount len)
|
||||||
@ -693,7 +696,8 @@ bool Sequence::InsertSilence(sampleCount s0, sampleCount len)
|
|||||||
bool bResult = Paste(s0, &sTrack);
|
bool bResult = Paste(s0, &sTrack);
|
||||||
wxASSERT(bResult);
|
wxASSERT(bResult);
|
||||||
|
|
||||||
return bResult && ConsistencyCheck(wxT("InsertSilence"));
|
ConsistencyCheck(wxT("InsertSilence"));
|
||||||
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::AppendAlias(const wxString &fullPath,
|
bool Sequence::AppendAlias(const wxString &fullPath,
|
||||||
@ -1253,7 +1257,8 @@ bool Sequence::Set(samplePtr buffer, sampleFormat format,
|
|||||||
b++;
|
b++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Set"));
|
ConsistencyCheck(wxT("Set"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -1683,7 +1688,8 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
|
|||||||
|
|
||||||
mNumSamples -= len;
|
mNumSamples -= len;
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Delete - branch one"));
|
ConsistencyCheck(wxT("Delete - branch one"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a NEW array of blocks
|
// Create a NEW array of blocks
|
||||||
@ -1790,44 +1796,120 @@ bool Sequence::Delete(sampleCount start, sampleCount len)
|
|||||||
// Update total number of samples and do a consistency check.
|
// Update total number of samples and do a consistency check.
|
||||||
mNumSamples -= len;
|
mNumSamples -= len;
|
||||||
|
|
||||||
return ConsistencyCheck(wxT("Delete - branch two"));
|
ConsistencyCheck(wxT("Delete - branch two"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sequence::ConsistencyCheck(const wxChar *whereStr) const
|
void Sequence::ConsistencyCheck(const wxChar *whereStr, bool mayThrow) const
|
||||||
{
|
{
|
||||||
unsigned int i;
|
ConsistencyCheck(mBlock, 0, mNumSamples, whereStr, mayThrow);
|
||||||
sampleCount pos = 0;
|
}
|
||||||
unsigned int numBlocks = mBlock.size();
|
|
||||||
bool bError = false;
|
|
||||||
|
|
||||||
for (i = 0; !bError && i < numBlocks; i++) {
|
void Sequence::ConsistencyCheck
|
||||||
|
(const BlockArray &mBlock, size_t from,
|
||||||
|
sampleCount mNumSamples, const wxChar *whereStr,
|
||||||
|
bool mayThrow)
|
||||||
|
{
|
||||||
|
bool bError = false;
|
||||||
|
// Construction of the exception at the appropriate line of the function
|
||||||
|
// gives a little more discrimination
|
||||||
|
InconsistencyException ex;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
sampleCount pos = mBlock[from].start;
|
||||||
|
if ( from == 0 && pos != 0 )
|
||||||
|
ex = CONSTRUCT_INCONSISTENCY_EXCEPTION, bError = true;
|
||||||
|
|
||||||
|
unsigned int numBlocks = mBlock.size();
|
||||||
|
|
||||||
|
for (i = from; !bError && i < numBlocks; i++) {
|
||||||
const SeqBlock &seqBlock = mBlock[i];
|
const SeqBlock &seqBlock = mBlock[i];
|
||||||
if (pos != seqBlock.start)
|
if (pos != seqBlock.start)
|
||||||
bError = true;
|
ex = CONSTRUCT_INCONSISTENCY_EXCEPTION, bError = true;
|
||||||
|
|
||||||
if (seqBlock.f)
|
if ( seqBlock.f )
|
||||||
pos += seqBlock.f->GetLength();
|
pos += seqBlock.f->GetLength();
|
||||||
else
|
else
|
||||||
bError = true;
|
ex = CONSTRUCT_INCONSISTENCY_EXCEPTION, bError = true;
|
||||||
}
|
}
|
||||||
if (pos != mNumSamples)
|
if ( !bError && pos != mNumSamples )
|
||||||
bError = true;
|
ex = CONSTRUCT_INCONSISTENCY_EXCEPTION, bError = true;
|
||||||
|
|
||||||
if (bError)
|
if ( bError )
|
||||||
{
|
{
|
||||||
wxLogError(wxT("*** Consistency check failed after %s. ***"), whereStr);
|
wxLogError(wxT("*** Consistency check failed after %s. ***"), whereStr);
|
||||||
wxString str;
|
wxString str;
|
||||||
DebugPrintf(&str);
|
DebugPrintf(mBlock, mNumSamples, &str);
|
||||||
wxLogError(wxT("%s"), str.c_str());
|
wxLogError(wxT("%s"), str.c_str());
|
||||||
wxLogError(wxT("*** Please report this error to feedback@audacityteam.org. ***\n\n")
|
wxLogError(wxT("*** Please report this error to feedback@audacityteam.org. ***\n\n")
|
||||||
wxT("Recommended course of action:\n")
|
wxT("Recommended course of action:\n")
|
||||||
wxT("Undo the failed operation(s), then export or save your work and quit."));
|
wxT("Undo the failed operation(s), then export or save your work and quit."));
|
||||||
}
|
|
||||||
|
|
||||||
return !bError;
|
if (mayThrow)
|
||||||
|
//throw ex
|
||||||
|
;
|
||||||
|
else
|
||||||
|
wxASSERT(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sequence::DebugPrintf(wxString *dest) const
|
void Sequence::CommitChangesIfConsistent
|
||||||
|
(BlockArray &newBlock, sampleCount numSamples, const wxChar *whereStr)
|
||||||
|
{
|
||||||
|
ConsistencyCheck( newBlock, 0, numSamples, whereStr ); // may throw
|
||||||
|
|
||||||
|
// now commit
|
||||||
|
// use NOFAIL-GUARANTEE
|
||||||
|
|
||||||
|
mBlock.swap(newBlock);
|
||||||
|
mNumSamples = numSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sequence::AppendBlocksIfConsistent
|
||||||
|
(BlockArray &additionalBlocks, bool replaceLast,
|
||||||
|
sampleCount numSamples, const wxChar *whereStr)
|
||||||
|
{
|
||||||
|
// Any additional blocks are meant to be appended,
|
||||||
|
// replacing the final block if there was one.
|
||||||
|
|
||||||
|
if (additionalBlocks.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool tmpValid = false;
|
||||||
|
SeqBlock tmp;
|
||||||
|
|
||||||
|
if ( replaceLast && ! mBlock.empty() ) {
|
||||||
|
tmp = mBlock.back(), tmpValid = true;
|
||||||
|
mBlock.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prevSize = mBlock.size();
|
||||||
|
|
||||||
|
bool consistent = false;
|
||||||
|
auto cleanup = finally( [&] {
|
||||||
|
if ( !consistent ) {
|
||||||
|
mBlock.resize( prevSize );
|
||||||
|
if ( tmpValid )
|
||||||
|
mBlock.push_back( tmp );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
std::copy( additionalBlocks.begin(), additionalBlocks.end(),
|
||||||
|
std::back_inserter( mBlock ) );
|
||||||
|
|
||||||
|
// Check consistency only of the blocks that were added,
|
||||||
|
// avoiding quadratic time for repeated checking of repeating appends
|
||||||
|
ConsistencyCheck( mBlock, prevSize, numSamples, whereStr ); // may throw
|
||||||
|
|
||||||
|
// now commit
|
||||||
|
// use NOFAIL-GUARANTEE
|
||||||
|
|
||||||
|
mNumSamples = numSamples;
|
||||||
|
consistent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sequence::DebugPrintf
|
||||||
|
(const BlockArray &mBlock, sampleCount mNumSamples, wxString *dest)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
decltype(mNumSamples) pos = 0;
|
decltype(mNumSamples) pos = 0;
|
||||||
|
@ -263,19 +263,38 @@ class PROFILE_DLL_API Sequence final : public XMLTagHandler{
|
|||||||
bool Get(int b, samplePtr buffer, sampleFormat format,
|
bool Get(int b, samplePtr buffer, sampleFormat format,
|
||||||
sampleCount start, size_t len, bool mayThrow) const;
|
sampleCount start, size_t len, bool mayThrow) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//
|
//
|
||||||
// Public methods intended for debugging only
|
// Public methods
|
||||||
//
|
//
|
||||||
|
|
||||||
// This function makes sure that the track isn't messed up
|
// This function throws if the track is messed up
|
||||||
// because of inconsistent block starts & lengths
|
// because of inconsistent block starts & lengths
|
||||||
bool ConsistencyCheck(const wxChar *whereStr) const;
|
void ConsistencyCheck (const wxChar *whereStr, bool mayThrow = true) const;
|
||||||
|
|
||||||
// This function prints information to stdout about the blocks in the
|
// This function prints information to stdout about the blocks in the
|
||||||
// tracks and indicates if there are inconsistencies.
|
// tracks and indicates if there are inconsistencies.
|
||||||
void DebugPrintf(wxString *dest) const;
|
static void DebugPrintf
|
||||||
|
(const BlockArray &block, sampleCount numSamples, wxString *dest);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void ConsistencyCheck
|
||||||
|
(const BlockArray &block, size_t from,
|
||||||
|
sampleCount numSamples, const wxChar *whereStr,
|
||||||
|
bool mayThrow = true);
|
||||||
|
|
||||||
|
// The next two are used in methods that give a strong guarantee.
|
||||||
|
// They either throw because final consistency check fails, or swap the
|
||||||
|
// changed contents into place.
|
||||||
|
|
||||||
|
void CommitChangesIfConsistent
|
||||||
|
(BlockArray &newBlock, sampleCount numSamples, const wxChar *whereStr);
|
||||||
|
|
||||||
|
void AppendBlocksIfConsistent
|
||||||
|
(BlockArray &additionalBlocks, bool replaceLast,
|
||||||
|
sampleCount numSamples, const wxChar *whereStr);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __AUDACITY_SEQUENCE__
|
#endif // __AUDACITY_SEQUENCE__
|
||||||
|
Loading…
x
Reference in New Issue
Block a user