Help us shape the future of Go! Take the 2026 Go Developer Survey

mirror

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package mirror is a blob store that keeps each blob on several member stores at once (decision 0028): different clouds, regions or accounts, any mix of the fs, s3, gcs and azure backends.

Writes go to Redundancy members in parallel and succeed once WriteQuorum of them hold the blob; members still committing get MemberTimeout to finish in the background, and every member's outcome is recorded in the replica index (store.ReplicaIndex) as present or pending, so the repair worker can fill missing copies later. Reads use the index to go straight to a member holding the blob, in read order: this instance's zone first, then by observed latency, members whose breaker is open last. A read that fails part-way reopens on the next holder at the same offset, which is safe because blobs are immutable.

This is Artifactory's sharding provider (redundancy, lenientLimit, zone-aware reads) with three differences: members may be any backend in any cloud, an index records which members hold which blob instead of every read probing every shard, and surplus copies are never deleted automatically.

Index

Constants

View Source
const (
	// DefaultMemberTimeout is how long members still committing after the
	// quorum may finish before their copy is left to the repair worker.
	DefaultMemberTimeout = 30 * time.Second
	// DefaultChunkSize is the smallest chunk New derives. A chunk is the
	// buffer one upload hands to every member at once, so a mirrored upload
	// holds one chunk in memory, not one per member.
	DefaultChunkSize = 8 << 20
	// MaxDerivedChunkSize caps the chunk New derives from the members' part
	// sizes. Part sizes whose least common multiple is larger (5, 7 and 11
	// MiB need 385 MiB) would cost that much memory per upload, and are
	// almost certainly a mistake.
	MaxDerivedChunkSize = 256 << 20
	// DefaultBreakerThreshold is the consecutive failures that open a
	// member's breaker.
	DefaultBreakerThreshold = 5
	// DefaultBreakerCooldown is how long an open breaker stays open before a
	// call is let through again; Artifactory's state-aware providers re-check
	// a failed store after the same 15 seconds (checkPeriod).
	DefaultBreakerCooldown = 15 * time.Second
	// DefaultRepairBatch is how many replicas one repair pass works on per
	// step, so a pass holds its lease for a bounded time.
	DefaultRepairBatch = 100
	// DefaultRepairMaxAttempts is how many failed copies make a pending
	// replica failed, for an operator to look at.
	DefaultRepairMaxAttempts = 10
	// DefaultRepairBackoff is the wait after a replica's first failed
	// attempt; it doubles with every attempt up to maxRepairBackoff, so a
	// copy that keeps failing is not retried in a tight loop.
	DefaultRepairBackoff = time.Minute
)

Defaults for the zero Options fields.

View Source
const DefaultRepairInterval = time.Minute

DefaultRepairInterval is how often RunRepair runs a pass when no interval is given.

Variables

View Source
var (
	// ErrConfig reports an unusable configuration.
	ErrConfig = errors.New("blob/mirror: invalid configuration")
	// ErrQuorum reports a write that fewer than WriteQuorum members accepted.
	ErrQuorum = errors.New("blob/mirror: write quorum not met")
)

Sentinel errors. Test with errors.Is.

View Source
var ErrSeek = errors.New("blob/mirror: invalid seek")

ErrSeek reports an invalid Seek.

Functions

This section is empty.

Types

type Member

type Member struct {
	// Name identifies the member in the replica index; it must stay stable.
	Name string
	// Zone places the member, for example "aws-eu-west-1"; members in the
	// instance's zone are read and written first.
	Zone string
	// Store is the member's blob store.
	Store blob.Store
	// WriteEnabled lets the member receive new copies. A member with it
	// false is drained: it serves reads but gets nothing new.
	WriteEnabled bool
	// Kind names the member's backend (fs, s3, gcs, azure) for Status; the
	// mirror itself does not use it.
	Kind string
}

Member is one store of the mirror.

type MemberStatus

type MemberStatus struct {
	Name, Zone, Kind string
	WriteEnabled     bool
	// Available is false while the member's breaker is open: reads and
	// writes go to the other members first.
	Available bool
	// Latency is the weighted average of recent successful calls; zero
	// before the first one.
	Latency time.Duration
	// Replicas are the member's replica records per state, ordered by state.
	Replicas []store.ReplicaCount
	// SoleCopies counts the blobs whose only present copy is on this
	// member. A drained member (WriteEnabled false) is safe to remove from
	// the configuration once it is zero.
	SoleCopies int64
}

MemberStatus is one member's view in Status.

type Options

type Options struct {
	Members []Member
	// Redundancy is how many members keep each blob; zero means every
	// member (a full mirror).
	Redundancy int
	// WriteQuorum is how many members must store a blob before an upload
	// succeeds. Zero means Redundancy-1 (at least 1): by default an upload
	// still succeeds with one member down, which is the outage the mirror
	// exists to ride out, and the missing copy is repaired later.
	WriteQuorum int
	// Zone is this instance's zone.
	Zone string
	// MemberTimeout bounds how long members may finish after the quorum;
	// zero means DefaultMemberTimeout.
	MemberTimeout time.Duration
	// ChunkSize is the fan-out buffer. Zero derives it: the smallest
	// multiple of every member's part size (blob.PartSizer) that is at least
	// DefaultChunkSize, so the s3 and azure defaults (8 MiB) with the gcs
	// default (16 MiB) give 16 MiB. An explicit size must be a multiple of
	// every member's part size.
	ChunkSize int64
	// Sessions keeps the mirror's own upload sessions (the member upload
	// IDs). Members keep their own sessions.
	Sessions session.Store
	// Replicas records which members hold which blobs.
	Replicas store.ReplicaIndex
	// BreakerThreshold and BreakerCooldown tune each member's breaker; zero
	// means the defaults.
	BreakerThreshold int
	BreakerCooldown  time.Duration
	// Now supplies the time for the breaker, latency and replica records;
	// nil means time.Now.
	Now func() time.Time

	// The repair worker's settings (repair.go). Blobs and Leases are only
	// required by Repair: a mirror that never repairs may leave them nil.
	//
	// Blobs is the blob index whose reference counts tell a deferred delete
	// whether the blob was uploaded again since.
	Blobs store.BlobIndex
	// Leases holds the lease that keeps two repair passes from overlapping.
	Leases store.LeaseStore
	// RepairLease names the lease a pass holds; empty means
	// "blob-mirror-repair". Two mirrors sharing a lease store (the hot and
	// cold tiers) need different names, or each pass of one skips the other.
	RepairLease string
	// RepairBatch, RepairMaxAttempts and RepairBackoff tune a pass; zero
	// means the defaults.
	RepairBatch       int
	RepairMaxAttempts int
	RepairBackoff     time.Duration
	// OnRepair, when set, receives every pass RunRepair makes, so the server
	// can log or count them.
	OnRepair func(RepairReport, error)
}

Options configures New.

type RemovedMember

type RemovedMember struct {
	Name string
	// Replicas are its replica records per state, ordered by state.
	Replicas []store.ReplicaCount
	// SoleCopies counts the blobs whose only present copy is on it.
	SoleCopies int64
}

RemovedMember is a member in Status.Removed.

type RepairReport

type RepairReport struct {
	// Skipped is set when another pass held the lease; nothing was done.
	Skipped bool
	// Copied counts pending replicas filled by copying from another member.
	Copied int
	// Found counts pending replicas whose member already held the blob, for
	// example a commit that finished after its record was written.
	Found int
	// Failed counts attempts that failed this pass.
	Failed int
	// Deleted counts tombstones whose copy was removed.
	Deleted int
	// DeletesSkipped counts tombstones of blobs uploaded again since the
	// delete, which were kept rather than removed.
	DeletesSkipped int
	// Backfilled counts pending records added to bring a blob up to the
	// redundancy, for example on a newly added member.
	Backfilled int
	// Drained counts pending records added because a blob's only copies are
	// on members no longer accepting writes.
	Drained int
}

RepairReport counts what one repair pass did.

type Status

type Status struct {
	Redundancy  int
	WriteQuorum int
	// Zone is this instance's zone.
	Zone string
	// UnderReplicated counts blobs with fewer present copies than
	// Redundancy (store.ReplicaIndex.UnderReplicated).
	UnderReplicated int64
	Members         []MemberStatus
	// Removed are members with replica records that are no longer
	// configured. Repair neither copies to nor reads from them, so a blob
	// whose only present copy is on one (SoleCopies) is out of the mirror's
	// reach until the member is configured again.
	Removed []RemovedMember
}

Status is a mirror's configuration, member health and replica counts, for the storage summary (#18). Artifactory's summary has nothing per shard.

type Store

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

Store is a blob.Store over several member stores.

func New

func New(o Options) (*Store, error)

New returns a mirror over o.Members.

func (*Store) BeginUpload

func (s *Store) BeginUpload(ctx context.Context, opts ...blob.UploadOption) (blob.Upload, error)

BeginUpload starts a session on the members placement chooses.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, sha string) error

Delete removes the blob from every member. A member that cannot be reached keeps a deleting record, a tombstone the repair worker acts on later; reads honour it, so the blob is gone for every reader as soon as Delete returns.

func (*Store) Exists

func (s *Store) Exists(ctx context.Context, sha string) (bool, error)

Exists reports whether any member holds the blob.

func (*Store) Open

func (s *Store) Open(ctx context.Context, sha string) (io.ReadSeekCloser, blob.Info, error)

Open returns a reader that serves the blob from the first member that holds it and moves to the next one, at the same offset, if a read fails.

func (*Store) Repair

func (s *Store) Repair(ctx context.Context) (RepairReport, error)

Repair runs one repair pass under the repair lease:

  1. pending replicas are copied to their member from a member that holds the blob, or marked present when the member already has it;
  2. deleting tombstones are carried out, unless the blob was uploaded again since the delete;
  3. blobs with fewer copies on write-enabled members than the redundancy get pending records, which fills a newly added member and moves the copies of a draining one.

Each step works on at most the repair batch, so a pass is bounded. It never deletes a copy because there are too many: removing a member stays an explicit operator action (decision 0028). When another pass holds the lease it returns a report with Skipped set and no error.

func (*Store) ResumeUpload

func (s *Store) ResumeUpload(ctx context.Context, id string) (blob.Upload, error)

ResumeUpload reopens a session and each active member's upload. A member whose upload cannot be resumed drops out of the session.

func (*Store) RunRepair

func (s *Store) RunRepair(ctx context.Context, every time.Duration, trigger <-chan struct{}) error

RunRepair runs a repair pass every interval, and at once whenever trigger fires (the storage optimize endpoint sends on it), until ctx ends, then returns ctx's error. Each pass's report and error go to OnRepair when it is set; a failed pass does not stop the loop.

func (*Store) SignURL

func (s *Store) SignURL(ctx context.Context, sha string, o blob.SignOptions) (string, error)

SignURL returns a URL from the first member, in read order, that holds the blob and signs o's route. A member's signing failure moves on to the next member but never counts against its health.

func (*Store) Signs

func (s *Store) Signs(via blob.Via) bool

Signs reports whether any member signs URLs for via. Members are fixed when the mirror is built, so the answer is too.

func (*Store) Stat

func (s *Store) Stat(ctx context.Context, sha string) (blob.Info, error)

Stat returns the blob's Info from the first member that holds it.

func (*Store) Status

func (s *Store) Status(ctx context.Context) (Status, error)

Status reports the mirror's members, their replica records, and the records of members no longer configured.

func (*Store) WaitIdle

func (s *Store) WaitIdle(ctx context.Context) error

WaitIdle waits until the background commits running when it is called have finished and recorded their outcome, or ctx ends. A server calls it on shutdown so a member finishing after the quorum is recorded rather than left pending for no reason; a test calls it before looking at the members.

func (*Store) Walk

func (s *Store) Walk(ctx context.Context, fn func(blob.Info) error) error

Walk visits every blob any member holds, once, and stops at the first error fn or a member returns. A member that cannot be listed fails the walk rather than shortening it, because garbage collection must never act on a partial listing.

Jump to

Keyboard shortcuts

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