changes in logic used by source cleanup to avoid endless recursion in sessions with...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 28 Jun 2016 19:05:48 +0000 (15:05 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 28 Jun 2016 19:05:56 +0000 (15:05 -0400)
This also fixes some potentially dangerous cleanup logic related to two sources with the same name (but different paths)

libs/ardour/ardour/playlist.h
libs/ardour/ardour/region.h
libs/ardour/ardour/session_playlists.h
libs/ardour/playlist.cc
libs/ardour/region.cc
libs/ardour/region_factory.cc
libs/ardour/session_playlists.cc
libs/ardour/session_state.cc

index cc968e18330c9b4d22167904fba2683a1152dcc9..7b19a08f6ac2cb2805034ffa5d53743ddd1d37db 100644 (file)
@@ -130,7 +130,6 @@ public:
 
        void add_region (boost::shared_ptr<Region>, framepos_t position, float times = 1, bool auto_partition = false);
        void remove_region (boost::shared_ptr<Region>);
-       void remove_region_by_source (boost::shared_ptr<Source>);
        void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
        void get_region_list_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
        void get_source_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
@@ -181,7 +180,8 @@ public:
        bool                       region_is_shuffle_constrained (boost::shared_ptr<Region>);
        bool                       has_region_at (framepos_t const) const;
 
-       bool uses_source (boost::shared_ptr<const Source> src) const;
+       bool uses_source (boost::shared_ptr<const Source> src, bool shallow = false) const;
+       void deep_sources (std::set<boost::shared_ptr<Source> >&) const;
 
        framepos_t find_next_transient (framepos_t position, int dir);
 
index 3a8a694c49e155cddf7aed43e10bb65089eaf36f..776a8a79669b76134ff71b221110f1a272b7b3a1 100644 (file)
@@ -197,7 +197,8 @@ class LIBARDOUR_API Region
        bool region_list_equivalent (boost::shared_ptr<const Region>) const;
        bool source_equivalent (boost::shared_ptr<const Region>) const;
        bool any_source_equivalent (boost::shared_ptr<const Region>) const;
-       bool uses_source (boost::shared_ptr<const Source>) const;
+       bool uses_source (boost::shared_ptr<const Source>, bool shallow = false) const;
+       void deep_sources (std::set<boost::shared_ptr<Source> >&) const;
 
        std::string source_string () const;
 
@@ -310,7 +311,7 @@ class LIBARDOUR_API Region
        /** merges _onsets OR _transients with _user_transients into given list
         * if _onsets and _transients are unset, run analysis.
         * list is not thinned, duplicates remain in place.
-        * 
+        *
         * intended for: Playlist::find_next_transient ()
         */
        virtual void get_transients (AnalysisFeatureList&) {
index e7ad1624dd9af7d71ee9d6f8d55c072434b4e7c3..cc6d301b3166bdbcb5214d37d897ca5406812f29 100644 (file)
@@ -54,12 +54,14 @@ public:
        uint32_t source_use_count (boost::shared_ptr<const Source> src) const;
        uint32_t region_use_count (boost::shared_ptr<Region> region) const;
        template<class T> void foreach (T *obj, void (T::*func)(boost::shared_ptr<Playlist>));
+       void foreach (boost::function<void(boost::shared_ptr<const Playlist>)> functor);
        void get (std::vector<boost::shared_ptr<Playlist> >&) const;
        void unassigned (std::list<boost::shared_ptr<Playlist> > & list);
        void destroy_region (boost::shared_ptr<Region>);
        boost::shared_ptr<Crossfade> find_crossfade (const PBD::ID &);
        void sync_all_regions_with_regions ();
        std::vector<boost::shared_ptr<Playlist> > playlists_for_track (boost::shared_ptr<Track>) const;
+       uint32_t n_playlists() const;
 
 private:
        friend class Session;
@@ -69,7 +71,6 @@ private:
        void remove_weak (boost::weak_ptr<Playlist>);
        void track (bool, boost::weak_ptr<Playlist>);
 
-       uint32_t n_playlists() const;
        void find_equivalent_playlist_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >& result);
        void update_after_tempo_map_change ();
        void add_state (XMLNode *, bool);
index eaee1c4326659fbb24b767fd90422e1402456ea3..7267ec8cdf8a02f067eb2e8314599e68e2aae0b7 100644 (file)
@@ -1774,12 +1774,23 @@ Playlist::region_bounds_changed (const PropertyChange& what_changed, boost::shar
   **********************************************************************/
 
 boost::shared_ptr<RegionList>
-Playlist::region_list() {
+Playlist::region_list()
+{
        RegionReadLock rlock (this);
        boost::shared_ptr<RegionList> rlist (new RegionList (regions.rlist ()));
        return rlist;
 }
 
+void
+Playlist::deep_sources (std::set<boost::shared_ptr<Source> >& sources) const
+{
+       RegionReadLock rlock (const_cast<Playlist*>(this));
+
+       for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+               (*i)->deep_sources (sources);
+       }
+}
+
 boost::shared_ptr<RegionList>
 Playlist::regions_at (framepos_t frame)
 {
@@ -2659,12 +2670,12 @@ Playlist::nudge_after (framepos_t start, framecnt_t distance, bool forwards)
 }
 
 bool
-Playlist::uses_source (boost::shared_ptr<const Source> src) const
+Playlist::uses_source (boost::shared_ptr<const Source> src, bool shallow) const
 {
        RegionReadLock rlock (const_cast<Playlist*> (this));
 
        for (set<boost::shared_ptr<Region> >::const_iterator r = all_regions.begin(); r != all_regions.end(); ++r) {
-               if ((*r)->uses_source (src)) {
+               if ((*r)->uses_source (src, true)) {
                        return true;
                }
        }
@@ -2672,6 +2683,7 @@ Playlist::uses_source (boost::shared_ptr<const Source> src) const
        return false;
 }
 
+
 boost::shared_ptr<Region>
 Playlist::find_region (const ID& id) const
 {
@@ -2936,25 +2948,6 @@ Playlist::has_region_at (framepos_t const p) const
        return (i != regions.end());
 }
 
-/** Remove any region that uses a given source */
-void
-Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
-{
-       RegionWriteLock rl (this);
-
-       RegionList::iterator i = regions.begin();
-       while (i != regions.end()) {
-               RegionList::iterator j = i;
-               ++j;
-
-               if ((*i)->uses_source (s)) {
-                       remove_region_internal (*i);
-               }
-
-               i = j;
-       }
-}
-
 /** Look from a session frame time and find the start time of the next region
  *  which is on the top layer of this playlist.
  *  @param t Time to look from.
index 91196598700c02880c022c9a540d297dc9135914..20cab959e7b7f567958e62f354334aad6e545f38 100644 (file)
@@ -81,55 +81,55 @@ void
 Region::make_property_quarks ()
 {
        Properties::muted.property_id = g_quark_from_static_string (X_("muted"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n",       Properties::muted.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for muted = %1\n",       Properties::muted.property_id));
        Properties::opaque.property_id = g_quark_from_static_string (X_("opaque"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n",      Properties::opaque.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for opaque = %1\n",      Properties::opaque.property_id));
        Properties::locked.property_id = g_quark_from_static_string (X_("locked"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n",      Properties::locked.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for locked = %1\n",      Properties::locked.property_id));
        Properties::video_locked.property_id = g_quark_from_static_string (X_("video-locked"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for video-locked = %1\n",        Properties::video_locked.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for video-locked = %1\n",        Properties::video_locked.property_id));
        Properties::automatic.property_id = g_quark_from_static_string (X_("automatic"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n",   Properties::automatic.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for automatic = %1\n",   Properties::automatic.property_id));
        Properties::whole_file.property_id = g_quark_from_static_string (X_("whole-file"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n",  Properties::whole_file.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for whole-file = %1\n",  Properties::whole_file.property_id));
        Properties::import.property_id = g_quark_from_static_string (X_("import"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n",      Properties::import.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for import = %1\n",      Properties::import.property_id));
        Properties::external.property_id = g_quark_from_static_string (X_("external"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n",    Properties::external.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for external = %1\n",    Properties::external.property_id));
        Properties::sync_marked.property_id = g_quark_from_static_string (X_("sync-marked"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n",         Properties::sync_marked.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-marked = %1\n",         Properties::sync_marked.property_id));
        Properties::left_of_split.property_id = g_quark_from_static_string (X_("left-of-split"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n",       Properties::left_of_split.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for left-of-split = %1\n",       Properties::left_of_split.property_id));
        Properties::right_of_split.property_id = g_quark_from_static_string (X_("right-of-split"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n",      Properties::right_of_split.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for right-of-split = %1\n",      Properties::right_of_split.property_id));
        Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",      Properties::hidden.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",      Properties::hidden.property_id));
        Properties::position_locked.property_id = g_quark_from_static_string (X_("position-locked"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n",     Properties::position_locked.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position-locked = %1\n",     Properties::position_locked.property_id));
        Properties::valid_transients.property_id = g_quark_from_static_string (X_("valid-transients"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n",    Properties::valid_transients.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for valid-transients = %1\n",    Properties::valid_transients.property_id));
        Properties::start.property_id = g_quark_from_static_string (X_("start"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n",       Properties::start.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for start = %1\n",       Properties::start.property_id));
        Properties::length.property_id = g_quark_from_static_string (X_("length"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n",      Properties::length.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for length = %1\n",      Properties::length.property_id));
        Properties::position.property_id = g_quark_from_static_string (X_("position"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n",    Properties::position.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position = %1\n",    Properties::position.property_id));
        Properties::sync_position.property_id = g_quark_from_static_string (X_("sync-position"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n",       Properties::sync_position.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sync-position = %1\n",       Properties::sync_position.property_id));
        Properties::layer.property_id = g_quark_from_static_string (X_("layer"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n",       Properties::layer.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layer = %1\n",       Properties::layer.property_id));
        Properties::ancestral_start.property_id = g_quark_from_static_string (X_("ancestral-start"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n",     Properties::ancestral_start.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-start = %1\n",     Properties::ancestral_start.property_id));
        Properties::ancestral_length.property_id = g_quark_from_static_string (X_("ancestral-length"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n",    Properties::ancestral_length.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for ancestral-length = %1\n",    Properties::ancestral_length.property_id));
        Properties::stretch.property_id = g_quark_from_static_string (X_("stretch"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n",     Properties::stretch.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for stretch = %1\n",     Properties::stretch.property_id));
        Properties::shift.property_id = g_quark_from_static_string (X_("shift"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n",       Properties::shift.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for shift = %1\n",       Properties::shift.property_id));
        Properties::position_lock_style.property_id = g_quark_from_static_string (X_("positional-lock-style"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n",         Properties::position_lock_style.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for position_lock_style = %1\n",         Properties::position_lock_style.property_id));
        Properties::layering_index.property_id = g_quark_from_static_string (X_("layering-index"));
-       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n",      Properties::layering_index.property_id));
+       DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for layering_index = %1\n",      Properties::layering_index.property_id));
 }
 
 void
@@ -1522,19 +1522,59 @@ Region::source_string () const
        return res.str();
 }
 
+void
+Region::deep_sources (std::set<boost::shared_ptr<Source> > & sources) const
+{
+       for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+
+               boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
+
+               if (ps) {
+                       if (sources.find (ps) == sources.end()) {
+                               ps->playlist()->deep_sources (sources);
+                               cerr << ps->name() << " new source\n";
+                       } else {
+                               cerr << ps->name() << " already in source list\n";
+                       }
+               }
+
+               sources.insert (*i);
+               cerr << "Added src " << (*i)->name() << endl;
+       }
+
+       for (SourceList::const_iterator i = _master_sources.begin(); i != _master_sources.end(); ++i) {
+
+               boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
+
+               if (ps) {
+                       if (sources.find (ps) == sources.end()) {
+                               ps->playlist()->deep_sources (sources);
+                               cerr << ps->name() << " new source2\n";
+                       } else {
+                               cerr << ps->name() << " already in source list2\n";
+                       }
+               }
+
+               sources.insert (*i);
+               cerr << "Added master src " << (*i)->name() << endl;
+       }
+}
+
 bool
-Region::uses_source (boost::shared_ptr<const Source> source) const
+Region::uses_source (boost::shared_ptr<const Source> source, bool shallow) const
 {
        for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
                if (*i == source) {
                        return true;
                }
 
-               boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
+               if (!shallow) {
+                       boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
 
-               if (ps) {
-                       if (ps->playlist()->uses_source (source)) {
-                               return true;
+                       if (ps) {
+                               if (ps->playlist()->uses_source (source)) {
+                                       return true;
+                               }
                        }
                }
        }
@@ -1544,11 +1584,13 @@ Region::uses_source (boost::shared_ptr<const Source> source) const
                        return true;
                }
 
-               boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
+               if (!shallow) {
+                       boost::shared_ptr<PlaylistSource> ps = boost::dynamic_pointer_cast<PlaylistSource> (*i);
 
-               if (ps) {
-                       if (ps->playlist()->uses_source (source)) {
-                               return true;
+                       if (ps) {
+                               if (ps->playlist()->uses_source (source)) {
+                                       return true;
+                               }
                        }
                }
        }
@@ -1556,6 +1598,7 @@ Region::uses_source (boost::shared_ptr<const Source> source) const
        return false;
 }
 
+
 framecnt_t
 Region::source_length(uint32_t n) const
 {
index b9a1e8d624b62774cf08d7e92f8086edd6f10621..549d0a252e59249654bdb5224193efacd65c7d61 100644 (file)
@@ -636,7 +636,7 @@ RegionFactory::get_regions_using_source (boost::shared_ptr<Source> s, std::set<b
 {
        Glib::Threads::Mutex::Lock lm (region_map_lock);
 
-       for (RegionMap::iterator i = region_map.begin(); i != region_map.end(); ++i) {
+       for (RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
                if (i->second->uses_source (s)) {
                        r.insert (i->second);
                }
index 649d42902bfa4f846a840c9c8c7ba17913ce858e..c2e0461546ec06332b336db7d2c347af21578805 100644 (file)
@@ -260,6 +260,7 @@ SessionPlaylists::source_use_count (boost::shared_ptr<const Source> src) const
 {
        uint32_t count = 0;
 
+       cerr << "\t\tcheck " << playlists.size() << " playlists\n";
        for (List::const_iterator p = playlists.begin(); p != playlists.end(); ++p) {
                 if ((*p)->uses_source (src)) {
                         ++count;
@@ -267,6 +268,7 @@ SessionPlaylists::source_use_count (boost::shared_ptr<const Source> src) const
                 }
        }
 
+       cerr << "\t\tcheck " << playlists.size() << " unused playlists\n";
        for (List::const_iterator p = unused_playlists.begin(); p != unused_playlists.end(); ++p) {
                 if ((*p)->uses_source (src)) {
                         ++count;
@@ -500,3 +502,20 @@ SessionPlaylists::playlists_for_track (boost::shared_ptr<Track> tr) const
 
        return pl_tr;
 }
+
+void
+SessionPlaylists::foreach (boost::function<void(boost::shared_ptr<const Playlist>)> functor)
+{
+       Glib::Threads::Mutex::Lock lm (lock);
+       for (List::iterator i = playlists.begin(); i != playlists.end(); i++) {
+               if (!(*i)->hidden()) {
+                       functor (*i);
+               }
+       }
+       for (List::iterator i = unused_playlists.begin(); i != unused_playlists.end(); i++) {
+               if (!(*i)->hidden()) {
+                       functor (*i);
+               }
+       }
+}
+
index 0075799a16e2bc813b28650fb9b4f5befaee8de4..752c8d03c956a171f3dfebc8461a707afa5cd11f 100644 (file)
@@ -2872,14 +2872,17 @@ Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_th
                return 0;
        }
 
-       this_snapshot_path = _path;
-       this_snapshot_path += legalize_for_path (_current_snapshot_name);
+       this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
        this_snapshot_path += statefile_suffix;
 
        for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
 
+               cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
+
                if (exclude_this_snapshot && *i == this_snapshot_path) {
+                       cerr << "\texcluded\n";
                        continue;
+
                }
 
                if (find_all_sources (*i, result) < 0) {
@@ -3010,6 +3013,12 @@ Session::cleanup_peakfiles ()
        return 0;
 }
 
+static void
+merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
+{
+       pl->deep_sources (*all_sources);
+}
+
 int
 Session::cleanup_sources (CleanupReport& rep)
 {
@@ -3020,14 +3029,14 @@ Session::cleanup_sources (CleanupReport& rep)
        string midi_path;
        vector<string> candidates;
        vector<string> unused;
-       set<string> all_sources;
-       bool used;
+       set<string> sources_used_by_all_snapshots;
        string spath;
        int ret = -1;
        string tmppath1;
        string tmppath2;
        Searchpath asp;
        Searchpath msp;
+       set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
 
        _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
 
@@ -3098,12 +3107,21 @@ Session::cleanup_sources (CleanupReport& rep)
        find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
        find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
 
-       /* find all sources, but don't use this snapshot because the
-          state file on disk still references sources we may have already
-          dropped.
+       /* add sources from all other snapshots as "used", but don't use this
+          snapshot because the state file on disk still references sources we
+          may have already dropped.
        */
 
-       find_all_sources_across_snapshots (all_sources, true);
+       find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
+
+       /* Although the region factory has a list of all regions ever created
+        * for this session, we're only interested in regions actually in
+        * playlists right now. So merge all playlist regions lists together.
+        *
+        * This will include the playlists used within compound regions.
+        */
+
+       playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
 
        /*  add our current source list
         */
@@ -3113,59 +3131,76 @@ Session::cleanup_sources (CleanupReport& rep)
                 SourceMap::iterator tmp = i;
                 ++tmp;
 
-               if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
+               if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
+                       /* not a file */
+                       i = tmp;
+                       continue;
+               }
 
-                       /* this is mostly for windows which doesn't allow file
-                        * renaming if the file is in use. But we don't special
-                        * case it because we need to know if this causes
-                        * problems, and the easiest way to notice that is to
-                        * keep it in place for all platforms.
-                        */
+               /* this is mostly for windows which doesn't allow file
+                * renaming if the file is in use. But we do not special
+                * case it because we need to know if this causes
+                * problems, and the easiest way to notice that is to
+                * keep it in place for all platforms.
+                */
 
-                       fs->close ();
+               fs->close ();
 
-                       if (!fs->is_stub()) {
+               if (!fs->is_stub()) {
 
-                               if (playlists->source_use_count (fs) != 0) {
-                                       all_sources.insert (fs->path());
-                               } else {
+                       /* Note that we're checking a list of all
+                        * sources across all snapshots with the list
+                        * of sources used by this snapshot.
+                        */
 
-                                       /* we might not remove this source from disk, because it may be used
-                                          by other snapshots, but its not being used in this version
-                                          so lets get rid of it now, along with any representative regions
-                                          in the region list.
-                                       */
+                       if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
+                               /* this source is in use by this snapshot */
+                               sources_used_by_all_snapshots.insert (fs->path());
+                               cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
+                       } else {
+                               cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
+                               /* this source is NOT in use by this snapshot
+                                */
 
-                                       RegionFactory::remove_regions_using_source (i->second);
+                               /* remove all related regions from RegionFactory master list
+                                */
 
-                                       // also remove source from all_sources
+                               RegionFactory::remove_regions_using_source (i->second);
 
-                                       for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
-                                               spath = Glib::path_get_basename (*j);
-                                               if (spath == i->second->name()) {
-                                                       all_sources.erase (j);
-                                                       break;
-                                               }
-                                       }
+                               /* remove from our current source list
+                                * also. We may not remove it from
+                                * disk, because it may be used by
+                                * other snapshots, but it isn't used inside this
+                                * snapshot anymore, so we don't need a
+                                * reference to it.
+                                */
 
-                                       sources.erase (i);
-                               }
+                               sources.erase (i);
                        }
                }
 
                 i = tmp;
        }
 
+       /* now check each candidate source to see if it exists in the list of
+          sources_used_by_all_snapshots. If it doesn't, put it into "unused".
+       */
+
+       cerr << "Candidates: " << candidates.size() << endl;
+       cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
+
        for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
 
-               used = false;
+               bool used = false;
                spath = *x;
 
-               for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
+               for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
 
                        tmppath1 = canonical_path (spath);
                        tmppath2 = canonical_path ((*i));
 
+                       cerr << "\t => " << tmppath2 << endl;
+
                        if (tmppath1 == tmppath2) {
                                used = true;
                                break;
@@ -3177,6 +3212,14 @@ Session::cleanup_sources (CleanupReport& rep)
                }
        }
 
+       cerr << "Actually unused: " << unused.size() << endl;
+
+       if (unused.empty()) {
+               /* Nothing to do */
+               ret = 0;
+               goto out;
+       }
+
        /* now try to move all unused files into the "dead" directory(ies) */
 
        for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
@@ -3239,19 +3282,13 @@ Session::cleanup_sources (CleanupReport& rep)
                                newpath = newpath_v;
                        }
 
-               } else {
-
-                       /* it doesn't exist, or we can't read it or something */
-
                }
 
                g_stat ((*x).c_str(), &statbuf);
 
                if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
-                       error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
-                                         (*x), newpath, strerror (errno))
-                             << endmsg;
-                       goto out;
+                       error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x), newpath, strerror (errno)) << endmsg;
+                       continue;
                }
 
                /* see if there an easy to find peakfile for this file, and remove it.