---
id: e52d68870be3de9f644fcfc584bd8aec
author: Lemon Mint
title: 'gosuda.org/zstd: Drop-In DataDog/zstd Compression fără CGO și cu izolarea erorilor fatale'
description: CGO_ENABLED=0 Bibliotecă Go Zstandard care rulează biblioteca C upstream libzstd 1.5.7 într-un worker cu memorie partajată, cu o API compatibilă cu DataDog/zstd, contexte reutilizabile și procesare în loturi (bulk batching).
language: ro
date: 2026-10-18T14:07:11.281986997Z
path: /zstd
go_package: gosuda.org/zstd
go_repourl: https://github.com/gosuda/hqq-zstd.git
category: lowlevel
---

`gosuda.org/zstd` este o bibliotecă de compresie Go cu `CGO_ENABLED=0` care rulează motorul oficial C Zstandard (`libzstd 1.5.7`) într-un proces worker izolat, peste memoria partajată [HQQ](https://gosuda.org/hqq). Oferă o API de înlocuire directă pentru `github.com/DataDog/zstd` (inclusiv `Compress`/`Decompress` one-shot, `io.Writer`/`io.Reader` pentru streaming, dicționare pre-procesate și contexte reutilizabile fără alocări), păstrând în același timp execuția C complet în afara spațiului de adrese al runtime-ului Go.

```bash
go get gosuda.org/zstd@v0.3.10507
```

## De ce decompresia trebuie să rămână în afara heap-ului Go

În backend-urile de producție, compresia și decompresia se află direct la granița intrărilor nesigure. Colectoarele de log-uri, brokerii de mesaje, gateway-urile RPC și motoarele de stocare decompresează, în fiecare minut, gigabytes de cadre furnizate din exterior.

Multe echipe Go aleg `github.com/DataDog/zstd` deoarece se leagă direct de `libzstd` upstream scris în C: implementarea C oferă un randament ridicat pe un singur nucleu, rapoarte de compresie strânse cu dicționare pentru înregistrări mici și arene C off-heap (`ZSTD_CCtx` și `ZSTD_DCtx`) care nu măresc timpii de scanare ai colectorului de gunoi Go.

Totuși, legarea `libzstd` într-un serviciu Go prin `cgo` aduce două puncte dureroase operaționale:

1. **Fricțiune la build și deployment**: la fel ca `go-sqlite3`, `DataDog/zstd` necesită `CGO_ENABLED=1` și un toolchain de compilare C pentru ținta respectivă. Compilarea încrucișată a serviciilor sau construirea de binare statice pentru `linux/arm64` ori `windows/arm64` necesită sysroot-uri C externe.
2. **Spațiu de adrese partajat la intrări nesigure**: decompresarea unor payload-uri corupte sau adversariale în același spațiu de adrese virtual cu serverul Go înseamnă că orice eroare din codul C nativ sau din gestionarea dicționarelor personalizate poate termina întregul proces Go.

`gosuda.org/zstd` păstrează motorul upstream exact `libzstd 1.5.7` și API-ul familiar `github.com/DataDog/zstd`, dar mută execuția C într-un proces copil verificat (`zstd_server`), conectat programului Go prin memorie partajată aliniată la linia de cache.

## Înlocuire directă pentru `github.com/DataDog/zstd`

Migrarea de la `github.com/DataDog/zstd` necesită modificarea doar a calea de import către `"gosuda.org/zstd"`. Nu este necesară instalarea unui binar extern sau cod de configurare: la primul apel, `gosuda.org/zstd` materializează un binar `zstd_server` embedded, atestat SLSA, pentru platforma ta, îi verifică digestul SHA-256 prin `gosuda.org/hqq/secureexec` și deschide un pool de sesiuni cu memorie partajată.

```go
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"

	"gosuda.org/zstd"
)

func main() {
	// 1. One-shot Compress / Decompress (mirrors github.com/DataDog/zstd)
	src := []byte("shared-memory zstd payload without cgo")
	compressed, err := zstd.CompressLevel(nil, src, zstd.BestSpeed)
	if err != nil {
		log.Fatal(err)
	}
	plain, err := zstd.Decompress(nil, compressed)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("one-shot: %d bytes -> %d bytes (%s)\n", len(src), len(compressed), plain)

	// 2. Streaming Writer and Reader with Dictionary Support
	var buf bytes.Buffer
	w := zstd.NewWriterLevel(&buf, zstd.DefaultCompression)
	if _, err := w.Write(src); err != nil {
		log.Fatal(err)
	}
	if err := w.Close(); err != nil {
		log.Fatal(err)
	}

	r := zstd.NewReader(&buf)
	defer r.Close()
	streamed, err := io.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("streamed: %s\n", streamed)
}
```

### Platforme suportate și binare embedded

Toate cele șase platforme țintă sunt livrate cu binare worker precompilate, fixate prin SHA-256, încorporate prin etichete de build specifice platformei (`internal/embedded/embed_<goos>_<goarch>.go`):

| OS țintă   | Arhitectură țintă (`GOARCH`) | Binar embedded                  |  Dimensiune binar | Toolchain de build și proveniență                 |
| :--------- | :--------------------------- | :------------------------------ | ----------------: | :------------------------------------------------ |
| **Linux**  | `amd64`, `arm64`             | `zstd_server_linux_<arch>`      | ~770 - 880 KiB    | GCC `-O3`, SLSA Build L3 Provenance               |
| **macOS**  | `arm64`, `amd64`             | `zstd_server_darwin_<arch>`     | ~660 - 795 KiB    | AppleClang `-O3`, SLSA Build L3 Provenance        |
| **Windows**| `amd64`                      | `zstd_server_windows_amd64.exe` |       ~818 KiB    | MSVC `-O2`, SLSA Build L3 Provenance              |
| **Windows**| `arm64`                      | `zstd_server_windows_arm64.exe` |       ~551 KiB    | `zig cc -target aarch64-windows-gnu -O3`, SLSA L3 |

## În interiorul căii de date din memoria partajată

Pentru a păstra randamentul competitiv cu `cgo` în proces, `gosuda.org/zstd` evită serializarea prin socket-uri și alocările de heap pe calea critică.

### 1. Codificare de slot fără alocări (`zstd_ctx.go` și `c/zstd_hooks.c`)

Când folosiți un `zstd.Ctx` reutilizabil (sau când funcțiile de nivel pachet `Compress` și `Decompress` împrumută un `Ctx` din pool-ul de sesiuni intern), datele circulă direct prin slotul `StandardLink` mapat în memorie:

```text
Go Caller (zstd.Ctx)                    Shared-Memory Slot                    C11 Worker (zstd_hooks.c)
--------------------                    ------------------                    -------------------------
src []byte  ------------------------->  Request Slot Payload  ------------->  ZSTD_compressCCtx(
                                                                                cctx, resp_slot, src, level)
dst []byte  <-------------------------  Response Slot Payload <-------------  Writes compressed frame directly
                                                                              into shared response slot
```

1. Clientul `hqq-bindgen` generat copiază `src` direct în slotul de cerere mapat în memorie și inversează cuvântul de secvență `SeqLock`.
2. Worker-ul C citește `src` în loc din slotul de cerere și transmite pointerul payload-ului din slotul de răspuns direct ca buffer de destinație către `ZSTD_compressCCtx` sau `ZSTD_decompressDCtx`.
3. Clientul Go copiază sliceul rezultat din slotul de răspuns în sliceul `dst` furnizat de apelant. În regim staționar, `ctx.CompressTo(dst, src, level)` și `ctx.DecompressInto(dst, src)` realizează `0 allocs/op`.

Dicționarele pre-procesate (`CDict` și `DDict`) trăiesc pe worker-ul C în spatele handle-urilor pe 64 de biți verificate prin generație (`handle CDict`, `handle DDict` în `zstd.idl`). Crearea unui dicționar o singură dată prin `ctx.NewCDict(rawDict, level)` analizează tabelele dicționarului în interiorul worker-ului C și returnează un handle ușor, care poate fi reutilizat în mii de apeluri fără retrimiterea octeților dicționarului.

### 2. Amortizarea overhead-ului IPC prin încadrare în bloc (`zstd_bulk.go`)

Pentru payload-uri mari (16 KiB și mai mult), round trip-ul de memorie partajată de ~200 ns este neglijabil în comparație cu timpul CPU petrecut în `libzstd`. Pentru sarcinile care comprimă mii de mesaje mici, de 100 de octeți până la 1 KiB, totuși, plătirea a chiar 200 ns per element se adună.

`gosuda.org/zstd` oferă `CompressBulk` și `DecompressBulk` pe `BulkCtx` (`zstd_bulk.go`) pentru a elimina round trip-urile per element:

```go
bctx, err := client.NewBulkCtx(1 << 20)
if err != nil {
	log.Fatal(err)
}
defer bctx.Close()

items := [][]byte{
	[]byte(`{"event":"login","user":101}`),
	[]byte(`{"event":"purchase","user":101,"amount":4200}`),
	[]byte(`{"event":"logout","user":101}`),
}
compressedItems, err := bctx.CompressBulk(nil, items, zstd.DefaultCompression)
```

`CompressBulk` împachetează întregul lot `[][]byte` într-un singur cadru de cerere cu prefix de lungime în memoria partajată. Worker-ul C parcurge fiecare element în C (`compress_bulk` în `c/zstd_hooks.c`), scrie toate cadrele comprimate contiguu în slotul de răspuns și returnează întregul lot într-un singur round trip de memorie partajată.

### 3. Supraviețuirea terminării worker-ului fără prăbușirea apelantului

Deoarece `zstd_server` rulează într-un proces OS separat, o eroare fatală în worker-ul C nu îți doboară niciodată aplicația Go:

- Dacă `zstd_server` este oprit din exterior (de exemplu, prin `SIGKILL` sau un eveniment OOM), stratul de transport HQQ detectează imediat peer-ul defect și returnează un `*rt.TransportError` tipizat din apelul `Compress` sau `Decompress` aflat în curs.
- Funcțiile de nivel pachet (`zstd.Compress`, `zstd.Decompress`, `zstd.NewWriter`, `zstd.NewReader`) detectează automat că worker-ul implicit partajat a dispărut, pornesc o nouă instanță `zstd_server` verificată la următorul apel și reiau funcționarea normală.

## Structura depozitului

Codul sursă separă fațada de înlocuire directă `DataDog/zstd` de primitivele de nivel scăzut `hqq-bindgen` pentru sesiuni și operații în bloc:

```text
gosuda.org/zstd
├── autolaunch.go / hashes.go  # API Compress/Decompress de înlocuire directă, pool cu recuperare automată și hash-uri SHA-256
├── zstd_stream.go             # Writer/Reader de streaming (NewWriterLevelDict, NewReaderDict)
├── zstd_ctx.go                # Ctx fără alocări, CDict și DDict, wrappere peste hqq-bindgen
├── zstd_bulk.go               # Încadrare CompressBulk și DecompressBulk cu un singur round trip
├── zstd.go                    # Clientul Go hqq-bindgen generat pentru serviciul IDL zstd
├── zstd.idl                   # Schema IDL HQQ care definește Context, CDict, DDict și metodele RPC
├── internal/embedded/         # Binare zstd_server //go:embed cu etichete de platformă (6 ținte OS/arhitectură)
└── c/                         # Implementarea serverului C11 (zstd_server.c, zstd_hooks.c, main.c)
```

## Noțiuni de bază

Instalați `gosuda.org/zstd` cu `go get` și utilizați-l cu `CGO_ENABLED=0`:

```bash
go get gosuda.org/zstd@v0.3.10507
```

- **Repository GitHub**: [https://github.com/gosuda/hqq-zstd](https://github.com/gosuda/hqq-zstd)
- **Arhitectură și benchmark-uri**: [docs/ARCHITECTURE.md](https://github.com/gosuda/hqq-zstd/blob/main/docs/ARCHITECTURE.md)
- **HQQ Core Runtime**: [https://gosuda.org/hqq](https://gosuda.org/hqq)
