Skip to content

Commit 8ef8b30

Browse files
authored
Implement safe, synchronous destruction in Firestore (#5620)
Now that the Executor makes strong guarantees that tasks submitted to it will either be completely run or not start at all once destruction starts (#5547), build a Dispose protocol on top of this to allow Firestore to shut itself down leaf first. Now that Firestore calls the Dispose chain down to the Executor, it's no longer possible for tasks to run while the instance is partially destructed nor can user callbacks execute after the instance has been destroyed. This is the other half of the iOS changes required to address firebase/quickstart-unity#638. There are a few follow-on tasks that this PR does not address: * Ownership of FirestoreClient and AsyncQueue are still shared though they no longer need to be. * The tests are still overly defensive about keeping different test cases isolated from each other. Much of this can be removed now that we're guaranteed to release resources by the time the test case shuts down (at least in GoogleTest; XCTest remains to be seen).
1 parent e462d04 commit 8ef8b30

13 files changed

+414
-200
lines changed

Firestore/core/src/api/firestore.cc

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Google
2+
* Copyright 2019 Google LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -67,13 +67,17 @@ Firestore::Firestore(model::DatabaseId database_id,
6767
}
6868

6969
Firestore::~Firestore() {
70-
std::lock_guard<std::mutex> lock{mutex_};
70+
Dispose();
71+
}
72+
73+
void Firestore::Dispose() {
74+
std::lock_guard<std::mutex> lock(mutex_);
7175

7276
// If the client hasn't been configured yet we don't need to create it just
7377
// to tear it down.
7478
if (!client_) return;
7579

76-
client_->Terminate();
80+
client_->Dispose();
7781
}
7882

7983
const std::shared_ptr<FirestoreClient>& Firestore::client() {
@@ -156,24 +160,24 @@ void Firestore::WaitForPendingWrites(util::StatusCallback callback) {
156160
}
157161

158162
void Firestore::ClearPersistence(util::StatusCallback callback) {
159-
worker_queue()->EnqueueEvenAfterShutdown([this, callback] {
160-
auto Yield = [=](Status status) {
163+
worker_queue()->EnqueueEvenWhileRestricted([this, callback] {
164+
auto MaybeCallback = [=](Status status) {
161165
if (callback) {
162-
this->user_executor_->Execute([=] { callback(status); });
166+
user_executor_->Execute([=] { callback(status); });
163167
}
164168
};
165169

166170
{
167171
std::lock_guard<std::mutex> lock{mutex_};
168-
if (client_ && !client()->is_terminated()) {
169-
Yield(util::Status(
172+
if (client_ && !client_->is_terminated()) {
173+
MaybeCallback(util::Status(
170174
Error::kErrorFailedPrecondition,
171175
"Persistence cannot be cleared while the client is running."));
172176
return;
173177
}
174178
}
175179

176-
Yield(LevelDbPersistence::ClearPersistence(MakeDatabaseInfo()));
180+
MaybeCallback(LevelDbPersistence::ClearPersistence(MakeDatabaseInfo()));
177181
});
178182
}
179183

@@ -192,7 +196,7 @@ std::unique_ptr<ListenerRegistration> Firestore::AddSnapshotsInSyncListener(
192196
EnsureClientConfigured();
193197
auto async_listener = AsyncEventListener<Empty>::Create(
194198
client_->user_executor(), std::move(listener));
195-
client_->AddSnapshotsInSyncListener(std::move(async_listener));
199+
client_->AddSnapshotsInSyncListener(async_listener);
196200
return absl::make_unique<SnapshotsInSyncListenerRegistration>(
197201
client_, std::move(async_listener));
198202
}

Firestore/core/src/api/firestore.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019 Google
2+
* Copyright 2019 Google LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,6 +55,8 @@ class Firestore : public std::enable_shared_from_this<Firestore> {
5555

5656
~Firestore();
5757

58+
void Dispose();
59+
5860
const model::DatabaseId& database_id() const {
5961
return database_id_;
6062
}

0 commit comments

Comments
 (0)