rowlock

package
v0.28.0 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package rowlock owns the invariant PostgreSQL lock order for durable resource mutations. Every caller locks Sandbox, then Workspace, then Snapshot when present, before acquiring operation-specific rows. A caller that holds the quota ledgers locks them before all of these; a Sandbox transition that can increase quota usage must hold them (see SandboxWorkspaceForTransition). A caller that holds several Sandboxes locks them in ascending identity order (see SandboxesInOrder).

Index

Constants

This section is empty.

Variables

View Source
var ErrQuotaLedgerRequired = errors.New("SecondBox Sandbox transition increases quota usage and requires its quota ledger lock")

ErrQuotaLedgerRequired reports that a Sandbox locked without its quota ledgers turned out to be in a state from which the caller's transition increases quota usage. The caller rolls back and retries with the ledgers.

Functions

func ActiveSubject added in v0.6.0

func ActiveSubject(
	ctx context.Context,
	tx pgx.Tx,
	tenantRef string,
	subjectRef string,
	now time.Time,
) error

ActiveSubject locks and validates the Subject after its quota ledger and before quota-bearing domain rows.

func AlwaysQuotaLedger added in v0.22.0

func AlwaysQuotaLedger(string, string) bool

AlwaysQuotaLedger is the QuotaTransition of a caller that holds the ledgers unconditionally, such as a retry after ErrQuotaLedgerRequired.

func NonIncreasingTransition added in v0.22.0

func NonIncreasingTransition(string, string) bool

NonIncreasingTransition is the QuotaTransition of a caller whose writes never increase quota usage.

func QuotaScopes added in v0.6.0

func QuotaScopes(ctx context.Context, tx pgx.Tx, scopes []QuotaScope) error

QuotaScopes locks all tenant ledgers first, then all Subject ledgers, with each level sorted by logical identity before any domain row is locked.

func QuotaUsageActive added in v0.22.0

func QuotaUsageActive(state, desiredState string) bool

QuotaUsageActive mirrors secondbox.sandbox_quota_active: the Sandbox holds a compute reservation (active Instance, CPU, and memory) in quota usage.

func QuotaUsageIncreases added in v0.22.0

func QuotaUsageIncreases(fromState, fromDesired, toState, toDesired string) bool

QuotaUsageIncreases mirrors the sandboxes_quota_ledger_lock trigger: moving a Sandbox from one state pair to another adds to counted quota usage.

func SandboxQuota added in v0.6.0

func SandboxQuota(ctx context.Context, tx pgx.Tx, sandboxID string) error

SandboxQuota locks the quota ledgers for a Sandbox before locking the Sandbox itself.

func SandboxQuotas added in v0.6.0

func SandboxQuotas(ctx context.Context, tx pgx.Tx, sandboxIDs []string) error

SandboxQuotas resolves Sandbox ownership without row locks, then locks every quota-ledger pair before a caller acquires any durable domain-row lock.

func SandboxesInOrder added in v0.22.0

func SandboxesInOrder(ctx context.Context, tx pgx.Tx, sandboxIDs []string) error

SandboxesInOrder locks several Sandboxes in ascending identity order. A transaction that holds more than one Sandbox row lock takes them in this order, so two such transactions cannot wait on each other's Sandboxes whether or not they also hold the quota ledgers.

func TenantAndSubjectQuota added in v0.6.0

func TenantAndSubjectQuota(
	ctx context.Context,
	tx pgx.Tx,
	tenantRef string,
	subjectRef string,
) error

TenantAndSubjectQuota establishes the global PostgreSQL mutation lock order: tenant quota ledger, subject quota ledger, then domain rows such as Subject, ApplicationAuthority, Sandbox, Workspace, Snapshot, PortSession, or data-plane session. Trigger-backed quota accounting depends on every writer that holds the ledgers taking them before any domain row. Sandbox transitions that cannot increase quota usage skip them through SandboxWorkspaceForTransition.

func TenantQuota added in v0.6.0

func TenantQuota(ctx context.Context, tx pgx.Tx, tenantRef string) error

TenantQuota locks the tenant-level quota ledger before any domain row.

Types

type QuotaScope added in v0.6.0

type QuotaScope struct {
	TenantRef  string
	SubjectRef string
}

QuotaScope identifies one tenant and Subject quota-ledger pair.

type QuotaTransition added in v0.22.0

type QuotaTransition func(state, desiredState string) bool

QuotaTransition reports, for a Sandbox's current state and desired state, whether the caller's transition increases the quota usage admission counts.

type SandboxWorkspace

type SandboxWorkspace struct {
	Resources         contracts.SandboxResources
	SandboxID         string
	TenantRef         string
	SubjectRef        string
	WorkspaceID       string
	ProfileRevisionID string
	EgressContext     *string
	SandboxState      string
	DesiredState      string
	Generation        int64
	Revision          int64
	CurrentInstanceID string
	ReconcileOwner    string
	Workspace         ports.HomeWorkspace
}

SandboxWorkspace is the durable authority protected by the first two locks.

func SandboxWorkspaceByID

func SandboxWorkspaceByID(
	ctx context.Context,
	tx pgx.Tx,
	sandboxID string,
) (SandboxWorkspace, error)

SandboxWorkspaceByID locks one internally identified Sandbox followed by its Workspace.

func SandboxWorkspaceForSubject

func SandboxWorkspaceForSubject(
	ctx context.Context,
	tx pgx.Tx,
	tenantRef string,
	subjectRef string,
	sandboxID string,
) (SandboxWorkspace, error)

SandboxWorkspaceForSubject locks one tenant-scoped Sandbox followed by its Workspace.

func SandboxWorkspaceForTransition added in v0.22.0

func SandboxWorkspaceForTransition(
	ctx context.Context,
	tx pgx.Tx,
	sandboxID string,
	increases QuotaTransition,
) (SandboxWorkspace, error)

SandboxWorkspaceForTransition locks one Sandbox and its Workspace for a transition, taking the quota ledgers first only when that transition can increase quota usage. Admission counts usage under the ledgers, so only an increase has to serialize with it; any other transition can at worst make a concurrent admission count conservatively.

The ledger decision reads the Sandbox without a lock and is confirmed once the row is locked. A Sandbox locked without its ledgers is recorded for the rest of the transaction, and the quota ledger trigger rejects any later write that increases its usage, because taking the ledgers after the Sandbox row would invert the lock order.

type Snapshot

type Snapshot struct {
	ID           string
	SandboxID    string
	WorkspaceID  string
	HomeRunnerID string
	State        string
}

Snapshot identifies the third row in the invariant lock order.

func SnapshotByID

func SnapshotByID(
	ctx context.Context,
	tx pgx.Tx,
	locked SandboxWorkspace,
	snapshotID string,
) (Snapshot, error)

SnapshotByID locks a Snapshot only after the caller holds its Sandbox and Workspace.

func SnapshotForSubject

func SnapshotForSubject(
	ctx context.Context,
	tx pgx.Tx,
	tenantRef string,
	subjectRef string,
	locked SandboxWorkspace,
	snapshotID string,
) (Snapshot, error)

SnapshotForSubject locks a Snapshot only after the caller holds its Sandbox and Workspace through SandboxWorkspaceForSubject or SandboxWorkspaceByID.

Jump to

Keyboard shortcuts

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