Skip to content
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

Merged
merged 6 commits into from
Mar 3, 2023

Conversation

tgoyne
Copy link
Member

@tgoyne tgoyne commented Feb 23, 2023

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 calling withTaskCancellationHandler() which is then shared by the two callbacks passed to withTaskCancellationHandler(), which means that creating the RLMAsyncOpenTask 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.

@tgoyne tgoyne self-assigned this Feb 23, 2023
@cla-bot cla-bot bot added the cla: yes label Feb 23, 2023
@tgoyne tgoyne force-pushed the tg/actor-refactoring branch 7 times, most recently from 87dc526 to 55fc1d0 Compare February 28, 2023 18:56
@tgoyne tgoyne marked this pull request as ready for review February 28, 2023 20:11
@@ -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;
Copy link
Contributor

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?

Copy link
Member Author

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.

}
else if (id actor = options.actor) {
// check for main actor?
return (__bridge void *)actor;
Copy link
Contributor

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?

Copy link
Member Author

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.

@tgoyne
Copy link
Member Author

tgoyne commented Mar 1, 2023

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.

Copy link
Contributor

@dianaafanador3 dianaafanador3 left a 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"
Copy link
Contributor

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?

Copy link
Member Author

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.

RealmSwift/Tests/RealmTests.swift Outdated Show resolved Hide resolved
RealmSwift/Tests/TestUtils.swift Outdated Show resolved Hide resolved
// 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
Copy link
Contributor

@dianaafanador3 dianaafanador3 Mar 1, 2023

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'

Copy link
Member Author

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
Copy link
Contributor

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() ?

Copy link
Member Author

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.

Copy link
Contributor

@dianaafanador3 dianaafanador3 left a 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.

Realm/RLMRealm_Private.h Outdated Show resolved Hide resolved

#import <Realm/RLMConstants.h>

#ifdef __cplusplus
Copy link
Contributor

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.

Copy link
Contributor

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

Copy link
Member Author

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);
Copy link
Contributor

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?

Copy link
Member Author

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.

Realm/ObjectServerTests/SwiftObjectServerTests.swift Outdated Show resolved Hide resolved
@tgoyne tgoyne merged commit 8524c4e into master Mar 3, 2023
@tgoyne tgoyne deleted the tg/actor-refactoring branch March 3, 2023 21:14
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants