mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
docs(commons): the cache's sorted store is what blocks commonMain
Correcting yesterday's audit, which said `LargeSoftCache`'s skip-list ordering was not load-bearing and that quartz's `ConcurrentMap` could substitute. Both halves were wrong, from reading only the first half of the file. `LargeSoftCache` implements `CacheOperations` — itself `quartz/jvmAndroid`, not commonMain — for its ranged `forEach(from, to, …)`, backed by `ConcurrentSkipListMap.subMap`. All of `LargeSoftCacheAddressExt` is built on it: `filter(kindStart(kind), kindEnd(kind), …)` walks one kind's slice of the `Address` key space, and `filterIntoSet` has 28 callers. On a hash map each of those degrades to a full scan of every addressable. `quartz/linuxTest/LargeCacheRangeFallbackTest` states the same invariant from the other side: the native range overloads fall back to full scans, and that is deemed safe *because* "the range overloads have no callers outside the JVM-only LargeSoftCache". Promoting the cache makes that false. So the remaining work is not the okio sink plus a `SortedSet` signature change. It needs a sorted KMP store first — an expect/actual `LargeSoftCache` with a hand-written sorted iOS actual, or a KMP sorted-concurrent map that exists in neither the tree nor the stdlib. Recorded as a question to answer before the ordered steps, not as one of them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkULS5SVq4GHDdoCzajKi8
This commit is contained in:
+10
-6
@@ -259,12 +259,16 @@ These are intentionally *documented*, not silently tolerated. Fix opportunistica
|
||||
(`WeakReference` + `ConcurrentSkipListMap`), as are the two
|
||||
`*ListMatchingFilter` observables, `MintDirectoryIndex` and
|
||||
`NwcPaymentTracker`. Promoting the cache means promoting those first.
|
||||
Most of it has answers already in the tree — `commons.util.WeakReference`
|
||||
is an expect/actual, and quartz's `commonMain` has `ConcurrentMap`,
|
||||
`ConcurrentSet` and `LargeCache` — so the genuinely new work is an okio (or
|
||||
`expect`) blob sink and getting `java.util.SortedSet` out of
|
||||
`EventCache.filter`'s signature, which has no common equivalent. See the
|
||||
audit in `commons/plans/2026-08-30-commons-migration-sweep.md`.
|
||||
The binding constraint is `LargeSoftCache`'s **sorted** store: it backs the
|
||||
ranged `forEach(from, to, …)` that all of `LargeSoftCacheAddressExt` uses to
|
||||
scan one kind's slice of the `Address` key space, and a hash map turns each
|
||||
of those into a full scan. `quartz/linuxTest/LargeCacheRangeFallbackTest`
|
||||
documents the matching invariant from the other side — the native range
|
||||
overloads fall back to full scans, and that is deemed safe precisely
|
||||
*because* the range callers live in the JVM-only `LargeSoftCache`. Moving
|
||||
this needs a sorted KMP store first, not just the okio blob sink and the
|
||||
`java.util.SortedSet` signature change. See the audit in
|
||||
`commons/plans/2026-08-30-commons-migration-sweep.md`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1030,11 +1030,15 @@ constraint rather than a hypothetical one.
|
||||
- quartz `commonMain` already ships `ConcurrentMap`, `ConcurrentSet`,
|
||||
`ConcurrentHashCache` and `LargeCache` — so every `ConcurrentHashMap` /
|
||||
`ConcurrentSkipListSet` above is a swap, not a design problem.
|
||||
- `LargeSoftCache`'s skip-list ordering is **not** load-bearing: its whole
|
||||
surface is `get`/`put`/`remove`/`size`/`containsKey`/`keys`/`forEach`, with
|
||||
no ordered read. `ConcurrentSkipListMap` is there for lock-free concurrency,
|
||||
so quartz's `ConcurrentMap` should substitute — worth confirming nothing
|
||||
iterates expecting order before relying on that.
|
||||
- ~~`LargeSoftCache`'s skip-list ordering is not load-bearing~~ — **wrong,
|
||||
corrected 2026-09-21.** It is load-bearing, and it is the thing that stops
|
||||
this migration. `LargeSoftCache` implements `CacheOperations` (which is
|
||||
itself `quartz/jvmAndroid`, not commonMain) for its ranged
|
||||
`forEach(from, to, …)`, backed by `ConcurrentSkipListMap.subMap`. The whole
|
||||
of `LargeSoftCacheAddressExt` is built on it: `filter(kindStart(kind),
|
||||
kindEnd(kind), …)` walks only one kind's slice of the `Address` key space,
|
||||
and `filterIntoSet` is called 28 times. On a hash map every one of those
|
||||
becomes a full scan of all addressables.
|
||||
- `AtomicInteger` → `kotlin.concurrent.atomics`; `BiConsumer` → a function
|
||||
type; the `dateFormatter` call is one log line and can go.
|
||||
- `androidx.collection.LruCache` in `AntiSpamFilter` is already KMP —
|
||||
@@ -1051,7 +1055,23 @@ constraint rather than a hypothetical one.
|
||||
a signature change rippling into `CacheSearch`, both observables and
|
||||
`LocalCacheSearchParityTest`.
|
||||
|
||||
**Recommended order** (bottom-up; each step is independently shippable):
|
||||
**The invariant this would break.** `quartz/linuxTest/LargeCacheRangeFallbackTest`
|
||||
pins the native `LargeCache` range overloads to a deliberate full-scan
|
||||
fallback, and says why that is acceptable: *"the range overloads have no
|
||||
callers outside the JVM-only `LargeSoftCache`"*. Promoting `LargeSoftCache` to
|
||||
`commonMain` makes that statement false. Any move has to either give iOS a
|
||||
genuinely sorted store or accept — explicitly, not silently — that addressable
|
||||
lookups there are full scans.
|
||||
|
||||
**Revised cost.** This is not the swap described above. It needs either an
|
||||
`expect`/`actual` `LargeSoftCache` with a hand-written sorted iOS actual (the
|
||||
`LargeCache` apple actual, for comparison, is 432 lines), or a KMP
|
||||
sorted-concurrent map that does not exist in the tree or the stdlib — which
|
||||
would want a `Comparable` bound on `Address` and would benefit quartz too.
|
||||
Neither is a step; both are projects.
|
||||
|
||||
**Recommended order** (bottom-up; each step is independently shippable), *if
|
||||
the ordering question above is answered first*:
|
||||
|
||||
1. `LargeSoftCache` → `commonMain` on the existing `WeakReference` expect plus
|
||||
quartz's `ConcurrentMap`. This is the keystone — everything else is behind it.
|
||||
|
||||
Reference in New Issue
Block a user