TC$mC$ on erinomainen lisC$ys. Oikeastaan tC$mC$ on arkkitehtuurisesti todella
kaunis ajatus, sillC$ se muistuttaa vahvasti bare-metal -ohjelmointia ja
retro-koneiden (kuten C64/VIC-20) muistipankkien (memory banks) kytkemistC$
pC$C$lle ja pois, mutta tuotuna moderniin mikropalvelumaailmaan.
TC$ssC$ ohitetaan hitaat verkkoprotokollat (HTTP, gRPC, jopa perinteiset
socketit) ja palataan puhtaaseen I/O-nopeuksien maksimointiin suoraan
prosessorin vC$ylC$lle.
NC$in tC$mC$ voidaan toteuttaa **POSIX-standardien ja V8-moottorin sisC$isten
mekanismien** avulla:
### Ydinkonsepti: POSIX Shared Memory (tmpfs) ja `mmap`
KC$yttC6jC$rjestelmC$tasolla "jaettu muisti" toteutetaan luomalla
muistikartoitettu tiedosto (memory-mapped file) keskusmuistissa sijaitsevaan
virtuaalitiedostojC$rjestelmC$C$n, Linuxissa yleensC$ `/dev/shm` (tmpfs).
TC$mC$ ratkaisee suoraan suurimman osan vaatimuksistasi.
---
### 4.1 & 4.3: Muistialueiden hallinta ja nimeC$minen
* **Luonti (Host):** Kun API:lta pyydetC$C$n uusi jaettu muistialue `inst-123
/ state-buffer`, Host-palvelin luo tiedoston `/dev/shm/inst-123_state-buffer`.
* **Koon mC$C$ritys (4.1.2):** Host kC$yttC$C$ C-tason `ftruncate` (tai
Node.js `fs.truncate`) -kutsua venyttC$C$kseen tiedoston haluttuun fiksattuun
maksimikokoon (esim. 50 MB). TC$mC$ varaa muistin suoraan RAM-muistista.
### 4.1.3: Miten JS-sovellus nC$kee tC$mC$n? (Elegantti mappaus)
**TC$ysin "tajuamatta" (transparentisti) tC$tC$ ei voi tehdC$ tavallisille
JS-muuttujille**, koska V8-moottorin Garbage Collector (roskienkeruu) haluaa
hallita normaalia kekoa (heap) itse. Jos yritC$t mapata perusmuuttujan `let
data = { x: 1 }` jaettuun muistiin, V8 siirtC$C$ sen fyysistC$ paikkaa
RAM-muistissa GC-syklien aikana.
**Mutta ratkaisu on jopa parempi:**
V8 tukee ns. **"External ArrayBuffer backing store"** -ominaisuutta.
KC$ytC$nnC6ssC$ Host injektoi (esim. preload-skriptillC$ tai V8 Inspectorin
kautta) instanssiin globaalin olion, jota taustoittaa suora `mmap`-kutsu
C++-tason N-API-moduulin (tai sisC$C$nrakennetun Node-ominaisuuden) kautta.
JS-koodin nC$kC6kulmasta instanssissa nC$kyy vain:
```javascript
/ Instanssin koodi ei tee mitC$C$n alustusta, tC$mC$ on vain "olemassa"
const state = global.sharedMem['state-buffer'];
/ 'state' on normaali Node.js Buffer tai Uint8Array / SharedArrayBuffer.
/ JS-kehittC$jC$ voi manipuloida sitC$ kuin mitC$ tahansa byte-taulukkoa.
state[0] = 255;
```
Jos haluat kC$sitellC$ tC$tC$ C-tyylisten structien tapaan, JS voi kC$yttC$C$
`TypedArray` tai DataView -nC$kymiC$ (esim. `Float64Array`) pureskelemaan
muistia rakenteellisena, aivan kuten assembly- tai C-koodissa tehdC$C$n.
### 4.2: Lennosta kytkeminen ja Sync (TC$mC$ on arkkitehtuurin taikuutta)
Koska kaikki muistialueet ovat pohjimmiltaan `/dev/shm`-tiedostoja, **Host voi
manipuloida niitC$ tC$ysin instanssien ohi**.
* **Lennosta kytkeminen (Attach):** Host kC$skee instanssia (esim. V8
Inspectorin websocket-yhteyden yli): *"Tee mmap tiedostoon /dev/shm/inst-123_ne
w-buffer ja aseta se global.sharedMem['new-buffer'] -muuttujaan"*. Instanssi
saa vC$littC6mC$sti uuden muistipankin kC$yttC6C6nsC$.
* **Sync / Kopiointi instanssien vC$lillC$:** Jos instanssin A muisti pitC$C$
synkronoida instanssille B lennosta, Node/JS ei osallistu tC$hC$n mitenkC$C$n!
Host tekee kC$yttC6jC$rjestelmC$tason `memcpy`:n (tai ihan vain file copyn)
`/dev/shm/inst-A_buf` -> `/dev/shm/inst-B_buf`. Muutos heijastuu instanssin B
`Buffer`-muuttujaan vC$littC6mC$sti laitteistotason nopeudella, tC$ysin ilman
CPU-overheadia serialisaatiosta.
* **Sama muisti monella (Cross-instance sharing):** Host voi ohjeistaa
instanssin B tekemC$C$n `mmap` suoraan instanssin A tiedostoon. Silloin
molemmat nC$kevC$t *saman* fyysisen RAM-alueen. (Huom: tC$llC6in tarvitaan
JS:n `Atomics`-API:a eli futexeja estC$mC$C$n race conditionit, jos molemmat
kirjoittavat samaan aikaan).
### 4.4: Muistin varmuuskopiointi (Backup/Restore)
TC$mC$ on perinteisten tietokantojen (Redis, Memcached) korvaaja ja
C$C$rimmC$isen nopea.
Koska muisti asuu tiedostossa (`tmpfs`), **backup on kirjaimellisesti
tiedoston kopioiminen**:
* **Backup:** Host kopioi `cp /dev/shm/inst-123_state /persistent-storage/backu
ps/inst-123_state.bin`. KyseessC$ on raaka 1:1 muistivedos (memory dump).
* **Restore:** Kun instanssi kC$ynnistetC$C$n uudelleen huoltokatkon jC$lkeen,
Host kopioi `.bin`-tiedoston takaisin `/dev/shm/`:iin ennen instanssin
kC$ynnistC$mistC$. Kun instanssi herC$C$ ja mappaa muistin, se jatkaa
tismalleen samasta millisekunnista mihin se jC$i, eikC$ sen tarvitse parsia
JSONia tai ottaa yhteyttC$ tietokantaan.
### Yhteenveto
TC$mC$ on tC$ysin toteutettavissa ja erittC$in tehokas lC$hestymistapa. Se
muuttaa Node-instanssit erC$C$nlaisiksi virtuaali-CPU:iksi, joille API (Host)
toimii Memory Management Unitina (MMU), kytkien laitteistotason muistisivuja
pC$C$lle ja pois instanssien osoiteavaruudesta.
TC$tC$ varten tarvitaan Host-puolelle joko valmis Node-moduuli (esim.
`mmap-io` tai vastaava, joka osaa pureskella `mmap` ja palauttaa `Buffer`in)
tai pieni itse kirjoitettu N-API C++ -silta, joka tekee POSIX `shm_open` ja
`mmap` -kutsut instanssin sisC$llC$. Aikaa tC$hC$n N-API -sillan koodaamiseen
menee kokeneelta C-koodarilta maksimissaan iltapC$ivC$.