Documentation
¶
Overview ¶
Package trove provides a multi-backend object storage engine with bi-directional streaming, composable middleware, and first-class Forge transport integration.
Trove is to object/file storage what Grove is to databases — a polyglot, driver-based abstraction that generates native operations per storage backend while delivering a unified, composable API surface.
Quick Start ¶
drv := localdriver.New()
drv.Open(ctx, "file:///tmp/storage")
t, err := trove.Open(drv)
if err != nil {
log.Fatal(err)
}
defer t.Close(ctx)
// Upload an object.
err = t.Put(ctx, "my-bucket", "hello.txt", strings.NewReader("hello world"))
// Download an object.
reader, err := t.Get(ctx, "my-bucket", "hello.txt")
defer reader.Close()
Drivers ¶
Every storage backend registers as a driver — the same pattern Grove uses for pgdriver, mongodriver, etc. Available drivers:
- localdriver: Local filesystem storage
- memdriver: In-memory storage (testing)
- s3driver: AWS S3, MinIO, R2, DigitalOcean Spaces (Phase 3)
- gcsdriver: Google Cloud Storage (Phase 3)
- azuredriver: Azure Blob Storage (Phase 3)
Multi-Backend Routing ¶
Trove supports multiple named backends simultaneously:
t, err := trove.Open(primaryDriver,
trove.WithBackend("archive", archiveDriver),
trove.WithRoute("*.log", "archive"),
)
Index ¶
- Variables
- func Permanent(err error) bool
- type ChecksumAlgorithm
- type Config
- type Option
- func WithBackend(name string, drv driver.Driver) Option
- func WithCAS(alg cas.HashAlgorithm) Option
- func WithChecksumAlgorithm(alg ChecksumAlgorithm) Option
- func WithChunkSize(size int64) Option
- func WithDefaultBucket(name string) Option
- func WithMetrics(r observe.Recorder) Option
- func WithMiddleware(mws ...middleware.Middleware) Option
- func WithMiddlewareAt(priority int, mws ...middleware.Middleware) Option
- func WithPoolConfig(cfg stream.PoolConfig) Option
- func WithPoolSize(n int) Option
- func WithReadMiddleware(mws ...middleware.Middleware) Option
- func WithRetry(policy RetryPolicy) Option
- func WithRoute(pattern, backend string) Option
- func WithRouteFunc(fn func(bucket, key string) string) Option
- func WithScopedMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
- func WithScopedReadMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
- func WithScopedWriteMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
- func WithStreamBufferSize(size int) Option
- func WithVFS(bucket string) Option
- func WithWriteMiddleware(mws ...middleware.Middleware) Option
- type RetryPolicy
- type RetryStrategy
- type Trove
- func (t *Trove) Backend(name string) (*Trove, error)
- func (t *Trove) Backends() []string
- func (t *Trove) CAS() *cas.CAS
- func (t *Trove) Close(ctx context.Context) error
- func (t *Trove) Config() Config
- func (t *Trove) Copy(ctx context.Context, srcBucket, srcKey, dstBucket, dstKey string, ...) (info *driver.ObjectInfo, err error)
- func (t *Trove) CreateBucket(ctx context.Context, name string, opts ...driver.BucketOption) (err error)
- func (t *Trove) Delete(ctx context.Context, bucket, key string, opts ...driver.DeleteOption) (err error)
- func (t *Trove) DeleteBucket(ctx context.Context, name string) (err error)
- func (t *Trove) Driver() driver.Driver
- func (t *Trove) DriverFor(bucket, key string) driver.Driver
- func (t *Trove) Get(ctx context.Context, bucket, key string, opts ...driver.GetOption) (obj *driver.ObjectReader, err error)
- func (t *Trove) Head(ctx context.Context, bucket, key string) (info *driver.ObjectInfo, err error)
- func (t *Trove) Health(ctx context.Context) error
- func (t *Trove) List(ctx context.Context, bucket string, opts ...driver.ListOption) (it *driver.ObjectIterator, err error)
- func (t *Trove) ListBuckets(ctx context.Context) (buckets []driver.BucketInfo, err error)
- func (t *Trove) Pool() *stream.Pool
- func (t *Trove) Put(ctx context.Context, bucket, key string, r io.Reader, opts ...driver.PutOption) (info *driver.ObjectInfo, err error)
- func (t *Trove) RemoveMiddleware(name string, scope middleware.Scope)
- func (t *Trove) Resolver() *middleware.Resolver
- func (t *Trove) Stream(ctx context.Context, bucket, key string, dir stream.Direction, ...) (*stream.Stream, error)
- func (t *Trove) UseMiddleware(reg middleware.Registration)
- func (t *Trove) VFS(bucket ...string) *vfs.FS
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNotFound is returned when a requested resource cannot be found. // It is the parent of ErrBucketNotFound and ErrObjectNotFound. ErrNotFound = driver.ErrNotFound // ErrBucketNotFound is returned when a bucket cannot be found. ErrBucketNotFound = driver.ErrBucketNotFound // ErrBucketExists is returned when creating a bucket that already exists. ErrBucketExists = driver.ErrBucketExists // ErrObjectNotFound is returned when an object cannot be found. ErrObjectNotFound = driver.ErrObjectNotFound // ErrPermissionDenied is returned when the backend rejects the operation // as unauthorized. Retrying will not help until access is granted. ErrPermissionDenied = driver.ErrPermissionDenied // ErrQuotaExceeded is returned when a storage quota or rate limit is // exceeded. Retrying later may succeed. ErrQuotaExceeded = driver.ErrQuotaExceeded // ErrInvalidPath is returned when a bucket name or object key is not // addressable — empty, containing a NUL byte, rooted, or resolving outside // the container it was addressed to. It does not unwrap to ErrNotFound: // nothing was looked up, so the request is malformed rather than the // resource missing, and an HTTP caller should answer 400 rather than 404. ErrInvalidPath = driver.ErrInvalidPath )
Errors that drivers classify. These are aliases of the sentinels defined in the driver package — the canonical values live there so that drivers in their own modules can wrap them without importing this package. Because errors.Is compares by identity, trove.ErrObjectNotFound and driver.ErrObjectNotFound match each other.
ErrObjectNotFound and ErrBucketNotFound unwrap to ErrNotFound, so a caller that only needs to know "this is permanently missing" can match ErrNotFound and catch both.
var ( // ErrKeyEmpty is returned when an object key is empty. ErrKeyEmpty = errors.New("trove: key is required") // ErrBucketEmpty is returned when a bucket name is empty. ErrBucketEmpty = errors.New("trove: bucket name is required") // ErrDriverClosed is returned when an operation is attempted on a closed driver. ErrDriverClosed = errors.New("trove: driver is closed") // ErrNilDriver is returned when Open is called with a nil driver. ErrNilDriver = errors.New("trove: driver is required") // ErrInvalidDSN is returned when a DSN string cannot be parsed. ErrInvalidDSN = errors.New("trove: invalid DSN") // ErrChecksumMismatch is returned when a checksum verification fails. ErrChecksumMismatch = errors.New("trove: checksum mismatch") // ErrContentBlocked is returned when content is rejected by scanning middleware. ErrContentBlocked = errors.New("trove: content blocked") // ErrStreamClosed is returned when writing to a closed stream. ErrStreamClosed = errors.New("trove: stream is closed") // ErrUploadExpired is returned when a resumable upload session has expired. ErrUploadExpired = errors.New("trove: upload session expired") // ErrBackendNotFound is returned when a named backend cannot be found. ErrBackendNotFound = errors.New("trove: backend not found") // ErrPoolClosed is returned when an operation targets a closed stream pool. ErrPoolClosed = errors.New("trove: stream pool is closed") // ErrStreamNotActive is returned when an operation requires an active stream. ErrStreamNotActive = errors.New("trove: stream is not active") // ErrMaxStreamsReached is returned when the pool's concurrency limit is hit. ErrMaxStreamsReached = errors.New("trove: maximum concurrent streams reached") )
Sentinel errors returned by Trove operations.
Functions ¶
func Permanent ¶
Permanent reports whether err describes a condition that retrying cannot resolve, so the caller should fail the operation now rather than spend its backoff budget on attempts certain to fail the same way.
A missing object, a permission failure, and an already-existing bucket are permanent. An exceeded quota is not: it may be granted later. Neither is an unclassified error — a condition Trove has not mapped is assumed transient, because treating it as permanent would silently discard work whenever a backend grows a failure mode the drivers do not yet recognize.
reader, err := t.Get(ctx, "artifacts", key)
if err != nil {
if trove.Permanent(err) {
return job.Fail(err) // straight to the dead letter queue
}
return job.Retry(err) // transient — back off and try again
}
See the driver package for the full classification.
Types ¶
type ChecksumAlgorithm ¶
type ChecksumAlgorithm int
ChecksumAlgorithm identifies the hash algorithm used for integrity verification.
const ( // SHA256 uses the SHA-256 hash algorithm (default). SHA256 ChecksumAlgorithm = iota // Blake3 uses the BLAKE3 hash algorithm (faster, modern). Blake3 // XXHash uses the XXHash algorithm (non-cryptographic, fastest). XXHash )
func (ChecksumAlgorithm) String ¶
func (a ChecksumAlgorithm) String() string
String returns the algorithm name.
type Config ¶
type Config struct {
// DefaultBucket is the bucket used when none is specified.
DefaultBucket string
// ChunkSize is the size in bytes for streaming chunks.
ChunkSize int64
// PoolSize is the maximum number of concurrent streams.
PoolSize int
// ChecksumAlgorithm is the hash algorithm for integrity verification.
ChecksumAlgorithm ChecksumAlgorithm
// StreamBufferSize is the buffer size in bytes for stream operations.
StreamBufferSize int
// Retry configures retry behavior for storage operations.
Retry RetryPolicy
}
Config holds the configuration for a Trove instance.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults.
type Option ¶
Option configures a Trove instance.
func WithBackend ¶
WithBackend registers a named storage backend. Named backends can be selected explicitly via Backend() or automatically via routing rules.
func WithCAS ¶
func WithCAS(alg cas.HashAlgorithm) Option
WithCAS enables content-addressable storage with the given hash algorithm. Open builds the CAS on the default driver once every option has run, so it records on the Recorder from WithMetrics wherever that option sits.
func WithChecksumAlgorithm ¶
func WithChecksumAlgorithm(alg ChecksumAlgorithm) Option
WithChecksumAlgorithm sets the hash algorithm for integrity verification.
func WithChunkSize ¶
WithChunkSize sets the size in bytes for streaming chunks.
func WithDefaultBucket ¶
WithDefaultBucket sets the bucket used when none is specified in operations.
func WithMetrics ¶
WithMetrics records Trove's metrics on r: the duration of every facade operation, object bytes through Put and Get, scans by the scan middleware and, when CAS is enabled, CAS stores and garbage collection. Package observe lists each metric with its labels. A nil r, the default, records nothing.
Spans need no option. They go to the global OpenTelemetry tracer provider, which a Forge app installs.
func WithMiddleware ¶
func WithMiddleware(mws ...middleware.Middleware) Option
WithMiddleware registers global middleware (read + write, all operations).
func WithMiddlewareAt ¶
func WithMiddlewareAt(priority int, mws ...middleware.Middleware) Option
WithMiddlewareAt registers middleware with explicit priority (lower = runs first).
func WithPoolConfig ¶
func WithPoolConfig(cfg stream.PoolConfig) Option
WithPoolConfig configures the default streaming pool. This overrides the pool created from PoolSize and ChunkSize in DefaultConfig.
func WithPoolSize ¶
WithPoolSize sets the maximum number of concurrent streams.
func WithReadMiddleware ¶
func WithReadMiddleware(mws ...middleware.Middleware) Option
WithReadMiddleware registers middleware that only runs on the download/read path.
func WithRetry ¶
func WithRetry(policy RetryPolicy) Option
WithRetry configures retry behavior for storage operations.
func WithRoute ¶
WithRoute adds a pattern-based routing rule that directs matching keys to a named backend. Pattern uses filepath.Match syntax.
Example:
trove.WithRoute("*.log", "archive") // All .log files → archive backend
trove.WithRoute("tmp/*", "local") // All tmp/ keys → local backend
func WithRouteFunc ¶
WithRouteFunc adds a custom routing function. The function receives the bucket and key and returns the backend name to use. Return empty string to fall through to the next rule or the default backend.
func WithScopedMiddleware ¶
func WithScopedMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
WithScopedMiddleware registers middleware with a composed scope (read + write).
func WithScopedReadMiddleware ¶
func WithScopedReadMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
WithScopedReadMiddleware registers read-only middleware with a composed scope.
func WithScopedWriteMiddleware ¶
func WithScopedWriteMiddleware(scope middleware.Scope, mws ...middleware.Middleware) Option
WithScopedWriteMiddleware registers write-only middleware with a composed scope.
func WithStreamBufferSize ¶
WithStreamBufferSize sets the buffer size in bytes for stream operations.
func WithVFS ¶
WithVFS sets the default bucket for VFS operations. When set, calling t.VFS() returns a filesystem view of this bucket.
func WithWriteMiddleware ¶
func WithWriteMiddleware(mws ...middleware.Middleware) Option
WithWriteMiddleware registers middleware that only runs on the upload/write path.
type RetryPolicy ¶
type RetryPolicy struct {
// Strategy is the backoff strategy.
Strategy RetryStrategy
// MaxAttempts is the maximum number of retry attempts.
MaxAttempts int
// BaseDelay is the initial delay between retries.
BaseDelay time.Duration
// MaxDelay is the maximum delay between retries (for exponential backoff).
MaxDelay time.Duration
}
RetryPolicy configures retry behavior for storage operations.
type RetryStrategy ¶
type RetryStrategy int
RetryStrategy identifies the retry backoff strategy.
const ( // RetryNone disables retries. RetryNone RetryStrategy = iota // RetryFixed uses a fixed delay between retries. RetryFixed // RetryExponential uses exponential backoff. RetryExponential )
type Trove ¶
type Trove struct {
// contains filtered or unexported fields
}
Trove is the root handle for object storage operations. It wraps one or more storage drivers, routing operations through the configured backend(s).
func Open ¶
Open creates a new Trove instance with the given default driver and options.
Example:
t, err := trove.Open(localdriver.New(),
trove.WithDefaultBucket("primary"),
trove.WithChunkSize(8 * 1024 * 1024),
)
func (*Trove) Backend ¶
Backend returns a new Trove handle pinned to the named backend. All operations on the returned handle bypass routing and go directly to the specified backend.
func (*Trove) Backends ¶
Backends returns the names of the backends registered with WithBackend, sorted. The default driver has no name and is never in the list, so an empty list means every operation goes to the default. A handle returned by Backend is pinned to one driver and returns an empty list.
func (*Trove) CAS ¶
CAS returns the content-addressable storage engine, or nil if CAS is not enabled.
func (*Trove) Copy ¶
func (t *Trove) Copy(ctx context.Context, srcBucket, srcKey, dstBucket, dstKey string, opts ...driver.CopyOption) (info *driver.ObjectInfo, err error)
Copy copies an object within or across buckets.
func (*Trove) CreateBucket ¶
func (t *Trove) CreateBucket(ctx context.Context, name string, opts ...driver.BucketOption) (err error)
CreateBucket creates a new bucket on the default driver.
func (*Trove) Delete ¶
func (t *Trove) Delete(ctx context.Context, bucket, key string, opts ...driver.DeleteOption) (err error)
Delete removes an object.
func (*Trove) DeleteBucket ¶
DeleteBucket removes a bucket from the default driver.
func (*Trove) DriverFor ¶
DriverFor returns the driver that serves bucket and key, after routing. Driver returns only the default; an object routed elsewhere is served by this one.
func (*Trove) Get ¶
func (t *Trove) Get(ctx context.Context, bucket, key string, opts ...driver.GetOption) (obj *driver.ObjectReader, err error)
Get retrieves an object, returning a ReadCloser for the content. Data passes through the read middleware pipeline (e.g., decryption, decompression) after being retrieved from the driver.
Its span ends when Get returns, so it covers the driver's request and the response headers but not the time the caller spends reading the body.
func (*Trove) List ¶
func (t *Trove) List(ctx context.Context, bucket string, opts ...driver.ListOption) (it *driver.ObjectIterator, err error)
List returns objects matching the given options.
func (*Trove) ListBuckets ¶
ListBuckets returns all buckets from the default driver.
func (*Trove) Put ¶
func (t *Trove) Put(ctx context.Context, bucket, key string, r io.Reader, opts ...driver.PutOption) (info *driver.ObjectInfo, err error)
Put stores an object from a reader. Data passes through the write middleware pipeline (e.g., encryption, compression) before reaching the driver.
func (*Trove) RemoveMiddleware ¶
func (t *Trove) RemoveMiddleware(name string, scope middleware.Scope)
RemoveMiddleware removes all registrations matching the given middleware name and scope. If scope is nil, removes all registrations with that name.
func (*Trove) Resolver ¶
func (t *Trove) Resolver() *middleware.Resolver
Resolver returns the middleware pipeline resolver.
func (*Trove) Stream ¶
func (t *Trove) Stream(ctx context.Context, bucket, key string, dir stream.Direction, opts ...stream.Option) (*stream.Stream, error)
Stream creates a new managed stream within the default pool. The stream provides chunked transfer with backpressure, resumability, and lifecycle hooks.
func (*Trove) UseMiddleware ¶
func (t *Trove) UseMiddleware(reg middleware.Registration)
UseMiddleware registers a middleware at runtime. Thread-safe.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package cas provides content-addressable storage for Trove.
|
Package cas provides content-addressable storage for Trove. |
|
Package driver defines the core interfaces and types that every Trove storage backend must implement.
|
Package driver defines the core interfaces and types that every Trove storage backend must implement. |
|
drivers
|
|
|
localdriver
Package localdriver provides a local filesystem storage driver.
|
Package localdriver provides a local filesystem storage driver. |
|
memdriver
Package memdriver provides an in-memory storage driver for testing.
|
Package memdriver provides an in-memory storage driver for testing. |
|
azuredriver
module
|
|
|
gcsdriver
module
|
|
|
s3driver
module
|
|
|
sftpdriver
module
|
|
|
extension
module
|
|
|
Package id defines TypeID-based identity types for all Trove entities.
|
Package id defines TypeID-based identity types for all Trove entities. |
|
Package internal contains core domain logic with zero Forge imports.
|
Package internal contains core domain logic with zero Forge imports. |
|
telemetry
Package telemetry is the tracing and metrics plumbing Trove's packages share: the tracer every span comes from, span names and attribute keys, how a failed span is marked, and how a measurement reaches the caller's observe.Recorder.
|
Package telemetry is the tracing and metrics plumbing Trove's packages share: the tracer every span comes from, span names and attribute keys, how a failed span is marked, and how a measurement reaches the caller's observe.Recorder. |
|
telemetrytest
Package telemetrytest records what Trove's telemetry emits, for tests: a span recorder installed as the global tracer provider, and an observe.Recorder that remembers every measurement and checks it against the metric definitions in package observe.
|
Package telemetrytest records what Trove's telemetry emits, for tests: a span recorder installed as the global tracer provider, and an observe.Recorder that remembers every measurement and checks it against the metric definitions in package observe. |
|
Package middleware provides a composable, scope-aware interceptor pipeline for Trove's read/write data path.
|
Package middleware provides a composable, scope-aware interceptor pipeline for Trove's read/write data path. |
|
compress
Package compress provides Zstd compression middleware for Trove.
|
Package compress provides Zstd compression middleware for Trove. |
|
dedup
Package dedup provides content-hash deduplication middleware for Trove.
|
Package dedup provides content-hash deduplication middleware for Trove. |
|
encrypt
Package encrypt provides AES-256-GCM encryption middleware for Trove.
|
Package encrypt provides AES-256-GCM encryption middleware for Trove. |
|
scan
Package scan provides content scanning middleware for Trove.
|
Package scan provides content scanning middleware for Trove. |
|
watermark
Package watermark provides invisible metadata watermarking middleware for Trove.
|
Package watermark provides invisible metadata watermarking middleware for Trove. |
|
Package observe defines the metrics Trove records and the small interface it records them through.
|
Package observe defines the metrics Trove records and the small interface it records them through. |
|
Package stream provides a managed streaming engine for Trove with backpressure, chunked transfers, buffer pooling, and concurrency control.
|
Package stream provides a managed streaming engine for Trove with backpressure, chunked transfers, buffer pooling, and concurrency control. |
|
Package trovetest provides testing utilities for Trove storage drivers.
|
Package trovetest provides testing utilities for Trove storage drivers. |
|
Package vfs provides a virtual filesystem abstraction over Trove object storage.
|
Package vfs provides a virtual filesystem abstraction over Trove object storage. |