mirror of
https://github.com/morluto/rea.git
synced 2026-10-22 05:42:31 -05:00
fix(javascript): preserve graphs within parent capacity (#1921)
Reserve the next sequential static checkpoint using its protocol size and existing retained-expansion accounting instead of 80% of the parent budget. Preserve total/live heap protections and explain parent admission failures with effective capacity, retention estimates and usable retained facts. Fixes #1911 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com>
This commit is contained in:
2 files changed
+163
-12
No files matched your search
@@ -59,6 +59,7 @@ import {
|
||||
const OPERATION = "analyze_javascript_application";
|
||||
const PROVIDER = "javascript-static-analysis";
|
||||
const MIB = 1024 * 1024;
|
||||
const STATIC_CHECKPOINT_RETENTION_EXPANSION = 6;
|
||||
const pendingCleanup = new Set<JavaScriptAnalysisWorker>();
|
||||
/** The worker runs on this executable; Bun accepts but ignores V8 heap flags. */
|
||||
const WORKER_HEAP_FLAGS_ENFORCED =
|
||||
@@ -80,7 +81,6 @@ export class JavaScriptAnalysisWorker {
|
||||
#estimatedRetainedBytes = 0;
|
||||
#applicationProjectionFailure: AnalysisResourceConstraintError | undefined;
|
||||
#parentCapacityExhausted = false;
|
||||
#retainedStaticBytes = 0;
|
||||
#sourcesRemaining: number | undefined;
|
||||
readonly #resultBudgetBytes: number;
|
||||
/** Null when the runtime enforces the V8 heap flags instead. */
|
||||
@@ -326,7 +326,13 @@ export class JavaScriptAnalysisWorker {
|
||||
{
|
||||
...this.#limits(),
|
||||
parent_result_budget_bytes: this.#resultBudgetBytes,
|
||||
parent_available_result_budget_bytes: remaining,
|
||||
module_transfer_bytes: descriptor.module_bytes,
|
||||
module_retention_estimate_bytes: moduleEstimate,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Use the retained static facts or analyze fewer source files. This limit belongs to the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
},
|
||||
),
|
||||
});
|
||||
@@ -358,9 +364,16 @@ export class JavaScriptAnalysisWorker {
|
||||
{
|
||||
...this.#limits(),
|
||||
parent_result_budget_bytes: this.#resultBudgetBytes,
|
||||
parent_available_result_budget_bytes: remaining,
|
||||
module_retention_estimate_bytes: moduleEstimate,
|
||||
graph_retention_estimate_bytes: graphEstimate,
|
||||
graph_transfer_bytes: descriptor.graph_bytes,
|
||||
graph_records: descriptor.graph_records,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Use the retained static and module facts or analyze fewer source files. This limit belongs to the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
},
|
||||
),
|
||||
});
|
||||
break;
|
||||
@@ -582,16 +595,16 @@ export class JavaScriptAnalysisWorker {
|
||||
const value: unknown = JSON.parse(text);
|
||||
const facts = javaScriptWorkerStaticAnalysisSchema.parse(value);
|
||||
const remaining = this.#remainingTotalResultBudget();
|
||||
const retainedBytes = bytes * 6;
|
||||
const retainedBytes = bytes * STATIC_CHECKPOINT_RETENTION_EXPANSION;
|
||||
this.#parentCapacityExhausted = retainedBytes > remaining;
|
||||
this.#estimatedRetainedBytes += retainedBytes;
|
||||
this.#retainedStaticBytes += retainedBytes;
|
||||
const expandedBytes = estimateJavaScriptStaticApplicationProjection(
|
||||
facts,
|
||||
bytes,
|
||||
sourcePath,
|
||||
);
|
||||
if (expandedBytes <= this.#remainingResultBudget())
|
||||
const availableResultBudget = this.#remainingResultBudget();
|
||||
if (expandedBytes <= availableResultBudget)
|
||||
this.#estimatedRetainedBytes += expandedBytes;
|
||||
else
|
||||
this.#applicationProjectionFailure = new AnalysisResourceConstraintError(
|
||||
@@ -600,8 +613,13 @@ export class JavaScriptAnalysisWorker {
|
||||
`Expanded application relationships for ${sourcePath} exceed the parent's result budget; complete static facts were retained on the file node`,
|
||||
{
|
||||
parent_result_budget_bytes: this.#resultBudgetBytes,
|
||||
parent_available_result_budget_bytes: availableResultBudget,
|
||||
application_projection_required_bytes: expandedBytes,
|
||||
},
|
||||
{
|
||||
remediationAction:
|
||||
"Read the complete static facts on the file node or analyze fewer source files. Expanded application relationships exceed the parent result budget; increasing the worker heap alone does not increase it.",
|
||||
},
|
||||
);
|
||||
return facts;
|
||||
}
|
||||
@@ -638,16 +656,17 @@ export class JavaScriptAnalysisWorker {
|
||||
);
|
||||
}
|
||||
#remainingResultBudget(): number {
|
||||
// Future sources need their compact observations before current modules
|
||||
// consume capacity with expanded relationships. A final or sole source
|
||||
// can use the unused reserve as well.
|
||||
// One sequential worker produces one next checkpoint at a time. Reserve
|
||||
// its maximum protocol size at the same retained expansion used on receipt;
|
||||
// earlier checkpoints are already charged to estimatedRetainedBytes.
|
||||
// Reserving every unexamined source's maximum would reject useful results
|
||||
// merely because many small files remain. Actual retained growth and live
|
||||
// heap capacity are checked again for every checkpoint and transfer.
|
||||
const checkpointReserve =
|
||||
DEFAULTS.checkpointBytes * STATIC_CHECKPOINT_RETENTION_EXPANSION;
|
||||
const staticReserve =
|
||||
this.#sourcesRemaining !== undefined && this.#sourcesRemaining > 0
|
||||
? Math.max(
|
||||
0,
|
||||
Math.floor((this.#resultBudgetBytes * 4) / 5) -
|
||||
this.#retainedStaticBytes,
|
||||
)
|
||||
? checkpointReserve
|
||||
: 0;
|
||||
return Math.max(0, this.#remainingTotalResultBudget() - staticReserve);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user