From 220bcfb9e2466081c0dbad7e216f512d97a34a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Fri, 6 Jan 2023 15:24:50 +0100 Subject: [PATCH] [ui] maximum number of thumbnails on disk --- meshroom/ui/app.py | 9 ++++++-- meshroom/ui/components/thumbnail.py | 36 +++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/meshroom/ui/app.py b/meshroom/ui/app.py index 5a3ed33f..65953efc 100644 --- a/meshroom/ui/app.py +++ b/meshroom/ui/app.py @@ -122,9 +122,14 @@ class MeshroomApp(QApplication): ThumbnailCache.thumbnailDir = thumbnailDir # User specifed time limit for thumbnails on disk (expressed in days) - thumbnailTimeLimit = float(os.getenv('MESHROOM_THUMBNAIL_TIME_LIMIT')) + thumbnailTimeLimit = os.getenv('MESHROOM_THUMBNAIL_TIME_LIMIT') if thumbnailTimeLimit is not None: - ThumbnailCache.storageTimeLimit = thumbnailTimeLimit + ThumbnailCache.storageTimeLimit = float(thumbnailTimeLimit) + + # User specifed maximum number of thumbnails on disk + thumbnailMaxNumberOnDisk = os.getenv('MESHROOM_MAX_THUMBNAILS_ON_DISK') + if thumbnailMaxNumberOnDisk is not None: + ThumbnailCache.maxThumbnailsOnDisk = int(thumbnailMaxNumberOnDisk) # Clean thumbnail directory ThumbnailCache.clean() diff --git a/meshroom/ui/components/thumbnail.py b/meshroom/ui/components/thumbnail.py index e1ca3737..45ac2dff 100644 --- a/meshroom/ui/components/thumbnail.py +++ b/meshroom/ui/components/thumbnail.py @@ -21,8 +21,14 @@ class ThumbnailCache(QObject): This class also takes care of cleaning the thumbnail directory, i.e. scanning this directory and removing thumbnails that have not been used for too long. - The default time limit is 90 days. - This time limit can be overriden with the MESHROOM_THUMBNAIL_TIME_LIMIT environment variable. + This operation also ensures that the number of thumbnails on disk does not exceed a certain limit, + by removing thumbnails if necessary (from least recently used to most recently used). + + The default time limit is 90 days, + and can be overriden with the MESHROOM_THUMBNAIL_TIME_LIMIT environment variable. + + The default maximum number of thumbnails on disk is 100000, + and can be overriden with the MESHROOM_MAX_THUMBNAILS_ON_DISK. The main use case for thumbnails in Meshroom is in the ImageGallery. """ @@ -36,6 +42,9 @@ class ThumbnailCache(QObject): # Time limit for thumbnail storage on disk, expressed in days storageTimeLimit = 90 + # Maximum number of thumbnails in the cache directory + maxThumbnailsOnDisk = 100000 + @Slot(QUrl, result=QUrl) def thumbnail(self, imgSource): """ @@ -100,8 +109,9 @@ class ThumbnailCache(QObject): @staticmethod def clean(): """ - Scan the thumbnail directory and - remove all thumbnails that have not been used for more than storageTimeLimit days. + Scan the thumbnail directory and: + 1. remove all thumbnails that have not been used for more than storageTimeLimit days + 2. ensure that the number of thumbnails on disk does not exceed maxThumbnailsOnDisk. """ # Check if thumbnail directory exists if not os.path.exists(ThumbnailCache.thumbnailDir): @@ -113,6 +123,7 @@ class ThumbnailCache(QObject): # Scan thumbnail directory and gather all thumbnails to remove toRemove = [] + remaining = [] for entry in os.scandir(ThumbnailCache.thumbnailDir): if not entry.is_file(): continue @@ -122,12 +133,27 @@ class ThumbnailCache(QObject): storageTime = now - lastUsage logging.debug(f'[ThumbnailCache] Thumbnail {entry.name} has been stored for {storageTime}s') - # Mark as removable if storage time exceeds limit if storageTime > ThumbnailCache.storageTimeLimit * 3600 * 24: + # Mark as removable if storage time exceeds limit logging.debug(f'[ThumbnailCache] {entry.name} exceeded storage time limit') toRemove.append(entry.path) + else: + # Store path and last usage time for potentially sorting and removing later + remaining.append((entry.path, lastUsage)) # Remove all thumbnails marked as removable for path in toRemove: logging.debug(f'[ThumbnailCache] Remove {path}') os.remove(path) + + # Check if number of thumbnails on disk exceeds limit + if len(remaining) > ThumbnailCache.maxThumbnailsOnDisk: + nbToRemove = len(remaining) - ThumbnailCache.maxThumbnailsOnDisk + logging.debug(f'[ThumbnailCache] Too many thumbnails: {len(remaining)} remaining, {nbToRemove} will be removed') + + # Sort by last usage order and remove excess + remaining.sort(key=lambda elt: elt[1]) + for i in range(nbToRemove): + path = remaining[i][0] + logging.debug(f'[ThumbnailCache] Remove {path}') + os.remove(path)