package dual import ( "errors" "fmt" "io" "lindenii.org/go/furgit/object/id" "lindenii.org/go/furgit/object/store" "lindenii.org/go/furgit/object/store/mix" "lindenii.org/go/furgit/object/typ" ) // BeginObjectQuarantine begins an object-wise quarantine on the object side. // //nolint:ireturn func (dual *Dual) BeginObjectQuarantine(opts store.ObjectQuarantineOptions) (store.ObjectQuarantine, error) { return dual.object.BeginObjectQuarantine(opts) //nolint:wrapcheck } // BeginPackQuarantine begins a pack-wise quarantine on the pack side. // //nolint:ireturn func (dual *Dual) BeginPackQuarantine(opts store.PackQuarantineOptions) (store.PackQuarantine, error) { return dual.pack.BeginPackQuarantine(opts) //nolint:wrapcheck } // BeginCoordinatedQuarantine begins a quarantine spanning both sides. // // If the pack side fails to begin, // the already-begun object side is discarded before returning. // //nolint:ireturn func (dual *Dual) BeginCoordinatedQuarantine(opts store.CoordinatedQuarantineOptions) (store.CoordinatedQuarantine, error) { objectQ, err := dual.object.BeginObjectQuarantine(opts.Object) if err != nil { return nil, fmt.Errorf("object/store/dual: begin object quarantine: %w", err) } packQ, err := dual.pack.BeginPackQuarantine(opts.Pack) if err != nil { _ = objectQ.Discard() return nil, fmt.Errorf("object/store/dual: begin pack quarantine: %w", err) } return newCoordinatedQuarantine(objectQ, packQ), nil } // coordinatedQuarantine is one coordinated quarantine over both sides. type coordinatedQuarantine struct { objectQ store.ObjectQuarantine packQ store.PackQuarantine reader store.ObjectReader } var _ store.CoordinatedQuarantine = (*coordinatedQuarantine)(nil) func newCoordinatedQuarantine( objectQ store.ObjectQuarantine, packQ store.PackQuarantine, ) *coordinatedQuarantine { return &coordinatedQuarantine{ objectQ: objectQ, packQ: packQ, reader: mix.New(objectQ, packQ), } } func (quarantine *coordinatedQuarantine) ReadBytesFull(id id.ObjectID) ([]byte, error) { return quarantine.reader.ReadBytesFull(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) ReadBytesContent(id id.ObjectID) (typ.Type, []byte, error) { return quarantine.reader.ReadBytesContent(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) ReadReaderFull(id id.ObjectID) (io.ReadCloser, error) { return quarantine.reader.ReadReaderFull(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) ReadReaderContent(id id.ObjectID) (typ.Type, uint64, io.ReadCloser, error) { return quarantine.reader.ReadReaderContent(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) ReadSize(id id.ObjectID) (uint64, error) { return quarantine.reader.ReadSize(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) ReadHeader(id id.ObjectID) (typ.Type, uint64, error) { return quarantine.reader.ReadHeader(id) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) Refresh() error { return quarantine.reader.Refresh() //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) WriteBytesFull(raw []byte) (id.ObjectID, error) { return quarantine.objectQ.WriteBytesFull(raw) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) WriteBytesContent(ty typ.Type, content []byte) (id.ObjectID, error) { return quarantine.objectQ.WriteBytesContent(ty, content) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) WriteReaderFull(src io.Reader) (id.ObjectID, error) { return quarantine.objectQ.WriteReaderFull(src) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) WriteReaderContent(ty typ.Type, size uint64, src io.Reader) (id.ObjectID, error) { return quarantine.objectQ.WriteReaderContent(ty, size, src) //nolint:wrapcheck } func (quarantine *coordinatedQuarantine) WritePack(src io.Reader, opts store.PackWriteOptions) error { return quarantine.packQ.WritePack(src, opts) //nolint:wrapcheck } // Promote publishes both halves and joins their errors. func (quarantine *coordinatedQuarantine) Promote() error { return errors.Join(quarantine.objectQ.Promote(), quarantine.packQ.Promote()) } // Discard abandons both halves and joins their errors. func (quarantine *coordinatedQuarantine) Discard() error { return errors.Join(quarantine.objectQ.Discard(), quarantine.packQ.Discard()) }