diff --git a/src/HistoryWindow.cpp b/src/HistoryWindow.cpp index 034c0704c..82d9adf1b 100644 --- a/src/HistoryWindow.cpp +++ b/src/HistoryWindow.cpp @@ -293,7 +293,7 @@ void HistoryDialog::OnCompact(wxCommandEvent & WXUNUSED(event)) auto walFile = wxFileName(projectFileIO.GetFileName() + wxT("-wal")); auto before = baseFile.GetSize() + walFile.GetSize(); - projectFileIO.Compact(nullptr, true); + projectFileIO.Compact({}, true); auto after = baseFile.GetSize() + walFile.GetSize(); diff --git a/src/ProjectFileIO.cpp b/src/ProjectFileIO.cpp index ecf9a9194..ba6495a65 100644 --- a/src/ProjectFileIO.cpp +++ b/src/ProjectFileIO.cpp @@ -678,21 +678,22 @@ bool ProjectFileIO::DeleteBlocks(const BlockIDs &blockids, bool complement) } bool ProjectFileIO::CopyTo(const FilePath &destpath, - const TranslatableString &msg, - bool isTemporary, - bool prune /* = false */, - const std::shared_ptr &tracks /* = nullptr */) + const TranslatableString &msg, + bool isTemporary, + bool prune /* = false */, + const std::vector &tracks /* = {} */) { // Get access to the active tracklist auto pProject = &mProject; - auto &tracklist = tracks ? *tracks : TrackList::Get(*pProject); SampleBlockIDSet blockids; // Collect all active blockids if (prune) { - InspectBlocks( tracklist, {}, &blockids ); + for (auto trackList : tracks) + if (trackList) + InspectBlocks( *trackList, {}, &blockids ); } // Collect ALL blockids else @@ -713,7 +714,7 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, // Create the project doc ProjectSerializer doc; WriteXMLHeader(doc); - WriteXML(doc, false, tracks); + WriteXML(doc, false, tracks.empty() ? nullptr : tracks[0]); auto db = DB(); Connection destConn = nullptr; @@ -888,15 +889,19 @@ bool ProjectFileIO::CopyTo(const FilePath &destpath, return true; } -bool ProjectFileIO::ShouldCompact(const std::shared_ptr &tracks) +bool ProjectFileIO::ShouldCompact(const std::vector &tracks) { SampleBlockIDSet active; unsigned long long current = 0; - InspectBlocks( *tracks, - BlockSpaceUsageAccumulator( current ), - &active // Visit unique blocks only - ); + { + auto fn = BlockSpaceUsageAccumulator( current ); + for (auto pTracks : tracks) + if (pTracks) + InspectBlocks( *pTracks, fn, + &active // Visit unique blocks only + ); + } // Get the number of blocks and total length from the project file. unsigned long long total = GetTotalUsage(); @@ -938,7 +943,8 @@ Connection &ProjectFileIO::CurrConn() return connectionPtr.mpConnection; } -void ProjectFileIO::Compact(const std::shared_ptr &tracks, bool force /* = false */) +void ProjectFileIO::Compact( + const std::vector &tracks, bool force) { // Haven't compacted yet mWasCompacted = false; @@ -972,7 +978,7 @@ void ProjectFileIO::Compact(const std::shared_ptr &tracks, bool force // Copy the original database to a new database. Only prune sample blocks if // we have a tracklist. - if (CopyTo(tempName, XO("Compacting project"), IsTemporary(), tracks != nullptr, tracks)) + if (CopyTo(tempName, XO("Compacting project"), IsTemporary(), !tracks.empty(), tracks)) { // Must close the database to rename it if (CloseConnection()) @@ -1273,7 +1279,7 @@ void ProjectFileIO::WriteXMLHeader(XMLWriter &xmlFile) const void ProjectFileIO::WriteXML(XMLWriter &xmlFile, bool recording /* = false */, - const std::shared_ptr &tracks /* = nullptr */) + const TrackList *tracks /* = nullptr */) // may throw { auto &proj = mProject; @@ -1303,7 +1309,7 @@ void ProjectFileIO::WriteXML(XMLWriter &xmlFile, tags.WriteXML(xmlFile); unsigned int ndx = 0; - tracklist.Any().Visit([&](Track *t) + tracklist.Any().Visit([&](const Track *t) { auto useTrack = t; if ( recording ) { @@ -1836,8 +1842,7 @@ bool ProjectFileIO::LoadProject(const FilePath &fileName) return true; } -bool ProjectFileIO::UpdateSaved( - const std::shared_ptr &tracks) +bool ProjectFileIO::UpdateSaved(const TrackList *tracks) { ProjectSerializer doc; WriteXMLHeader(doc); @@ -1854,7 +1859,8 @@ bool ProjectFileIO::UpdateSaved( return true; } -bool ProjectFileIO::SaveProject(const FilePath &fileName, const std::shared_ptr &lastSaved) +bool ProjectFileIO::SaveProject( + const FilePath &fileName, const TrackList *lastSaved) { // In the case where we're saving a temporary project to a permanent project, // we'll try to simply rename the project to save a bit of time. We then fall @@ -1945,7 +1951,8 @@ bool ProjectFileIO::SaveProject(const FilePath &fileName, const std::shared_ptr< AutoSaveDelete(); // Try to compact the original project file - Compact(lastSaved ? lastSaved : TrackList::Create(&mProject)); + auto empty = TrackList::Create(&mProject); + Compact( { lastSaved ? lastSaved : empty.get() } ); // Save to close the original project file now CloseProject(); @@ -2125,11 +2132,18 @@ int64_t ProjectFileIO::GetBlockUsage(SampleBlockID blockid) return GetDiskUsage(CurrConn().get(), blockid); } -int64_t ProjectFileIO::GetCurrentUsage(const std::shared_ptr &tracks) +int64_t ProjectFileIO::GetCurrentUsage( + const std::vector &trackLists) const { unsigned long long current = 0; + const auto fn = BlockSpaceUsageAccumulator(current); - InspectBlocks(*tracks, BlockSpaceUsageAccumulator(current), nullptr); + // Must pass address of this set, even if not otherwise used, to avoid + // possible multiple count of shared blocks + SampleBlockIDSet seen; + for (auto pTracks: trackLists) + if (pTracks) + InspectBlocks(*pTracks, fn, &seen); return current; } diff --git a/src/ProjectFileIO.h b/src/ProjectFileIO.h index ee95cfae2..6a6d24e4a 100644 --- a/src/ProjectFileIO.h +++ b/src/ProjectFileIO.h @@ -83,8 +83,8 @@ public: bool ImportProject(const FilePath &fileName); bool LoadProject(const FilePath &fileName); - bool UpdateSaved(const std::shared_ptr &tracks = nullptr); - bool SaveProject(const FilePath &fileName, const std::shared_ptr &lastSaved); + bool UpdateSaved(const TrackList *tracks = nullptr); + bool SaveProject(const FilePath &fileName, const TrackList *lastSaved); bool SaveCopy(const FilePath& fileName); wxLongLong GetFreeDiskSpace() const; @@ -93,7 +93,8 @@ public: int64_t GetBlockUsage(SampleBlockID blockid); // Returns the bytes used for all blocks owned by the given track list - int64_t GetCurrentUsage(const std::shared_ptr &tracks); + int64_t GetCurrentUsage( + const std::vector &trackLists) const; // Return the bytes used by all sample blocks in the project file, whether // they are attached to the active tracks or held by the Undo manager. @@ -121,7 +122,8 @@ public: void SetBypass(); // Remove all unused space within a project file - void Compact(const std::shared_ptr &tracks, bool force = false); + void Compact( + const std::vector &tracks, bool force = false); // The last compact check did actually compact the project file if true bool WasCompacted(); @@ -141,7 +143,8 @@ public: private: void WriteXMLHeader(XMLWriter &xmlFile) const; - void WriteXML(XMLWriter &xmlFile, bool recording = false, const std::shared_ptr &tracks = nullptr) /* not override */; + void WriteXML(XMLWriter &xmlFile, bool recording = false, + const TrackList *tracks = nullptr) /* not override */; // XMLTagHandler callback methods bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override; @@ -189,10 +192,14 @@ private: // Return a database connection if successful, which caller must close bool CopyTo(const FilePath &destpath, - const TranslatableString &msg, - bool isTemporary, - bool prune = false, - const std::shared_ptr &tracks = nullptr); + const TranslatableString &msg, + bool isTemporary, + bool prune = false, + const std::vector &tracks = {} /*!< + First track list (or if none, then the project's track list) are tracks to write into document blob; + That list, plus any others, contain tracks whose sample blocks must be kept + */ + ); //! Just set stored errors void SetError(const TranslatableString & msg, @@ -202,7 +209,7 @@ private: void SetDBError(const TranslatableString & msg, const TranslatableString &libraryError = {}); - bool ShouldCompact(const std::shared_ptr &tracks); + bool ShouldCompact(const std::vector &tracks); // Gets values from SQLite B-tree structures static unsigned int get2(const unsigned char *ptr); diff --git a/src/ProjectFileManager.cpp b/src/ProjectFileManager.cpp index fbff1e170..2c5c63454 100644 --- a/src/ProjectFileManager.cpp +++ b/src/ProjectFileManager.cpp @@ -304,7 +304,7 @@ bool ProjectFileManager::DoSave(const FilePath & fileName, const bool fromSaveAs } } - bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks); + bool success = projectFileIO.SaveProject(fileName, mLastSavedTracks.get()); if (!success) { ShowErrorDialog( @@ -674,7 +674,7 @@ void ProjectFileManager::CompactProjectOnClose() } // Attempt to compact the project - projectFileIO.Compact(mLastSavedTracks); + projectFileIO.Compact( { mLastSavedTracks.get() } ); if ( !projectFileIO.WasCompacted() && UndoManager::Get( project ).UnsavedChanges() ) { @@ -682,7 +682,7 @@ void ProjectFileManager::CompactProjectOnClose() // without save. Don't leave the document blob from the last // push of undo history, when that undo state may get purged // with deletion of some new sample blocks. - projectFileIO.UpdateSaved( mLastSavedTracks ); + projectFileIO.UpdateSaved( mLastSavedTracks.get() ); } } } @@ -1239,7 +1239,7 @@ void ProjectFileManager::Compact() } int64_t total = projectFileIO.GetTotalUsage(); - int64_t used = projectFileIO.GetCurrentUsage(currentTracks); + int64_t used = projectFileIO.GetCurrentUsage({currentTracks.get()}); auto before = wxFileName::GetSize(projectFileIO.GetFileName()); @@ -1276,7 +1276,7 @@ void ProjectFileManager::Compact() // above actions. auto before = wxFileName::GetSize(projectFileIO.GetFileName()); - projectFileIO.Compact(currentTracks, true); + projectFileIO.Compact( { currentTracks.get() }, true); auto after = wxFileName::GetSize(projectFileIO.GetFileName());