perf: fix slow duplicate-group navigation and related redundant calls (#118) #133
No reviewers
Labels
No labels
Kind/Bug
Kind/Feature
Priority/High
Priority/Medium
Reviewed/Confirmed
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ai-collab/bulk-image-organizer!133
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "0.2.0/issue-118-dupe-group-nav-perf"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes #118 (slow duplicate-group navigation), then expanded into a general audit for the same redundant-call bug classes elsewhere in the app.
Root causes in the Duplicates workbench (#118):
ImageFilterProxy.set_dupe_group_filter(and a redundant second call inmain_window._apply_dupe_group_filter) forced a fullinvalidate()— refilter and resort of the entire image list — on every group navigation click, even though the dupe-group filter never affects sort order.DupeMultiGriddestroyed and recreated every comparison tile (each owning its ownQGraphicsView/QGraphicsScene) on every group switch, instead of reusing them.get_all_tags()queried separately for the current group + 2 preloaded neighbors;count_distinct_dupe_tags()duplicating a count already available).Generalized to the rest of the app (same bug classes):
ImageFilterProxyfilter setters (tag filter, search, hide-deleted, orientation, etc.) shared the same over-broadinvalidate()— fixed for all of them, not just the dupe-group filter.TagPanelfully rebuilt every tag swatch button on every grid selection change and every viewer navigation step. Now updates existing buttons in place.tag_manager.py) opened one SQLite connection per image for planning and applying changes — a 200-image selection meant ~800-1000 connections for one keypress. Added bulkWorkingDBhelpers (get_images_by_paths,get_tags_for_images,add_tags_to_images,remove_tags_from_images) and routed every per-path loop through them.main_window.pyselection/tag-sync helpers, fixed identically.ImageListModel(grid data model) did an O(n) linear scan to find a row by path on every upsert/thumbnail-batch/remove/relocate call — hit repeatedly during scan and thumbnail-generation progress. Added a path→row index for O(1) lookups, and batcheddataChangedemissions per call instead of one per item.Measured ~8x faster for the dupe-grid widget-rebuild step alone in an isolated offscreen benchmark (15.7ms → 1.9ms per switch, excluding image decode/IO).
Test plan
ruff check/ruff format --checkcleanImageListModelscripts/smoke-ui-exit.shclean (no Qt teardown errors) — relevant since several fixes change widget pooling/lifecyclescripts/check-version-bump.shpasses (VERSION bumped 0.2.0 → 0.2.1, compiled inputs changed)🤖 Generated with Claude Code