-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crashes when encoding user models #1412
Merged
Merged
Conversation
This file contains 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
Closed
1 task
4adea7b
to
600a5db
Compare
* Adds two tests that encode Identity Model and Properties Model while their aliases and tags dictionary are written to. * The tests try to add data, clear data, and encode these models concurrently
* Identity Model and Properties Model have access to their aliases and tags dictionary wrapped in a lock. However, this lock was missing from the encode method, and is necessary.
* I noticed we were always hydrating the same identity model twice. * This is because we are parsing a fetch user response, we end up hydrating the identity model twice, unnecessarily, which drives caching it twice as well. * We already hydrate the identity model attached to the request. * Here, we were hydrating it again if the current user is the same. However, if the current user is the same, the model is the same and has already been hydrated.
* Removing multiple aliases via `removeAliases(array)` will now be done in one go: - Creates one OSDelta that will be parsed by the executor into individual Remove Alias Requests - Caches the new aliases once instead of in a loop for each label to remove * Hydrating aliases will now be done in one go as well: - Now, cache the new aliases once at the end. Prior, we cache the aliases after each alias as we hydrate. * In addition, put the call to `self.set` outside of the tagsLock, since the call to `self.set` will drive encoding itself, which also requires the tagsLock. The UnfairLock does not handle nested locking.
* Drop UnfairLock and use NSRecursiveLock * UnfairLock is fast, but it doesn’t support recursive locking. So, it crashes whenever you lock it twice from the same thread. * So far, we haven't encountered this, but this is possible, especially if we are not careful about how changes are propagated up.
* Keep the lock minimal, just around write and read access to the tags dictionary * Move the events-driving outside of the lock, that create Deltas and caches the model, etc.
* Adding tags with blank value will remove the tag
48e6983
to
98908ee
Compare
21661e5
to
98908ee
Compare
emawby
approved these changes
Apr 23, 2024
This was referenced Apr 30, 2024
Merged
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
Fix crashes during model encoding due to concurrent data access.
Details
Models are encoded often: any change encodes them in the model store, when deltas are cached in the operation repo, when deltas are flushed in the operation repo, when deltas are enqueued to executors, when deltas are turned into requests, when requests are sent and removed, etc. These all have references to models.
Identity Model and Properties Model have access to their aliases and tags dictionary wrapped in a lock. However, this lock was missing from the encode method, and is necessary.
The changes made in this PR already avoid recursive locking, but let's also replace the lock that is used to a
NSRecursiveLock
for future-proofing. During development, I ran into this before trying to avoid recursive locking as models are encoded so often. This occurred when tags change on a model (in a lock), driving the model store to encode it's models, which eventually calls the model's own encode method (which is also in a lock).Another change in this PR is to reduce extra caching of the Identity Model.
Motivation
Fixes any stack trace with this signature.
Scope
Locking in models
Alternative to Consider
OSDelta
may references an Identity Model, but only for the purpose of identifying the user and retrieving the OSID.Testing
Unit testing
Added tests reproducing crash when encoding models with concurrency
Manual testing
Device: iPhone 13 with iOS 17.4
Affected code checklist
Checklist
Overview
Testing
Final pass
This change is![Reviewable](https://camo.githubusercontent.com/1541c4039185914e83657d3683ec25920c672c6c5c7ab4240ee7bff601adec0b/68747470733a2f2f72657669657761626c652e696f2f7265766965775f627574746f6e2e737667)