[vlc-commits] [Git][videolan/vlc][master] 2 commits: macosx: Only notify of caches having been dropped after the cache writes are complete

François Cartegnie (@fcartegnie) gitlab at videolan.org
Fri Sep 25 07:58:07 UTC 2026



François Cartegnie pushed to branch master at VideoLAN / VLC


Commits:
f000d09a by Claudio Cambra at 2026-09-25T09:48:51+02:00
macosx: Only notify of caches having been dropped after the cache writes are complete

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -
9e59d4b3 by Claudio Cambra at 2026-09-25T09:48:51+02:00
macosx: Only notify cache changes after writes are actually complete

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -


1 changed file:

- modules/gui/macosx/library/VLCLibraryModel.m


Changes:

=====================================
modules/gui/macosx/library/VLCLibraryModel.m
=====================================
@@ -147,6 +147,8 @@ NSString * const VLCLibraryModelDiscoveryFailed = @"VLCLibraryModelDiscoveryFail
 - (void)handleGenreUpdateEvent:(const vlc_ml_event_t * const)p_event;
 - (void)handleGroupUpdateEvent:(const vlc_ml_event_t * const)p_event;
 - (void)handlePlaylistUpdateEvent:(const vlc_ml_event_t * const)p_event;
+- (void)performAfterCacheWritesOnQueue:(dispatch_queue_t)queue
+                                 block:(dispatch_block_t)block;
 
 @end
 
@@ -482,6 +484,15 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
     return result;
 }
 
+- (void)performAfterCacheWritesOnQueue:(dispatch_queue_t)queue
+                                 block:(dispatch_block_t)block
+{
+    // The sentinel runs after all cache writes already queued on this queue.
+    dispatch_barrier_async(queue, ^{
+        dispatch_async(dispatch_get_main_queue(), block);
+    });
+}
+
 - (void)resetCachedListOfAudioMedia
 {
     dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
@@ -494,8 +505,10 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         vlc_ml_media_list_release(p_media_list);
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedAudioMedia = mediaArray;
-            [self.changeDelegate notifyChange:VLCLibraryModelAudioMediaListReset withObject:self];
-            [self resetCachedListOfMediaTitles];
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelAudioMediaListReset withObject:self];
+                [self resetCachedListOfMediaTitles];
+            }];
         });
     });
 }
@@ -544,7 +557,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedArtists = mutableArtistArray.copy;
             self->_artistDict = mutableArtistDict.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelArtistListReset withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_artistCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelArtistListReset withObject:self];
+            }];
         });
     });
 }
@@ -590,7 +605,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedAlbums = mutableAlbumArray.copy;
             self->_albumDict = mutableAlbumDict.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelAlbumListReset withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_albumCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelAlbumListReset withObject:self];
+            }];
         });
     });
 }
@@ -636,7 +653,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedGenres = mutableGenreArray.copy;
             self->_genreDict = mutableGenreDict.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelGenreListReset withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_genreCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelGenreListReset withObject:self];
+            }];
         });
     });
 }
@@ -681,8 +700,10 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         vlc_ml_media_list_release(p_media_list);
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedVideoMedia = [mutableArray copy];
-            [self.changeDelegate notifyChange:VLCLibraryModelVideoMediaListReset withObject:self];
-            [self resetCachedListOfMediaTitles];
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelVideoMediaListReset withObject:self];
+                [self resetCachedListOfMediaTitles];
+            }];
         });
     });
 }
@@ -721,7 +742,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         NSArray<NSString *> * const sortedTitles = [titleSet.allObjects sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
 
         dispatch_barrier_async(self->_mediaTitlesCacheModificationQueue, ^{
-            self.cachedMediaTitles = sortedTitles;
+            self->_cachedMediaTitles = [sortedTitles copy];
         });
     });
 }
@@ -776,7 +797,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                       withCountLimit:_recentMediaLimit
                       withCompletion:^(NSArray * const mediaArray) {
         self.cachedRecentMedia = mediaArray;
-        [self.changeDelegate notifyChange:VLCLibraryModelRecentsMediaListReset withObject:self];
+        [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+            [self.changeDelegate notifyChange:VLCLibraryModelRecentsMediaListReset withObject:self];
+        }];
     }];
 }
 
@@ -810,7 +833,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                       withCountLimit:_recentAudioMediaLimit
                       withCompletion:^(NSArray * const mediaArray) {
         self.cachedRecentAudioMedia = mediaArray;
-        [self.changeDelegate notifyChange:VLCLibraryModelRecentAudioMediaListReset withObject:self];
+        [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+            [self.changeDelegate notifyChange:VLCLibraryModelRecentAudioMediaListReset withObject:self];
+        }];
     }];
 }
 
@@ -854,7 +879,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         vlc_ml_show_list_release(p_show_list);
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedListOfShows = mutableArray.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelListOfShowsReset withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelListOfShowsReset withObject:self];
+            }];
         });
     });
 }
@@ -881,8 +908,10 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         vlc_ml_media_list_release(p_movie_list);
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedListOfMovies = mutableArray.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelListOfMoviesReset withObject:self];
-            [NSNotificationCenter.defaultCenter postNotificationName:VLCLibraryModelListOfMoviesReset object:self];
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelListOfMoviesReset withObject:self];
+                [NSNotificationCenter.defaultCenter postNotificationName:VLCLibraryModelListOfMoviesReset object:self];
+            }];
         });
     });
 }
@@ -971,7 +1000,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         vlc_ml_group_list_release(p_group_list);
         dispatch_async(dispatch_get_main_queue(), ^{
             self.cachedListOfGroups = mutableArray.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelListOfGroupsReset withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_groupCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelListOfGroupsReset withObject:self];
+            }];
         });
     });
 }
@@ -1064,7 +1095,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
 
             self.cachedListOfMonitoredFolders = mutableArray.copy;
             self.folderObservers = mutableObservers.copy;
-            [self.changeDelegate notifyChange:VLCLibraryModelListOfMonitoredFoldersUpdated withObject:self];
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
+                [self.changeDelegate notifyChange:VLCLibraryModelListOfMonitoredFoldersUpdated withObject:self];
+            }];
         });
     });
 }
@@ -1162,20 +1195,44 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
 
 - (void)dropCaches
 {
-        self.cachedVideoMedia = nil;
-        self.cachedAudioMedia = nil;
-        self.cachedRecentMedia = nil;
-        self.cachedRecentAudioMedia = nil;
-        self.cachedListOfShows = nil;
-        self.cachedListOfMovies = nil;
-        self.cachedListOfMonitoredFolders = nil;
-        self.cachedAlbums = nil;
-        self.cachedArtists = nil;
-        self.cachedGenres = nil;
-        self.cachedListOfGroups = nil;
-        self.cachedMediaTitles = nil;
+    dispatch_queue_t const cacheQueues[] = {
+        _mediaItemCacheModificationQueue,
+        _albumCacheModificationQueue,
+        _artistCacheModificationQueue,
+        _genreCacheModificationQueue,
+        _groupCacheModificationQueue,
+        _mediaTitlesCacheModificationQueue,
+    };
+    const NSUInteger cacheQueueCount = sizeof(cacheQueues) / sizeof(cacheQueues[0]);
+    dispatch_group_t const cacheDropGroup = dispatch_group_create();
+
+    for (NSUInteger index = 0; index < cacheQueueCount; index++) {
+        dispatch_group_enter(cacheDropGroup);
+    }
 
-    [self.changeDelegate notifyChange:VLCLibraryModelAllCachesDropped withObject:self];
+    self.cachedVideoMedia = nil;
+    self.cachedAudioMedia = nil;
+    self.cachedRecentMedia = nil;
+    self.cachedRecentAudioMedia = nil;
+    self.cachedListOfShows = nil;
+    self.cachedListOfMovies = nil;
+    self.cachedListOfMonitoredFolders = nil;
+    self.cachedAlbums = nil;
+    self.cachedArtists = nil;
+    self.cachedGenres = nil;
+    self.cachedListOfGroups = nil;
+    self.cachedMediaTitles = nil;
+
+    // Barrier sentinels complete after the setter writes on each queue.
+    for (NSUInteger index = 0; index < cacheQueueCount; index++) {
+        dispatch_barrier_async(cacheQueues[index], ^{
+            dispatch_group_leave(cacheDropGroup);
+        });
+    }
+
+    dispatch_group_notify(cacheDropGroup, dispatch_get_main_queue(), ^{
+        [self.changeDelegate notifyChange:VLCLibraryModelAllCachesDropped withObject:self];
+    });
 }
 
 - (void)performActionOnMediaItemInCache:(const int64_t)libraryId 
@@ -1286,7 +1343,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
 
         if (recentMediaArray != nil && recentMediaIndex != NSNotFound) {
             [recentMediaArray replaceObjectAtIndex:recentMediaIndex withObject:mediaItem];
-            dispatch_async(dispatch_get_main_queue(), ^{
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
                 switch (mediaItem.mediaType) {
                     case VLC_ML_MEDIA_TYPE_VIDEO:
                         [self.changeDelegate notifyChange:VLCLibraryModelRecentsMediaItemUpdated 
@@ -1300,7 +1357,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                         NSLog(@"Unknown type of media type encountered, don't know what to do in deletion");
                         break;
                 }
-            });
+            }];
         }
 
         if (showsArray != nil && showIndex != NSNotFound) {
@@ -1308,12 +1365,12 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
             VLCMediaLibraryShow * const staleShow = showsArray[showIndex];
             VLCMediaLibraryShow * const updatedShow = [VLCMediaLibraryShow showWithLibraryId:staleShow.libraryID];
             [showsArray replaceObjectAtIndex:showIndex withObject:updatedShow];
-            dispatch_async(dispatch_get_main_queue(), ^{
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
                 [self.changeDelegate notifyChange:VLCLibraryModelShowUpdated withObject:updatedShow];
-            });
+            }];
         }
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
             switch (mediaItem.mediaType) {
                 case VLC_ML_MEDIA_TYPE_VIDEO:
                     [self.changeDelegate notifyChange:VLCLibraryModelVideoMediaItemUpdated 
@@ -1327,7 +1384,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                     NSLog(@"Unknown type of media type encountered, don't know what to do in update");
                     break;
             }
-        });
+        }];
     }];
 }
 
@@ -1358,7 +1415,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
 
         if (recentMediaArray != nil && recentMediaIndex != NSNotFound) {
             [recentMediaArray removeObjectAtIndex:recentMediaIndex];
-            dispatch_async(dispatch_get_main_queue(), ^{
+            [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
                 switch (mediaItem.mediaType) {
                     case VLC_ML_MEDIA_TYPE_VIDEO:
                         [self.changeDelegate notifyChange:VLCLibraryModelRecentsMediaItemDeleted
@@ -1372,7 +1429,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                         NSLog(@"Unknown type of media type encountered, don't know what to do in deletion");
                         break;
                 }
-            });
+            }];
         }
 
         if (showsArray != nil && showIndex != NSNotFound) {
@@ -1382,20 +1439,20 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                 [VLCMediaLibraryShow showWithLibraryId:staleShow.libraryID];
 
             if (updatedShow == nil || updatedShow.episodeCount == 0) {
-                dispatch_async(dispatch_get_main_queue(), ^{
+                [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
                     [self.changeDelegate notifyChange:VLCLibraryModelShowDeleted
                                            withObject:@(staleShow.libraryID)];
-                });
+                }];
             } else {
                 [showsArray replaceObjectAtIndex:showIndex withObject:updatedShow];
-                dispatch_async(dispatch_get_main_queue(), ^{
+                [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
                     [self.changeDelegate notifyChange:VLCLibraryModelShowUpdated
                                            withObject:updatedShow];
-                });
+                }];
             }
         }
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:self->_mediaItemCacheModificationQueue block:^{
             switch (mediaItem.mediaType) {
                 case VLC_ML_MEDIA_TYPE_VIDEO:
                     [self.changeDelegate notifyChange:VLCLibraryModelVideoMediaItemDeleted
@@ -1409,7 +1466,7 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
                     NSLog(@"Unknown type of media type encountered, don't know what to do in deletion");
                     break;
             }
-        });
+        }];
     }];
 }
 
@@ -1458,9 +1515,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         void (*cacheSetterFunction)(id, SEL, NSArray *) = (void *)cacheSetterImp;
         cacheSetterFunction(self, setterSelector, mutableAudioGroupCache.copy);
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:queue block:^{
             [self.changeDelegate notifyChange:notificationName withObject:audioGroupItem];
-        });
+        }];
     });
 }
 
@@ -1499,9 +1556,9 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         void (*cacheSetterFunction)(id, SEL, NSArray *) = (void *)cacheSetterImp;
         cacheSetterFunction(self, setterSelector, mutableAudioGroupCache.copy);
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:queue block:^{
             [self.changeDelegate notifyChange:notificationName withObject:audioGroupItem];
-        });
+        }];
     });
 }
 
@@ -1631,10 +1688,10 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         [mutableGroups removeObjectAtIndex:groupIdx];
         self.cachedListOfGroups = mutableGroups.copy;
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:self->_groupCacheModificationQueue block:^{
             [self->_defaultNotificationCenter postNotificationName:VLCLibraryModelGroupDeleted
                                                             object:groupToDelete];
-        });
+        }];
     });
 }
 
@@ -1672,10 +1729,10 @@ static void libraryCallback(void *p_data, const vlc_ml_event_t *p_event)
         [mutableGroups replaceObjectAtIndex:groupIdx withObject:group];
         self.cachedListOfGroups = mutableGroups.copy;
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        [self performAfterCacheWritesOnQueue:self->_groupCacheModificationQueue block:^{
             [self->_defaultNotificationCenter postNotificationName:VLCLibraryModelGroupUpdated
                                                             object:group];
-        });
+        }];
     });
 }
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c90941a0b9039aabe6e7442f6447ca34f7954c6d...9e59d4b38f804b33491b332df7643c1f80cc0b57

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/c90941a0b9039aabe6e7442f6447ca34f7954c6d...9e59d4b38f804b33491b332df7643c1f80cc0b57
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list