Recreate blobs directory after store schema migration#366
Merged
Conversation
removePreviousStore wipes storeURL on schema-version mismatch and recreates only the top-level directory. The blobs subdirectory created earlier in init() is gone for the remainder of the session, and every Data.write(to: blobsURL/<hex>) inside storeBlob() silently fails because the parent directory is missing. The metadata row is still saved, so the console shows 'Unavailable / The response body was deleted from the store to reduce its size' for any body larger than inlineLimit (16 KB compressed) captured during the upgrade session. Mirror the pattern already used by _removeAll() and recreate the blobs directory at the end of removePreviousStore.
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.
Problem
When
LoggerStoreis initialized against an existing store whosemanifest.jsonversion differs fromcurrentStoreVersion,removePreviousStore(at:)is invoked to wipe the previous data. It removesstoreURLentirely and recreates it as an empty directory — but does not recreate theblobs/subdirectory. Theblobs/directory was created earlier ininit(viaFiles.createDirectoryIfNeeded(at: blobsURL)), and afterremovePreviousStoreit no longer exists for the rest of the session.For every blob captured during this session whose compressed size exceeds
Configuration.inlineLimit(16 KB by default — i.e. almost any real-world JSON response body),storeBlobfalls through to:The write silently fails because the parent directory is missing. The
LoggerBlobHandleEntityrow is still saved (withinlineData == nil, no file on disk), andresponseBodySizeis populated onNetworkTaskEntity. The console then shows:The error message is misleading —
responseBodySizeLimithad nothing to do with it; bumping it doesn't help.Reproduction
Empirical reproduction on iOS 26 simulator with a host app integrating Pulse:
currentStoreVersion = 3.6.0). Capture a network response > 16 KB compressed. Confirm a file exists atcurrent.pulse/blobs/<sha1>matching theZLOGGERBLOBHANDLEENTITY.ZKEYrow.currentStoreVersion = 3.7.0). Relaunch the app without uninstalling (so the oldmanifest.jsonis present). Make another large request. Observe:manifest.jsonis nowversion: \"3.7.0\"(migration ran)blobs/directory exists but is emptyZNETWORKTASKENTITYhas the task with non-zeroZRESPONSEBODYSIZEand a non-nullZRESPONSEBODYFKZLOGGERBLOBHANDLEENTITYrow exists, butZINLINEDATAisNULLand no file exists atblobs/<hex(ZKEY)>Confirmed end-to-end on a real app upgrade path — this is what users will hit when bumping their dependency from 5.1.x to 5.2.x.
Fix
Mirror the cleanup pattern already used by
_removeAll()(LoggerStore.swift:862-863) and recreate theblobs/subdirectory at the end ofremovePreviousStore:After applying the fix, repeating step 2 of the reproduction produces a populated
blobs/<sha1>file matching the entity row, and the response body renders correctly in PulseUI.Scope
One-line change. Affects only the migration path — fresh installs already work because the initial
Files.createDirectoryIfNeeded(at: blobsURL)ininitis never invalidated.