---
id: f5707f0f4f230a276a3428b1eb1e6469
author: Lemon Mint
title: 'Schottky: Allokeringsfri, ordningsbevarande kodning av bytenycklar för Go'
description: Biblioteket i Go utan allokeringar kodar sammansatta tupler till byte-nycklar ordnade enligt memcmp, med oberoende ASC/DESC-sortering, taggar för placering av NULL-värden samt gränser för prefixskanning.
language: sv
date: 2026-08-31T07:47:42.614875839Z
path: /schottky
go_package: gosuda.org/schottky
go_repourl: https://github.com/gosuda/schottky.git
category: database
---

När man implementerar nyckel-värde-lager baserade på LSM-träd eller B-träd samt databasindex behöver sammansatta fält ofta kombineras till en enda byte-nyckel.

Standardiserade serialiseringsformat som JSON eller Protocol Buffers är inte utformade för detta ändamål, eftersom deras serialiserade bytesekvenser inte bevarar den naturliga sorteringsordningen som krävs för osignerade bytevisa jämförelser (`bytes.Compare` eller `memcmp`).

Schottky är ett Go-bibliotek utformat för att koda sammansatta tupler med flera typer till ordningsbevarande byte-nycklar.

```bash
go get gosuda.org/schottky@latest
```

### Serialisering kontra sorteringsnycklar

För att garantera korrekt bytevis sortering måste flera lågnivådetaljer i datarepresentationen hanteras:

- **Heltal**: Standardkodning i tvåkomplement med big-endian bryter den naturliga ordningen på grund av den mest signifikanta teckenbiten. Inversion av teckenbiten är nödvändig för korrekta osignerade bytejämförelser.
- **Flyttal**: Kräver justeringar av teckenbiten, omvänd ordning för negativa värden samt konsekvent hantering av `NaN` och `-0`.
- **Strängar och byteslices med variabel längd**: Fältgränser måste bevaras utan att prefixens sorteringsordning bryts.
- **Krav på sammansatta nycklar**: Stöd för oberoende ASC/DESC-ordning per fält, frikopplade regler för NULLS FIRST/LAST, strikt lexikografisk prioritet (tidigare fält avgör ordningen) samt kompatibilitet med prefixskanning.

Schottky omvandlar varje värde till en kanonisk nyttolast innan närvaromarkeringar och riktningsorientering tillämpas. För DESC-fält inverteras varje byte i ASC-nyttolasten bitvis (`^b`). NULL-placering hanteras via dedikerade närvaromarkeringar och är oberoende av sorteringsriktningen.

### Grundläggande användning

Följande exempel bygger en sammansatt nyckel bestående av ett konto-ID (`ASC, NULLS LAST`) och ett namn (`DESC, NULLS FIRST`):

```go
package main

import (
        "fmt"

        "gosuda.org/schottky"
)

func main() {
        storage := make([]byte, 0, 128)
        builder := schottky.NewBuilder(storage)

        builder.Int64(42, schottky.AscNullsLast)
        accountPrefixLen := builder.Len()

        builder.String("Ada", schottky.DescNullsFirst)
        key, err := builder.Key()

        if err != nil {
                panic(err)
        }
        accountPrefix := key[:accountPrefixLen]
        fmt.Printf("key=%x\nprefix=%x\n", key, accountPrefix)
}
```

Schottky tillhandahåller fyra explicita konfigurationer för sorteringsordning:

- `AscNullsFirst`
- `AscNullsLast`
- `DescNullsFirst`
- `DescNullsLast`

NULL-positionering härleds aldrig implicit. Om ett ogiltigt `Order`-värde skickas registrerar builder `ErrInvalidOrder`, vilket returneras vid anrop av `Key()` eller `Err()`.

### Prefixskanning och intervallgränser

Schottky-nycklar innehåller inga globala huvuden, metadata om antal fält, typtaggar eller avslutningar. Förutsatt att schemat är känt i förväg sammanfogas fältkodningarna helt enkelt.

På grund av denna layout utgör de kodade bytena för ledande fält ett giltigt prefix för intervallskanningar. I exemplet ovan kan `accountPrefix` direkt användas som ett prefixfilter för att skanna alla poster där `Account ID == 42`.

För att beräkna den exklusiva övre gränsen för halvöppna intervallskanningar `[prefix, upper)` används `PrefixUpperBound`:

```go
upperStorage := make([]byte, 0, len(accountPrefix))
upper, finite, err := schottky.PrefixUpperBound(upperStorage, accountPrefix)

if err != nil {
        panic(err)
}

if finite {
        // Halvöppen intervallskanning [accountPrefix, upper)
} else {
        // Obegränsad öppen intervallskanning
}
```

_Observera: `Builder.Len()` måste mätas vid rena fältgränser. Att skära inne i ett fälts interna bytesström ger ett ogiltigt prefix._

### Nollallokering och bufferhantering

Nyckelgenerering körs ofta på kritiska databasvägar. För att eliminera heap-allokeringar och overhead från buffertomallokering arbetar `Builder` strikt inom kapaciteten hos den slice som anropande kod tillhandahåller och omallokerar aldrig internt.

Om bufferten får slut på kapacitet registreras `ErrShortBuffer` utan att några partiella bytes skrivs. Fältskrivningar är atomära, och det första fel som uppstår bevaras tills det kontrolleras via `Key()` eller `Err()`. Att tillhandahålla tillräcklig kapacitet i förväg säkerställer nollallokerande kodning.

Bufferstorlekar kan beräknas i förväg med hjälpfunktioner såsom `EncodedBytesSize`, `EncodedStringSize` och `EncodedDecimalSize`, eller via fasta konstanter. Den returnerade nyckeln refererar direkt till den tillhandahållna bufferten, och ansvaret för minneslivscykeln ligger hos anropande kod.

`Decoder` fungerar symmetriskt: den lånar direkt från indatanyckeln, kräver av anropande kod tillhandahållna destinationsbuffertar för fält med variabel längd, och tillhandahåller `Remaining() == 0` för att upptäcka avslutande bytes eller schemafel.

### Stödda datatyper

- **Heltal**: Signerade och osignerade (8 till 64 bitar), `Int128`
- **Flyttal och numeriska värden**: `Float32`, `Float64`, decimal text
- **Grundläggande typer**: Binär sträng, byteslice, boolean, enum-rang
- **Datum och tid**: Date, Time, Zoned Time, Timestamp, Duration, Calendar Interval
- **Nätverk och identifierare**: UUID, MAC, IP, IP Prefix, Canonical Network Prefix, LSN
- **Sammansatta strukturer**: Kapslade tupler, Ranges samt råa strukturella kodningar
- **Kollation**: Unicode-kollationsnycklar och externa kanoniska tokens

SQL-typmappningen är anpassad till sorteringsreglerna för PostgreSQL 18 B-träd. Typer som beror av databaskataloger eller internt motortillstånd hanteras genom att externa kanoniska tokens skickas in.

### Strängkollation

`Builder.String` används som standard med rå UTF-8-binärordning. För lokalmedveten sortering tillhandahåller Schottky en samtidighetssäker, oföränderlig `Collator`:

- **Deterministisk kollation**: Kodar kollationsnyckeln tillsammans med rå UTF-8-bytes för att utgöra en tiebreaker när kollationsvikterna är identiska.
- **Icke-deterministisk kollation**: Behandlar kollationsekvivalenta strängar som identiska och utelämnar den råa bytetiebreakern.

Unicode- och profilversioner bör spåras i metadataschemat. Om kollationsleverantörer eller profilinställningar ändras måste befintliga nycklar byggas om.

### Schemahantering

Eftersom Schottky-nycklar är råa byte-sekvenser utan huvuden måste schemalagret spåra:

1. Fältsekvens och datatyper.
2. Sorteringsriktningar (`ASC`/`DESC`) och NULL-ordning (`NULLS FIRST`/`LAST`).
3. Strängkollations- och normaliseringsregler.
4. Versioner av Schottky- och kollationsprofiler.

Att jämföra nycklar genererade med olika scheman eller att avkoda mot ett avvikande schema bryter ordningsgarantierna.

### Prestanda och länkar

På Go 1.27+ kan experimentell portabel SIMD-acceleration aktiveras med `GOEXPERIMENT=simd`. Skalära och SIMD-vägar producerar byte-identiska nycklar.

- **GitHub-repositorium**: https://github.com/gosuda/schottky
- **Specifikation för nyckellayout**: https://github.com/gosuda/schottky/blob/main/docs/03-key-layout.md
- **Guide för SQL-typmappning**: https://github.com/gosuda/schottky/blob/main/docs/17-sql-type-map.md
- **Go API-referens**: https://github.com/gosuda/schottky/blob/main/docs/18-api.md
