Skip to content

fix: snapshot lastModified before sort in TelegramCacheManager#1899

Merged
theovilardo merged 1 commit into
PixelPlayerHQ:masterfrom
faraz152:fix/telegram-cache-timsort-contract
May 4, 2026
Merged

fix: snapshot lastModified before sort in TelegramCacheManager#1899
theovilardo merged 1 commit into
PixelPlayerHQ:masterfrom
faraz152:fix/telegram-cache-timsort-contract

Conversation

@faraz152

@faraz152 faraz152 commented May 4, 2026

Copy link
Copy Markdown
Contributor

Problem

TelegramCacheManager.trimEmbeddedArtCache() sorted embedded art files with:

embeddedArtFiles.sortBy { it.lastModified() }

File.lastModified() is called for every pairwise comparison during the sort. If a concurrent coroutine touches any of those files (e.g. a Telegram thumbnail download calling setLastModified()), the same file can return a different timestamp in a later comparison — breaking TimSort's transitivity requirement and crashing with:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo

This is the same root cause as the crash reported in #1886 ("app crash when scanning .lrc"), which occurs during the broad sync sweep that runs album-art caching and Telegram operations in parallel.

Fix

Snapshot all lastModified() timestamps into an immutable map before entering the sort, so the comparator always sees a stable value:

val snapshots = embeddedArtFiles.associateWith { it.lastModified() }
embeddedArtFiles.sortWith(compareBy { snapshots[it] })

This is exactly the pattern already applied to AlbumArtCacheManager (snapshotFilesForCleanup).

Test plan

  • Trigger a full library sync while Telegram channel is active — no IllegalArgumentException in logs
  • Verify LRU eviction still deletes oldest embedded art files when cache exceeds limit

Closes #1886

Reading file.lastModified() inside the comparator lambda on every
pairwise comparison lets a concurrent setLastModified() call change
the value mid-sort, breaking TimSort's transitivity requirement and
crashing with 'Comparison method violates its general contract!'.

Snapshot all timestamps into a map before sorting so the comparator
sees a stable, immutable view — the same fix applied to
AlbumArtCacheManager in an earlier commit.
@theovilardo theovilardo merged commit a5c983b into PixelPlayerHQ:master May 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

app crash when scanning .lrc

2 participants