
# Sharding

`DocStore` skriver en fil per post. Utan sharding skulle en stor samling
samla alla filer i en katalog, och katalogåtgärder försämras när
antalet poster växer. storh delar därför in postfiler i hinkar efter två tecken av
postens id:

```text
pages/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc
```

Hinken hämtas från början av UUID:s sista grupp (tecken 24
och 25), som består av slumpmässig entropi. Två hexadecimala tecken ger 256 hinkar, så en
samling med 100k poster har i genomsnitt färre än 400 filer per katalog.

## Varför svansen och inte huvudet

UUIDv7-id:n börjar med en tidsstämpel på 48 bitar i millisekunder, så id:n som skapas nära
varandra delar inledande tecken. Sharding efter prefix skulle skicka varje
skrivningstopp till samma belastade katalog och rotera hinkar först när tiden går.
Svansens byte är slumpmässiga för varje post, så skrivningar fördelas jämnt från
första posten.

Sharding märks inte vid läsningar och frågor: `get()` beräknar hinken från
id:t och `stream()` returnerar poster sorterade efter id över alla hinkar, så
markörsidnumrering fungerar som om samlingen vore en enda ordnad lista.

## I stor skala

Antalet hinkar växer aldrig: två hexadecimala tecken betyder 256 kataloger oavsett
samlingens storlek. Det som växer är antalet filer per hink:

| Poster | Filer per hink |
| ------- | ---------------- |
| 10k     | ~40              |
| 100k    | ~390             |
| 1M      | ~3,900           |
| 10M     | ~39,000          |

Moderna filsystem indexerar katalogposter, så några tusen filer per
hink håller punktuppslagningar snabba; 1M poster fungerar bra för `get()` och
indexerade frågor. Att öppna ett lager tar konstant tid oavsett samlingens
storlek: rensningen av föräldralösa temporärfiler körs bara när en kvarlämnad skrivarmarkör visar
att en tidigare process kraschade mitt i en skrivning. Det som växer linjärt i
stor skala är åtgärder över hela samlingen: oindexerade skanningar, `reindex()` och `verify()`
går igenom varje postfil, så behandla dem som batchjobb. När en samling passerar ungefär 10M
poster börjar antalet filer per hink och det totala antalet inoder spela roll:
dela upp samlingarna eller använd den segmenterade loggen för skanningsdata,
som håller filantalet lågt genom sin konstruktion.

## De andra motorerna

`SegmentedLog` och `Queue` använder inte sharding eftersom de inte skapar en fil
per post. Loggen lägger till poster i segmentfiler under `segments/`, med en gräns på
`max_segment_bytes` (1 MiB som standard), och kön lägger till händelser i en
enda `queue.log`. Filantalet hålls lågt genom konstruktionen.
