leijurv left a comment (osm2pgsql-dev/osm2pgsql#2505)

Further progress, I have pushed a "v2", which adds some more complexity but 
reduces the filesize, speeds up reading, and speeds up applying osmchanges, at 
the cost of creation a bit slower. 
https://github.com/leijurv/osm2pgsql/commit/24888e48c8aebefe0777bc54821b9dade4a02374

|Comparison|v1|v2|
|---|---|---|
|Middle size|81.32GB|70.03GB|
|PBF -> middle time|~14m30s|~15m|
|middle -> Carto time|~39m|~38m|
|1 hour osmchange<br/>median time (EC2)|26s|17s|
|1 minute osmchange<br/>median time (EC2)|0.41s|0.24s|

Some of the changes:
- `-1.56GB` In v1, every node coordinate was coded as a delta from the previous 
node in the way. Now, we decide between three strategies based on the way. If 
the way is not closed loop, then we linearly extrapolate our best guess for the 
next node from the delta of the last two nodes: `nodes[i-1] + (nodes[i-1] - 
nodes[i-2])`. The delta encoding is from there, which results in lower numbers 
and less entropy for zstd in the higher bits (lower delta bits and the sign bit 
are stored ~raw). If the way is a closed ring we just do it like v1 (delta from 
`nodes[i-1]`), **unless** it's a ring of 4 segments and we are on the last 
point, in which case we predict it's a parallelogram `fourth_guess = first + 
third - second` (and `delta = fourth - fourth_guess`). This works well for 
buildings (perhaps thanks to iD "Square"). The paralellogram predictor alone 
saves 0.65GB!
- `-2.34GB` in the node-to-way index. Within each block of `node_id>>14`, we 
sort the `(node_id,way_id)` pairs by way (we can forget/ignore the actual order 
of the nodes in the way), then for each way we store the way_id (delta'd), the 
number of node_id "runs" (meaning consecutive increases, run length encoded), 
and then actual runs (start and length). The run length encode works well 
because within a way, very often node_ids are consecutive. That start used to 
be delta relative to `block<<14` (meaning the lowest `node_id` that could be 
here), but now it's delta relative to the prior run's end (even if the prior 
run was part of a different way). The deltas are also now split coded in v2 
(like the x,y deltas), where we barrel roll the sign bit to the LSB, leave 
those lower bits as-is, and zstd the upper bits.
- `-1.88GB` Deduplicate node locations within a way block. If a node appears in 
multiple different ways that have similar IDs (e.g. roads sharing nodes at 
junctions, buildings/landuse/etc having glued edges, etc), meaning they end up 
in the same `ways` block, we now refer to the prior encoded location by its 
node ID (skipping it implicitly in the delta stream). Node ids that appear in 
multiple ways that don't share `way_id>>10` are still repeated though.
- `-2.8GB` Better LMDB paging. Anything over 2KB was put in overflow pages, 
which are made in units of 4KB, leaving half the last page wasted in 
expectation. Instead, store in chunks of 4080 bytes, and put the remainder in 
leaf pages which pack many such entries together. This removes the need for 
contiguous runs of pages for those overflows, so any 4KB page can be used. This 
is what flattens the free list growth. And, `-0.83GB` Split tail data between 
2KB and 4KB in half. LMDB's page split threshold only allows up to ~2KB to live 
in a B+ leaf so this reduces fragmentation a little more.

Filesize bloat from applying osmchanges and fragmenting the LMDB free list is 
also ~resolved:
<img height="600" alt="Image" 
src="https://github.com/user-attachments/assets/17022dd5-d483-4fe7-8e0d-b6e93aa65b84";
 />


-- 
Reply to this email directly or view it on GitHub:
https://github.com/osm2pgsql-dev/osm2pgsql/issues/2505#issuecomment-5926478592
You are receiving this because you are subscribed to this thread.

Message ID: <osm2pgsql-dev/osm2pgsql/issues/2505/[email protected]>
_______________________________________________
Tile-serving mailing list
[email protected]
https://lists.openstreetmap.org/listinfo/tile-serving

Reply via email to