Skip to content

feat(remote-config): store inlined blobs to disk#7073

Open
rickvdl wants to merge 4 commits into
rickvdl/remote-config-container-validationfrom
rickvdl/remote-config-blob-store
Open

feat(remote-config): store inlined blobs to disk#7073
rickvdl wants to merge 4 commits into
rickvdl/remote-config-container-validationfrom
rickvdl/remote-config-blob-store

Conversation

@rickvdl

@rickvdl rickvdl commented Jun 23, 2026

Copy link
Copy Markdown
Member

Part of a stack of PRs, builds on #7074 and aligned with Android PR RevenueCat/purchases-android#3615.

How it works

The decision on when to store / delete / keep (inlined) blobs on disk can get a bit complicated, so I generated some psuedo code that might help understand the process.

/// Start from the topic blob refs we already knew about.
topicBlobRefsToKeep = previousCache.topicBlobRefs

// Anything included in the new response replaces the cached value.
for topic in response.topics {
    topicBlobRefsToKeep[topic.name] = topic.blobRefs
}

// Anything no longer active is removed from the topic ref list.
topicBlobRefsToKeep = topicBlobRefsToKeep.filter { topic, _ in
    response.activeTopics.contains(topic)
}

// Final wanted blob set:
// - current response prefetch blobs
// - blob refs for all active topics after applying the response
blobRefsToKeep =
    Set(response.prefetchBlobs)
    + allBlobRefs(in: topicBlobRefsToKeep)

// Add/write inline blobs from this container only if we want them.
for inlineBlob in container.inlineBlobs {
    guard blobRefsToKeep.contains(inlineBlob.ref) else { continue }
    guard inlineBlob.checksumIsValid else { continue }

    blobStore.write(inlineBlob)
}

// Remove anything already on disk that is not wanted anymore.
for cachedBlobRef in blobStore.cachedRefs {
    if !blobRefsToKeep.contains(cachedBlobRef) {
        blobStore.delete(cachedBlobRef)
    }
}

So basically the blob refs we want to keep are:

`blobRefsToKeep`  = `prefetch_blobs` from the new response
    +
active topic `blob_refs` after merging the new response's topics with the unchanged cached topics

After that we'll store any inlined blobs if they are in the blobRefsToKeep list and valid (checksum matches) and we'll delete any cached blobs if they are no longer in blobRefsToKeep


Note

Medium Risk
Changes remote config on-disk state, blob retention, and what the SDK tells the server it already has; mistakes could drop cached blobs or skew sync, though checksum checks, ref validation, and tests mitigate this.

Overview
Adds a content-addressed on-disk blob cache (RemoteConfigBlobStore) under remote config storage and wires it into refresh persistence so inline container payloads can be kept locally across launches.

On a successful container response, RemoteConfigManager now computes which blob refs should exist (response prefetch_blobs plus active-topic refs after merging/pruning), writes only referenced inline elements with valid checksums, persists JSON state (including new prefetchedBlobRefs for refs actually present on disk), and prunes the blob directory via retainOnly—but only after the disk cache write succeeds. Refresh requests advertise prefetchedBlobs using persisted refs that still exist in the blob store, not the full server prefetch list.

RemoteConfigDiskCache.write returns Bool; shared RemoteConfigStorage centralizes the config directory path. New log strings cover blob read/write/delete and invalid checksum skips. Unit tests cover the blob store (including malformed ref rejection) and expanded manager/cache behavior.

Reviewed by Cursor Bugbot for commit 21b1db7. Bugbot is set up for automated code reviews on this repo. Configure here.

@emerge-tools

emerge-tools Bot commented Jun 23, 2026

Copy link
Copy Markdown

4 builds increased size

Name Version Download Change Install Change Approval
RevenueCat
com.revenuecat.PaywallsTester
1.0 (1) 19.0 MB ⬆️ 66.3 kB (0.35%) 68.6 MB ⬆️ 243.9 kB (0.36%) N/A
BinarySizeTest
com.revenuecat.binary-size-test.local-source
1.0 (1) 4.4 MB ⬆️ 8.3 kB (0.19%) 13.2 MB ⬆️ 28.9 kB (0.22%) ⏳ Needs approval
BinarySizeTest
com.revenuecat.binary-size-test.cocoapods
1.0 (1) 6.6 MB ⬆️ 14.4 kB (0.22%) 29.0 MB ⬆️ 50.0 kB (0.17%) ⏳ Needs approval
BinarySizeTest
com.revenuecat.binary-size-test.spm
1.0 (1) 4.5 MB ⬆️ 7.2 kB (0.16%) 11.5 MB ⬆️ 25.3 kB (0.22%) ⏳ Needs approval

RevenueCat 1.0 (1)
com.revenuecat.PaywallsTester

⚖️ Compare build
⏱️ Analyze build performance

Total install size change: ⬆️ 243.9 kB (0.36%)
Total download size change: ⬆️ 66.3 kB (0.35%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 73.2 kB
Code Signature ⬆️ 5.6 kB
DYLD.Exports ⬆️ 5.6 kB
Strings.Unmapped ⬆️ 1.2 kB
📝 RevenueCat.RemoteConfigManager.RemoteConfigManager ⬆️ 548 B
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.local-source

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 28.9 kB (0.22%)
Total download size change: ⬆️ 8.3 kB (0.19%)

Largest size changes

Item Install Size Change
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 8.7 kB
DYLD.String Table ⬆️ 1.7 kB
📝 RevenueCat.RCContainer.Element.withBytes(in) ⬆️ 1.6 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
📝 RevenueCat.RemoteConfigStrings.description ⬆️ 1.4 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.cocoapods

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 50.0 kB (0.17%)
Total download size change: ⬆️ 14.4 kB (0.22%)

Largest size changes

Item Install Size Change
DYLD.String Table ⬆️ 14.3 kB
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 8.7 kB
📝 RevenueCat.RCContainer.Element.withBytes(in) ⬆️ 1.6 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
Code Signature ⬆️ 1.5 kB
View Treemap

Image of diff

BinarySizeTest 1.0 (1)
com.revenuecat.binary-size-test.spm

⚖️ Compare build
📦 Install build
⏱️ Analyze build performance

Total install size change: ⬆️ 25.3 kB (0.22%)
Total download size change: ⬆️ 7.2 kB (0.16%)

Largest size changes

Item Install Size Change
📝 RevenueCat.RemoteConfigStrings.value witness ⬆️ 8.7 kB
📝 RevenueCat.RCContainer.Element.withBytes(in) ⬆️ 1.6 kB
🗑 RevenueCat.RCContainer.Parser.checksumString(in) ⬇️ -1.5 kB
📝 RevenueCat.RemoteConfigStrings.description ⬆️ 1.4 kB
📝 RevenueCat.RCContainer.Element.payloadChecksum ⬆️ 1.4 kB
View Treemap

Image of diff


🛸 Powered by Emerge Tools

Comment trigger: Size diff threshold of 100.00kB exceeded

@RevenueCat-Danger-Bot

RevenueCat-Danger-Bot commented Jun 23, 2026

Copy link
Copy Markdown

❌ CI Job Failed — run-test-ios-26

View Build

@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from 6395a96 to 75cb074 Compare June 23, 2026 10:51
@rickvdl rickvdl changed the base branch from rickvdl/remote-config-manager-config-cache to rickvdl/remote-config-container-validation June 23, 2026 10:51
@rickvdl

rickvdl commented Jun 23, 2026

Copy link
Copy Markdown
Member Author

@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from 75cb074 to 8bb16f8 Compare June 23, 2026 14:00
@rickvdl rickvdl force-pushed the rickvdl/remote-config-container-validation branch from df013db to bc6262d Compare June 23, 2026 14:24
@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from 8bb16f8 to c61505d Compare June 23, 2026 14:26
@rickvdl rickvdl changed the title feat(remote-config): add blob store feat(remote-config): store inlined blobs to disk Jun 24, 2026
@rickvdl rickvdl force-pushed the rickvdl/remote-config-container-validation branch from bc6262d to 0efbcc6 Compare June 24, 2026 11:11
@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from c61505d to 00af423 Compare June 24, 2026 11:16
@rickvdl

rickvdl commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

@RCGitBot please test

@rickvdl rickvdl marked this pull request as ready for review June 25, 2026 05:17
@rickvdl rickvdl requested a review from a team as a code owner June 25, 2026 05:17
@rickvdl

rickvdl commented Jun 25, 2026

Copy link
Copy Markdown
Member Author

@RCGitBot please test

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3e8be9b. Configure here.

Comment thread Sources/Networking/RemoteConfigManager.swift
Comment thread Sources/Networking/RemoteConfigBlobStore.swift
Comment thread Sources/Networking/RemoteConfigBlobStore.swift
@rickvdl rickvdl force-pushed the rickvdl/remote-config-container-validation branch from c2e57c7 to 560c8e3 Compare June 25, 2026 06:24
@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from b1aa3e8 to eddd148 Compare June 25, 2026 06:28
@rickvdl rickvdl force-pushed the rickvdl/remote-config-container-validation branch from 560c8e3 to f87390e Compare June 25, 2026 07:11
@rickvdl rickvdl force-pushed the rickvdl/remote-config-blob-store branch from eddd148 to 21b1db7 Compare June 25, 2026 07:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants