feat: [SDK-5065] share crash-record retention policy across platforms - #20
Open
abdulraqeeb33 wants to merge 2 commits into
Open
feat: [SDK-5065] share crash-record retention policy across platforms#20abdulraqeeb33 wants to merge 2 commits into
abdulraqeeb33 wants to merge 2 commits into
Conversation
Retention was Android-only: an age ceiling, count and byte caps, and a write-time size limit that together keep the crash directory bounded. iOS implements ILogFileStore independently and has none of them, so a record that never uploads is re-read and re-POSTed on every launch and the directory grows until the OS reclaims the cache. The policy is pure decision logic over a directory listing, so it belongs here rather than in either platform. CrashRetention takes entries plus a clock reading and returns what to reclaim; platforms keep only the file I/O. Exposed as an object so Swift sees CrashRetention.shared rather than a file facade, and every bound is a defaulted parameter so a platform whose payload profile differs can tune it without forking the algorithm. Also corrects the ILogFileStore contract, which told implementers that owned records "must always be preserved". Following that literally is what leaves the directory unbounded. It now states the retention obligations and points at the shared helpers. 20 tests run in commonTest against fixed timestamps and no filesystem, green on both the iOS simulator and Android JVM. Co-authored-by: Cursor <cursoragent@cursor.com>
Kotlin `const val` is folded at compile time and never reaches the generated Objective-C header, so Swift callers could see CrashRetention.shared but none of the bounds it is parameterized by — the API was unusable from iOS, which is the platform it exists for. Verified against the built XCFramework header: only `shared` was exported. Plain `val` does cross the boundary. Renamed to camelCase at the same time since this is now a Swift-facing surface and the values are no longer compile-time constants. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
|
The shared policy looks right under the production defaults, and the tests lock the overflow cases that matter. A few things to fix before merge, since this is the Swift-facing surface the iOS follow-up will copy from:
The rest (no callers yet, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
One Line Summary
Moves the crash-record retention policy (age ceiling, count/byte caps, write-size limit) into
commonMainso iOS gets it too, and corrects theILogFileStorecontract that currently mandates the unbounded behavior.Relates to SDK-5065.
Why
Removing OpenTelemetry took
disk-buffering's retention with it. Android rebuilt that policy over several review rounds; iOS implementsILogFileStoreindependently in Swift and has none of it:save()enforces no size limitlistReadable()has only the lowerminAgeMillisgate, no ceilingdeleteUnrecognizedEntries()reaps only.otlp.tmp, never owned records at any ageSo an iOS crash record that fails to upload is re-read and re-POSTed every launch, indefinitely. The directory sits under
.cachesDirectory, so the OS reclaims the disk under pressure — but the repeated re-upload is unmitigated.Retention is pure decision logic over a directory listing. It was only in the Android module by accident of where it was written.
What
CrashRetentionincommonMainowns the policy: ownership by suffix, expiry, overflow selection, a cheap within-caps predicate for crash paths, and the inventory formatter. Platforms supply the listing and a clock reading, then apply the returned decisions with their own I/O.Design notes:
object, not top-level functions, so Swift seesCrashRetention.shared.selectOverflowOwned(...)rather than aCrashRetentionKtfile facade.isWithinCapsuses the same capped-claim arithmetic asselectOverflowOwned, so a crash-path fast exit can never disagree with the selector about whether work is needed. Android shipped a bug from exactly that disagreement.Contract correction
ILogFileStoretold implementers that owned records "must always be preserved". Taken literally — as iOS did — that is what leaves the directory unbounded. The KDoc now states the retention obligations and points at the shared helpers, anddeleteUnrecognizedEntriesdocuments that it is the only scan that runs when remote logging is off, so it is the sole chance to bound a directory nothing else reads.Behavior change
None for Android — this is a lift of logic it already runs, with tests that already pass. iOS behavior does not change in this PR either; adopting
CrashRetentioninFileLogStore.swiftis a follow-up in the iOS repo.Testing
20 tests in
commonTestcovering ownership, the exact-ceiling and future-timestamp boundaries, oldest-first eviction, the skip-not-cutoff rule,keepNameincluding the oversized case, name-based tie-breaking, cheap-path agreement with the selector, and inventory formatting. Fixed timestamps, no filesystem.Green on both
iosSimulatorArm64TestandtestDebugUnitTest— the same 20 assertions on both platforms, which is the point.:kmp:allTestsandspotlessCheckpass.Made with Cursor