-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Refactor async open to add support for Task cancellation #8148
Conversation
87dc526
to
55fc1d0
Compare
@@ -484,11 +371,11 @@ + (instancetype)realmWithConfiguration:(RLMRealmConfiguration *)configuration | |||
realm->_dynamic = dynamic; | |||
|
|||
// protects the realm cache and accessors cache | |||
static std::mutex& initLock = *new std::mutex(); | |||
std::lock_guard<std::mutex> lock(initLock); | |||
static auto& initLock = *new RLMUnfairMutex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we want this to be static? I.e., isn't this locking in the case of multiple realms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scope of this lock can probably be reduced, but all of this code has always been written under the assumption that it's called with a global lock held and changing that is an unrelated project.
Realm/RLMRealmUtil.mm
Outdated
} | ||
else if (id actor = options.actor) { | ||
// check for main actor? | ||
return (__bridge void *)actor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are we checking actor equality?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actors are reference types, so pointer equality works fine.
RLMConfinement has turned out to be miserable to work with so I'm reworking things to replace it with a RLMScheduler type that's an ordinary obj-c class and works similarly to the object store Scheduler type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First overview, I have to finish reviewing the recent changes
@@ -86,6 +86,13 @@ | |||
ReferencedContainer = "container:Realm.xcodeproj"> | |||
</BuildableReference> | |||
</MacroExpansion> | |||
<EnvironmentVariables> | |||
<EnvironmentVariable | |||
key = "SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this make the app crash in cases where the executor fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By default the actor data race detection merely logs a warning if it detects a problem, and we want our tests to visibly fail if they have a bug.
// checking eliminates a lot of the benefit of using os_unfair_lock (better perf | ||
// and less storage required), so only use os_unfair_lock when our minimum | ||
// deployment target is high enough | ||
#if __clang_major__ >= 14 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this change may solve some issues we have like this one RLMUnfairMutex?, I know this was introduced a few releases ago but I'm curious if this change may solve this issues'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using os_unfair_mutex is purely just a minor performance optimization.
@@ -1192,35 +1204,54 @@ extension Realm { | |||
@MainActor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that we are still constrained to the the main actor to call try await Realm() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this does not add support for confining Realms to arbitrary actors.
516d6bf
to
25eedd3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Just some minor comments and questions.
|
||
#import <Realm/RLMConstants.h> | ||
|
||
#ifdef __cplusplus |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we exposing this to the Objective-C API but this can't be used, should we expose this in our private API so swift can use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or maybe this is intended for future PRs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RLMRealm.mm gets osScheduler
from RLMScheduler
, but that's a c++ type so it needs to not be exposed when Swift is importing this header (which it does for async Realm.init()
).
error:&error]; | ||
auto completion = _completion; | ||
[self releaseResources]; | ||
completion(localRealm, error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there some cases where we have an error and we return a Realm, or this never happens?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we always either have a Realm or an error.
25eedd3
to
2a307d1
Compare
82c1ed9
to
e9a2daa
Compare
This has most of the supporting refactoring to enable actor-confined Realms, and some of it won't make a ton of sense without that part.
This adjusts the behavior of async open cancellation a bit. We used to sometimes report a cancellation error and sometimes just never invoke the callback at all. This was weird and inconsistent and doesn't work for async continuations (which need to always be completed), so it now always reports an error.
withTaskCancellationHandler()
has a really awkward API which drives the design of this. It needs an object which is allocated before callingwithTaskCancellationHandler()
which is then shared by the two callbacks passed towithTaskCancellationHandler()
, which means that creating theRLMAsyncOpenTask
and starting it need to be separate steps.RLMAsyncTask currently only has
RLMAsyncOpenTask
, but with actor-confined Realms there's an assortment of async tasks defined there (async write and async refresh).RLMConfinement
stores all of the various things that a Realm can be confined to, which soon will be either a runloop, queue, or actor. It has an awkward definition to make it constructible in Swift but still retain things when used in C++. This is a maybe-not-actually-legal pattern used extensively by Foundation and libdispatch.Setting
SWIFT_UNEXPECTED_EXECUTOR_LOG_LEVEL=2
makes the process abort when actor data races are detected rather than just logging a warning.