scratch

package
v0.19.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 3 Imported by: 0

README

scratch

Shared, size-bounded buffer recycling for the SDK's service codecs.

scratch centralises the *bytes.Buffer pooling that every codec previously reimplemented: one shared sync.Pool, one cap-discard threshold, one acquire/release pair.

API

const MaxRetainedBufBytes = 256 << 10

func AcquireBuffer() *bytes.Buffer          // returns an already-Reset buffer
func ReleaseBuffer(buf *bytes.Buffer)       // repools, or drops if Cap > MaxRetainedBufBytes
func DetachBuffer(buf *bytes.Buffer) []byte // the encoded bytes: cloned + repooled, or handed over if over the cap

func AcquireReader(src []byte) *bytes.Reader // returns a reader positioned at src
func ReleaseReader(r *bytes.Reader)          // repools (no cap-discard — fixed-size)

MaxRetainedBufBytes is the codec domain's one ceiling. A codec that pools a buffer shape this package does not offer passes it to a recycler.CappedPool of its own rather than declaring another threshold.

Usage

buf := scratch.AcquireBuffer()
// ... encode into buf ...
out := slices.Clone(buf.Bytes()) // clone before release if bytes escape
scratch.ReleaseBuffer(buf)
return out

Lifetime

A buffer is caller-owned from AcquireBuffer until ReleaseBuffer or DetachBuffer. After release, neither the buffer nor any slice aliasing buf.Bytes() may be used. Clone the encoded bytes first if they must outlive the release — or let DetachBuffer do it: it clones a buffer within the cap before repooling it, and hands an over-cap one over without a copy, since the pool would drop it anyway.

A single shared pool is used deliberately: sync.Pool is per-P sharded, so consolidation raises the reuse rate without adding contention.

This package is internal to the SDK; consumers reach codecs through pkg/v1/data/codec.

Documentation

Overview

Package scratch provides shared, size-bounded recycling primitives for the service codecs. Every codec that encodes into a transient *bytes.Buffer previously declared its own sync.Pool, its own 256 KiB cap-discard constant, and its own release helper. Centralising them here gives a single source of truth for the cap-discard policy and a single shared pool whose reuse rate is higher than nine independent pools (sync.Pool is internally per-P sharded, so consolidation does not add contention).

The pooling MECHANISM lives in internal/kernel/concur/recycler (ADR 0010); scratch is a codec-domain consumer that keeps the 256 KiB threshold and the concrete *bytes.Buffer / *bytes.Reader types here.

Lifetime contract: a value returned by an Acquire* call is owned by the caller until the matching Release* call. After Release the value — and any slice aliasing it (e.g. buf.Bytes()) — MUST NOT be used; clone the encoded bytes first if they need to outlive the release.

Index

Constants

View Source
const MaxRetainedBufBytes int = 256 << 10

MaxRetainedBufBytes is the project-wide cap-discard threshold for pooled codec buffers. A buffer whose capacity exceeds this is dropped on release rather than re-pooled, so a one-off oversized payload cannot pin a large allocation for the lifetime of the pool's GC window. It bounds the shared *bytes.Buffer pool below, and it is also the ceiling a codec passes to a recycler.CappedPool of its own when it pools a buffer shape this package does not offer — so the codec domain keeps one threshold, not one per codec.

Variables

This section is empty.

Functions

func AcquireBuffer

func AcquireBuffer() *bytes.Buffer

AcquireBuffer returns a clean, zero-length *bytes.Buffer from the shared pool. The recycler reset the buffer on its previous Put, so callers append directly without re-resetting. The caller owns it until ReleaseBuffer.

func AcquireReader

func AcquireReader(src []byte) *bytes.Reader

AcquireReader returns a *bytes.Reader from the shared pool, reset to read from src. The caller owns it until ReleaseReader; src must stay alive and unmodified for as long as the reader is used.

func DetachBuffer

func DetachBuffer(buf *bytes.Buffer) []byte

DetachBuffer hands the caller the bytes encoded into buf and ends the caller's ownership of buf, by the cheaper of two releases for its size. A buffer within MaxRetainedBufBytes is cloned and repooled: the clone is small, and the next encode reuses the buffer. An over-cap buffer would pay a full copy of a large payload AND be dropped by the pool anyway, so it is orphaned instead: the returned slice IS its storage, now the caller's, and buf is left for the GC without a reset — a reset would not zero the bytes, but a later write through buf would overwrite them. Either way, buf must not be used after the call. A nil buf yields nil.

func ReleaseBuffer

func ReleaseBuffer(buf *bytes.Buffer)

ReleaseBuffer returns buf to the shared pool unless its capacity exceeds MaxRetainedBufBytes, in which case the recycler orphans it for the GC. Callers MUST NOT use buf — or any slice aliasing buf.Bytes() — after this call; clone first if the encoded bytes must outlive the release.

func ReleaseReader

func ReleaseReader(r *bytes.Reader)

ReleaseReader returns r to the shared pool. A bytes.Reader is fixed-size, so there is no cap-discard. Callers MUST NOT use r after this call.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL