Skip to content

perf: Cache installationId lookup in ParseClient.buildHeaders#1

Open
AdrianCurtin wants to merge 3 commits into
chadpav:pr/send-installation-idfrom
AdrianCurtin:cache-installation-id
Open

perf: Cache installationId lookup in ParseClient.buildHeaders#1
AdrianCurtin wants to merge 3 commits into
chadpav:pr/send-installation-idfrom
AdrianCurtin:cache-installation-id

Conversation

@AdrianCurtin
Copy link
Copy Markdown

Stacks on top of parse-community#1140.

Issue

After parse-community#1140, ParseClient.buildHeaders runs on every outgoing HTTP request and calls ParseInstallation.currentInstallation(), which in turn:

  • reads keyParseStoreInstallation from the local store (coreStore.getString),
  • json.decodes the stored installation document,
  • constructs a fresh ParseInstallation instance with fromJson (allocates dirty-tracking maps),

…just to read a single immutable field — installationId. On hot paths like paginated query loops or batched saves, this is unnecessary CPU and GC pressure on every request, and real disk I/O for stores like CoreStoreSembast.

Approach

  • Add ParseInstallation.currentInstallationId(), a static cache-first helper that returns just the install UUID. Populates from the local store on first call (or bootstraps a fresh installation if none exists) and stores the result in the existing _currentInstallationId static. Subsequent calls are a single static-field read.
  • ParseClient.buildHeaders now calls currentInstallationId() instead of currentInstallation().installationId.

Safety

  • The install ID is the device UUID written at first launch — immutable for the lifetime of the app on a given device, so the cache never needs invalidation.
  • App restart resets the static to null, so the cache repopulates from storage on the first call. Correct across launches.
  • Concurrent first-callers each see null and may both read the store, but they converge on the same cached value. Worst-case is a redundant getString — no correctness issue. _createInstallation already guards against duplicate UUID generation via ??=.
  • Existing currentInstallation() is unchanged — callers that need the full document (e.g. push setup, save(), channel subscriptions) still work the same way.

Tests

All 224 existing tests pass, including the per-verb wiring tests you added in this PR. Happy to add a dedicated cache-hit test if you'd like.

Add ParseInstallation.currentInstallationId() that returns a cached installationId (or reads it from the local store / creates an installation if missing). Update ParseClient to call currentInstallationId() instead of loading and JSON-decoding the full ParseInstallation on every HTTP request to avoid repeated local-store reads and improve performance; _createInstallation still populates the cached value.
Copilot AI review requested due to automatic review settings May 22, 2026 14:16
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces per-request overhead in the Dart SDK by caching the Parse installation UUID used for the X-Parse-Installation-Id header, avoiding repeated local-store reads/JSON decoding on hot HTTP paths introduced by parse-community#1140.

Changes:

  • Added ParseInstallation.currentInstallationId() to cache and return the installation UUID.
  • Updated ParseClient.buildHeaders to use currentInstallationId() instead of loading the full ParseInstallation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/dart/lib/src/objects/parse_installation.dart Adds a cache-first helper for retrieving the installation UUID.
packages/dart/lib/src/network/parse_client.dart Switches header construction to use the cached installation UUID helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/dart/lib/src/objects/parse_installation.dart Outdated
Comment thread packages/dart/lib/src/objects/parse_installation.dart Outdated
Address Copilot review feedback:
- Skip constructing a full ParseInstallation when only the UUID is
  needed; read keyInstallationId straight from the stored JSON map.
- Clear the cache if bootstrap persistence fails so the next call
  retries, matching the pre-cache retry semantics.
- Add @VisibleForTesting debugResetInstallationIdCache() so tests
  and apps that clear core storage mid-session can invalidate the
  static cache.
Add validation for installationId and update install handling/tests.

- Introduce _isUsableInstallationId to centralize validation (non-null, String, non-whitespace).
- Ensure cached _currentInstallationId and values read from local store are validated and treated as missing when invalid.
- Reject stored installations with missing/empty/whitespace or non-string installationId in _getFromLocalStore (with debug logging).
- Re-stage a usable installationId into _unsavedChanges in _updateInstallation when objectId == null so create() POST bodies include the installationId.
- Ensure _createInstallation generates a fresh UUID when cache is empty/invalid instead of reusing poisoned values.
- Tests: initialize Parse once, clear store/cache between tests, add regression tests to verify re-staging behavior and that empty/whitespace/non-string installationIds in local store are rejected.

These changes prevent corrupted local state (e.g. installationId == "" or whitespace) from being reused in headers or API request bodies and avoid creating server rows with missing installationId.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants