Stop Navara's memory growth on engine switches, hide polygon zones reliably, and drop the Cesium camera rig

- Navara 0.2.1 never frees pick batch ids, and the mover banks rebuilt
  their instanced meshes on each attach, leaking about 260 KiB of
  WebAssembly memory per switch. A per-view pool hands released ids back
  out; the long soak now asserts native growth of at most 32 KiB per switch.
- Navara 0.2.1 sometimes drops the first show:false update on a new
  vector layer, so a zone turned off right after a switch back stayed
  drawn. Polygon displays hide by deleting their layers and rebuild them
  when shown.
- Camera verbs drive both engines through the globe contract; the Cesium
  viewer rig and the tests of states it can no longer reach are gone.
- Flights and military tracking share src/layers/aircraft/tracking.js.
- The geo import scenario reads movers only where the engine has them.
- Add the Navara section to docs/CURRENT-STATE.md and a changelog fragment.
This commit is contained in:
German Khokhlov committed 2026-11-05 21:18:23 +04:00
1 parent 7abf74518f
commit a6c64713ee
46 files changed
+2367 -2894

No files matched your search

+3
View File
@@ -368,8 +368,10 @@
"src/layers/military/index.js",
"src/layers/aircraft/index.js",
"src/layers/aircraft/classification.js",
"src/layers/aircraft/tracking.js",
"src/layers/military/ownership.test.mjs",
"src/layers/aircraft/classification.test.mjs",
"src/layers/aircraft/tracking.test.mjs",
"src/data/aisLiveVessels.js",
"src/layers/vessels/cards.js",
"src/layers/vessels/evidence.js",
@@ -1297,6 +1299,7 @@
"src/globe/cesium/engineFromViewer.js",
"src/globe/cesium/engineFromViewer.test.mjs",
"src/globe/cesium/testing/fakeViewer.mjs",
"src/globe/cesium/testing/cameraViewer.mjs",
"src/app/globeEngine.js",
"src/app/globeEngine.test.mjs",
"src/layers/transit/render/cesium.js",
+5
View File
@@ -1352,6 +1352,7 @@
"src/layers/flights/ingestion.js",
"src/layers/flights/lifecycle.js",
"src/layers/aircraft/sceneBinding.js",
"src/layers/aircraft/tracking.js",
"src/layers/flights/motion.js",
"src/layers/flights/policy.js",
"src/layers/flights/queries.js",
@@ -1419,6 +1420,7 @@
"src/layers/military/index.js",
"src/layers/military/ingestion.js",
"src/layers/aircraft/sceneBinding.js",
"src/layers/aircraft/tracking.js",
"src/layers/military/lifecycle.js",
"src/layers/military/motion.js",
"src/layers/military/policy.js",
@@ -2650,6 +2652,7 @@
"src/layers/flights/ingestion.js",
"src/layers/flights/lifecycle.js",
"src/layers/aircraft/sceneBinding.js",
"src/layers/aircraft/tracking.js",
"src/layers/flights/motion.js",
"src/layers/flights/policy.js",
"src/layers/flights/queries.js",
@@ -3414,6 +3417,7 @@
"src/globe/follow.js",
"src/globe/lines.js",
"src/globe/navara/movers/pickIds.js",
"src/globe/navara/movers/batchIds.js",
"src/globe/movers.js",
"src/globe/cesium/follow.js",
"src/globe/cpuPicks.js",
@@ -3789,6 +3793,7 @@
"src/layers/flights/ingestion.js",
"src/layers/flights/lifecycle.js",
"src/layers/aircraft/sceneBinding.js",
"src/layers/aircraft/tracking.js",
"src/layers/flights/motion.js",
"src/layers/flights/policy.js",
"src/layers/flights/queries.js",
+2 -2
View File
@@ -176,8 +176,8 @@ await strict.run(
rows: document.querySelectorAll('#geo-import-list .geo-import-row')
.length,
hint: document.getElementById('geo-import-hint')?.textContent || '',
pins: window.__godsEyeView.engine.movers
.list()
// Movers are a Navara capability; Cesium draws the pins as entities.
pins: (window.__godsEyeView.engine.movers?.list() ?? [])
.filter(({ id }) => id.startsWith('geo-import-'))
.reduce((n, set) => n + set.count, 0),
}));
+12 -10
View File
@@ -18,11 +18,12 @@
// below), then after the warm-up (switch 20): live WebGL
// objects per engine context grow by at most 0.1 per switch (least-squares
// slope over the checkpoints) and by at most 64 overall; no new WebGL
// context; the JS objects grow by at most 10 KiB per switch (heap snapshots
// at the warm-up and the end, V8's compiled code and native memory left out
// and reported apart, with the used heap's slope); no new document; the
// webglcontextlost/restored listener counts on both engine canvases stay as
// they were (each canvas keeps its webglcontextlost listener).
// context; the JS objects grow by at most 10 KiB per switch and native
// memory by at most 32 KiB (heap snapshots at the warm-up and the end, V8's
// compiled code left out and reported apart, with the used heap's slope); no
// new document; the webglcontextlost/restored listener counts on both engine
// canvases stay as they were (each canvas keeps its webglcontextlost
// listener).
//
// node scripts/qa-strict-soak.mjs http://127.0.0.1:4208 --runs=6 --swaps=50
// node scripts/qa-strict-soak.mjs http://127.0.0.1:4208 --runs=1 --swaps=500 --assert
@@ -396,21 +397,22 @@ if (strictMode) {
const perSwitch = (mib) =>
Math.round(((mib * 1024) / (to.swap - from.swap)) * 100) / 100;
const objectGrowth = perSwitch(objects(to) - objects(from));
const nativeGrowth = perSwitch(
(to.typesMiB.native ?? 0) - (from.typesMiB.native ?? 0),
);
checks.push({
check: 'JS heap KiB per switch',
objectsKiBPerSwitch: objectGrowth,
fromMiB: Math.round(objects(from) * 100) / 100,
toMiB: Math.round(objects(to) * 100) / 100,
// Reported, not asserted: the used heap's slope (compiled code
// included), compiled code's and native memory's growth.
// included) and compiled code's growth.
usedSlopePerSwap: Math.round(slope(heap) * 100) / 100,
codeKiBPerSwitch: perSwitch(
(to.typesMiB.code ?? 0) - (from.typesMiB.code ?? 0),
),
nativeKiBPerSwitch: perSwitch(
(to.typesMiB.native ?? 0) - (from.typesMiB.native ?? 0),
),
pass: objectGrowth <= 10,
nativeKiBPerSwitch: nativeGrowth,
pass: objectGrowth <= 10 && nativeGrowth <= 32,
});
checks.push({
check: 'documents',