Fabric: Introducing MountingTransaction
Summary: `MountingTransaction` encapsulates all artifacts of `ShadowTree` commit, particularly list of mutations and meta-data. We will rely on this heavily in the coming diffs. Reviewed By: JoshuaGross Differential Revision: D15021795 fbshipit-source-id: 811da7afd7b929a34a81aa66566193d46bbc34f8
This commit is contained in:
Родитель
c257a57e8e
Коммит
af0daaf583
|
@ -11,8 +11,8 @@
|
|||
#import <React/RCTPrimitives.h>
|
||||
#import <react/core/ComponentDescriptor.h>
|
||||
#import <react/core/ReactPrimitives.h>
|
||||
#import <react/mounting/MountingTransaction.h>
|
||||
#import <react/mounting/ShadowView.h>
|
||||
#import <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
@ -27,10 +27,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (nonatomic, strong) RCTComponentViewRegistry *componentViewRegistry;
|
||||
|
||||
/**
|
||||
* Schedule mutations to be performed on the main thread.
|
||||
* Schedule a mounting transaction to be performed on the main thread.
|
||||
* Can be called from any thread.
|
||||
*/
|
||||
- (void)scheduleMutations:(facebook::react::ShadowViewMutationList const &)mutations rootTag:(ReactTag)rootTag;
|
||||
- (void)scheduleTransaction:(facebook::react::MountingTransaction &&)mountingTransaction;
|
||||
|
||||
/**
|
||||
* Suggests preliminary creation of a component view of given type.
|
||||
|
|
|
@ -211,23 +211,23 @@ static void RNPerformMountInstructions(ShadowViewMutationList const &mutations,
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)scheduleMutations:(ShadowViewMutationList const &)mutations rootTag:(ReactTag)rootTag
|
||||
- (void)scheduleTransaction:(facebook::react::MountingTransaction &&)mountingTransaction;
|
||||
{
|
||||
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:mutations rootTag:rootTag];
|
||||
[self mountMutations:mountingTransaction.getMutations() rootTag:mountingTransaction.getSurfaceId()];
|
||||
return;
|
||||
}
|
||||
|
||||
// We need a non-reference for `mutations` to allow copy semantic.
|
||||
auto mutationsCopy = mutations;
|
||||
// We need a non-reference for `mountingTransaction` to allow copy semantic.
|
||||
__block auto mountingTransactionCopy = MountingTransaction{mountingTransaction};
|
||||
|
||||
RCTExecuteOnMainQueue(^{
|
||||
RCTAssertMainQueue();
|
||||
[self mountMutations:mutationsCopy rootTag:rootTag];
|
||||
[self mountMutations:mountingTransactionCopy.getMutations() rootTag:mountingTransactionCopy.getSurfaceId()];
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +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/uimanager/ComponentDescriptorFactory.h>
|
||||
#import <react/utils/ContextContainer.h>
|
||||
|
@ -25,8 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@protocol RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList const &)mutations
|
||||
rootTag:(ReactTag)rootTag;
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingTransaction &&)mountingTransaction;
|
||||
|
||||
- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
|
||||
|
||||
|
|
|
@ -22,14 +22,10 @@ class SchedulerDelegateProxy : public SchedulerDelegate {
|
|||
public:
|
||||
SchedulerDelegateProxy(void *scheduler) : scheduler_(scheduler) {}
|
||||
|
||||
void schedulerDidFinishTransaction(
|
||||
Tag rootTag,
|
||||
const ShadowViewMutationList &mutations,
|
||||
const long commitStartTime,
|
||||
const long layoutTime) override
|
||||
void schedulerDidFinishTransaction(MountingTransaction &&mountingTransaction) override
|
||||
{
|
||||
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
|
||||
[scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
|
||||
[scheduler.delegate schedulerDidFinishTransaction:std::move(mountingTransaction)];
|
||||
}
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowView &shadowView) override
|
||||
|
|
|
@ -309,14 +309,13 @@ using namespace facebook::react;
|
|||
|
||||
#pragma mark - RCTSchedulerDelegate
|
||||
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::ShadowViewMutationList const &)mutations
|
||||
rootTag:(ReactTag)rootTag
|
||||
- (void)schedulerDidFinishTransaction:(facebook::react::MountingTransaction &&)mountingTransaction
|
||||
{
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:rootTag];
|
||||
RCTFabricSurface *surface = [_surfaceRegistry surfaceForRootTag:mountingTransaction.getSurfaceId()];
|
||||
|
||||
[surface _setStage:RCTSurfaceStagePrepared];
|
||||
|
||||
[_mountingManager scheduleMutations:mutations rootTag:rootTag];
|
||||
[_mountingManager scheduleTransaction:std::move(mountingTransaction)];
|
||||
}
|
||||
|
||||
- (void)schedulerOptimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
|
||||
|
|
|
@ -329,11 +329,12 @@ local_ref<JMountItem::javaobject> createDeleteMountItem(
|
|||
}
|
||||
|
||||
void Binding::schedulerDidFinishTransaction(
|
||||
const Tag rootTag,
|
||||
const ShadowViewMutationList& mutations,
|
||||
const long commitStartTime,
|
||||
const long layoutTime) {
|
||||
MountingTransaction &&mountingTransaction) {
|
||||
SystraceSection s("FabricUIManager::schedulerDidFinishTransaction");
|
||||
|
||||
auto telemetry = mountingTransaction.getTelemetry();
|
||||
auto mutations = mountingTransaction.getMutations();
|
||||
|
||||
std::vector<local_ref<jobject>> queue;
|
||||
// Upper bound estimation of mount items to be delivered to Java side.
|
||||
int size = mutations.size() * 3 + 42;
|
||||
|
@ -466,8 +467,8 @@ void Binding::schedulerDidFinishTransaction(
|
|||
scheduleMountItems(
|
||||
javaUIManager_,
|
||||
batch.get(),
|
||||
commitStartTime,
|
||||
layoutTime,
|
||||
telemetry.commitStartTime,
|
||||
telemetry.layoutTime,
|
||||
finishTransactionStartTime,
|
||||
finishTransactionEndTime);
|
||||
}
|
||||
|
|
|
@ -57,10 +57,7 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
|
|||
void stopSurface(jint surfaceId);
|
||||
|
||||
void schedulerDidFinishTransaction(
|
||||
const Tag rootTag,
|
||||
const ShadowViewMutationList& mutations,
|
||||
const long commitStartTime,
|
||||
const long layoutTime);
|
||||
MountingTransaction &&mountingTransaction);
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(
|
||||
const SurfaceId surfaceId,
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* 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 "MountingTransaction.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using Telemetry = MountingTransaction::Telemetry;
|
||||
using Revision = MountingTransaction::Revision;
|
||||
|
||||
MountingTransaction::MountingTransaction(
|
||||
SurfaceId surfaceId,
|
||||
Revision revision,
|
||||
ShadowViewMutationList &&mutations,
|
||||
Telemetry telemetry)
|
||||
: surfaceId_(surfaceId),
|
||||
revision_(revision),
|
||||
mutations_(std::move(mutations)),
|
||||
telemetry_(std::move(telemetry)) {}
|
||||
|
||||
ShadowViewMutationList const &MountingTransaction::getMutations() const & {
|
||||
return mutations_;
|
||||
}
|
||||
|
||||
ShadowViewMutationList MountingTransaction::getMutations() && {
|
||||
return std::move(mutations_);
|
||||
}
|
||||
|
||||
Telemetry const &MountingTransaction::getTelemetry() const {
|
||||
return telemetry_;
|
||||
}
|
||||
|
||||
SurfaceId MountingTransaction::getSurfaceId() const {
|
||||
return surfaceId_;
|
||||
}
|
||||
|
||||
Revision MountingTransaction::getRevision() const {
|
||||
return revision_;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* 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 <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
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.
|
||||
*/
|
||||
class MountingTransaction final {
|
||||
public:
|
||||
/*
|
||||
* Revision grows continuously starting from `1`. Value `0` represents the
|
||||
* state before the very first transaction happens.
|
||||
*/
|
||||
using Revision = int64_t;
|
||||
|
||||
/*
|
||||
* Represent arbitrary telementry data that can be associated with the
|
||||
* particular transaction.
|
||||
*/
|
||||
struct Telemetry final {
|
||||
long commitStartTime{};
|
||||
long layoutTime{};
|
||||
};
|
||||
|
||||
/*
|
||||
* Copying a list of `ShadowViewMutation` is expensive, so the constructor
|
||||
* accepts it as rvalue reference to discourage copying.
|
||||
*/
|
||||
MountingTransaction(
|
||||
SurfaceId surfaceId,
|
||||
Revision revision,
|
||||
ShadowViewMutationList &&mutations,
|
||||
Telemetry telemetry);
|
||||
|
||||
/*
|
||||
* Copy semantic.
|
||||
* Copying of MountingTransaction is expensive, so copy-constructor is
|
||||
* explicit and copy-assignment is deleted to prevent accidental copying.
|
||||
*/
|
||||
explicit MountingTransaction(const MountingTransaction &mountingTransaction) =
|
||||
default;
|
||||
MountingTransaction &operator=(const MountingTransaction &other) = delete;
|
||||
|
||||
/*
|
||||
* Move semantic.
|
||||
*/
|
||||
MountingTransaction(MountingTransaction &&mountingTransaction) noexcept =
|
||||
default;
|
||||
MountingTransaction &operator=(MountingTransaction &&other) = default;
|
||||
|
||||
/*
|
||||
* Returns a list of mutations that represent the transaction. The list can be
|
||||
* empty (theoretically).
|
||||
*/
|
||||
ShadowViewMutationList const &getMutations() const &;
|
||||
ShadowViewMutationList getMutations() &&;
|
||||
|
||||
/*
|
||||
* Returns telemetry associated with this transaction.
|
||||
*/
|
||||
Telemetry const &getTelemetry() const;
|
||||
|
||||
/*
|
||||
* Returns the id of the surface that the transaction belongs to.
|
||||
*/
|
||||
SurfaceId getSurfaceId() const;
|
||||
|
||||
/*
|
||||
* Returns the revision of the ShadowTree that this transaction represents.
|
||||
*/
|
||||
Revision getRevision() const;
|
||||
|
||||
private:
|
||||
SurfaceId surfaceId_;
|
||||
Revision revision_;
|
||||
ShadowViewMutationList mutations_;
|
||||
Telemetry telemetry_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -127,15 +127,14 @@ Tag ShadowTree::getSurfaceId() const {
|
|||
|
||||
void ShadowTree::commit(
|
||||
ShadowTreeCommitTransaction transaction,
|
||||
long commitStartTime,
|
||||
int *revision) const {
|
||||
long commitStartTime) const {
|
||||
SystraceSection s("ShadowTree::commit");
|
||||
|
||||
int attempts = 0;
|
||||
|
||||
while (true) {
|
||||
attempts++;
|
||||
if (tryCommit(transaction, commitStartTime, revision)) {
|
||||
if (tryCommit(transaction, commitStartTime)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,8 +146,7 @@ void ShadowTree::commit(
|
|||
|
||||
bool ShadowTree::tryCommit(
|
||||
ShadowTreeCommitTransaction transaction,
|
||||
long commitStartTime,
|
||||
int *revision) const {
|
||||
long commitStartTime) const {
|
||||
SystraceSection s("ShadowTree::tryCommit");
|
||||
|
||||
SharedRootShadowNode oldRootShadowNode;
|
||||
|
@ -170,6 +168,7 @@ bool ShadowTree::tryCommit(
|
|||
layoutTime = getTime() - layoutTime;
|
||||
newRootShadowNode->sealRecursive();
|
||||
|
||||
int revision;
|
||||
auto mutations =
|
||||
calculateShadowViewMutations(*oldRootShadowNode, *newRootShadowNode);
|
||||
|
||||
|
@ -190,13 +189,9 @@ bool ShadowTree::tryCommit(
|
|||
oldRootShadowNode->getChildren(), newRootShadowNode->getChildren());
|
||||
}
|
||||
|
||||
revision = revision_;
|
||||
revision_++;
|
||||
|
||||
// Returning last revision if requested.
|
||||
if (revision) {
|
||||
*revision = revision_;
|
||||
}
|
||||
|
||||
#ifdef RN_SHADOW_TREE_INTROSPECTION
|
||||
stubViewTree_.mutate(mutations);
|
||||
auto stubViewTree = stubViewTreeFromShadowNode(*rootShadowNode_);
|
||||
|
@ -219,7 +214,11 @@ bool ShadowTree::tryCommit(
|
|||
|
||||
if (delegate_) {
|
||||
delegate_->shadowTreeDidCommit(
|
||||
*this, mutations, commitStartTime, layoutTime);
|
||||
*this,
|
||||
{surfaceId_,
|
||||
revision,
|
||||
std::move(mutations),
|
||||
{commitStartTime, layoutTime}});
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -55,22 +55,16 @@ class ShadowTree final {
|
|||
* Performs commit calling `transaction` function with a `oldRootShadowNode`
|
||||
* and expecting a `newRootShadowNode` as a return value.
|
||||
* The `transaction` function can abort commit returning `nullptr`.
|
||||
* If a `revision` pointer is not null, the method will store there a
|
||||
* contiguous revision number of the successfully performed transaction.
|
||||
* Returns `true` if the operation finished successfully.
|
||||
*/
|
||||
bool tryCommit(
|
||||
ShadowTreeCommitTransaction transaction,
|
||||
long commitStartTime,
|
||||
int *revision = nullptr) const;
|
||||
bool tryCommit(ShadowTreeCommitTransaction transaction, long commitStartTime)
|
||||
const;
|
||||
|
||||
/*
|
||||
* Calls `tryCommit` in a loop until it finishes successfully.
|
||||
*/
|
||||
void commit(
|
||||
ShadowTreeCommitTransaction transaction,
|
||||
long commitStartTime,
|
||||
int *revision = nullptr) const;
|
||||
void commit(ShadowTreeCommitTransaction transaction, long commitStartTime)
|
||||
const;
|
||||
|
||||
#pragma mark - Delegate
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -22,9 +22,7 @@ class ShadowTreeDelegate {
|
|||
*/
|
||||
virtual void shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
const ShadowViewMutationList &mutations,
|
||||
long commitStartTime,
|
||||
long layoutTime) const = 0;
|
||||
MountingTransaction &&transaction) const = 0;
|
||||
|
||||
virtual ~ShadowTreeDelegate() noexcept = default;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace react {
|
|||
struct ShadowView final {
|
||||
ShadowView() = default;
|
||||
ShadowView(const ShadowView &shadowView) = default;
|
||||
ShadowView(ShadowView &&shadowView) noexcept = default;
|
||||
|
||||
~ShadowView(){};
|
||||
|
||||
|
@ -32,6 +33,7 @@ struct ShadowView final {
|
|||
explicit ShadowView(const ShadowNode &shadowNode);
|
||||
|
||||
ShadowView &operator=(const ShadowView &other) = default;
|
||||
ShadowView &operator=(ShadowView &&other) = default;
|
||||
|
||||
bool operator==(const ShadowView &rhs) const;
|
||||
bool operator!=(const ShadowView &rhs) const;
|
||||
|
|
|
@ -242,14 +242,11 @@ SchedulerDelegate *Scheduler::getDelegate() const {
|
|||
|
||||
void Scheduler::shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
const ShadowViewMutationList &mutations,
|
||||
long commitStartTime,
|
||||
long layoutTime) const {
|
||||
MountingTransaction &&transaction) const {
|
||||
SystraceSection s("Scheduler::shadowTreeDidCommit");
|
||||
|
||||
if (delegate_) {
|
||||
delegate_->schedulerDidFinishTransaction(
|
||||
shadowTree.getSurfaceId(), mutations, commitStartTime, layoutTime);
|
||||
delegate_->schedulerDidFinishTransaction(std::move(transaction));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,9 +93,7 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate {
|
|||
|
||||
void shadowTreeDidCommit(
|
||||
const ShadowTree &shadowTree,
|
||||
const ShadowViewMutationList &mutations,
|
||||
long commitStartTime,
|
||||
long layoutTime) const override;
|
||||
MountingTransaction &&transaction) const override;
|
||||
|
||||
private:
|
||||
SchedulerDelegate *delegate_;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <react/core/ReactPrimitives.h>
|
||||
#include <react/core/ShadowNode.h>
|
||||
#include <react/mounting/MountingTransaction.h>
|
||||
#include <react/mounting/ShadowViewMutation.h>
|
||||
|
||||
namespace facebook {
|
||||
|
@ -25,10 +26,7 @@ class SchedulerDelegate {
|
|||
* to construct a new one.
|
||||
*/
|
||||
virtual void schedulerDidFinishTransaction(
|
||||
Tag rootTag,
|
||||
ShadowViewMutationList const &mutations,
|
||||
const long commitStartTime,
|
||||
const long layoutTime) = 0;
|
||||
MountingTransaction &&mountingTransaction) = 0;
|
||||
|
||||
/*
|
||||
* Called right after a new ShadowNode was created.
|
||||
|
|
Загрузка…
Ссылка в новой задаче