Files
acp/opt_device.go
T
Samuel Cui ac02c71d3f feat!: stream caller-owned items and own the result queue
Reshape the public API around one push engine and restore the af05f05c
surface as a compatibility shell over it.

- NewStream takes caller-owned items (Source/Targets), reports every accepted
  item through one results callback, and Wait returns the run's terminal error.
  Run, BatchSource and the item callbacks are gone.
- The engine owns the result path: WithResultBuffer is the depth of the result
  queue, WithResultBatch is how many results one delivery carries, and
  WithResultFlushInterval is how long a successful result may wait. A result
  that carries any error is delivered immediately as its own batch.
- Restore the af05f05c API byte-compatibly in the same package: New, Copyer,
  Wait/WaitErr, AccurateJob, WildcardJob, the report events and the JSON report
  round-trip through encoding/json alone.
- One descriptor serves a whole item; the stored hash is read through the
  descriptor that reads the content and the computed hash is published through
  it before it closes.
- Make every handoff escapable by a hard stop: the read buffer, a chunk send,
  an event send and the result buffer.
- Fix the recorded sweep findings: report indent and round-trip, cmd/acp exit
  status, acp-rewrite final paths, mmap EOF/close/slice, disk-usage
  reservations, ErrTargetIO identity, the fatal-panic safety net, option
  validation, and the FreeBSD/Windows build paths.
- Cover the contract with semantic tests, add Makefile check/race/vet/cross
  targets, and document the withdrawn v0.1.0/v0.2.0 migration in README.
2026-09-19 15:18:13 +08:00

71 lines
1.4 KiB
Go

package acp
import "fmt"
// ReadMode selects how a source device reads its content.
type ReadMode uint8
const (
// ReadBuffered reads through the kernel's buffered path, which is the default.
ReadBuffered ReadMode = iota
// ReadMapped reads through a memory mapping.
ReadMapped
)
func (m ReadMode) String() string {
switch m {
case ReadBuffered:
return "buffered"
case ReadMapped:
return "mapped"
}
return fmt.Sprintf("unknown(%d)", uint8(m))
}
type deviceOption struct {
linear bool
threads int
readMode ReadMode
}
func (do *deviceOption) check() error {
if do.threads < 0 {
return fmt.Errorf("device threads cannot be negative, threads=%d", do.threads)
}
if do.threads == 0 {
do.threads = 8
}
if do.linear {
do.threads = 1
}
if do.readMode != ReadBuffered && do.readMode != ReadMapped {
return fmt.Errorf("unknown read mode, mode= %s", do.readMode)
}
return nil
}
type DeviceOption func(*deviceOption) *deviceOption
func LinearDevice(b bool) DeviceOption {
return func(d *deviceOption) *deviceOption {
d.linear = b
return d
}
}
func DeviceThreads(threads int) DeviceOption {
return func(d *deviceOption) *deviceOption {
d.threads = threads
return d
}
}
// WithReadMode selects how a source device reads its content. It applies to the source
// device only and defaults to buffered reads.
func WithReadMode(mode ReadMode) DeviceOption {
return func(d *deviceOption) *deviceOption {
d.readMode = mode
return d
}
}