github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/ioctx/spliceio/spliceio.go (about)

     1  package spliceio
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  
     7  	"github.com/Schaudge/grailbase/ioctx/fsctx"
     8  )
     9  
    10  // ReaderAt reads data by giving the caller an OS file descriptor plus coordinates so the
    11  // caller can directly splice (or just read) the file descriptor. Concurrent calls are allowed.
    12  //
    13  // It's possible for gotSize to be less than wantSize with nil error. This is different from
    14  // io.ReaderAt. Callers should simply continue their read at off + gotSize.
    15  type ReaderAt interface {
    16  	// SpliceReadAt returns a file descriptor and coordinates, or error.
    17  	//
    18  	// Note that fdOff is totally unrelated to off; fdOff must only be used for operations on fd.
    19  	// No guarantees are made about fd from different calls (no consistency, no uniqueness).
    20  	// No guarantees are made about fdOff from different calls (no ordering, no uniqueness).
    21  	SpliceReadAt(_ context.Context, wantSize int, off int64) (fd uintptr, gotSize int, fdOff int64, _ error)
    22  }
    23  
    24  // OSFile is a ReaderAt wrapping os.File. It's also a fsctx.File and a
    25  // fsnodefuse.Writable.
    26  type OSFile os.File
    27  
    28  var (
    29  	_ fsctx.File = (*OSFile)(nil)
    30  	_ ReaderAt   = (*OSFile)(nil)
    31  )
    32  
    33  func (f *OSFile) SpliceReadAt(
    34  	_ context.Context, wantSize int, off int64,
    35  ) (
    36  	fd uintptr, gotSize int, fdOff int64, _ error,
    37  ) {
    38  	// TODO: Validation? Probably don't need to check file size. Maybe wantSize, off >= 0?
    39  	return (*os.File)(f).Fd(), wantSize, off, nil
    40  }
    41  
    42  func (f *OSFile) Stat(context.Context) (os.FileInfo, error)     { return (*os.File)(f).Stat() }
    43  func (f *OSFile) Read(_ context.Context, b []byte) (int, error) { return (*os.File)(f).Read(b) }
    44  func (f *OSFile) Close(context.Context) error                   { return (*os.File)(f).Close() }
    45  
    46  func (f *OSFile) WriteAt(_ context.Context, b []byte, offset int64) (int, error) {
    47  	return (*os.File)(f).WriteAt(b, offset)
    48  }
    49  func (f *OSFile) Truncate(_ context.Context, size int64) error { return (*os.File)(f).Truncate(size) }
    50  func (f *OSFile) Flush(_ context.Context) error                { return nil }
    51  func (f *OSFile) Fsync(_ context.Context) error                { return (*os.File)(f).Sync() }