Skip to content

Commit c9db779

Browse files
committed
do not store initialResultRecord on context
as then memory for the result record tree cannot be freed
1 parent 6e3eecd commit c9db779

File tree

2 files changed

+93
-93
lines changed

2 files changed

+93
-93
lines changed

src/execution/IncrementalPublisher.ts

Lines changed: 51 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -97,34 +97,17 @@ export type FormattedIncrementalResult<
9797
* parents have completed so that they can no longer be filtered. This includes all Incremental
9898
* Data records in `released`, as well as Incremental Data records that have not yet completed.
9999
*
100-
* `_initialResult`: a record containing the state of the initial result, as follows:
101-
* `isCompleted`: indicates whether the initial result has completed.
102-
* `children`: the set of Incremental Data records that can be be published when the initial
103-
* result is completed.
104-
*
105-
* Each Incremental Data record also contains similar metadata, i.e. these records also contain
106-
* similar `isCompleted` and `children` properties.
107-
*
108100
* @internal
109101
*/
110102
export class IncrementalPublisher {
111-
private _initialResult: {
112-
children: Set<IncrementalDataRecord>;
113-
isCompleted: boolean;
114-
};
115-
116-
private _released: Set<IncrementalDataRecord>;
117-
private _pending: Set<IncrementalDataRecord>;
103+
private _released: Set<SubsequentDataRecord>;
104+
private _pending: Set<SubsequentDataRecord>;
118105

119106
// these are assigned within the Promise executor called synchronously within the constructor
120107
private _signalled!: Promise<unknown>;
121108
private _resolve!: () => void;
122109

123110
constructor() {
124-
this._initialResult = {
125-
children: new Set(),
126-
isCompleted: false,
127-
};
128111
this._released = new Set();
129112
this._pending = new Set();
130113
this._reset();
@@ -210,19 +193,22 @@ export class IncrementalPublisher {
210193
};
211194
}
212195

196+
prepareInitialResultRecord(): InitialResultRecord {
197+
return {
198+
errors: [],
199+
children: new Set(),
200+
};
201+
}
202+
213203
prepareNewDeferredFragmentRecord(opts: {
214204
label: string | undefined;
215205
path: Path | undefined;
216-
parentContext: IncrementalDataRecord | undefined;
206+
parentContext: IncrementalDataRecord;
217207
}): DeferredFragmentRecord {
218208
const deferredFragmentRecord = new DeferredFragmentRecord(opts);
219209

220210
const parentContext = opts.parentContext;
221-
if (parentContext) {
222-
parentContext.children.add(deferredFragmentRecord);
223-
} else {
224-
this._initialResult.children.add(deferredFragmentRecord);
225-
}
211+
parentContext.children.add(deferredFragmentRecord);
226212

227213
return deferredFragmentRecord;
228214
}
@@ -231,16 +217,12 @@ export class IncrementalPublisher {
231217
label: string | undefined;
232218
path: Path | undefined;
233219
asyncIterator?: AsyncIterator<unknown>;
234-
parentContext: IncrementalDataRecord | undefined;
220+
parentContext: IncrementalDataRecord;
235221
}): StreamItemsRecord {
236222
const streamItemsRecord = new StreamItemsRecord(opts);
237223

238224
const parentContext = opts.parentContext;
239-
if (parentContext) {
240-
parentContext.children.add(streamItemsRecord);
241-
} else {
242-
this._initialResult.children.add(streamItemsRecord);
243-
}
225+
parentContext.children.add(streamItemsRecord);
244226

245227
return streamItemsRecord;
246228
}
@@ -274,29 +256,31 @@ export class IncrementalPublisher {
274256
incrementalDataRecord.errors.push(error);
275257
}
276258

277-
publishInitial() {
278-
for (const child of this._initialResult.children) {
259+
publishInitial(initialResult: InitialResultRecord) {
260+
for (const child of initialResult.children) {
279261
if (child.filtered) {
280262
continue;
281263
}
282264
this._publish(child);
283265
}
284266
}
285267

286-
filter(
287-
nullPath: Path,
288-
erroringIncrementalDataRecord: IncrementalDataRecord | undefined,
289-
) {
268+
getInitialErrors(
269+
initialResult: InitialResultRecord,
270+
): ReadonlyArray<GraphQLError> {
271+
return initialResult.errors;
272+
}
273+
274+
filter(nullPath: Path, erroringIncrementalDataRecord: IncrementalDataRecord) {
290275
const nullPathArray = pathToArray(nullPath);
291276

292277
const asyncIterators = new Set<AsyncIterator<unknown>>();
293278

294-
const children =
295-
erroringIncrementalDataRecord === undefined
296-
? this._initialResult.children
297-
: erroringIncrementalDataRecord.children;
279+
const descendants = this._getDescendants(
280+
erroringIncrementalDataRecord.children,
281+
);
298282

299-
for (const child of this._getDescendants(children)) {
283+
for (const child of descendants) {
300284
if (!this._matchesPath(child.path, nullPathArray)) {
301285
continue;
302286
}
@@ -332,31 +316,31 @@ export class IncrementalPublisher {
332316
this._signalled = signalled;
333317
}
334318

335-
private _introduce(item: IncrementalDataRecord) {
319+
private _introduce(item: SubsequentDataRecord) {
336320
this._pending.add(item);
337321
}
338322

339-
private _release(item: IncrementalDataRecord): void {
323+
private _release(item: SubsequentDataRecord): void {
340324
if (this._pending.has(item)) {
341325
this._released.add(item);
342326
this._trigger();
343327
}
344328
}
345329

346-
private _push(item: IncrementalDataRecord): void {
330+
private _push(item: SubsequentDataRecord): void {
347331
this._released.add(item);
348332
this._pending.add(item);
349333
this._trigger();
350334
}
351335

352-
private _delete(item: IncrementalDataRecord) {
336+
private _delete(item: SubsequentDataRecord) {
353337
this._released.delete(item);
354338
this._pending.delete(item);
355339
this._trigger();
356340
}
357341

358342
private _getIncrementalResult(
359-
completedRecords: ReadonlySet<IncrementalDataRecord>,
343+
completedRecords: ReadonlySet<SubsequentDataRecord>,
360344
): SubsequentIncrementalExecutionResult | undefined {
361345
const incrementalResults: Array<IncrementalResult> = [];
362346
let encounteredCompletedAsyncIterator = false;
@@ -398,18 +382,18 @@ export class IncrementalPublisher {
398382
: undefined;
399383
}
400384

401-
private _publish(incrementalDataRecord: IncrementalDataRecord) {
402-
if (incrementalDataRecord.isCompleted) {
403-
this._push(incrementalDataRecord);
385+
private _publish(subsequentResultRecord: SubsequentDataRecord) {
386+
if (subsequentResultRecord.isCompleted) {
387+
this._push(subsequentResultRecord);
404388
} else {
405-
this._introduce(incrementalDataRecord);
389+
this._introduce(subsequentResultRecord);
406390
}
407391
}
408392

409393
private _getDescendants(
410-
children: ReadonlySet<IncrementalDataRecord>,
411-
descendants = new Set<IncrementalDataRecord>(),
412-
): ReadonlySet<IncrementalDataRecord> {
394+
children: ReadonlySet<SubsequentDataRecord>,
395+
descendants = new Set<SubsequentDataRecord>(),
396+
): ReadonlySet<SubsequentDataRecord> {
413397
for (const child of children) {
414398
descendants.add(child);
415399
this._getDescendants(child.children, descendants);
@@ -431,13 +415,18 @@ export class IncrementalPublisher {
431415
}
432416
}
433417

418+
export interface InitialResultRecord {
419+
errors: Array<GraphQLError>;
420+
children: Set<SubsequentDataRecord>;
421+
}
422+
434423
/** @internal */
435424
export class DeferredFragmentRecord {
436425
errors: Array<GraphQLError>;
437426
label: string | undefined;
438427
path: Array<string | number>;
439428
data: ObjMap<unknown> | null;
440-
children: Set<IncrementalDataRecord>;
429+
children: Set<SubsequentDataRecord>;
441430
isCompleted: boolean;
442431
filtered: boolean;
443432
constructor(opts: { label: string | undefined; path: Path | undefined }) {
@@ -457,7 +446,7 @@ export class StreamItemsRecord {
457446
label: string | undefined;
458447
path: Array<string | number>;
459448
items: Array<unknown> | null;
460-
children: Set<IncrementalDataRecord>;
449+
children: Set<SubsequentDataRecord>;
461450
asyncIterator: AsyncIterator<unknown> | undefined;
462451
isCompletedAsyncIterator?: boolean;
463452
isCompleted: boolean;
@@ -479,10 +468,12 @@ export class StreamItemsRecord {
479468
}
480469
}
481470

482-
export type IncrementalDataRecord = DeferredFragmentRecord | StreamItemsRecord;
471+
export type SubsequentDataRecord = DeferredFragmentRecord | StreamItemsRecord;
472+
473+
export type IncrementalDataRecord = InitialResultRecord | SubsequentDataRecord;
483474

484475
function isStreamItemsRecord(
485-
incrementalDataRecord: IncrementalDataRecord,
486-
): incrementalDataRecord is StreamItemsRecord {
487-
return incrementalDataRecord instanceof StreamItemsRecord;
476+
subsequentResultRecord: SubsequentDataRecord,
477+
): subsequentResultRecord is StreamItemsRecord {
478+
return subsequentResultRecord instanceof StreamItemsRecord;
488479
}

0 commit comments

Comments
 (0)