AUP3: Remove obsolete audio file cache

This commit is contained in:
Leland Lucius 2020-06-21 18:53:54 -05:00
parent cbf1bb558e
commit b1beb20ae9
9 changed files with 38 additions and 393 deletions

View File

@ -77,15 +77,6 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ {
// Other Properties
// Write cache to disk, if it has any
virtual bool GetNeedWriteCacheToDisk() { return false; }
virtual void WriteCacheToDisk() { /* no cache by default */ }
// Fill read cache of block file, if it has any
virtual bool GetNeedFillCache() { return false; }
virtual void FillCache() /* noexcept */ { /* no cache by default */ }
/// Stores a representation of this file in XML
virtual void SaveXML(XMLWriter &xmlFile) = 0;

View File

@ -1689,97 +1689,3 @@ void DirManager::RemoveOrphanBlockfiles()
wxRemoveFile(orphan);
}
void DirManager::FillBlockfilesCache()
{
#ifdef DEPRECATED_AUDIO_CACHE
// See http://bugzilla.audacityteam.org/show_bug.cgi?id=545.
bool cacheBlockFiles = false;
gPrefs->Read(wxT("/Directories/CacheBlockFiles"), &cacheBlockFiles);
if (!cacheBlockFiles)
return; // user opted not to cache block files
int lowMem = gPrefs->Read(wxT("/Directories/CacheLowMem"), 16l);
if (lowMem < 16) {
lowMem = 16;
}
lowMem <<= 20;
BlockHash::iterator iter;
int numNeed = 0;
iter = mBlockFileHash.begin();
while (iter != mBlockFileHash.end())
{
BlockFilePtr b = iter->second.lock();
if (b) {
if (b->GetNeedFillCache())
numNeed++;
}
++iter;
}
if (numNeed == 0)
return;
ProgressDialog progress(XO("Caching audio"),
XO("Caching audio into memory"));
iter = mBlockFileHash.begin();
int current = 0;
while (iter != mBlockFileHash.end())
{
BlockFilePtr b = iter->second.lock();
if (b) {
if (b->GetNeedFillCache() && (GetFreeMemory() > lowMem)) {
b->FillCache();
}
if (ProgressResult::Cancelled != progress.Update(current, numNeed))
break; // user cancelled progress dialog, stop caching
current++;
}
++iter;
}
#endif // DEPRECATED_AUDIO_CACHE
}
void DirManager::WriteCacheToDisk()
{
BlockHash::iterator iter;
int numNeed = 0;
iter = mBlockFileHash.begin();
while (iter != mBlockFileHash.end())
{
BlockFilePtr b = iter->second.lock();
if (b) {
if (b->GetNeedWriteCacheToDisk())
numNeed++;
}
++iter;
}
if (numNeed == 0)
return;
ProgressDialog progress(XO("Saving recorded audio"),
XO("Saving recorded audio to disk"));
iter = mBlockFileHash.begin();
int current = 0;
while (iter != mBlockFileHash.end())
{
BlockFilePtr b = iter->second.lock();
if (b) {
if (b->GetNeedWriteCacheToDisk())
{
b->WriteCacheToDisk();
progress.Update(current, numNeed);
}
current++;
}
++iter;
}
}

View File

@ -226,14 +226,6 @@ class PROFILE_DLL_API DirManager final
// auto recovery is cancelled and should be retried later
static void SetDontDeleteTempFiles() { dontDeleteTempFiles = true; }
// Write all write-cached block files to disc, if any
void WriteCacheToDisk();
// (Try to) fill cache of blockfiles, if caching is enabled (otherwise do
// nothing)
// A no-fail operation that does not throw
void FillBlockfilesCache();
private:
wxFileNameWrapper MakeBlockFileName();

View File

@ -916,9 +916,6 @@ You are saving directly to a slow external storage device\n\
history.PushState(XO("Recorded Audio"), XO("Record"));
}
// Write all cached files to disk, if any
dirManager.WriteCacheToDisk();
// Now we auto-save again to get the project to a "normal" state again.
projectFileIO.AutoSave();
}
@ -1170,4 +1167,4 @@ GetPropertiesOfSelected(const AudacityProject &proj)
result.rateOfSelected = rateOfSelection;
return result;
}
}

View File

@ -1284,11 +1284,6 @@ void ProjectFileManager::OpenFile(const FilePath &fileNameArg, bool addtohistory
bool closed = false;
auto cleanup = finally( [&] {
if (! closed ) {
if ( bParseSuccess ) {
// This is a no-fail:
dirManager.FillBlockfilesCache();
}
// For an unknown reason, OSX requires that the project window be
// raised if a recovery took place.
window.CallAfter( [&] { window.Raise(); } );
@ -1567,7 +1562,5 @@ bool ProjectFileManager::Import(
}
}
// This is a no-fail:
dirManager.FillBlockfilesCache();
return true;
}

View File

@ -460,12 +460,11 @@ namespace {
BlockFilePtr NewSimpleBlockFile( DirManager &dm,
samplePtr sampleData, size_t sampleLen,
sampleFormat format,
bool allowDeferredWrite = false)
sampleFormat format)
{
return dm.NewBlockFile( [&]( wxFileNameWrapper filePath ) {
return make_blockfile<SimpleBlockFile>(
std::move(filePath), sampleData, sampleLen, format, allowDeferredWrite);
std::move(filePath), sampleData, sampleLen, format);
} );
}
}
@ -1555,9 +1554,7 @@ void Sequence::Append(samplePtr buffer, sampleFormat format,
SeqBlock newLastBlock(
NewSimpleBlockFile( *mDirManager,
buffer2.ptr(), newLastBlockLen, mSampleFormat,
blockFileLog != NULL
),
buffer2.ptr(), newLastBlockLen, mSampleFormat),
lastBlock.start
);
@ -1581,12 +1578,12 @@ void Sequence::Append(samplePtr buffer, sampleFormat format,
BlockFilePtr pFile;
if (format == mSampleFormat) {
pFile = NewSimpleBlockFile( *mDirManager,
buffer, addedLen, mSampleFormat, blockFileLog != NULL);
buffer, addedLen, mSampleFormat);
}
else {
CopySamples(buffer, format, buffer2.ptr(), mSampleFormat, addedLen);
pFile = NewSimpleBlockFile( *mDirManager,
buffer2.ptr(), addedLen, mSampleFormat, blockFileLog != NULL);
buffer2.ptr(), addedLen, mSampleFormat);
}
if (blockFileLog)

View File

@ -26,28 +26,6 @@ supply data and have the constructor write the file. The other
is for when the file already exists and we simply want to create
the data structure to refer to it.
The block file can be cached in two ways. Caching is enabled if the
preference "/Directories/CacheBlockFiles" is set, otherwise disabled. The
default is to disable caching.
* Read-caching: If caching is enabled, all block files will always be
read-cached. Block files on disk will be read as soon as they are created
and held in memory. New block files will be written to disk, but held in
memory, so they are never read from disk in the current session.
* Write-caching: If caching is enabled and the parameter allowDeferredWrite
is enabled at the block file constructor, NEW block files are held in memory
and written to disk only when WriteCacheToDisk() is called. This is used
during recording to prevent disk access. After recording, WriteCacheToDisk()
will be called on all block files and they will be written to disk. During
normal editing, no write cache is active, that is, any block files will be
written to disk instantly.
Even with write cache, auto recovery during normal editing will work as
expected. However, auto recovery during recording will not work (not even
manual auto recovery, because the files are never written physically to
disk).
*//****************************************************************//**
\class auHeader
@ -98,9 +76,7 @@ static wxUint32 SwapUintEndianess(wxUint32 in)
/// @param allowDeferredWrite Allow deferred write-caching
SimpleBlockFile::SimpleBlockFile(wxFileNameWrapper &&baseFileName,
samplePtr sampleData, size_t sampleLen,
sampleFormat format,
bool allowDeferredWrite /* = false */,
bool bypassCache /* = false */):
sampleFormat format):
BlockFile {
(baseFileName.SetExt(wxT("au")), std::move(baseFileName)),
sampleLen
@ -108,33 +84,10 @@ SimpleBlockFile::SimpleBlockFile(wxFileNameWrapper &&baseFileName,
{
mFormat = format;
mCache.active = false;
bool useCache = GetCache() && (!bypassCache);
if (!(allowDeferredWrite && useCache) && !bypassCache)
{
bool bSuccess = WriteSimpleBlockFile(sampleData, sampleLen, format, NULL);
if (!bSuccess)
throw FileException{
FileException::Cause::Write, GetFileName().name };
}
if (useCache) {
//wxLogDebug("SimpleBlockFile::SimpleBlockFile(): Caching block file data.");
mCache.active = true;
mCache.needWrite = true;
mCache.format = format;
const auto sampleDataSize = sampleLen * SAMPLE_SIZE(format);
mCache.sampleData.reinit(sampleDataSize);
memcpy(mCache.sampleData.get(), sampleData, sampleDataSize);
ArrayOf<char> cleanup;
void* summaryData = BlockFile::CalcSummary(sampleData, sampleLen,
format, cleanup);
mCache.summaryData.reinit(mSummaryInfo.totalSummaryBytes);
memcpy(mCache.summaryData.get(), summaryData,
mSummaryInfo.totalSummaryBytes);
}
bool bSuccess = WriteSimpleBlockFile(sampleData, sampleLen, format, NULL);
if (!bSuccess)
throw FileException{
FileException::Cause::Write, GetFileName().name };
}
/// Construct a SimpleBlockFile memory structure that will point to an
@ -151,8 +104,6 @@ SimpleBlockFile::SimpleBlockFile(wxFileNameWrapper &&existingFile, size_t len,
mMin = min;
mMax = max;
mRMS = rms;
mCache.active = false;
}
SimpleBlockFile::~SimpleBlockFile()
@ -268,74 +219,6 @@ bool SimpleBlockFile::WriteSimpleBlockFile(
return true;
}
// This function should try to fill the cache, but just return without effect
// (not throwing) if there is failure.
void SimpleBlockFile::FillCache()
{
if (mCache.active)
return; // cache is already filled
// Check sample format
wxFFile file(mFileName.GetFullPath(), wxT("rb"));
if (!file.IsOpened())
{
// Don't read into cache if file not available
return;
}
auHeader header;
if (file.Read(&header, sizeof(header)) != sizeof(header))
{
// Corrupt file
return;
}
wxUint32 encoding;
if (header.magic == 0x2e736e64)
encoding = header.encoding; // correct endianness
else
encoding = SwapUintEndianess(header.encoding);
switch (encoding)
{
case AU_SAMPLE_FORMAT_16:
mCache.format = int16Sample;
break;
case AU_SAMPLE_FORMAT_24:
mCache.format = int24Sample;
break;
default:
// floatSample is a safe default (we will never loose data)
mCache.format = floatSample;
break;
}
file.Close();
// Read samples into cache
mCache.sampleData.reinit(mLen * SAMPLE_SIZE(mCache.format));
if (ReadData(mCache.sampleData.get(), mCache.format, 0, mLen,
// no exceptions!
false) != mLen)
{
// Could not read all samples
mCache.sampleData.reset();
return;
}
// Read summary data into cache
// Fills with zeroes in case of failure:
ReadSummary(mCache.summaryData);
// Cache is active but already on disk
mCache.active = true;
mCache.needWrite = false;
//wxLogDebug("SimpleBlockFile::FillCache(): Successfully read simple block file into cache.");
}
/// Read the summary section of the disk file.
///
/// @param *data The buffer to write the data to. It must be at least
@ -343,43 +226,35 @@ void SimpleBlockFile::FillCache()
bool SimpleBlockFile::ReadSummary(ArrayOf<char> &data)
{
data.reinit( mSummaryInfo.totalSummaryBytes );
if (mCache.active) {
//wxLogDebug("SimpleBlockFile::ReadSummary(): Summary is already in cache.");
memcpy(data.get(), mCache.summaryData.get(), mSummaryInfo.totalSummaryBytes);
return true;
}
else
//wxLogDebug("SimpleBlockFile::ReadSummary(): Reading summary from disk.");
wxFFile file(mFileName.GetFullPath(), wxT("rb"));
{
//wxLogDebug("SimpleBlockFile::ReadSummary(): Reading summary from disk.");
wxFFile file(mFileName.GetFullPath(), wxT("rb"));
{
Optional<wxLogNull> silence{};
if (mSilentLog)
silence.emplace();
// FIXME: TRAP_ERR no report to user of absent summary files?
// filled with zero instead.
if (!file.IsOpened()){
memset(data.get(), 0, mSummaryInfo.totalSummaryBytes);
mSilentLog = TRUE;
return false;
}
}
mSilentLog = FALSE;
// The offset is just past the au header
if( !file.Seek(sizeof(auHeader)) ||
file.Read(data.get(), mSummaryInfo.totalSummaryBytes) !=
mSummaryInfo.totalSummaryBytes ) {
Optional<wxLogNull> silence{};
if (mSilentLog)
silence.emplace();
// FIXME: TRAP_ERR no report to user of absent summary files?
// filled with zero instead.
if (!file.IsOpened()){
memset(data.get(), 0, mSummaryInfo.totalSummaryBytes);
mSilentLog = TRUE;
return false;
}
FixSummary(data.get());
return true;
}
mSilentLog = FALSE;
// The offset is just past the au header
if( !file.Seek(sizeof(auHeader)) ||
file.Read(data.get(), mSummaryInfo.totalSummaryBytes) !=
mSummaryInfo.totalSummaryBytes ) {
memset(data.get(), 0, mSummaryInfo.totalSummaryBytes);
return false;
}
FixSummary(data.get());
return true;
}
/// Read the data portion of the block file using libsndfile. Convert it
@ -392,28 +267,8 @@ bool SimpleBlockFile::ReadSummary(ArrayOf<char> &data)
size_t SimpleBlockFile::ReadData(samplePtr data, sampleFormat format,
size_t start, size_t len, bool mayThrow) const
{
if (mCache.active)
{
//wxLogDebug("SimpleBlockFile::ReadData(): Data are already in cache.");
auto framesRead = std::min(len, std::max(start, mLen) - start);
CopySamples(
(samplePtr)(mCache.sampleData.get() +
start * SAMPLE_SIZE(mCache.format)),
mCache.format, data, format, framesRead);
if ( framesRead < len ) {
if (mayThrow)
// Not the best exception class?
throw FileException{ FileException::Cause::Read, mFileName };
ClearSamples(data, format, framesRead, len - framesRead);
}
return framesRead;
}
else
return CommonReadData( mayThrow,
mFileName, mSilentLog, nullptr, 0, 0, data, format, start, len);
return CommonReadData( mayThrow,
mFileName, mSilentLog, nullptr, 0, 0, data, format, start, len);
}
void SimpleBlockFile::SaveXML(XMLWriter &xmlFile)
@ -491,12 +346,6 @@ BlockFilePtr SimpleBlockFile::Copy(wxFileNameWrapper &&newFileName)
auto SimpleBlockFile::GetSpaceUsage() const -> DiskByteCount
{
if (mCache.active && mCache.needWrite)
{
// We don't know space usage yet
return 0;
}
// Don't know the format, so it must be read from the file
if (mFormat == (sampleFormat) 0)
{
@ -504,7 +353,6 @@ auto SimpleBlockFile::GetSpaceUsage() const -> DiskByteCount
wxFFile file(mFileName.GetFullPath(), wxT("rb"));
if (!file.IsOpened())
{
// Don't read into cache if file not available
return 0;
}
@ -575,41 +423,6 @@ void SimpleBlockFile::Recover(){
}
void SimpleBlockFile::WriteCacheToDisk()
{
if (!GetNeedWriteCacheToDisk())
return;
if (WriteSimpleBlockFile(mCache.sampleData.get(), mLen, mCache.format,
mCache.summaryData.get()))
mCache.needWrite = false;
}
bool SimpleBlockFile::GetNeedWriteCacheToDisk()
{
return mCache.active && mCache.needWrite;
}
bool SimpleBlockFile::GetCache()
{
#ifdef DEPRECATED_AUDIO_CACHE
// See http://bugzilla.audacityteam.org/show_bug.cgi?id=545.
bool cacheBlockFiles = false;
gPrefs->Read(wxT("/Directories/CacheBlockFiles"), &cacheBlockFiles);
if (!cacheBlockFiles)
return false;
int lowMem = gPrefs->Read(wxT("/Directories/CacheLowMem"), 16l);
if (lowMem < 16) {
lowMem = 16;
}
lowMem <<= 20;
return (GetFreeMemory() > lowMem);
#else
return false;
#endif
}
static DirManager::RegisteredBlockFileDeserializer sRegistration {
"simpleblockfile",
[]( DirManager &dm, const wxChar **attrs ){

View File

@ -15,15 +15,6 @@
class DirManager;
struct SimpleBlockFileCache {
bool active;
bool needWrite;
sampleFormat format;
ArrayOf<char> sampleData, summaryData;
SimpleBlockFileCache() {}
};
// The AU formats we care about
enum {
AU_SAMPLE_FORMAT_16 = 3,
@ -48,9 +39,7 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile {
/// Create a disk file and write summary and sample data to it
SimpleBlockFile(wxFileNameWrapper &&baseFileName,
samplePtr sampleData, size_t sampleLen,
sampleFormat format,
bool allowDeferredWrite = false,
bool bypassCache = false );
sampleFormat format);
/// Create the memory structure to refer to the given block file
SimpleBlockFile(wxFileNameWrapper &&existingFile, size_t len,
float min, float max, float rms);
@ -75,21 +64,10 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile {
static BlockFilePtr BuildFromXML(DirManager &dm, const wxChar **attrs);
bool GetNeedWriteCacheToDisk() override;
void WriteCacheToDisk() override;
bool GetNeedFillCache() override { return !mCache.active; }
void FillCache() /* noexcept */ override;
protected:
bool WriteSimpleBlockFile(samplePtr sampleData, size_t sampleLen,
sampleFormat format, void* summaryData);
static bool GetCache();
void ReadIntoCache();
SimpleBlockFileCache mCache;
private:
mutable sampleFormat mFormat; // may be found lazily

View File

@ -120,28 +120,6 @@ void DirectoriesPrefs::PopulateOrExchange(ShuttleGui & S)
}
S.EndStatic();
#ifdef DEPRECATED_AUDIO_CACHE
// See http://bugzilla.audacityteam.org/show_bug.cgi?id=545.
S.StartStatic(XO("Audio cache"));
{
S.TieCheckBox(XO("Play and/or record using &RAM (useful for slow drives)"),
wxT("/Directories/CacheBlockFiles"),
false);
S.StartTwoColumn();
{
S.TieIntegerTextBox(XO("Mi&nimum Free Memory (MB):"),
{wxT("/Directories/CacheLowMem"), 16},
9);
}
S.EndTwoColumn();
S.AddVariableText(XO(
"If the available system memory falls below this value, audio will no longer\nbe cached in memory and will be written to disk."),
false, 0, 600);
}
S.EndStatic();
#endif // DEPRECATED_AUDIO_CACHE
S.EndScroller();
}