
# Sharding

`DocStore` menulis satu file per rekaman. Tanpa sharding, koleksi besar akan menumpuk semua file dalam satu direktori, dan operasi direktori melambat seiring bertambahnya jumlah entri. Karena itu, storh mengelompokkan file rekaman berdasarkan dua karakter dari id rekaman:

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

Bucket diambil dari awal grup terakhir UUID (karakter 24 dan 25), yang berisi entropi acak. Dua karakter heksadesimal menghasilkan 256 bucket, sehingga koleksi dengan 100k rekaman rata-rata memiliki kurang dari 400 file per direktori.

## Mengapa bagian akhir, bukan bagian awal

Id UUIDv7 dimulai dengan stempel waktu milidetik 48-bit, sehingga id yang dibuat berdekatan memiliki karakter awal yang sama. Sharding berdasarkan prefiks akan mengirim setiap lonjakan penulisan ke direktori panas yang sama dan baru mengganti bucket seiring berjalannya waktu. Byte bagian akhir bersifat acak untuk setiap rekaman, sehingga penulisan tersebar merata sejak rekaman pertama.

Sharding tidak terlihat dalam pembacaan dan kueri: `get()` menghitung bucket dari id, dan `stream()` mengembalikan rekaman yang diurutkan berdasarkan id dari semua bucket, sehingga paginasi kursor berperilaku seolah-olah koleksi tersebut adalah satu daftar terurut.

## Dalam skala besar

Jumlah bucket tidak pernah bertambah: dua karakter heksadesimal berarti 256 direktori untuk ukuran koleksi berapa pun. Yang bertambah adalah jumlah file per bucket:

| Rekaman | File per bucket |
| ------- | ---------------- |
| 10k     | ~40              |
| 100k    | ~390             |
| 1M      | ~3,900           |
| 10M     | ~39,000          |

Sistem file modern mengindeks entri direktori, sehingga beberapa ribu file per bucket menjaga pencarian langsung tetap cepat; 1M rekaman masih nyaman untuk `get()` dan kueri terindeks. Membuka penyimpanan membutuhkan waktu konstan berapa pun ukuran koleksinya: pemindaian file sementara yatim hanya berjalan ketika penanda penulis mati menunjukkan bahwa proses sebelumnya mengalami crash saat menulis. Yang bertambah secara linear dalam skala besar adalah operasi seluruh koleksi: pemindaian tanpa indeks, `reindex()`, dan `verify()` masing-masing menelusuri setiap file rekaman, jadi perlakukan sebagai tugas batch. Ketika jumlah rekaman per koleksi melewati sekitar 10M, jumlah per bucket dan total penggunaan inode mulai menjadi perhatian: pisahkan koleksi, atau gunakan log tersegmentasi untuk data yang perlu dipindai, yang menjaga jumlah file tetap rendah sejak awal.

## Mesin lainnya

`SegmentedLog` dan `Queue` tidak menggunakan sharding karena keduanya tidak membuat satu file per rekaman. Log menambahkan data ke file segmen di bawah `segments/`, yang dibatasi oleh `max_segment_bytes` (default 1 MiB), dan antrean menambahkan peristiwa ke satu `queue.log`. Jumlah file tetap rendah sejak awal.
