Repository navigation
perf(data): hold paged service features as their JSON text - #841
Conversation
Reading a service layer page by page kept every feature as a serde_json::Value tree, about 8x the text's size: 100,000 Brentwood parcels (155 MB) peaked at 1.27 GB through service.add. Pages now keeps each feature as the text the server sent (Box<RawValue>) and splices it into the joined collection; only a page's other members are read into values. The live read now peaks at 576 MB. Features come through as written (spacing, 1.50, escapes, integers past u64). ArcGIS's "first features again" check still compares the first feature as a value. A page nested deeper than serde_json's limit still stops the read, by a byte scan, since raw text isn't held to the limit. Part of opengeos#830. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes.
|
| Layer / File(s) | Summary |
|---|---|
Split pages and retain feature text crates/data/src/ogc.rs |
Page splitting separates collection metadata from raw feature text. Paging state stores raw features and initializes from the split result. |
Compare and join paged features crates/data/src/ogc.rs |
ArcGIS repeated-page detection compares first features as parsed values. Joined responses append retained feature text. Tests cover formatting, numeric forms, escapes, large integers, and nesting limits. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Refactor
Possibly related issues
- [Feature]: Read a service's pages in memory close to the data's size #830: This PR implements the raw-feature-text step described in the issue; it does not include the issue’s other proposed paging changes.
- [Feature]: Read every feature of an ArcGIS FeatureServer or MapServer layer, past its record limit #764: This PR changes the ArcGIS paging path mentioned in the issue, but does not change its
maxRecordCountbehavior.
Possibly related PRs
- opengeos/RustGIS#823: This PR introduced the
read_pagesandPagesflow that this change updates.
Suggested reviewers: giswqs
Merge Risk: 
Minimal · up to 6e8a9
-
No actionable merge-blocking issue is identified; merge after the normal checks.
Pre-merge checks: 
5
Finishing Touches: 💡 1
-
🛠️ Fix failing CI checks: 💡
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
A rabbit keeps each feature’s text,
Its commas, digits, braces next.
It checks the pages by meaning clear,
Then joins their words without a smear.
Hop, raw JSON, preserved right here!
Comment @coderabbitai help to get the list of available commands.
Code reviewI read the whole diff (one file, BugsNothing found. What I checked:
SecurityNothing found. The code is still free of Performance
Quality
AGENTS.mdNo violations. There is no panic path, no UI text, no new dependency, and nothing that affects wasm. Please still run Change sizeCompared: the whole PR against main (merge base e1e70a9 to PR head 6e8a94c)
|
Code reviewI read the full diff of BugsNothing found. What I checked:
SecurityNo concerns. Hostile input is still bounded by the depth guard, the Performance
Quality
AGENTS.md
Change sizeCompared: the whole PR against main (merge base 302288d to PR head 11c63fe)
|
📖 Docs preview
GitHub Pages takes a minute or two to publish a new commit. |
Summary
Reading a service layer page by page (OGC API Features, or ArcGIS past its record limit) used several times more memory than its data. Reading 100,000 Brentwood, TN parcels (155 MB of GeoJSON) through
service.addpeaked at 1.27 GB. With this change it peaks at 576 MB.Where the memory went. I profiled each step separately: the 100,000 parcels replayed offline as 50 ArcGIS pages of 2,000, each step in its own process, measured as the step's peak resident memory.
ogc::read_pages, beforeogc::read_pages, afterio::read_bytes(the joined GeoJSON into a dataset), unchangedlayer.addDownload, unchangedThe peak was in
Pages, which held every feature as aserde_json::Valuetree: about 8 bytes in memory for each byte of text.The change.
Pagesnow keeps each feature as the JSON text the server sent (Box<RawValue>; the workspace already enablesraw_value). Only a page's other members (links,numberMatched,properties, …) are read into values.finishwrites those members, then splices the features' text in as it came.read_pagesis now about 2× the data, and 4× faster (2.4 s → 0.5 s for Brentwood).1.50,éescapes, and integers too large for au64, which the old round trip turned into floats. The offline replay's output is JSON-equal tomain's for both layers.too_deep) rejects such a page, and the read stops there with a note, as it did before.Not in this PR (both are separate decisions in #830):
layer.addDownloadand the GeoJSON read, not the paging. Step 3 would remove the joined text, about 1× the data, from that peak.MAX_PAGED_FEATURES(step 4).No new dependency, and no change to commands, the data model or the project format.
Testing
cargo xtask ci: passed (1,996 tests, layers ok)cargo build --locked --target wasm32-unknown-unknown -p rustgis-web: passedNew
ogc::tests::pages_joined_as_writtencovers:It fails on
main(the text is re-serialized). Disabling the depth guard fails it too. It checks that the features are held as text. It doesn't measure memory: the workspace forbidsunsafe, so a test can't install a counting allocator. The numbers above come from a separate harness.Live:
service.addof Brentwood's county parcels (ArcGIS Enterprise 11.3, 100,000 of 105,117 features, with the cap note) went from 32.7 s and 1,270 MB peak onmainto 28.9 s and 576 MB, in the same release build.Related issue
Part of #830 (steps 1 and 2).
🤖 Generated with Claude Code
Summary by CodeRabbit