mirror of
https://github.com/morluto/rea.git
synced 2026-10-28 10:25:42 +00:00
* fix(managed): charge admitted member facts once in the final projection inspect_managed_members admits method bodies, signatures, call edges, field accesses and user strings as they are produced, then admits the whole result again before returning it. The final pass re-counted every already-admitted record, so the 64 MiB representation budget was spent at roughly twice the result's JSON size. Ordinary assemblies such as MathNet.Numerics, MongoDB.Driver, Npgsql, ClosedXML, System.Reactive and Azure.Storage.Blobs returned resource-limit with no members. The budget now remembers each admitted projection. A containing projection spends that charge once instead of counting the subtree again; a value that serializes more than once still pays for every further occurrence. Results that already fit are byte-identical. Refs #3449 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(managed): check a repeated occurrence pays with fresh credit Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
3.4 KiB
TypeScript
95 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
admitManagedProjection,
|
|
ManagedDecodeBudget,
|
|
} from "./ManagedDecodeBudget.js";
|
|
import { ManagedReaderFailure } from "./ManagedReaderFailure.js";
|
|
|
|
describe("managed projection admission", () => {
|
|
it("charges decoded strings by their JSON bytes", () => {
|
|
const name = "a".repeat(12 * 1024 * 1024);
|
|
|
|
expect(admitManagedProjection({ name })).toEqual({ name });
|
|
});
|
|
|
|
it("charges escaped and multibyte characters at their encoded size", () => {
|
|
expect(() =>
|
|
admitManagedProjection({ name: "\u0001".repeat(12 * 1024 * 1024) }),
|
|
).toThrow(ManagedReaderFailure);
|
|
expect(() =>
|
|
admitManagedProjection({ name: "€".repeat(23 * 1024 * 1024) }),
|
|
).toThrow(ManagedReaderFailure);
|
|
});
|
|
|
|
it("counts escaped JSON bytes exactly at the budget boundary", () => {
|
|
// Control escapes, quotes, three-byte text, surrogate pairs and lone
|
|
// surrogates each have a distinct JSON size; fill the rest with ASCII.
|
|
const mixed = "\u0001".repeat(4096) + '"\\' + "€😀\ud800\udc00\ud800";
|
|
const used = Buffer.byteLength(JSON.stringify(mixed));
|
|
const filled = (extra: number) =>
|
|
mixed + "a".repeat(64 * 1024 * 1024 - used + extra);
|
|
|
|
expect(() => admitManagedProjection(filled(0))).not.toThrow();
|
|
expect(() => admitManagedProjection(filled(1))).toThrow(
|
|
ManagedReaderFailure,
|
|
);
|
|
});
|
|
|
|
it("charges an admitted record once inside its containing projection", () => {
|
|
const budget = new ManagedDecodeBudget();
|
|
const record = admitManagedProjection(
|
|
{ name: "a".repeat(40 * 1024 * 1024) },
|
|
budget,
|
|
);
|
|
|
|
expect(() =>
|
|
admitManagedProjection({ records: [record] }, budget),
|
|
).not.toThrow();
|
|
// The containing projection spent the credit, so later reuse pays again.
|
|
expect(() =>
|
|
admitManagedProjection({ records: [record, record] }, budget),
|
|
).toThrow(ManagedReaderFailure);
|
|
});
|
|
|
|
it("charges a repeated occurrence of an admitted record again", () => {
|
|
const budget = new ManagedDecodeBudget();
|
|
const record = admitManagedProjection(
|
|
{ name: "a".repeat(40 * 1024 * 1024) },
|
|
budget,
|
|
);
|
|
|
|
// The first occurrence spends the credit; the second serializes again.
|
|
expect(() =>
|
|
admitManagedProjection({ records: [record, record] }, budget),
|
|
).toThrow(ManagedReaderFailure);
|
|
});
|
|
});
|
|
|
|
describe("managed decoding bounds", () => {
|
|
it("bounds new row identities without charging lookup replay or merging tables", () => {
|
|
const budget = new ManagedDecodeBudget();
|
|
budget.reserve(64 * 1024 * 1024 - 512, null);
|
|
budget.reserveRow(2, 1, 100);
|
|
budget.reserveRow(12, 1, 200);
|
|
|
|
expect(() => budget.reserveRow(2, 1, 100)).not.toThrow();
|
|
expect(() => budget.reserveRow(2, 2, 300)).toThrow(ManagedReaderFailure);
|
|
// A rejected row has no retained reservation; replay cannot bypass capacity.
|
|
expect(() => budget.reserveRow(2, 2, 300)).toThrow(ManagedReaderFailure);
|
|
});
|
|
|
|
it("keeps concurrent decoding bounds within one budget until released", () => {
|
|
const budget = new ManagedDecodeBudget();
|
|
const bound = 40 * 1024 * 1024;
|
|
|
|
budget.admitTransient(bound, null);
|
|
expect(() => budget.admitTransient(bound, null)).toThrow(
|
|
ManagedReaderFailure,
|
|
);
|
|
expect(() => budget.reserve(bound, null)).toThrow(ManagedReaderFailure);
|
|
budget.releaseTransient();
|
|
expect(() => budget.admitTransient(bound, null)).not.toThrow();
|
|
});
|
|
});
|