mirror of
https://github.com/samuelncui/acp.git
synced 2026-11-08 04:21:16 +00:00
Both were invisible on Darwin: one needs a real Linux ENOSPC, the other needs the command's own stderr. - A non-linear target pre-allocates with fallocate, and a failure there was reported as a bare error: it never ran through mappingError, never aborted the device and never ended a linear target, unlike every neighbouring path. A volume that fills up after the disk-usage snapshot therefore reported a target that was "not written" instead of ErrTargetNoSpace. Classify it like the rest. TestFullVolumePreallocationReportsNoSpace pins it with a real ENOSPC on a small tmpfs (it fails on the previous revision), and TestNonLinearTargetOnRefusingDeviceReportsATargetFailure records that a device refusing fallocate reports its own refusal rather than claiming no space. The drain test now uses a linear target, which is the shape that actually queues buffers before the write fails. - cmd/acp registered the progress bar and then the report collector, and a run keeps one event handler, so the bar received nothing: the command printed its construction frame and no update. Compose the two handlers in the command and pin it end to end (the new test fails on the previous revision). README now says a command that wants both composes them. - item.go still promised that an empty Targets slice hashes the source; the default HashOff reads nothing. TESTING.md and TODO.md now describe the Linux suite that actually exists.
86 lines
3.3 KiB
Go
86 lines
3.3 KiB
Go
package acp
|
|
|
|
import (
|
|
"io/fs"
|
|
"time"
|
|
)
|
|
|
|
// Item is one unit of work owned by the caller.
|
|
//
|
|
// The caller implements Item over whatever state it owns, so the item is the handle that ties a
|
|
// result back to that state: Result.Job is the exact instance that was submitted, and no id
|
|
// lookup or payload plumbing is needed. ACP calls Source and Targets under panic protection: the
|
|
// first call describes the item, and an item whose description failed is asked for its Source once
|
|
// more when it is reported, so a failure path may read Source twice. ACP never keeps the item
|
|
// afterwards.
|
|
type Item interface {
|
|
// Source returns the exact path to read.
|
|
Source() string
|
|
|
|
// Targets returns the destinations of a copy. An empty slice writes nothing: the source is
|
|
// read and hashed only when the hash policy produces a hash, so the default HashOff reports
|
|
// neither a copy nor a hash.
|
|
Targets() []string
|
|
}
|
|
|
|
// SimpleJob is an Item that carries no state of its own: Path is the source and Dsts are the
|
|
// destinations. A caller that submits a SimpleJob finds its result by matching Result.Job
|
|
// against the pointer it submitted, because SimpleJob has no callback of its own.
|
|
type SimpleJob struct {
|
|
Path string
|
|
Dsts []string
|
|
}
|
|
|
|
// Source returns the path to read.
|
|
func (j *SimpleJob) Source() string { return j.Path }
|
|
|
|
// Targets returns the destinations; an empty slice reads without writing, and it produces a
|
|
// hash only when the run's hash policy does.
|
|
func (j *SimpleJob) Targets() []string { return j.Dsts }
|
|
|
|
// Result reports the content facts of one finished item, one outcome per requested target, and
|
|
// the item's own error.
|
|
//
|
|
// A result that carries an error is delivered as soon as it is produced; results without an
|
|
// error are buffered. Result order is unspecified: results arrive in completion order, and a
|
|
// failure may therefore arrive before a success of the same submission batch. A linear target
|
|
// still writes in request order, because one writer consumes items in that order.
|
|
type Result struct {
|
|
// Job is the exact Item instance that was submitted.
|
|
Job Item
|
|
|
|
// Err is the item-level error. A nil Err means the item completed, even when every
|
|
// requested target failed: an item that could not be processed at all is what fails,
|
|
// and its target outcomes are still reported.
|
|
Err error
|
|
|
|
// Size, Mode and ModTime describe the source facts the item observed, and WriteTime is
|
|
// when its copy stage started.
|
|
Size int64
|
|
Mode fs.FileMode
|
|
ModTime time.Time
|
|
WriteTime time.Time
|
|
|
|
// SHA256 is the hash of the bytes actually read; it is nil when the hash policy produces
|
|
// no hash. SignatureCacheHit reports that a stored hash was reused instead of computed.
|
|
SHA256 []byte
|
|
SignatureCacheHit bool
|
|
|
|
// Targets holds one outcome per requested target, in request order. A target that was
|
|
// not written still has an outcome.
|
|
Targets []TargetResult
|
|
}
|
|
|
|
// TargetResult is the outcome of one requested target.
|
|
type TargetResult struct {
|
|
Path string
|
|
// Size is the item's size as read, so a failed or partially written target reports that
|
|
// size rather than a count of the bytes that landed there.
|
|
Size int64
|
|
WriteTime time.Time
|
|
|
|
// Err is nil when the target was written. Target failures keep their error identity, so
|
|
// errors.Is(err, ErrTargetNoSpace) identifies an exhausted medium.
|
|
Err error
|
|
}
|