Fabric: Support for interleaving/followup transactions in RCTMountingManager (iOS)

Summary:
Imagine a case where we initiate a synchronous state update right in the middle of the mount transaction. With the current implementation, the mount transaction caused by the change will be mounted right inside the in-flight transaction, which will probably cause a crash or incorrect mounting side-effects (which will cause a crash later).
Instead of executing all mounting instructions cased by the state change, we actually need to execute them right after the end of the current transaction (synchronously, inside the same main run loop tick).
This diff implements exactly this.

Changelog: [Internal] Fabric-specific internal change.

Reviewed By: mdvacca

Differential Revision: D18444730

fbshipit-source-id: 3e777a7aa70ff28205d40588970c7478869b6899
This commit is contained in:
Valentin Shergin
2019-11-18 14:28:44 -08:00
committed by Facebook Github Bot
parent 9349ee26e7
commit 5f0435fb85
+25 -5
View File
@@ -207,6 +207,8 @@ static void RNPerformMountInstructions(
@implementation RCTMountingManager {
RCTMountingTransactionObserverCoordinator _observerCoordinator;
BOOL _transactionInFlight;
BOOL _followUpTransactionRequired;
}
- (instancetype)init
@@ -225,14 +227,14 @@ static void RNPerformMountInstructions(
// * No need to do a thread jump;
// * No need to do expensive copy of all mutations;
// * No need to allocate a block.
[self mountMutations:mountingCoordinator];
[self initiateTransaction:mountingCoordinator];
return;
}
auto mountingCoordinatorCopy = mountingCoordinator;
RCTExecuteOnMainQueue(^{
RCTAssertMainQueue();
[self mountMutations:mountingCoordinatorCopy];
[self initiateTransaction:mountingCoordinatorCopy];
});
}
@@ -252,9 +254,28 @@ static void RNPerformMountInstructions(
});
}
- (void)mountMutations:(MountingCoordinator::Shared const &)mountingCoordinator
- (void)initiateTransaction:(MountingCoordinator::Shared const &)mountingCoordinator
{
SystraceSection s("-[RCTMountingManager mountMutations:]");
SystraceSection s("-[RCTMountingManager initiateTransaction:]");
RCTAssertMainQueue();
if (_transactionInFlight) {
_followUpTransactionRequired = YES;
return;
}
do {
_followUpTransactionRequired = NO;
_transactionInFlight = YES;
[self performTransaction:mountingCoordinator];
_transactionInFlight = NO;
} while (_followUpTransactionRequired);
}
- (void)performTransaction:(MountingCoordinator::Shared const &)mountingCoordinator
{
SystraceSection s("-[RCTMountingManager performTransaction:]");
RCTAssertMainQueue();
auto transaction = mountingCoordinator->pullTransaction();
if (!transaction.has_value()) {
@@ -268,7 +289,6 @@ static void RNPerformMountInstructions(
return;
}
RCTAssertMainQueue();
auto telemetry = transaction->getTelemetry();
auto number = transaction->getNumber();