Documentation
¶
Index ¶
- Constants
- Variables
- func IsValidStore(storeType string) bool
- type Blob
- type CommandResult
- type FileMetadata
- type LocalFileBlob
- type NscStore
- func (n *NscStore) Download(ctx context.Context, key, filePath string) (*TransferInfo, error)
- func (n *NscStore) RefreshRetention(ctx context.Context, key string, retention time.Duration)
- func (n *NscStore) Upload(ctx context.Context, filePath, key string, retention time.Duration) (*TransferInfo, error)
- type Options
- type RetentionRefresher
- type S3Blob
- type TransferInfo
Constants ¶
const ( // local file store type LocalFileStore = "local_file" // agent-managed store type (cache v2): the agent manages the blob store // itself via BUILDKITE_AGENT_CACHE_STORE_URL AgentManaged = "agent_managed" )
Variables ¶
var ErrBlobNotFound = errors.New("blob not found")
ErrBlobNotFound is returned by a Blob's Download when the requested object does not exist in the backing store.
Functions ¶
func IsValidStore ¶
Types ¶
type Blob ¶
type Blob interface {
// Upload uploads a file to blob storage. retention is how long the blob
// should be kept.
Upload(ctx context.Context, filePath, key string, retention time.Duration) (*TransferInfo, error)
// Download downloads a file from blob storage
Download(ctx context.Context, key, destPath string) (*TransferInfo, error)
}
Blob interface defines the operations for blob storage
type CommandResult ¶
type FileMetadata ¶
type FileMetadata struct {
Key string `json:"key"` // Original cache key
Size int64 `json:"size"` // File size in bytes
ModTime string `json:"mod_time"` // Original modification time (RFC3339Nano)
Mode string `json:"mode"` // Original file permissions (octal)
SHA256 string `json:"sha256,omitempty"` // SHA256 checksum for integrity verification
CreatedAt string `json:"created_at"` // Timestamp when cached (RFC3339Nano)
Version int `json:"version"` // Metadata schema version
}
FileMetadata contains metadata for cached files. Persisted as compact JSON in a sidecar file alongside each data file.
type LocalFileBlob ¶
type LocalFileBlob struct {
// contains filtered or unexported fields
}
LocalFileBlob implements the Blob interface for local filesystem storage. Cache artifacts are stored as files with accompanying JSON metadata sidecars. Cache keys map directly to file paths under the configured root directory.
Storage layout:
- Data files: <root>/<key>
- Metadata files: <root>/<key>.attrs.json
Features:
- Atomic writes using temp files + rename
- Path traversal protection via multi-layer validation
- SHA256 integrity checksums computed during upload
- Last-writer-wins semantics for concurrent updates
func NewLocalFileBlob ¶
func NewLocalFileBlob(ctx context.Context, fileURL string) (*LocalFileBlob, error)
NewLocalFileBlob creates a new local file storage backend from a file:// URL.
Supported URL formats:
- file:///absolute/path/to/cache
- file://~/cache (expands to user's home directory)
- file://~/.buildkitecache
The root directory will be created if it doesn't exist.
Returns an error if:
- URL scheme is not "file"
- Path is empty or invalid (e.g., "/", ".")
- Directory creation fails
func (*LocalFileBlob) Download ¶
func (b *LocalFileBlob) Download(ctx context.Context, key, destPath string) (*TransferInfo, error)
Download retrieves a cached file identified by key and writes it to destPath.
The download process:
- Validates the cache key and destination path
- Reads the cached data file from storage
- Writes atomically to destination using temp file + fsync + rename
- Restores original file metadata (mtime) from sidecar if available (best-effort)
- Syncs parent directory for durability (best-effort)
Metadata restoration is best-effort; failures are logged but don't fail the download. Atomic writes ensure partial files are never visible at the destination path.
Returns TransferInfo with bytes transferred, transfer speed, and duration. Returns an error if the cache key doesn't exist or file operations fail.
func (*LocalFileBlob) Upload ¶
func (b *LocalFileBlob) Upload(ctx context.Context, srcPath, key string, _ time.Duration) (*TransferInfo, error)
Upload copies a file from srcPath to the cache storage identified by key.
The upload process:
- Validates the source path and cache key
- Computes SHA256 hash during copy for integrity verification
- Writes data atomically using temp file + fsync + rename
- Writes metadata (size, permissions, checksum, timestamps) atomically to sidecar file
- Syncs parent directory for durability (best-effort)
Atomic writes ensure readers never see partial data. On Windows, existing files are removed before rename due to platform limitations, creating last-writer-wins semantics for concurrent uploads to the same key.
Returns TransferInfo with bytes transferred, transfer speed, and duration.
type NscStore ¶
type NscStore struct {
// contains filtered or unexported fields
}
NscStore implements the Blob interface for NSC artifact storage which uses the nsc CLI tool https://namespace.so/docs/reference/cli/artifact-download https://namespace.so/docs/reference/cli/artifact-upload
func NewNscStore ¶
NewNscStore creates a store backed by the nsc CLI. The namespace is parsed from the nsc://<namespace> cache store URL and is required.
func (*NscStore) RefreshRetention ¶ added in v4.0.2
RefreshRetention pushes the artifact's expiry out to at least retention from now (falling back to nscDefaultRetention when unset) via `nsc artifact extend --ensure_minimum`. Using --ensure_minimum makes the refresh idempotent, so calling it on every restore keeps a hot cache alive without growing its expiry unbounded.
This is best-effort: any failure is logged and swallowed so a restore never fails because its TTL could not be refreshed. Whether to call this at all (e.g. skipping it on a fallback match) is the restore flow's decision, not this store's — see store.RetentionRefresher.
type Options ¶
type Options struct {
S3Endpoint string
Bucket string
Region string
Prefix string
UsePathStyle bool
Concurrency int
PartSizeMB int
}
Options holds configuration for S3Blob and can be constructed from an S3 URL in a similar way to gocloud.dev Example S3 URLs:
s3://my-bucket s3://my-bucket/prefix s3://my-bucket?region=us-east-1 s3://my-bucket/prefix?region=us-east-1&endpoint=http://localhost:9000&use_path_style=true
func OptionsFromURL ¶
type RetentionRefresher ¶ added in v4.0.2
type RetentionRefresher interface {
RefreshRetention(ctx context.Context, key string, retention time.Duration)
}
RetentionRefresher is implemented by Blob stores that support extending a blob's effective retention/TTL on access (NscStore, S3Blob). Optional because not every store has a retention concept to refresh (LocalFileBlob does not implement it).
type S3Blob ¶
type S3Blob struct {
// contains filtered or unexported fields
}
S3Blob implements the Blob interface using AWS S3
func (*S3Blob) Download ¶
Download downloads a file from S3 using parallel range requests for large files
func (*S3Blob) RefreshRetention ¶ added in v4.0.2
RefreshRetention extends an object's effective TTL by performing CopyObject on itself to refresh its LastModified timestamp — S3 has no native touch/extend-TTL API, and lifecycle expiration rules key off LastModified.
Whether to call this at all (e.g. skipping it on a fallback match) is the restore flow's decision, not this store's — see store.RetentionRefresher.
The CopySourceIfUnmodifiedSince precondition aborts the operation with an HTTP status code 412 if the object's LastModified timestamp falls within restoreRefreshMinInterval.
This refresh is best-effort only: any failure (incl. objects exceeding S3's 5GB CopyObject limit) must not cause the overall restore operation to fail.
retention is ignored: the self-copy only refreshes LastModified, and the effective lifetime is whatever window the bucket's lifecycle policy applies from that timestamp — the agent cannot lengthen it per object.
func (*S3Blob) Upload ¶
func (b *S3Blob) Upload(ctx context.Context, filePath, key string, _ time.Duration) (*TransferInfo, error)
Upload uploads a file to S3 using multipart upload for parallel transfers. retention is ignored: S3 object lifetime is governed by the bucket's lifecycle policy, which the agent does not set per object.