remoteblob

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package remoteblob implements the casstore blobstore.Storage interface for an mlfs node's direct-S3 data plane (ADR-001 §2.2, §5).

A node never holds tenant S3 credentials. Instead it asks blobgw for a short-lived presigned URL (via remotepresign.Client over NATS) and then transfers bytes directly against S3 over plain HTTP (via s3http.Client). BlobStore wires those two primitives behind the kopia blob.Storage contract so the existing casstore chunk path can write/read packs without change.

Scope: what this adapter does NOT do

The node data plane only ever calls PutBlob (whole pack) and GetBlob (whole pack today; ranged reads are wired through for #18). Listing, metadata and deletion are garbage-collection concerns, and GC runs on blobgw — it owns the per-tenant credentials and the authoritative index. Therefore GetMetadata, ListBlobs and DeleteBlob return ErrNotSupported rather than guessing at an implementation the node has no business performing.

Blob-ID → S3-object-key mapping

casstore blob IDs use the convention "pack-<domain>-<hash>" / "chunk-<domain>-<hash>" (see casstore/blobstore.ID). Those strings are already valid, stable, printable-ASCII S3 object keys with no leading slash, so the default keyFn maps the ID verbatim: key == string(id). Both the node and blobgw must agree on the object key for a given blob; mapping the ID verbatim keeps that agreement trivial and avoids re-deriving structure on two sides. Callers that need a different layout (e.g. a "blobs/" prefix) supply WithKeyFunc.

Idempotent PutBlob

Blob IDs are content hashes, so an unconditional presigned PUT is byte- idempotent: re-putting the same ID re-uploads identical bytes. We therefore IGNORE PutOptions.DoNotRecreate and never return ErrBlobAlreadyExists — the CAS contract is satisfied by the content-addressing itself.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotSupported = errors.New("remoteblob: not supported on node: GC and listing are blobgw-owned")

ErrNotSupported is returned by GetMetadata, ListBlobs and DeleteBlob. Those operations are owned by blobgw (it holds the credentials and the index and runs GC); the node's direct-S3 data plane intentionally does not implement them. errors.Is friendly.

Functions

This section is empty.

Types

type BlobStore

type BlobStore struct {
	kblob.DefaultProviderImplementation
	// contains filtered or unexported fields
}

BlobStore implements casstore blobstore.Storage over presigned-URL direct-S3 transfers. It embeds kblob.DefaultProviderImplementation to inherit the no-op Close/FlushCaches/GetCapacity/ExtendBlobRetention/IsReadOnly methods. It is safe for concurrent use (its dependencies are).

func NewBlobStore

func NewBlobStore(presign *remotepresign.Client, http *s3http.Client, tenant string, opts ...Option) *BlobStore

NewBlobStore constructs a BlobStore. presign and http must not be nil; tenant is the domain whose bucket the node transfers against (it is forwarded to remotepresign for subject-tenant validation).

func (*BlobStore) ConnectionInfo

func (b *BlobStore) ConnectionInfo() kblob.ConnectionInfo

ConnectionInfo returns a minimal description of this storage. The node data plane has no serializable credential config to expose (credentials live on blobgw), so only the Type is set.

func (*BlobStore) DeleteBlob

func (b *BlobStore) DeleteBlob(_ context.Context, _ blobstore.ID) error

DeleteBlob is not supported on the node. See ErrNotSupported and the package doc: metadata/listing/deletion are blobgw-owned GC concerns.

func (*BlobStore) DisplayName

func (b *BlobStore) DisplayName() string

DisplayName returns a human-readable identifier for this storage.

func (*BlobStore) GetBlob

func (b *BlobStore) GetBlob(ctx context.Context, id blobstore.ID, offset, length int64, output blobstore.OutputBuffer) error

GetBlob fetches full or partial blob contents into output.

Per the kopia Reader.GetBlob contract (repo/blob/storage.go): length<0 fetches the whole blob (the casstore case), length>0 fetches the range [offset, offset+length). A negative offset is invalid and returns blobstore.ErrInvalidRange. length==0 is also invalid (a zero-byte ranged read is undefined by the contract and would produce a degenerate HTTP Range header); it returns ErrInvalidRange without issuing any S3 request. The whole-blob path uses s3http.Get; the ranged path uses s3http.GetRange (wired through for #18 readahead).

func (*BlobStore) GetMetadata

func (b *BlobStore) GetMetadata(_ context.Context, _ blobstore.ID) (blobstore.Metadata, error)

GetMetadata is not supported on the node. See ErrNotSupported and the package doc: metadata/listing/deletion are blobgw-owned GC concerns.

func (*BlobStore) ListBlobs

func (b *BlobStore) ListBlobs(_ context.Context, _ blobstore.ID, _ func(blobstore.Metadata) error) error

ListBlobs is not supported on the node. See ErrNotSupported and the package doc: metadata/listing/deletion are blobgw-owned GC concerns.

func (*BlobStore) PutBlob

PutBlob uploads data to the blob's S3 object via a presigned PUT.

PutOptions.DoNotRecreate is ignored: blob IDs are content hashes so the PUT is byte-idempotent (see package doc). All other PutOptions are unused by the direct-S3 data plane.

type KeyFunc

type KeyFunc func(blobstore.ID) string

KeyFunc maps a blob ID to an S3 object key within the tenant bucket.

type Option

type Option func(*options)

Option is a functional option for NewBlobStore.

func WithKeyFunc

func WithKeyFunc(fn KeyFunc) Option

WithKeyFunc overrides the blob-ID → S3-object-key mapping. The default maps the ID verbatim (key == string(id)).

func WithPresignTTL

func WithPresignTTL(d time.Duration) Option

WithPresignTTL overrides the requested presigned-URL validity. The default is 15 minutes. blobgw may cap the effective TTL lower.

Jump to

Keyboard shortcuts

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