Skip to content

Commit f4b118e

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

File tree

2 files changed

+95
-93
lines changed

2 files changed

+95
-93
lines changed

src/execution/IncrementalPublisher.ts

Lines changed: 53 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,23 @@ export class IncrementalPublisher {
210193
};
211194
}
212195

196+
prepareInitialResultRecord(): InitialResultRecord {
197+
return {
198+
errors: [],
199+
children: new Set(),
200+
isCompleted: false,
201+
};
202+
}
203+
213204
prepareNewDeferredFragmentRecord(opts: {
214205
label: string | undefined;
215206
path: Path | undefined;
216-
parentContext: IncrementalDataRecord | undefined;
207+
parentContext: IncrementalDataRecord;
217208
}): DeferredFragmentRecord {
218209
const deferredFragmentRecord = new DeferredFragmentRecord(opts);
219210

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

227214
return deferredFragmentRecord;
228215
}
@@ -231,16 +218,12 @@ export class IncrementalPublisher {
231218
label: string | undefined;
232219
path: Path | undefined;
233220
asyncIterator?: AsyncIterator<unknown>;
234-
parentContext: IncrementalDataRecord | undefined;
221+
parentContext: IncrementalDataRecord;
235222
}): StreamItemsRecord {
236223
const streamItemsRecord = new StreamItemsRecord(opts);
237224

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

245228
return streamItemsRecord;
246229
}
@@ -274,29 +257,31 @@ export class IncrementalPublisher {
274257
incrementalDataRecord.errors.push(error);
275258
}
276259

277-
publishInitial() {
278-
for (const child of this._initialResult.children) {
260+
publishInitial(initialResult: InitialResultRecord) {
261+
for (const child of initialResult.children) {
279262
if (child.filtered) {
280263
continue;
281264
}
282265
this._publish(child);
283266
}
284267
}
285268

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

292278
const asyncIterators = new Set<AsyncIterator<unknown>>();
293279

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

299-
for (const child of this._getDescendants(children)) {
284+
for (const child of descendants) {
300285
if (!this._matchesPath(child.path, nullPathArray)) {
301286
continue;
302287
}
@@ -332,31 +317,31 @@ export class IncrementalPublisher {
332317
this._signalled = signalled;
333318
}
334319

335-
private _introduce(item: IncrementalDataRecord) {
320+
private _introduce(item: SubsequentDataRecord) {
336321
this._pending.add(item);
337322
}
338323

339-
private _release(item: IncrementalDataRecord): void {
324+
private _release(item: SubsequentDataRecord): void {
340325
if (this._pending.has(item)) {
341326
this._released.add(item);
342327
this._trigger();
343328
}
344329
}
345330

346-
private _push(item: IncrementalDataRecord): void {
331+
private _push(item: SubsequentDataRecord): void {
347332
this._released.add(item);
348333
this._pending.add(item);
349334
this._trigger();
350335
}
351336

352-
private _delete(item: IncrementalDataRecord) {
337+
private _delete(item: SubsequentDataRecord) {
353338
this._released.delete(item);
354339
this._pending.delete(item);
355340
this._trigger();
356341
}
357342

358343
private _getIncrementalResult(
359-
completedRecords: ReadonlySet<IncrementalDataRecord>,
344+
completedRecords: ReadonlySet<SubsequentDataRecord>,
360345
): SubsequentIncrementalExecutionResult | undefined {
361346
const incrementalResults: Array<IncrementalResult> = [];
362347
let encounteredCompletedAsyncIterator = false;
@@ -398,18 +383,18 @@ export class IncrementalPublisher {
398383
: undefined;
399384
}
400385

401-
private _publish(incrementalDataRecord: IncrementalDataRecord) {
402-
if (incrementalDataRecord.isCompleted) {
403-
this._push(incrementalDataRecord);
386+
private _publish(subsequentResultRecord: SubsequentDataRecord) {
387+
if (subsequentResultRecord.isCompleted) {
388+
this._push(subsequentResultRecord);
404389
} else {
405-
this._introduce(incrementalDataRecord);
390+
this._introduce(subsequentResultRecord);
406391
}
407392
}
408393

409394
private _getDescendants(
410-
children: ReadonlySet<IncrementalDataRecord>,
411-
descendants = new Set<IncrementalDataRecord>(),
412-
): ReadonlySet<IncrementalDataRecord> {
395+
children: ReadonlySet<SubsequentDataRecord>,
396+
descendants = new Set<SubsequentDataRecord>(),
397+
): ReadonlySet<SubsequentDataRecord> {
413398
for (const child of children) {
414399
descendants.add(child);
415400
this._getDescendants(child.children, descendants);
@@ -431,13 +416,19 @@ export class IncrementalPublisher {
431416
}
432417
}
433418

419+
export interface InitialResultRecord {
420+
errors: Array<GraphQLError>;
421+
children: Set<SubsequentDataRecord>;
422+
isCompleted: boolean;
423+
}
424+
434425
/** @internal */
435426
export class DeferredFragmentRecord {
436427
errors: Array<GraphQLError>;
437428
label: string | undefined;
438429
path: Array<string | number>;
439430
data: ObjMap<unknown> | null;
440-
children: Set<IncrementalDataRecord>;
431+
children: Set<SubsequentDataRecord>;
441432
isCompleted: boolean;
442433
filtered: boolean;
443434
constructor(opts: { label: string | undefined; path: Path | undefined }) {
@@ -457,7 +448,7 @@ export class StreamItemsRecord {
457448
label: string | undefined;
458449
path: Array<string | number>;
459450
items: Array<unknown> | null;
460-
children: Set<IncrementalDataRecord>;
451+
children: Set<SubsequentDataRecord>;
461452
asyncIterator: AsyncIterator<unknown> | undefined;
462453
isCompletedAsyncIterator?: boolean;
463454
isCompleted: boolean;
@@ -479,10 +470,12 @@ export class StreamItemsRecord {
479470
}
480471
}
481472

482-
export type IncrementalDataRecord = DeferredFragmentRecord | StreamItemsRecord;
473+
export type SubsequentDataRecord = DeferredFragmentRecord | StreamItemsRecord;
474+
475+
export type IncrementalDataRecord = InitialResultRecord | SubsequentDataRecord;
483476

484477
function isStreamItemsRecord(
485-
incrementalDataRecord: IncrementalDataRecord,
486-
): incrementalDataRecord is StreamItemsRecord {
487-
return incrementalDataRecord instanceof StreamItemsRecord;
478+
subsequentResultRecord: SubsequentDataRecord,
479+
): subsequentResultRecord is StreamItemsRecord {
480+
return subsequentResultRecord instanceof StreamItemsRecord;
488481
}

0 commit comments

Comments
 (0)