Skip to content

Commit 8a6c589

Browse files
authored
[Flight] Keep a separate ref count for debug chunks (#33717)
Same as #33716 but without the separate close signal. We'll need the ref count for separate debug channel anyway but I'm not sure we'll need the separate close signal.
1 parent 7cafeff commit 8a6c589

File tree

1 file changed

+47
-55
lines changed

1 file changed

+47
-55
lines changed

packages/react-server/src/ReactFlightServer.js

Lines changed: 47 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ function patchConsole(consoleInst: typeof console, methodName: string) {
278278
request,
279279
parseStackTrace(new Error('react-stack-top-frame'), 1),
280280
);
281-
request.pendingChunks++;
281+
request.pendingDebugChunks++;
282282
const owner: null | ReactComponentInfo = resolveOwner();
283283
const args = Array.from(arguments);
284284
// Extract the env if this is a console log that was replayed from another env.
@@ -468,6 +468,7 @@ export type Request = {
468468
timeOrigin: number,
469469
abortTime: number,
470470
// DEV-only
471+
pendingDebugChunks: number,
471472
completedDebugChunks: Array<Chunk | BinaryChunk>,
472473
environmentName: () => string,
473474
filterStackFrame: (
@@ -587,6 +588,7 @@ function RequestInstance(
587588
this.onFatalError = onFatalError;
588589

589590
if (__DEV__) {
591+
this.pendingDebugChunks = 0;
590592
this.completedDebugChunks = ([]: Array<Chunk>);
591593
this.environmentName =
592594
environmentName === undefined
@@ -725,7 +727,7 @@ function serializeDebugThenable(
725727
thenable: Thenable<any>,
726728
): string {
727729
// Like serializeThenable but for renderDebugModel
728-
request.pendingChunks++;
730+
request.pendingDebugChunks++;
729731
const id = request.nextChunkId++;
730732
const ref = serializePromiseID(id);
731733
request.writtenDebugObjects.set(thenable, ref);
@@ -737,20 +739,9 @@ function serializeDebugThenable(
737739
}
738740
case 'rejected': {
739741
const x = thenable.reason;
740-
if (
741-
enablePostpone &&
742-
typeof x === 'object' &&
743-
x !== null &&
744-
(x: any).$$typeof === REACT_POSTPONE_TYPE
745-
) {
746-
const postponeInstance: Postpone = (x: any);
747-
// We don't log this postpone.
748-
emitPostponeChunk(request, id, postponeInstance);
749-
} else {
750-
// We don't log these errors since they didn't actually throw into Flight.
751-
const digest = '';
752-
emitErrorChunk(request, id, digest, x, true);
753-
}
742+
// We don't log these errors since they didn't actually throw into Flight.
743+
const digest = '';
744+
emitErrorChunk(request, id, digest, x, true);
754745
return ref;
755746
}
756747
}
@@ -787,20 +778,9 @@ function serializeDebugThenable(
787778
enqueueFlush(request);
788779
return;
789780
}
790-
if (
791-
enablePostpone &&
792-
typeof reason === 'object' &&
793-
reason !== null &&
794-
(reason: any).$$typeof === REACT_POSTPONE_TYPE
795-
) {
796-
const postponeInstance: Postpone = (reason: any);
797-
// We don't log this postpone.
798-
emitPostponeChunk(request, id, postponeInstance);
799-
} else {
800-
// We don't log these errors since they didn't actually throw into Flight.
801-
const digest = '';
802-
emitErrorChunk(request, id, digest, reason, true);
803-
}
781+
// We don't log these errors since they didn't actually throw into Flight.
782+
const digest = '';
783+
emitErrorChunk(request, id, digest, reason, true);
804784
enqueueFlush(request);
805785
},
806786
);
@@ -1445,7 +1425,7 @@ function renderFunctionComponent<Props>(
14451425
const componentName =
14461426
(Component: any).displayName || Component.name || '';
14471427
const componentEnv = (0, request.environmentName)();
1448-
request.pendingChunks++;
1428+
request.pendingDebugChunks++;
14491429
componentDebugInfo = ({
14501430
name: componentName,
14511431
env: componentEnv,
@@ -2219,7 +2199,7 @@ function visitAsyncNode(
22192199
const env = (0, request.environmentName)();
22202200
advanceTaskTime(request, task, startTime);
22212201
// Then emit a reference to us awaiting it in the current task.
2222-
request.pendingChunks++;
2202+
request.pendingDebugChunks++;
22232203
emitDebugChunk(request, task.id, {
22242204
awaited: ((ioNode: any): ReactIOInfo), // This is deduped by this reference.
22252205
env: env,
@@ -2276,7 +2256,7 @@ function emitAsyncSequence(
22762256
} else if (awaitedNode !== null) {
22772257
// Nothing in user space (unfiltered stack) awaited this.
22782258
serializeIONode(request, awaitedNode, awaitedNode.promise);
2279-
request.pendingChunks++;
2259+
request.pendingDebugChunks++;
22802260
// We log the environment at the time when we ping which may be later than what the
22812261
// environment was when we actually started awaiting.
22822262
const env = (0, request.environmentName)();
@@ -2457,7 +2437,7 @@ function serializeDeferredObject(
24572437
// This client supports a long lived connection. We can assign this object
24582438
// an ID to be lazy loaded later.
24592439
// This keeps the connection alive until we ask for it or release it.
2460-
request.pendingChunks++;
2440+
request.pendingDebugChunks++;
24612441
const id = request.nextChunkId++;
24622442
deferredDebugObjects.existing.set(value, id);
24632443
deferredDebugObjects.retained.set(id, value);
@@ -2594,7 +2574,7 @@ function serializeDebugClientReference(
25942574
try {
25952575
const clientReferenceMetadata: ClientReferenceMetadata =
25962576
resolveClientReferenceMetadata(request.bundlerConfig, clientReference);
2597-
request.pendingChunks++;
2577+
request.pendingDebugChunks++;
25982578
const importId = request.nextChunkId++;
25992579
emitImportChunk(request, importId, clientReferenceMetadata, true);
26002580
if (parent[0] === REACT_ELEMENT_TYPE && parentPropertyName === '1') {
@@ -2607,7 +2587,7 @@ function serializeDebugClientReference(
26072587
}
26082588
return serializeByValueID(importId);
26092589
} catch (x) {
2610-
request.pendingChunks++;
2590+
request.pendingDebugChunks++;
26112591
const errorId = request.nextChunkId++;
26122592
const digest = logRecoverableError(request, x, null);
26132593
emitErrorChunk(request, errorId, digest, x, true);
@@ -2710,7 +2690,7 @@ function serializeLargeTextString(request: Request, text: string): string {
27102690
}
27112691

27122692
function serializeDebugLargeTextString(request: Request, text: string): string {
2713-
request.pendingChunks++;
2693+
request.pendingDebugChunks++;
27142694
const textId = request.nextChunkId++;
27152695
emitTextChunk(request, textId, text, true);
27162696
return serializeByValueID(textId);
@@ -2819,7 +2799,7 @@ function serializeDebugTypedArray(
28192799
tag: string,
28202800
typedArray: $ArrayBufferView,
28212801
): string {
2822-
request.pendingChunks++;
2802+
request.pendingDebugChunks++;
28232803
const bufferId = request.nextChunkId++;
28242804
emitTypedArrayChunk(request, bufferId, tag, typedArray, true);
28252805
return serializeByValueID(bufferId);
@@ -2828,6 +2808,7 @@ function serializeDebugTypedArray(
28282808
function serializeDebugBlob(request: Request, blob: Blob): string {
28292809
const model: Array<string | Uint8Array> = [blob.type];
28302810
const reader = blob.stream().getReader();
2811+
request.pendingDebugChunks++;
28312812
const id = request.nextChunkId++;
28322813
function progress(
28332814
entry: {done: false, value: Uint8Array} | {done: true, value: void},
@@ -4095,7 +4076,7 @@ function outlineIOInfo(request: Request, ioInfo: ReactIOInfo): void {
40954076
return;
40964077
}
40974078
// We can't serialize the ConsoleTask/Error objects so we need to omit them before serializing.
4098-
request.pendingChunks++;
4079+
request.pendingDebugChunks++;
40994080
const id = request.nextChunkId++;
41004081
const owner = ioInfo.owner;
41014082
// Ensure the owner is already outlined.
@@ -4173,7 +4154,7 @@ function serializeIONode(
41734154
request.abortTime
41744155
: ioNode.end;
41754156

4176-
request.pendingChunks++;
4157+
request.pendingDebugChunks++;
41774158
const id = request.nextChunkId++;
41784159
emitIOInfoChunk(
41794160
request,
@@ -4210,7 +4191,11 @@ function emitTypedArrayChunk(
42104191
}
42114192
}
42124193
}
4213-
request.pendingChunks++; // Extra chunk for the header.
4194+
if (debug) {
4195+
request.pendingDebugChunks++;
4196+
} else {
4197+
request.pendingChunks++; // Extra chunk for the header.
4198+
}
42144199
// TODO: Convert to little endian if that's not the server default.
42154200
const binaryChunk = typedArrayToBinaryChunk(typedArray);
42164201
const binaryLength = byteLengthOfBinaryChunk(binaryChunk);
@@ -4235,7 +4220,11 @@ function emitTextChunk(
42354220
'Existence of byteLengthOfChunk should have already been checked. This is a bug in React.',
42364221
);
42374222
}
4238-
request.pendingChunks++; // Extra chunk for the header.
4223+
if (debug) {
4224+
request.pendingDebugChunks++;
4225+
} else {
4226+
request.pendingChunks++; // Extra chunk for the header.
4227+
}
42394228
const textChunk = stringToChunk(text);
42404229
const binaryLength = byteLengthOfChunk(textChunk);
42414230
const row = id.toString(16) + ':T' + binaryLength.toString(16) + ',';
@@ -4620,7 +4609,7 @@ function renderDebugModel(
46204609
// $FlowFixMe[method-unbinding]
46214610
'(' + Function.prototype.toString.call(value) + ')',
46224611
);
4623-
request.pendingChunks++;
4612+
request.pendingDebugChunks++;
46244613
const id = request.nextChunkId++;
46254614
const processedChunk = encodeReferenceChunk(request, id, serializedValue);
46264615
request.completedDebugChunks.push(processedChunk);
@@ -4778,7 +4767,7 @@ function outlineDebugModel(
47784767
}
47794768

47804769
const id = request.nextChunkId++;
4781-
request.pendingChunks++;
4770+
request.pendingDebugChunks++;
47824771
emitOutlinedDebugModelChunk(request, id, counter, model);
47834772
return id;
47844773
}
@@ -4827,7 +4816,7 @@ function emitTimeOriginChunk(request: Request, timeOrigin: number): void {
48274816
// We emit the time origin once. All ReactTimeInfo timestamps later in the stream
48284817
// are relative to this time origin. This allows for more compact number encoding
48294818
// and lower precision loss.
4830-
request.pendingChunks++;
4819+
request.pendingDebugChunks++;
48314820
const row = ':N' + timeOrigin + '\n';
48324821
const processedChunk = stringToChunk(row);
48334822
// TODO: Move to its own priority queue.
@@ -4854,7 +4843,7 @@ function forwardDebugInfo(
48544843
// being no references to this as an owner.
48554844
outlineComponentInfo(request, (info: any));
48564845
// Emit a reference to the outlined one.
4857-
request.pendingChunks++;
4846+
request.pendingDebugChunks++;
48584847
emitDebugChunk(request, id, info);
48594848
} else if (info.awaited) {
48604849
const ioInfo = info.awaited;
@@ -4895,11 +4884,11 @@ function forwardDebugInfo(
48954884
// $FlowFixMe[cannot-write]
48964885
debugAsyncInfo.stack = debugStack;
48974886
}
4898-
request.pendingChunks++;
4887+
request.pendingDebugChunks++;
48994888
emitDebugChunk(request, id, debugAsyncInfo);
49004889
}
49014890
} else {
4902-
request.pendingChunks++;
4891+
request.pendingDebugChunks++;
49034892
emitDebugChunk(request, id, info);
49044893
}
49054894
}
@@ -5001,7 +4990,7 @@ function forwardDebugInfoFromAbortedTask(request: Request, task: Task): void {
50014990
// complete in time before aborting.
50024991
// The best we can do is try to emit the stack of where this Promise was created.
50034992
serializeIONode(request, node, null);
5004-
request.pendingChunks++;
4993+
request.pendingDebugChunks++;
50054994
const env = (0, request.environmentName)();
50064995
const asyncInfo: ReactAsyncInfo = {
50074996
awaited: ((node: any): ReactIOInfo), // This is deduped by this reference.
@@ -5030,7 +5019,7 @@ function emitTimingChunk(
50305019
if (!enableProfilerTimer || !enableComponentPerformanceTrack) {
50315020
return;
50325021
}
5033-
request.pendingChunks++;
5022+
request.pendingDebugChunks++;
50345023
const relativeTimestamp = timestamp - request.timeOrigin;
50355024
const row =
50365025
serializeRowHeader('D', id) + '{"time":' + relativeTimestamp + '}\n';
@@ -5242,7 +5231,7 @@ function retryTask(request: Request, task: Task): void {
52425231
if (__DEV__) {
52435232
const currentEnv = (0, request.environmentName)();
52445233
if (currentEnv !== task.environmentName) {
5245-
request.pendingChunks++;
5234+
request.pendingDebugChunks++;
52465235
// The environment changed since we last emitted any debug information for this
52475236
// task. We emit an entry that just includes the environment name change.
52485237
emitDebugChunk(request, task.id, {env: currentEnv});
@@ -5462,7 +5451,7 @@ function flushCompletedChunks(
54625451
const debugChunks = request.completedDebugChunks;
54635452
i = 0;
54645453
for (; i < debugChunks.length; i++) {
5465-
request.pendingChunks--;
5454+
request.pendingDebugChunks--;
54665455
const chunk = debugChunks[i];
54675456
const keepWriting: boolean = writeChunkAndReturn(destination, chunk);
54685457
if (!keepWriting) {
@@ -5510,7 +5499,10 @@ function flushCompletedChunks(
55105499
completeWriting(destination);
55115500
}
55125501
flushBuffered(destination);
5513-
if (request.pendingChunks === 0) {
5502+
if (
5503+
request.pendingChunks === 0 &&
5504+
(!__DEV__ || request.pendingDebugChunks === 0)
5505+
) {
55145506
// We're done.
55155507
if (enableTaint) {
55165508
cleanupTaintQueue(request);
@@ -5729,7 +5721,7 @@ export function resolveDebugMessage(request: Request, message: string): void {
57295721
const retainedValue = deferredDebugObjects.retained.get(id);
57305722
if (retainedValue !== undefined) {
57315723
// We're no longer blocked on this. We won't emit it.
5732-
request.pendingChunks--;
5724+
request.pendingDebugChunks--;
57335725
deferredDebugObjects.retained.delete(id);
57345726
deferredDebugObjects.existing.delete(retainedValue);
57355727
enqueueFlush(request);
@@ -5772,7 +5764,7 @@ export function closeDebugChannel(request: Request): void {
57725764
);
57735765
}
57745766
deferredDebugObjects.retained.forEach((value, id) => {
5775-
request.pendingChunks--;
5767+
request.pendingDebugChunks--;
57765768
deferredDebugObjects.retained.delete(id);
57775769
deferredDebugObjects.existing.delete(value);
57785770
});

0 commit comments

Comments
 (0)