Skip to content

spike: Phase 4 — measure parallel rendering, decide against sharding - #5

Closed
TheMeinerLP wants to merge 5 commits into
feat/phase-3-hostingfrom
feat/phase-4-sharding
Closed

spike: Phase 4 — measure parallel rendering, decide against sharding#5
TheMeinerLP wants to merge 5 commits into
feat/phase-3-hostingfrom
feat/phase-4-sharding

Conversation

@TheMeinerLP

Copy link
Copy Markdown
Contributor

Phase 4 of Apus was gated on a spike. It ran, it came out negative, and this PR records that plus the resulting decision. No sharding is implemented, deliberately.

The question

Can two BlueMap processes render disjoint region sets of the same map into the same map storage without damaging the zoomed-out views?

Render state is stored granularly per tile and chunk, so disjoint regions do not collide there. But lowres levels are built by aggregation — a lowres tile averages colour, height and light across a group of higher-resolution tiles, and those groups span region boundaries. Earlier research called conflicts "unlikely" because lowres tiles are also stored granularly. That reasoning conflates two different things, which is why this was measured rather than assumed.

The measurement

A single-pass reference render of the whole world, against two concurrently running containers rendering disjoint, adjacent region sets into a second bucket.

  • 7 of 24 lowres tiles diverge from the reference, reproduced identically three times.
  • One tile drops from 99 % rendered terrain to 91 % empty.
  • A sequential control run — no race at all — corrupts 10 of 24 tiles. Order dependence confirms the mechanism independently of timing.

Granular storage prevents corruption of individual tiles. It does not prevent two shards overwriting the same aggregated lowres tile.

Full report with setup, raw numbers and an honest assessment of what the experiment does and does not cover: docs/superpowers/spikes/2026-08-09-lowres-sharding-spike.md.

The decision

The spec offered two fallbacks. This picks the second — vertical scaling via render-threads — over the two-stage alternative (shards render hires only, a final pass builds lowres):

  • The two-stage route needs a custom runner bound to BlueMap-Core. Section 1.4 rules that out for the MVP, and 2.1 explains why: BlueMap-Core is not a stable public API.
  • Vertical scaling already exists and costs nothing.
  • No world has yet taken long enough to justify the work.

The architecture stays sharding-capable — the region list is in the bundle manifest, BlueMapMap.spec.shards exists. If a world ever does take too long, the two-stage approach is what to evaluate, and this spike is the ground to build on. Until then shards stays at 1.

Limits of the experiment, as stated in the report

Small test world, render-mask used to split rather than the scheduleMapUpdateTask API a real implementation would use, and only one split topology tested.

Runs BlueMap CLI in two disjoint, adjacent region-masked processes
concurrently against the same MinIO-backed map storage and compares the
result against a single-process reference render. The lowres pyramid
(tiles/1..3) reproducibly corrupts across 3 concurrent repeats -- one LOD1
tile goes from 99% opaque terrain to 91% blank -- while hires tiles and
object counts stay structurally complete. A sequential control run (no
race window) corrupts even more tiles, confirming the failure is
order-dependent rather than an unrelated masking artifact.

Extends testdata/mini-world with two more region files (r.-1.0.mca,
r.-1.1.mca, region-only, no player data) so a shard split has a full
1024-block shared boundary instead of the original 512-block edge.

Result: negative for naive concurrent same-storage sharding. See the
report for the two alternatives this leaves open.
The spike measured 7 of 24 lowres tiles diverging from a single-pass
reference render, reproduced three times, with a sequential control run
corrupting 10 of 24. Granular storage prevents corruption but not two
shards overwriting the same aggregated lowres tile.

Choosing vertical scaling over the two-stage alternative: that one needs a
custom runner bound to BlueMap-Core, which section 1.4 rules out for the
MVP and 2.1 explains is not a stable public API.
@gitguardian

gitguardian Bot commented Aug 9, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 2 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
35899483 Triggered Generic High Entropy Secret 36f5807 docs/superpowers/spikes/2026-08-09-lowres-sharding-spike/spike-entrypoint.sh View secret
35899484 Triggered Generic High Entropy Secret 36f5807 docs/superpowers/spikes/2026-08-09-lowres-sharding-spike/spike-entrypoint.sh View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

…onfig

The strings the secret scanner flagged were not only in old commits: the
phase 1 plan carried them in a code sample, and .gitguardian.yaml listed
them in plaintext, which made the exemption file a finding of its own.

The plan sample now shows a placeholder, and the exemptions are SHA256
digests.
@TheMeinerLP

Copy link
Copy Markdown
Contributor Author

Closing in favor of #13: same content, rebuilt as a single squash commit on a new clean/* branch because a secret scanner flagged disposable test credentials in this PR's commit history and history cannot be rewritten in this environment. See #13 for detail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant