hold

package
v0.12.1 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package hold is the platform-wide hold (ADR-0206 Decision 6): <storage.dataDir>/.hold exists iff the platform is held, every side-effect runner asks the Gate before it acts, and only the release deletes the marker. A restore in progress leaves restore.inprogress, which refuses a start until the operator empties what it wrote (Decision 2).

Index

Constants

View Source
const MarkerFile, BusyFile, ReleasedFile = ".hold", "restore.inprogress", ".hold-released"

The files the hold keeps in the data directory; BusyFile marks a restore in progress (Decision 2).

View Source
const NamespaceDir, NamespaceReleasedDir = ".hold-ns", ".hold-ns-released"

The per-namespace hold (ADR-0222 Decision 8): <dataDir>/.hold-ns/<ns>.<reason> holds a Marker, and a release writes its time to <dataDir>/.hold-ns-released/<ns> before it deletes the marker.

View Source
const ReasonRestore, ReasonData = "restore", "data"

The reasons a namespace is held for: an in-place Restore loading it, or a platform restore that returned its BackupSchedules without their data. HeldIn reads only these.

View Source
const ReportFile = "restore.json"

ReportFile is restore.json, the report restore run writes beside the marker (Decision 2 step 5).

Variables

This section is empty.

Functions

func Begin

func Begin(dataDir, command string) error

Begin writes BusyFile naming command (run, kv, blob); a BusyFile naming another command is fault.Conflict. One naming the same command is a rerun after a kill, whose directories the command itself found empty.

func End

func End(dataDir string) error

End removes BusyFile: the restore finished.

func MarkNamespaces

func MarkNamespaces(dataDir string, nss []v1.NamespaceName, m Marker) error

MarkNamespaces writes m's marker for each of nss, offline: restore run holds the namespaces whose BackupSchedules return without their data.

func Own

func Own(ref string, roots ...string) error

Own gives each root that exists, and everything below it, ref's owner and group where they differ (os.Lchown), so a restore run as root leaves what funcd, running as the data directory's owner, can open (ADR-0026 §4).

func Write

func Write(dataDir string, m Marker) error

Write writes the marker: the platform is held from the next start until a release.

func WriteFile

func WriteFile(op, dir, name string, data []byte) error

WriteFile replaces dir/name with data, mode 0600: a temporary file synced and renamed, then the directory synced, so a crash leaves the old file or the new one. op names the caller in the error; ADR-0207's safemode.json uses it.

func WriteReport

func WriteReport(dataDir string, report json.RawMessage) error

WriteReport writes ReportFile, mode 0600, synced as Write is.

Types

type Created added in v0.12.0

type Created []string

Created is the topmost directories a restore created on the way to the directories it writes: the restore gives them the data directory's owner with the rest (Own), or removes them when it fails (ADR-0206 Decision 2).

func (Created) Remove added in v0.12.0

func (c Created) Remove() error

Remove removes the recorded directories and all below them, the last recorded first.

func (*Created) Track added in v0.12.0

func (c *Created) Track(dir string)

Track records the topmost directory on dir's path that does not exist yet, the first one os.MkdirAll(dir) creates; nothing when dir exists.

type Evidence

type Evidence struct {
	Held              bool                      `json:"held"`
	Marker            *Marker                   `json:"marker,omitempty"`
	ReleasedAt        *v1.Timestamp             `json:"releasedAt,omitempty"`
	Report            json.RawMessage           `json:"report,omitempty"`
	Counts            map[v1.Kind]int           `json:"counts,omitempty"`
	PausedRuns        []string                  `json:"pausedRuns,omitempty"`
	DeadLetters       []string                  `json:"deadLetters,omitempty"`
	Pending           map[string]map[string]int `json:"pending,omitempty"`
	Orphans           []string                  `json:"orphans,omitempty"`
	BucketOrphans     []string                  `json:"bucketOrphans,omitempty"`
	FunctionsNotReady []string                  `json:"functionsNotReady,omitempty"`
	Namespaces        []NamespaceHold           `json:"namespaces,omitempty"`
}

Evidence is what the hold shows the operator (Decisions 1, 8): GET …/hold returns it, `funcdctl hold status` prints it. Report is restore.json as written; runs and dead letters are <ns>/<name> and <ns>/<id>; Pending is, per <ns>/<source>, the blob keys per event a release replays; Orphans and BucketOrphans are data no object names, which the reclaims would drop; FunctionsNotReady are <ns>/<name>; Namespaces are the per-namespace markers.

type Gate

type Gate interface {
	Held() bool
	ReleasedAt() time.Time
}

Gate is what a runner asks: Held, and the time of the last release (zero when none).

var Never Gate = never{}

Never is the gate of a platform without a hold: never held, never released.

type Hold

type Hold struct {
	// contains filtered or unexported fields
}

Hold is the opened hold of one data directory, a Gate whose release is live.

func Open

func Open(dataDir string) (*Hold, error)

Open reads the hold of dataDir: BusyFile ⇒ fault.Conflict naming the interrupted restore; no marker ⇒ not held; a file that does not read or decode ⇒ fault.Internal.

func (*Hold) Held

func (h *Hold) Held() bool

Held reports whether the marker exists.

func (*Hold) HeldIn

func (h *Hold) HeldIn(ns v1.NamespaceName) bool

HeldIn reports whether the platform is held or ns holds a restore or data marker.

func (*Hold) HoldNamespace

func (h *Hold) HoldNamespace(ns v1.NamespaceName, m Marker) error

HoldNamespace writes ns's marker for m.Reason and holds ns live. It never replaces a marker: ns already held for m.Reason ⇒ fault.Conflict naming the Restore of the marker that stands.

func (*Hold) Marker

func (h *Hold) Marker() (Marker, bool)

Marker returns the marker while held.

func (*Hold) NamespaceMarkers

func (h *Hold) NamespaceMarkers() map[v1.NamespaceName]map[string]Marker

NamespaceMarkers is a copy of each held namespace's markers by reason.

func (*Hold) Release

func (h *Hold) Release(now time.Time) error

Release lifts the hold (Decision 8): it writes now to ReleasedFile, deletes the marker, syncs the directory, then lifts the gate. Not held ⇒ fault.Conflict.

func (*Hold) ReleaseNamespace

func (h *Hold) ReleaseNamespace(ns v1.NamespaceName, reason string) error

ReleaseNamespace lifts ns's reason, as Release lifts the platform: it writes now to .hold-ns-released/<ns>, deletes the marker, syncs the directory, then lifts the gate. No such marker ⇒ fault.Conflict.

func (*Hold) ReleaseNamespaceMarker

func (h *Hold) ReleaseNamespaceMarker(ns v1.NamespaceName, m Marker) error

ReleaseNamespaceMarker lifts ns's m.Reason as ReleaseNamespace does, only while that marker is still m: one another Restore wrote since ⇒ fault.Conflict.

func (*Hold) ReleasedAt

func (h *Hold) ReleasedAt() time.Time

ReleasedAt is the time the last release wrote to ReleasedFile, zero when none did.

func (*Hold) ReleasedAtIn

func (h *Hold) ReleasedAtIn(ns v1.NamespaceName) time.Time

ReleasedAtIn is the later of ReleasedAt and ns's last release, zero when neither happened.

func (*Hold) Report

func (h *Hold) Report() (json.RawMessage, error)

Report reads ReportFile, nil when absent.

type Marker

type Marker struct {
	Reason  string        `json:"reason"`
	Since   v1.Timestamp  `json:"since"`
	Restore v1.ObjectName `json:"restore,omitempty"`
}

Marker is the content of MarkerFile; Reason is "restore" or "safe-mode" (ADR-0207). A namespace's restore marker also names the in-place Restore that wrote it (ADR-0222 Decision 8).

type NamespaceGate

type NamespaceGate interface {
	HeldIn(ns v1.NamespaceName) bool
	ReleasedAtIn(ns v1.NamespaceName) time.Time
}

NamespaceGate is what a per-namespace runner asks: HeldIn is true while the platform or ns is held; ReleasedAtIn is the later of the platform's release and ns's.

var NeverNamespace NamespaceGate = never{}

NeverNamespace is the namespace gate of a platform without a hold.

type NamespaceHold

type NamespaceHold struct {
	Namespace v1.NamespaceName `json:"namespace"`
	Marker
	Phase v1.RunPhase `json:"phase,omitempty"`
}

NamespaceHold is one per-namespace marker (ADR-0222 Decision 8); Phase is the phase of the in-place Restore a restore marker names, empty once that Restore is deleted.

Jump to

Keyboard shortcuts

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