mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-03-06 22:37:14 +08:00
Fabric: MountingCoordinator - the new way to ensure ordering of mount transaction
Summary: TBD. This thing fixes flickering during appearing of Fabric screens on iOS. Reviewed By: mdvacca Differential Revision: D15116079 fbshipit-source-id: 95ed0ba94667cad67fe4317025128d01b34f69c5
This commit is contained in:
committed by
Facebook Github Bot
parent
4803cab8c4
commit
0f2a09d1f6
@@ -11,7 +11,7 @@
|
||||
#import <React/RCTPrimitives.h>
|
||||
#import <react/core/ComponentDescriptor.h>
|
||||
#import <react/core/ReactPrimitives.h>
|
||||
#import <react/mounting/MountingTransaction.h>
|
||||
#import <react/mounting/MountingCoordinator.h>
|
||||
#import <react/mounting/ShadowView.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Schedule a mounting transaction to be performed on the main thread.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
- (void)scheduleTransaction:(facebook::react::MountingTransaction &&)mountingTransaction;
|
||||
- (void)scheduleTransaction:(facebook::react::MountingCoordinator::Shared const &)mountingCoordinator;
|
||||
|
||||
/**
|
||||
* Suggests preliminary creation of a component view of given type.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#import <react/core/LayoutableShadowNode.h>
|
||||
#import <react/core/RawProps.h>
|
||||
#import <react/debug/SystraceSection.h>
|
||||
#import <react/mounting/MountingTransactionSynchronizer.h>
|
||||
|
||||
#import "RCTComponentViewProtocol.h"
|
||||
#import "RCTComponentViewRegistry.h"
|
||||
@@ -204,9 +203,7 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
||||
}
|
||||
}
|
||||
|
||||
@implementation RCTMountingManager {
|
||||
better::map<SurfaceId, MountingTransactionSynchronizer> syncronizers_;
|
||||
}
|
||||
@implementation RCTMountingManager
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
@@ -217,49 +214,39 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)scheduleTransaction:(MountingTransaction &&)mountingTransaction;
|
||||
- (void)scheduleTransaction:(MountingCoordinator::Shared const &)mountingCoordinator
|
||||
{
|
||||
if (RCTIsMainQueue()) {
|
||||
// Already on the proper thread, so:
|
||||
// * No need to do a thread jump;
|
||||
// * No need to do expensive copy of all mutations;
|
||||
// * No need to allocate a block.
|
||||
[self mountMutations:std::move(mountingTransaction)];
|
||||
[self mountMutations:mountingCoordinator];
|
||||
return;
|
||||
}
|
||||
|
||||
// We need a non-reference for `mountingTransaction` to allow copy semantic.
|
||||
auto sharedMountingTransaction = std::make_shared<MountingTransaction>(std::move(mountingTransaction));
|
||||
|
||||
auto mountingCoordinatorCopy = mountingCoordinator;
|
||||
RCTExecuteOnMainQueue(^{
|
||||
RCTAssertMainQueue();
|
||||
[self mountMutations:std::move(*sharedMountingTransaction)];
|
||||
[self mountMutations:mountingCoordinatorCopy];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)mountMutations:(MountingTransaction &&)mountingTransaction
|
||||
- (void)mountMutations:(MountingCoordinator::Shared const &)mountingCoordinator
|
||||
{
|
||||
SystraceSection s("-[RCTMountingManager mountMutations:]");
|
||||
|
||||
RCTAssertMainQueue();
|
||||
|
||||
auto &syncronizer = syncronizers_[mountingTransaction.getSurfaceId()];
|
||||
|
||||
syncronizer.push(std::move(mountingTransaction));
|
||||
|
||||
while (true) {
|
||||
auto mountingTransactionOptional = syncronizer.pull();
|
||||
if (!mountingTransactionOptional.has_value()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto transaction = std::move(*mountingTransactionOptional);
|
||||
auto surfaceId = transaction.getSurfaceId();
|
||||
|
||||
[self.delegate mountingManager:self willMountComponentsWithRootTag:surfaceId];
|
||||
RNPerformMountInstructions(transaction.getMutations(), self.componentViewRegistry);
|
||||
[self.delegate mountingManager:self didMountComponentsWithRootTag:surfaceId];
|
||||
auto transaction = mountingCoordinator->pullTransaction();
|
||||
if (!transaction.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto surfaceId = transaction->getSurfaceId();
|
||||
|
||||
RCTAssertMainQueue();
|
||||
[self.delegate mountingManager:self willMountComponentsWithRootTag:surfaceId];
|
||||
RNPerformMountInstructions(transaction->getMutations(), self.componentViewRegistry);
|
||||
[self.delegate mountingManager:self didMountComponentsWithRootTag:surfaceId];
|
||||
}
|
||||
|
||||
- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
#import <react/core/ComponentDescriptor.h>
|
||||
#import <react/core/LayoutConstraints.h>
|
||||
#import <react/core/LayoutContext.h>
|
||||
#import <react/mounting/MountingTransaction.h>
|
||||
#import <react/mounting/ShadowViewMutation.h>
|
||||
#import <react/mounting/MountingCoordinator.h>
|
||||
#import <react/uimanager/ComponentDescriptorFactory.h>
|
||||
#import <react/utils/ContextContainer.h>
|
||||
|
||||
@@ -26,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@protocol RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingTransaction &&)mountingTransaction;
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingCoordinator::Shared const &)mountingCoordinator;
|
||||
|
||||
- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
|
||||
public:
|
||||
SchedulerDelegateProxy(void *scheduler) : scheduler_(scheduler) {}
|
||||
|
||||
void schedulerDidFinishTransaction(MountingTransaction &&mountingTransaction) override
|
||||
void schedulerDidFinishTransaction(MountingCoordinator::Shared const &mountingCoordinator) override
|
||||
{
|
||||
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
|
||||
[scheduler.delegate schedulerDidFinishTransaction:std::move(mountingTransaction)];
|
||||
[scheduler.delegate schedulerDidFinishTransaction:mountingCoordinator];
|
||||
}
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowView &shadowView) override
|
||||
|
||||
@@ -311,13 +311,13 @@ using namespace facebook::react;
|
||||
|
||||
#pragma mark - RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingTransaction &&)mountingTransaction
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingCoordinator::Shared const &)mountingCoordinator
|
||||
{
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:mountingTransaction.getSurfaceId()];
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:mountingCoordinator->getSurfaceId()];
|
||||
|
||||
[surface _setStage:RCTSurfaceStagePrepared];
|
||||
|
||||
[_mountingManager scheduleTransaction:std::move(mountingTransaction)];
|
||||
[_mountingManager scheduleTransaction:mountingCoordinator];
|
||||
}
|
||||
|
||||
- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
|
||||
|
||||
@@ -353,12 +353,18 @@ local_ref<JMountItem::javaobject> createCreateMountItem(
|
||||
}
|
||||
|
||||
void Binding::schedulerDidFinishTransaction(
|
||||
MountingTransaction &&mountingTransaction) {
|
||||
MountingCoordinator::Shared const &mountingCoordinator) {
|
||||
SystraceSection s("FabricUIManager::schedulerDidFinishTransaction");
|
||||
|
||||
auto telemetry = mountingTransaction.getTelemetry();
|
||||
auto mutations = mountingTransaction.getMutations();
|
||||
auto surfaceId = mountingTransaction.getSurfaceId();
|
||||
auto mountingTransaction = mountingCoordinator->pullTransaction();
|
||||
|
||||
if (!mountingTransaction.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto telemetry = mountingTransaction->getTelemetry();
|
||||
auto surfaceId = mountingTransaction->getSurfaceId();
|
||||
auto &mutations = mountingTransaction->getMutations();
|
||||
|
||||
std::vector<local_ref<jobject>> queue;
|
||||
// Upper bound estimation of mount items to be delivered to Java side.
|
||||
|
||||
@@ -57,7 +57,7 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
|
||||
void stopSurface(jint surfaceId);
|
||||
|
||||
void schedulerDidFinishTransaction(
|
||||
MountingTransaction &&mountingTransaction);
|
||||
MountingCoordinator::Shared const &mountingCoordinator);
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(
|
||||
const SurfaceId surfaceId,
|
||||
|
||||
88
ReactCommon/fabric/mounting/MountingCoordinator.cpp
Normal file
88
ReactCommon/fabric/mounting/MountingCoordinator.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "MountingCoordinator.h"
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
#include <glog/logging.h>
|
||||
#endif
|
||||
|
||||
#include <react/mounting/Differentiator.h>
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
MountingCoordinator::MountingCoordinator(ShadowTreeRevision baseRevision)
|
||||
: surfaceId_(baseRevision.getRootShadowNode().getSurfaceId()),
|
||||
baseRevision_(baseRevision) {
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
stubViewTree_ = stubViewTreeFromShadowNode(baseRevision_.getRootShadowNode());
|
||||
#endif
|
||||
}
|
||||
|
||||
SurfaceId MountingCoordinator::getSurfaceId() const {
|
||||
return surfaceId_;
|
||||
}
|
||||
|
||||
void MountingCoordinator::push(ShadowTreeRevision &&revision) const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
assert(revision.getNumber() > baseRevision_.getNumber());
|
||||
assert(
|
||||
!lastRevision_.has_value() ||
|
||||
revision.getNumber() != lastRevision_->getNumber());
|
||||
|
||||
if (!lastRevision_.has_value() ||
|
||||
lastRevision_->getNumber() < revision.getNumber()) {
|
||||
lastRevision_ = std::move(revision);
|
||||
}
|
||||
}
|
||||
|
||||
better::optional<MountingTransaction> MountingCoordinator::pullTransaction()
|
||||
const {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (!lastRevision_.has_value()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
number_++;
|
||||
|
||||
auto mutations = calculateShadowViewMutations(
|
||||
baseRevision_.getRootShadowNode(), lastRevision_->getRootShadowNode());
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
stubViewTree_.mutate(mutations);
|
||||
auto stubViewTree =
|
||||
stubViewTreeFromShadowNode(lastRevision_->getRootShadowNode());
|
||||
if (stubViewTree_ != stubViewTree) {
|
||||
LOG(ERROR) << "Old tree:"
|
||||
<< "\n"
|
||||
<< baseRevision_.getRootShadowNode().getDebugDescription()
|
||||
<< "\n";
|
||||
LOG(ERROR) << "New tree:"
|
||||
<< "\n"
|
||||
<< lastRevision_->getRootShadowNode().getDebugDescription()
|
||||
<< "\n";
|
||||
LOG(ERROR) << "Mutations:"
|
||||
<< "\n"
|
||||
<< getDebugDescription(mutations);
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto telemetry = lastRevision_->getTelemetry();
|
||||
baseRevision_ = std::move(*lastRevision_);
|
||||
lastRevision_.reset();
|
||||
|
||||
return MountingTransaction{
|
||||
surfaceId_, number_, std::move(mutations), telemetry};
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
81
ReactCommon/fabric/mounting/MountingCoordinator.h
Normal file
81
ReactCommon/fabric/mounting/MountingCoordinator.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/optional.h>
|
||||
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
#include <react/mounting/ShadowTreeRevision.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define RN_SHADOW_TREE_INTROSPECTION
|
||||
#endif
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
#include <react/mounting/stubs.h>
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Stores inside all non-mounted yet revisions of a shadow tree and coordinates
|
||||
* mounting. The object stores the most recent mounted revision and the most
|
||||
* recent committed one. Then when a new mounting transaction is requested the
|
||||
* object generates mutation instructions and returns it as a
|
||||
* `MountingTransaction`.
|
||||
*/
|
||||
class MountingCoordinator final {
|
||||
public:
|
||||
using Shared = std::shared_ptr<MountingCoordinator const>;
|
||||
|
||||
/*
|
||||
* The constructor is ment to be used only inside `ShadowTree`, and it's
|
||||
* `public` only to enable using with `std::make_shared<>`.
|
||||
*/
|
||||
MountingCoordinator(ShadowTreeRevision baseRevision);
|
||||
|
||||
/*
|
||||
* Returns the id of the surface that the coordinator belongs to.
|
||||
*/
|
||||
SurfaceId getSurfaceId() const;
|
||||
|
||||
/*
|
||||
* Computes a consequent mounting transaction and returns it.
|
||||
* The returning transaction can accumulate multiple recent revisions of a
|
||||
* shadow tree. Returns empty optional if there no new shadow tree revision to
|
||||
* mount.
|
||||
* The method is thread-safe and can be called from any thread.
|
||||
* However, a consumer should always call it on the same thread (e.g. on the
|
||||
* main thread) or ensure sequentiality of mount transaction separately.
|
||||
*/
|
||||
better::optional<MountingTransaction> pullTransaction() const;
|
||||
|
||||
private:
|
||||
friend class ShadowTree;
|
||||
|
||||
/*
|
||||
* Methods from this section are meant to be used by `ShadowTree` only.
|
||||
*/
|
||||
void push(ShadowTreeRevision &&revision) const;
|
||||
|
||||
private:
|
||||
SurfaceId const surfaceId_;
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
mutable ShadowTreeRevision baseRevision_;
|
||||
mutable better::optional<ShadowTreeRevision> lastRevision_{};
|
||||
mutable MountingTransaction::Number number_{0};
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
mutable StubViewTree stubViewTree_; // Protected by `mutex_`.
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -10,15 +10,15 @@
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using Revision = MountingTransaction::Revision;
|
||||
using Number = MountingTransaction::Number;
|
||||
|
||||
MountingTransaction::MountingTransaction(
|
||||
SurfaceId surfaceId,
|
||||
Revision revision,
|
||||
Number number,
|
||||
ShadowViewMutationList &&mutations,
|
||||
MountingTelemetry telemetry)
|
||||
: surfaceId_(surfaceId),
|
||||
revision_(revision),
|
||||
number_(number),
|
||||
mutations_(std::move(mutations)),
|
||||
telemetry_(std::move(telemetry)) {}
|
||||
|
||||
@@ -38,8 +38,8 @@ SurfaceId MountingTransaction::getSurfaceId() const {
|
||||
return surfaceId_;
|
||||
}
|
||||
|
||||
Revision MountingTransaction::getRevision() const {
|
||||
return revision_;
|
||||
Number MountingTransaction::getNumber() const {
|
||||
return number_;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -14,19 +14,19 @@ namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Encapsulates all artifacts of `ShadowTree` commit, particularly list of
|
||||
* mutations and meta-data.
|
||||
* Movable and copyable, but moving is strongly preferred.
|
||||
* A moved-from object of this type has unspecified value and accessing that is
|
||||
* UB.
|
||||
* Encapsulates all artifacts of `ShadowTree` commit (or a series of them),
|
||||
* particularly list of mutations and meta-data associated with the commit.
|
||||
* Movable and copyable, but moving is strongly encouraged.
|
||||
* Beware: A moved-from object of this type has unspecified value and accessing
|
||||
* that is UB.
|
||||
*/
|
||||
class MountingTransaction final {
|
||||
public:
|
||||
/*
|
||||
* Revision grows continuously starting from `1`. Value `0` represents the
|
||||
* state before the very first transaction happens.
|
||||
* A Number (or revision) grows continuously starting from `1`. Value `0`
|
||||
* represents the state before the very first transaction happens.
|
||||
*/
|
||||
using Revision = int64_t;
|
||||
using Number = int64_t;
|
||||
|
||||
/*
|
||||
* Copying a list of `ShadowViewMutation` is expensive, so the constructor
|
||||
@@ -34,7 +34,7 @@ class MountingTransaction final {
|
||||
*/
|
||||
MountingTransaction(
|
||||
SurfaceId surfaceId,
|
||||
Revision revision,
|
||||
Number number,
|
||||
ShadowViewMutationList &&mutations,
|
||||
MountingTelemetry telemetry);
|
||||
|
||||
@@ -72,13 +72,13 @@ class MountingTransaction final {
|
||||
SurfaceId getSurfaceId() const;
|
||||
|
||||
/*
|
||||
* Returns the revision of the ShadowTree that this transaction represents.
|
||||
* Returns a sequential number of the particular transaction.
|
||||
*/
|
||||
Revision getRevision() const;
|
||||
Number getNumber() const;
|
||||
|
||||
private:
|
||||
SurfaceId surfaceId_;
|
||||
Revision revision_;
|
||||
Number number_;
|
||||
ShadowViewMutationList mutations_;
|
||||
MountingTelemetry telemetry_;
|
||||
};
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "MountingTransactionSynchronizer.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
void MountingTransactionSynchronizer::push(MountingTransaction &&transaction) {
|
||||
assert(transaction.getRevision() >= 1 && "Invalid transaction revision.");
|
||||
|
||||
if (transaction.getRevision() == 1 && revision_ > 0) {
|
||||
// Special case:
|
||||
// Seems we have a completely new flow of mutations probably caused by the
|
||||
// hot-reload process. At this point, there is no way to guarantee anything,
|
||||
// so let's just start over.
|
||||
queue_.clear();
|
||||
revision_ = 0;
|
||||
}
|
||||
|
||||
auto it = queue_.begin();
|
||||
|
||||
while (it != queue_.end()) {
|
||||
assert(
|
||||
it->getRevision() != transaction.getRevision() &&
|
||||
"Attempt to re-insert transaction with same revision.");
|
||||
|
||||
if (it->getRevision() > transaction.getRevision()) {
|
||||
queue_.insert(it, std::move(transaction));
|
||||
return;
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
queue_.push_back(std::move(transaction));
|
||||
}
|
||||
|
||||
better::optional<MountingTransaction> MountingTransactionSynchronizer::pull() {
|
||||
if (queue_.size() == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (queue_.front().getRevision() != revision_ + 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
revision_++;
|
||||
|
||||
auto transaction = std::move(queue_.front());
|
||||
queue_.pop_front();
|
||||
|
||||
return {std::move(transaction)};
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/optional.h>
|
||||
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* ShadowTree commits happen concurrently with limited synchronization that only
|
||||
* ensures the correctness of the commit from ShadowTree perspective. At the
|
||||
* same time artifacts of the commit () needs to be delivered (also
|
||||
* concurrently) to the proper thread and executed in order (not-concurrently).
|
||||
* To achieve this we need some synchronization mechanism on the receiving
|
||||
* (mounting) side. This class implements this process. This class is *not*
|
||||
* thread-safe (and must not be).
|
||||
*/
|
||||
class MountingTransactionSynchronizer final {
|
||||
public:
|
||||
/*
|
||||
* Pushes (adds) a new MountingTransaction to the internal queue.
|
||||
*/
|
||||
void push(MountingTransaction &&transaction);
|
||||
|
||||
/*
|
||||
* Pulls (returns and removes) a MountingTransaction from the internal queue
|
||||
* if it has something ready to be pulled. Return an empty optional otherwise.
|
||||
*/
|
||||
better::optional<MountingTransaction> pull();
|
||||
|
||||
private:
|
||||
MountingTransaction::Revision revision_{0};
|
||||
std::deque<MountingTransaction> queue_{};
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -5,15 +5,13 @@
|
||||
|
||||
#include "ShadowTree.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <react/components/root/RootComponentDescriptor.h>
|
||||
#include <react/components/view/ViewShadowNode.h>
|
||||
#include <react/core/LayoutContext.h>
|
||||
#include <react/core/LayoutPrimitives.h>
|
||||
#include <react/debug/SystraceSection.h>
|
||||
#include <react/mounting/Differentiator.h>
|
||||
#include <react/mounting/MountingTelemetry.h>
|
||||
#include <react/mounting/ShadowTreeRevision.h>
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
#include "ShadowTreeDelegate.h"
|
||||
@@ -100,9 +98,8 @@ ShadowTree::ShadowTree(
|
||||
/* .eventEmitter = */ noopEventEmitter,
|
||||
}));
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
stubViewTree_ = stubViewTreeFromShadowNode(*rootShadowNode_);
|
||||
#endif
|
||||
mountingCoordinator_ = std::make_shared<MountingCoordinator const>(
|
||||
ShadowTreeRevision{rootShadowNode_, 0, {}});
|
||||
}
|
||||
|
||||
ShadowTree::~ShadowTree() {
|
||||
@@ -171,9 +168,7 @@ bool ShadowTree::tryCommit(ShadowTreeCommitTransaction transaction) const {
|
||||
|
||||
newRootShadowNode->sealRecursive();
|
||||
|
||||
int revision;
|
||||
auto mutations =
|
||||
calculateShadowViewMutations(*oldRootShadowNode, *newRootShadowNode);
|
||||
auto revisionNumber = ShadowTreeRevision::Number{};
|
||||
|
||||
{
|
||||
// Updating `rootShadowNode_` in unique manner if it hasn't changed.
|
||||
@@ -192,34 +187,19 @@ bool ShadowTree::tryCommit(ShadowTreeCommitTransaction transaction) const {
|
||||
oldRootShadowNode->getChildren(), newRootShadowNode->getChildren());
|
||||
}
|
||||
|
||||
revision = revision_;
|
||||
revision_++;
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
stubViewTree_.mutate(mutations);
|
||||
auto stubViewTree = stubViewTreeFromShadowNode(*rootShadowNode_);
|
||||
if (stubViewTree_ != stubViewTree) {
|
||||
LOG(ERROR) << "Old tree:"
|
||||
<< "\n"
|
||||
<< oldRootShadowNode->getDebugDescription() << "\n";
|
||||
LOG(ERROR) << "New tree:"
|
||||
<< "\n"
|
||||
<< newRootShadowNode->getDebugDescription() << "\n";
|
||||
LOG(ERROR) << "Mutations:"
|
||||
<< "\n"
|
||||
<< getDebugDescription(mutations);
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
revisionNumber_++;
|
||||
revisionNumber = revisionNumber_;
|
||||
}
|
||||
|
||||
emitLayoutEvents(affectedLayoutableNodes);
|
||||
|
||||
telemetry.didCommit();
|
||||
|
||||
mountingCoordinator_->push(
|
||||
ShadowTreeRevision{newRootShadowNode, revisionNumber, telemetry});
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->shadowTreeDidCommit(
|
||||
*this, {surfaceId_, revision, std::move(mutations), telemetry});
|
||||
delegate_->shadowTreeDidCommit(*this, mountingCoordinator_);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define RN_SHADOW_TREE_INTROSPECTION
|
||||
#endif
|
||||
|
||||
#include <better/mutex.h>
|
||||
#include <memory>
|
||||
@@ -17,12 +14,9 @@
|
||||
#include <react/core/LayoutConstraints.h>
|
||||
#include <react/core/ReactPrimitives.h>
|
||||
#include <react/core/ShadowNode.h>
|
||||
#include <react/mounting/MountingCoordinator.h>
|
||||
#include <react/mounting/ShadowTreeDelegate.h>
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
#include <react/mounting/stubs.h>
|
||||
#endif
|
||||
#include <react/mounting/ShadowTreeRevision.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@@ -83,15 +77,13 @@ class ShadowTree final {
|
||||
void emitLayoutEvents(
|
||||
std::vector<LayoutableShadowNode const *> &affectedLayoutableNodes) const;
|
||||
|
||||
const SurfaceId surfaceId_;
|
||||
SurfaceId const surfaceId_;
|
||||
mutable better::shared_mutex commitMutex_;
|
||||
mutable SharedRootShadowNode rootShadowNode_; // Protected by `commitMutex_`.
|
||||
mutable int revision_{1}; // Protected by `commitMutex_`.
|
||||
mutable ShadowTreeRevision::Number revisionNumber_{
|
||||
0}; // Protected by `commitMutex_`.
|
||||
ShadowTreeDelegate const *delegate_;
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
mutable StubViewTree stubViewTree_; // Protected by `commitMutex_`.
|
||||
#endif
|
||||
MountingCoordinator::Shared mountingCoordinator_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
#include <react/mounting/MountingCoordinator.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@@ -21,8 +21,8 @@ class ShadowTreeDelegate {
|
||||
* Called right after Shadow Tree commit a new state of the the tree.
|
||||
*/
|
||||
virtual void shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
MountingTransaction &&transaction) const = 0;
|
||||
ShadowTree const &shadowTree,
|
||||
MountingCoordinator::Shared const &mountingCoordinator) const = 0;
|
||||
|
||||
virtual ~ShadowTreeDelegate() noexcept = default;
|
||||
};
|
||||
|
||||
34
ReactCommon/fabric/mounting/ShadowTreeRevision.cpp
Normal file
34
ReactCommon/fabric/mounting/ShadowTreeRevision.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "ShadowTreeRevision.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using Number = ShadowTreeRevision::Number;
|
||||
|
||||
ShadowTreeRevision::ShadowTreeRevision(
|
||||
ShadowNode::Shared const &rootShadowNode,
|
||||
Number number,
|
||||
MountingTelemetry telemetry)
|
||||
: rootShadowNode_(rootShadowNode), number_(number), telemetry_(telemetry) {}
|
||||
|
||||
MountingTelemetry const &ShadowTreeRevision::getTelemetry() const {
|
||||
return telemetry_;
|
||||
}
|
||||
|
||||
ShadowNode const &ShadowTreeRevision::getRootShadowNode() {
|
||||
return *rootShadowNode_;
|
||||
}
|
||||
|
||||
Number ShadowTreeRevision::getNumber() const {
|
||||
return number_;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
62
ReactCommon/fabric/mounting/ShadowTreeRevision.h
Normal file
62
ReactCommon/fabric/mounting/ShadowTreeRevision.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <better/optional.h>
|
||||
|
||||
#include <react/mounting/MountingTelemetry.h>
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
/*
|
||||
* Represent a particular committed state of a shadow tree. The object contains
|
||||
* a pointer to a root shadow node, a sequential number of commit and telemetry.
|
||||
*/
|
||||
class ShadowTreeRevision final {
|
||||
public:
|
||||
/*
|
||||
* Sequential number of the commit that created this revision of a shadow
|
||||
* tree.
|
||||
*/
|
||||
using Number = int64_t;
|
||||
|
||||
/*
|
||||
* Creates the object with given root shadow node, revision number and
|
||||
* telemetry.
|
||||
*/
|
||||
ShadowTreeRevision(
|
||||
ShadowNode::Shared const &rootShadowNode,
|
||||
Number number,
|
||||
MountingTelemetry telemetry);
|
||||
|
||||
/*
|
||||
* Returns telemetry associated with this revision.
|
||||
*/
|
||||
MountingTelemetry const &getTelemetry() const;
|
||||
|
||||
private:
|
||||
friend class MountingCoordinator;
|
||||
|
||||
/*
|
||||
* Methods from this section are meant to be used by `MountingCoordinator`
|
||||
* only.
|
||||
*/
|
||||
ShadowNode const &getRootShadowNode();
|
||||
Number getNumber() const;
|
||||
|
||||
private:
|
||||
ShadowNode::Shared rootShadowNode_;
|
||||
Number number_;
|
||||
MountingTelemetry telemetry_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -228,12 +228,12 @@ SchedulerDelegate *Scheduler::getDelegate() const {
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void Scheduler::shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
MountingTransaction &&transaction) const {
|
||||
ShadowTree const &shadowTree,
|
||||
MountingCoordinator::Shared const &mountingCoordinator) const {
|
||||
SystraceSection s("Scheduler::shadowTreeDidCommit");
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->schedulerDidFinishTransaction(std::move(transaction));
|
||||
delegate_->schedulerDidFinishTransaction(mountingCoordinator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
|
||||
#pragma mark - ShadowTreeDelegate
|
||||
|
||||
void shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
MountingTransaction &&transaction) const override;
|
||||
ShadowTree const &shadowTree,
|
||||
MountingCoordinator::Shared const &mountingCoordinator) const override;
|
||||
|
||||
private:
|
||||
SchedulerDelegate *delegate_;
|
||||
|
||||
@@ -26,7 +26,7 @@ class SchedulerDelegate {
|
||||
* to construct a new one.
|
||||
*/
|
||||
virtual void schedulerDidFinishTransaction(
|
||||
MountingTransaction &&mountingTransaction) = 0;
|
||||
MountingCoordinator::Shared const &mountingCoordinator) = 0;
|
||||
|
||||
/*
|
||||
* Called right after a new ShadowNode was created.
|
||||
|
||||
Reference in New Issue
Block a user