Documentation
¶
Overview ¶
Package b5session implements the feature-off B5 S3 coordination contracts: a strongly-consistent session directory, continuation capabilities, shared connection and plan admission, durable dial identities, quarantine, and the owner-crash reaper.
The package is deliberately not imported by a production MCP/HTTP handler. It owns metadata only and never receives a business SQL executor.
Index ¶
- Constants
- Variables
- func DigestSessionID(sessionID string) [32]byte
- func InstallPostgresSchema(ctx context.Context, db *sql.DB) error
- func SignContinuation(secret string, sessionID, method, requestID string, ownerEpoch uint64, ...) (string, error)
- type AESGCMSealer
- type AbsenceProof
- type BackendIdentity
- type BackendInventory
- type Budget
- type Claim
- type ClaimKind
- type ClaimRequest
- type ClaimState
- type ContinuationInput
- type CreateSession
- type CreatedSession
- type DialIdentity
- type DialIdentityCodec
- type DialPermitIssuer
- type Directory
- func (d *Directory) Close(ctx context.Context, input ContinuationInput) (RouteDecision, error)
- func (d *Directory) Create(ctx context.Context, input CreateSession) (CreatedSession, error)
- func (d *Directory) Expire(ctx context.Context, limit int) (int, error)
- func (d *Directory) Lookup(ctx context.Context, input ContinuationInput) (RouteDecision, error)
- func (d *Directory) String() string
- func (d *Directory) Touch(ctx context.Context, input ContinuationInput) (RouteDecision, error)
- func (d *Directory) TransferOwner(ctx context.Context, input ContinuationInput, newOwner, newRoute string) (store.B5Session, error)
- type DirectoryConfig
- type DispositionProof
- type InventoryObservation
- type KeySealer
- type Lease
- type LeaseState
- type LedgerStore
- type MemoryLedger
- func (l *MemoryLedger) AbandonUndialed(_ context.Context, id string, generation uint64, digest [32]byte) (Lease, error)
- func (l *MemoryLedger) AcquireClaim(_ context.Context, request ClaimRequest) (Claim, error)
- func (l *MemoryLedger) AcquireFree(_ context.Context, id string, generation uint64, owner, incarnation string) (Lease, error)
- func (l *MemoryLedger) ApplyDisposition(_ context.Context, id string, generation uint64, proof DispositionProof) (Lease, error)
- func (l *MemoryLedger) BeginTermination(_ context.Context, id string, generation uint64) (Lease, error)
- func (l *MemoryLedger) BindBackend(_ context.Context, id string, generation uint64, backend BackendIdentity) (Lease, error)
- func (l *MemoryLedger) Budget(_ context.Context, datasource string) (Budget, error)
- func (l *MemoryLedger) Claim(_ context.Context, id string) (Claim, error)
- func (l *MemoryLedger) ConfigureBudget(_ context.Context, budget Budget) (Budget, error)
- func (l *MemoryLedger) FenceOwner(_ context.Context, owner, incarnation string) ([]Claim, error)
- func (l *MemoryLedger) IssueDialPermit(_ context.Context, claimID string, generation uint64, permitID, token string) (Lease, error)
- func (l *MemoryLedger) ListClaimLeases(_ context.Context, claimID string) ([]Lease, error)
- func (l *MemoryLedger) MarkDialStarted(_ context.Context, id string, generation uint64) (Lease, error)
- func (l *MemoryLedger) ReconcileAbsence(_ context.Context, id string, generation uint64, proof AbsenceProof) (Lease, error)
- func (l *MemoryLedger) ReleasePlan(_ context.Context, id string) error
- func (l *MemoryLedger) ReservePlan(_ context.Context, lease PlanLease) error
- func (l *MemoryLedger) ShrinkFencedClaim(_ context.Context, id string, generation uint64) (Claim, error)
- type MemorySessionStore
- func (s *MemorySessionStore) CASOwner(_ context.Context, id string, revision int64, owner string, epoch uint64, ...) (store.B5Session, error)
- func (s *MemorySessionStore) CASStatus(_ context.Context, id string, revision int64, from, to b5.SessionStatus, ...) (store.B5Session, error)
- func (s *MemorySessionStore) Create(_ context.Context, value store.B5Session) (store.B5Session, error)
- func (s *MemorySessionStore) Get(_ context.Context, id string) (store.B5Session, error)
- func (s *MemorySessionStore) ListExpired(_ context.Context, now time.Time, limit int) ([]store.B5Session, error)
- type PGInventory
- type PlanLease
- type ReapReport
- type Reaper
- type RouteDecision
- type SQLLedger
- func (l *SQLLedger) AbandonUndialed(ctx context.Context, id string, generation uint64, digest [32]byte) (Lease, error)
- func (l *SQLLedger) AcquireClaim(ctx context.Context, request ClaimRequest) (Claim, error)
- func (l *SQLLedger) AcquireFree(ctx context.Context, id string, generation uint64, owner, incarnation string) (Lease, error)
- func (l *SQLLedger) ApplyDisposition(ctx context.Context, id string, generation uint64, proof DispositionProof) (Lease, error)
- func (l *SQLLedger) BeginTermination(ctx context.Context, id string, generation uint64) (Lease, error)
- func (l *SQLLedger) BindBackend(ctx context.Context, id string, generation uint64, backend BackendIdentity) (Lease, error)
- func (l *SQLLedger) Budget(ctx context.Context, datasource string) (Budget, error)
- func (l *SQLLedger) Claim(ctx context.Context, id string) (Claim, error)
- func (l *SQLLedger) ConfigureBudget(ctx context.Context, input Budget) (Budget, error)
- func (l *SQLLedger) ConfigureTombstones(ctx context.Context, budget TombstoneBudget, now time.Time) error
- func (l *SQLLedger) FenceOwner(ctx context.Context, owner, incarnation string) ([]Claim, error)
- func (l *SQLLedger) GCTombstones(ctx context.Context, now time.Time, limit int) (int, error)
- func (l *SQLLedger) IssueDialPermit(ctx context.Context, claimID string, generation uint64, permitID, token string) (Lease, error)
- func (l *SQLLedger) ListClaimLeases(ctx context.Context, claimID string) ([]Lease, error)
- func (l *SQLLedger) MarkDialStarted(ctx context.Context, id string, generation uint64) (Lease, error)
- func (l *SQLLedger) PutTombstone(ctx context.Context, value Tombstone, now time.Time) error
- func (l *SQLLedger) ReconcileAbsence(ctx context.Context, id string, generation uint64, proof AbsenceProof) (Lease, error)
- func (l *SQLLedger) ReleasePlan(ctx context.Context, id string) error
- func (l *SQLLedger) ReservePlan(ctx context.Context, lease PlanLease) error
- func (l *SQLLedger) ShrinkFencedClaim(ctx context.Context, id string, generation uint64) (Claim, error)
- func (l *SQLLedger) TombstoneUsage(ctx context.Context) (entries int, bytes int64, err error)
- type SessionStore
- type TerminalDisposition
- type Tombstone
- type TombstoneBudget
Constants ¶
const MaxTombstoneTerminalCodeBytes = 96
const PostgreSQLSchema = `` /* 4324-byte string literal not displayed */
PostgreSQLSchema is intentionally package-owned and feature-off. It is not registered in the application's production migration stream. S10 can move the reviewed DDL into that stream without changing this ledger contract.
Variables ¶
var ( ErrInvalidDirectoryConfig = errors.New("b5session: invalid directory configuration") ErrInvalidContinuation = errors.New("b5session: invalid continuation request") )
var ( ErrAdmissionDenied = errors.New("b5session: shared admission denied") ErrCASConflict = errors.New("b5session: generation compare-and-swap conflict") ErrInvalidTransition = errors.New("b5session: invalid lease transition") ErrUnknownProofSchema = errors.New("b5session: unknown proof schema") ErrBackendStillPresent = errors.New("b5session: backend still present") )
var ErrInvalidDialIdentity = errors.New("b5session: invalid dial permit identity")
Functions ¶
func DigestSessionID ¶
Types ¶
type AESGCMSealer ¶
type AESGCMSealer struct {
// contains filtered or unexported fields
}
func NewAESGCMSealer ¶
func NewAESGCMSealer(keyID string, key []byte) (*AESGCMSealer, error)
func (*AESGCMSealer) KeyID ¶
func (s *AESGCMSealer) KeyID() string
type AbsenceProof ¶
type AbsenceProof struct {
SchemaID string
SchemaVersion uint16
Digest [32]byte
InventoryEpoch uint64
ObservedAt time.Time
}
func NewAbsenceProof ¶
func NewAbsenceProof(epoch uint64, observed time.Time, material []byte) AbsenceProof
type BackendIdentity ¶
type BackendIdentity struct {
ServerID string
Database string
PID int32
BackendStarted time.Time
DialToken string
}
func (BackendIdentity) Complete ¶
func (identity BackendIdentity) Complete() bool
func (BackendIdentity) Equal ¶
func (identity BackendIdentity) Equal(other BackendIdentity) bool
type BackendInventory ¶
type BackendInventory interface {
ObservePermit(context.Context, string) (InventoryObservation, error)
Terminate(context.Context, BackendIdentity) error
}
type ClaimRequest ¶
type ClaimState ¶
type ClaimState string
const ( ClaimActive ClaimState = "ACTIVE" ClaimFenced ClaimState = "FENCED" ClaimReleased ClaimState = "RELEASED" )
type ContinuationInput ¶
type ContinuationInput struct {
AgentSQLSessionID string
McpSessionID string
PrincipalID string
InstanceID string
Method string
RequestID string
OwnerEpoch uint64
ExpectedSeq *uint64
BodyDigest [32]byte
Proof string
}
ContinuationInput intentionally has separate MCP and AgentSQL identifiers. McpSessionID is transport metadata only and is never a fallback lookup key.
type CreateSession ¶
type CreatedSession ¶
type DialIdentity ¶
type DialIdentityCodec ¶
type DialIdentityCodec struct {
// contains filtered or unexported fields
}
DialIdentityCodec produces a PostgreSQL application_name below the 63-byte NAMEDATALEN limit. The field carries a random durable permit id, a digest of the owner incarnation, and a truncated HMAC. Inventory accepts it only after verifying the HMAC and expected incarnation.
func NewDialIdentityCodec ¶
func NewDialIdentityCodec(key []byte) (*DialIdentityCodec, error)
func (*DialIdentityCodec) New ¶
func (c *DialIdentityCodec) New(ownerIncarnation string) (DialIdentity, error)
func (*DialIdentityCodec) Verify ¶
func (c *DialIdentityCodec) Verify(applicationName, ownerIncarnation string) (DialIdentity, error)
type DialPermitIssuer ¶
type DialPermitIssuer struct {
Ledger LedgerStore
Codec *DialIdentityCodec
}
func (DialPermitIssuer) Issue ¶
func (issuer DialPermitIssuer) Issue(ctx context.Context, claimID string, generation uint64) (Lease, DialIdentity, error)
type Directory ¶
type Directory struct {
// contains filtered or unexported fields
}
func NewDirectory ¶
func NewDirectory(config DirectoryConfig) (*Directory, error)
func (*Directory) Close ¶
func (d *Directory) Close(ctx context.Context, input ContinuationInput) (RouteDecision, error)
func (*Directory) Create ¶
func (d *Directory) Create(ctx context.Context, input CreateSession) (CreatedSession, error)
func (*Directory) Lookup ¶
func (d *Directory) Lookup(ctx context.Context, input ContinuationInput) (RouteDecision, error)
func (*Directory) Touch ¶
func (d *Directory) Touch(ctx context.Context, input ContinuationInput) (RouteDecision, error)
func (*Directory) TransferOwner ¶
func (d *Directory) TransferOwner(ctx context.Context, input ContinuationInput, newOwner, newRoute string) (store.B5Session, error)
TransferOwner increments the owner epoch exactly once. The request is authenticated against the old owner/epoch; the same key is re-sealed with new-epoch AAD before the atomic directory CAS.
type DirectoryConfig ¶
type DispositionProof ¶
type DispositionProof struct {
SchemaID string
SchemaVersion uint16
Disposition b5.ConnectionDisposition
Digest [32]byte
PoolTransfer bool
BackendAbsence bool
InventoryEpoch uint64
SourceDigest [32]byte
}
func DispositionProofFromTerminal ¶
func DispositionProofFromTerminal(resolution TerminalDisposition, sourceDigest [32]byte, poolTransfer, backendAbsence bool, inventoryEpoch uint64) (DispositionProof, error)
DispositionProofFromTerminal is the only normal constructor. It consumes the frozen b5terminal result instead of allowing the pool layer to infer a disposition from an error string.
type InventoryObservation ¶
type InventoryObservation struct {
Epoch uint64
ObservedAt time.Time
Backends []BackendIdentity
}
type KeySealer ¶
type KeySealer interface {
Seal(plaintext, aad []byte) (string, error)
Open(ciphertext string, aad []byte) ([]byte, error)
KeyID() string
}
KeySealer keeps the continuation key encrypted in the directory. AAD is canonical and includes the owner epoch, so an owner transfer must re-seal in the same CAS that increments the epoch.
type Lease ¶
type Lease struct {
ID, ClaimID, DatasourceID string
OwnerInstanceID, OwnerIncarnation string
ClaimGeneration, Generation uint64
DialPermitID, DialToken string
DialAttempted bool
State LeaseState
Backend BackendIdentity
Disposition b5.ConnectionDisposition
ProofSchemaID string
ProofSchemaVersion uint16
ProofDigest [32]byte
InventoryEpoch uint64
Charged bool
Revision int64
}
type LeaseState ¶
type LeaseState string
const ( LeaseDialPermitOutstanding LeaseState = "DIAL_PERMIT_OUTSTANDING" LeaseInUse LeaseState = "IN_USE" LeaseTerminating LeaseState = "TERMINATING" LeaseQuarantined LeaseState = "QUARANTINED" LeaseFree LeaseState = "FREE" LeaseNeverAllocated LeaseState = "NEVER_ALLOCATED" LeaseBackendAbsent LeaseState = "BACKEND_ABSENT_CONFIRMED" )
type LedgerStore ¶
type LedgerStore interface {
ConfigureBudget(context.Context, Budget) (Budget, error)
Budget(context.Context, string) (Budget, error)
AcquireClaim(context.Context, ClaimRequest) (Claim, error)
Claim(context.Context, string) (Claim, error)
ReservePlan(context.Context, PlanLease) error
ReleasePlan(context.Context, string) error
IssueDialPermit(context.Context, string, uint64, string, string) (Lease, error)
MarkDialStarted(context.Context, string, uint64) (Lease, error)
BindBackend(context.Context, string, uint64, BackendIdentity) (Lease, error)
AcquireFree(context.Context, string, uint64, string, string) (Lease, error)
BeginTermination(context.Context, string, uint64) (Lease, error)
ApplyDisposition(context.Context, string, uint64, DispositionProof) (Lease, error)
FenceOwner(context.Context, string, string) ([]Claim, error)
ListClaimLeases(context.Context, string) ([]Lease, error)
AbandonUndialed(context.Context, string, uint64, [32]byte) (Lease, error)
ReconcileAbsence(context.Context, string, uint64, AbsenceProof) (Lease, error)
ShrinkFencedClaim(context.Context, string, uint64) (Claim, error)
}
LedgerStore is the complete durable S3 surface. Implementations must linearize admission and every generation transition in their shared store.
type MemoryLedger ¶
type MemoryLedger struct {
// contains filtered or unexported fields
}
func NewMemoryLedger ¶
func NewMemoryLedger() *MemoryLedger
func (*MemoryLedger) AbandonUndialed ¶
func (*MemoryLedger) AcquireClaim ¶
func (l *MemoryLedger) AcquireClaim(_ context.Context, request ClaimRequest) (Claim, error)
func (*MemoryLedger) AcquireFree ¶
func (*MemoryLedger) ApplyDisposition ¶
func (l *MemoryLedger) ApplyDisposition(_ context.Context, id string, generation uint64, proof DispositionProof) (Lease, error)
func (*MemoryLedger) BeginTermination ¶
func (*MemoryLedger) BindBackend ¶
func (l *MemoryLedger) BindBackend(_ context.Context, id string, generation uint64, backend BackendIdentity) (Lease, error)
func (*MemoryLedger) ConfigureBudget ¶
func (*MemoryLedger) FenceOwner ¶
func (*MemoryLedger) IssueDialPermit ¶
func (*MemoryLedger) ListClaimLeases ¶
func (*MemoryLedger) MarkDialStarted ¶
func (*MemoryLedger) ReconcileAbsence ¶
func (l *MemoryLedger) ReconcileAbsence(_ context.Context, id string, generation uint64, proof AbsenceProof) (Lease, error)
func (*MemoryLedger) ReleasePlan ¶
func (l *MemoryLedger) ReleasePlan(_ context.Context, id string) error
func (*MemoryLedger) ReservePlan ¶
func (l *MemoryLedger) ReservePlan(_ context.Context, lease PlanLease) error
func (*MemoryLedger) ShrinkFencedClaim ¶
type MemorySessionStore ¶
type MemorySessionStore struct {
// contains filtered or unexported fields
}
MemorySessionStore is a deterministic CAS reference implementation. Multiple Directory instances may share it in race tests; cross-process deployments use B5SessionRepository.
func NewMemorySessionStore ¶
func NewMemorySessionStore() *MemorySessionStore
type PGInventory ¶
type PGInventory struct {
// contains filtered or unexported fields
}
PGInventory uses a separately supplied administrative pool. It never uses the socket being reconciled. Exact termination predicates include backend start time and the authenticated dial token, so PID reuse cannot kill an unrelated backend.
func NewPGInventory ¶
func (*PGInventory) ObservePermit ¶
func (inventory *PGInventory) ObservePermit(ctx context.Context, token string) (InventoryObservation, error)
func (*PGInventory) Terminate ¶
func (inventory *PGInventory) Terminate(ctx context.Context, backend BackendIdentity) error
type ReapReport ¶
type Reaper ¶
type Reaper struct {
Ledger LedgerStore
Inventory BackendInventory
}
type RouteDecision ¶
type SQLLedger ¶
type SQLLedger struct {
// contains filtered or unexported fields
}
func (*SQLLedger) AbandonUndialed ¶
func (*SQLLedger) AcquireClaim ¶
func (*SQLLedger) AcquireFree ¶
func (*SQLLedger) ApplyDisposition ¶
func (*SQLLedger) BeginTermination ¶
func (*SQLLedger) BindBackend ¶
func (*SQLLedger) ConfigureBudget ¶
func (*SQLLedger) ConfigureTombstones ¶
func (*SQLLedger) FenceOwner ¶
func (*SQLLedger) GCTombstones ¶
func (*SQLLedger) IssueDialPermit ¶
func (*SQLLedger) ListClaimLeases ¶
func (*SQLLedger) MarkDialStarted ¶
func (*SQLLedger) PutTombstone ¶
func (*SQLLedger) ReconcileAbsence ¶
func (*SQLLedger) ReleasePlan ¶
func (*SQLLedger) ReservePlan ¶
func (*SQLLedger) ShrinkFencedClaim ¶
type SessionStore ¶
type SessionStore interface {
Create(context.Context, store.B5Session) (store.B5Session, error)
Get(context.Context, string) (store.B5Session, error)
CASStatus(context.Context, string, int64, b5.SessionStatus, b5.SessionStatus, time.Time) (store.B5Session, error)
CASOwner(context.Context, string, int64, string, uint64, string, string, string, []byte) (store.B5Session, error)
ListExpired(context.Context, time.Time, int) ([]store.B5Session, error)
}
type TerminalDisposition ¶
type TerminalDisposition struct {
Schema string
SchemaVersion uint16
Disposition b5.ConnectionDisposition
}
type Tombstone ¶
type Tombstone struct {
ID string
SessionIDDigest [32]byte
TerminalCode string
FinalSeq uint64
OwnerEpoch uint64
EventDigest [32]byte
ExpiresAt time.Time
}
Tombstone is digest-only by construction: it has no SQL, plan, rows, response, reason, or secret field that a caller could accidentally retain.