Files
amethyst/quartz/src
Claude 50486341a6 fix(quartz): back Apple LargeCache with StripedHashMap, not CacheMap
NostrSignerRemotePrivateZapTest failed on iosSimulatorArm64 with
kotlin.ConcurrentModificationException. Apple's LargeCache wrapped
charlietap's CacheMap, a left-right map whose entries/keys/values return
live views of an inner HashMap and drop the read guard before the caller
iterates. Every bulk op (filter, map, keys(), even forEach's
entries.toList() "snapshot") therefore walked a HashMap a writer could be
mutating, and Kotlin/Native's HashMap throws CME when that happens. The
bunker round-trip has NostrClient's pool scanning its LargeCaches while
subscribe/publish mutate them from other threads.

Reproduced on linuxX64 (same Kotlin/Native HashMap) by racing CacheMap
scans against put/remove workers: kotlin.ConcurrentModificationException.

Linux already had a purpose-built replacement, StripedHashMap: lock-free,
weakly consistent reads and striped-lock writes, so scans never throw and
never copy. It only needs PlatformLock, which has a parking
(NSRecursiveLock) Apple actual. Move it and the LargeCache /
ConcurrentHashCache actuals from linuxMain to nativeMain so Apple uses
them too, move their tests to nativeTest so they run on iOS, and drop the
now-unused cachemap dependency.

Adds LargeCacheConcurrencyTest.scansNeverThrowWhileKeysComeAndGo, which
covers the filter/map/keys/values/forEach scans against concurrent puts
and removes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PcC7xe3bTb9fnJhESGukuD
2026-10-02 15:43:13 +00:00
..