github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/asyncreader/asyncreader.go (about)

     1  // Package asyncreader provides an asynchronous reader which reads
     2  // independently of write
     3  package asyncreader
     4  
     5  import (
     6  	"io"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  	"github.com/rclone/rclone/fs"
    12  	"github.com/rclone/rclone/lib/pool"
    13  	"github.com/rclone/rclone/lib/readers"
    14  )
    15  
    16  const (
    17  	// BufferSize is the default size of the async buffer
    18  	BufferSize           = 1024 * 1024
    19  	softStartInitial     = 4 * 1024
    20  	bufferCacheSize      = 64              // max number of buffers to keep in cache
    21  	bufferCacheFlushTime = 5 * time.Second // flush the cached buffers after this long
    22  )
    23  
    24  // ErrorStreamAbandoned is returned when the input is closed before the end of the stream
    25  var ErrorStreamAbandoned = errors.New("stream abandoned")
    26  
    27  // AsyncReader will do async read-ahead from the input reader
    28  // and make the data available as an io.Reader.
    29  // This should be fully transparent, except that once an error
    30  // has been returned from the Reader, it will not recover.
    31  type AsyncReader struct {
    32  	in      io.ReadCloser // Input reader
    33  	ready   chan *buffer  // Buffers ready to be handed to the reader
    34  	token   chan struct{} // Tokens which allow a buffer to be taken
    35  	exit    chan struct{} // Closes when finished
    36  	buffers int           // Number of buffers
    37  	err     error         // If an error has occurred it is here
    38  	cur     *buffer       // Current buffer being served
    39  	exited  chan struct{} // Channel is closed been the async reader shuts down
    40  	size    int           // size of buffer to use
    41  	closed  bool          // whether we have closed the underlying stream
    42  	mu      sync.Mutex    // lock for Read/WriteTo/Abandon/Close
    43  }
    44  
    45  // New returns a reader that will asynchronously read from
    46  // the supplied Reader into a number of buffers each of size BufferSize
    47  // It will start reading from the input at once, maybe even before this
    48  // function has returned.
    49  // The input can be read from the returned reader.
    50  // When done use Close to release the buffers and close the supplied input.
    51  func New(rd io.ReadCloser, buffers int) (*AsyncReader, error) {
    52  	if buffers <= 0 {
    53  		return nil, errors.New("number of buffers too small")
    54  	}
    55  	if rd == nil {
    56  		return nil, errors.New("nil reader supplied")
    57  	}
    58  	a := &AsyncReader{}
    59  	a.init(rd, buffers)
    60  	return a, nil
    61  }
    62  
    63  func (a *AsyncReader) init(rd io.ReadCloser, buffers int) {
    64  	a.in = rd
    65  	a.ready = make(chan *buffer, buffers)
    66  	a.token = make(chan struct{}, buffers)
    67  	a.exit = make(chan struct{}, 0)
    68  	a.exited = make(chan struct{}, 0)
    69  	a.buffers = buffers
    70  	a.cur = nil
    71  	a.size = softStartInitial
    72  
    73  	// Create tokens
    74  	for i := 0; i < buffers; i++ {
    75  		a.token <- struct{}{}
    76  	}
    77  
    78  	// Start async reader
    79  	go func() {
    80  		// Ensure that when we exit this is signalled.
    81  		defer close(a.exited)
    82  		defer close(a.ready)
    83  		for {
    84  			select {
    85  			case <-a.token:
    86  				b := a.getBuffer()
    87  				if a.size < BufferSize {
    88  					b.buf = b.buf[:a.size]
    89  					a.size <<= 1
    90  				}
    91  				err := b.read(a.in)
    92  				a.ready <- b
    93  				if err != nil {
    94  					return
    95  				}
    96  			case <-a.exit:
    97  				return
    98  			}
    99  		}
   100  	}()
   101  }
   102  
   103  // bufferPool is a global pool of buffers
   104  var bufferPool *pool.Pool
   105  var bufferPoolOnce sync.Once
   106  
   107  // return the buffer to the pool (clearing it)
   108  func (a *AsyncReader) putBuffer(b *buffer) {
   109  	bufferPool.Put(b.buf)
   110  	b.buf = nil
   111  }
   112  
   113  // get a buffer from the pool
   114  func (a *AsyncReader) getBuffer() *buffer {
   115  	bufferPoolOnce.Do(func() {
   116  		// Initialise the buffer pool when used
   117  		bufferPool = pool.New(bufferCacheFlushTime, BufferSize, bufferCacheSize, fs.Config.UseMmap)
   118  	})
   119  	return &buffer{
   120  		buf: bufferPool.Get(),
   121  	}
   122  }
   123  
   124  // Read will return the next available data.
   125  func (a *AsyncReader) fill() (err error) {
   126  	if a.cur.isEmpty() {
   127  		if a.cur != nil {
   128  			a.putBuffer(a.cur)
   129  			a.token <- struct{}{}
   130  			a.cur = nil
   131  		}
   132  		b, ok := <-a.ready
   133  		if !ok {
   134  			// Return an error to show fill failed
   135  			if a.err == nil {
   136  				return ErrorStreamAbandoned
   137  			}
   138  			return a.err
   139  		}
   140  		a.cur = b
   141  	}
   142  	return nil
   143  }
   144  
   145  // Read will return the next available data.
   146  func (a *AsyncReader) Read(p []byte) (n int, err error) {
   147  	a.mu.Lock()
   148  	defer a.mu.Unlock()
   149  
   150  	// Swap buffer and maybe return error
   151  	err = a.fill()
   152  	if err != nil {
   153  		return 0, err
   154  	}
   155  
   156  	// Copy what we can
   157  	n = copy(p, a.cur.buffer())
   158  	a.cur.increment(n)
   159  
   160  	// If at end of buffer, return any error, if present
   161  	if a.cur.isEmpty() {
   162  		a.err = a.cur.err
   163  		return n, a.err
   164  	}
   165  	return n, nil
   166  }
   167  
   168  // WriteTo writes data to w until there's no more data to write or when an error occurs.
   169  // The return value n is the number of bytes written.
   170  // Any error encountered during the write is also returned.
   171  func (a *AsyncReader) WriteTo(w io.Writer) (n int64, err error) {
   172  	a.mu.Lock()
   173  	defer a.mu.Unlock()
   174  
   175  	n = 0
   176  	for {
   177  		err = a.fill()
   178  		if err == io.EOF {
   179  			return n, nil
   180  		}
   181  		if err != nil {
   182  			return n, err
   183  		}
   184  		n2, err := w.Write(a.cur.buffer())
   185  		a.cur.increment(n2)
   186  		n += int64(n2)
   187  		if err != nil {
   188  			return n, err
   189  		}
   190  		if a.cur.err == io.EOF {
   191  			a.err = a.cur.err
   192  			return n, err
   193  		}
   194  		if a.cur.err != nil {
   195  			a.err = a.cur.err
   196  			return n, a.cur.err
   197  		}
   198  	}
   199  }
   200  
   201  // SkipBytes will try to seek 'skip' bytes relative to the current position.
   202  // On success it returns true. If 'skip' is outside the current buffer data or
   203  // an error occurs, Abandon is called and false is returned.
   204  func (a *AsyncReader) SkipBytes(skip int) (ok bool) {
   205  	a.mu.Lock()
   206  	defer func() {
   207  		a.mu.Unlock()
   208  		if !ok {
   209  			a.Abandon()
   210  		}
   211  	}()
   212  
   213  	if a.err != nil {
   214  		return false
   215  	}
   216  	if skip < 0 {
   217  		// seek backwards if skip is inside current buffer
   218  		if a.cur != nil && a.cur.offset+skip >= 0 {
   219  			a.cur.offset += skip
   220  			return true
   221  		}
   222  		return false
   223  	}
   224  	// early return if skip is past the maximum buffer capacity
   225  	if skip >= (len(a.ready)+1)*BufferSize {
   226  		return false
   227  	}
   228  
   229  	refillTokens := 0
   230  	for {
   231  		if a.cur.isEmpty() {
   232  			if a.cur != nil {
   233  				a.putBuffer(a.cur)
   234  				refillTokens++
   235  				a.cur = nil
   236  			}
   237  			select {
   238  			case b, ok := <-a.ready:
   239  				if !ok {
   240  					return false
   241  				}
   242  				a.cur = b
   243  			default:
   244  				return false
   245  			}
   246  		}
   247  
   248  		n := len(a.cur.buffer())
   249  		if n > skip {
   250  			n = skip
   251  		}
   252  		a.cur.increment(n)
   253  		skip -= n
   254  		if skip == 0 {
   255  			for ; refillTokens > 0; refillTokens-- {
   256  				a.token <- struct{}{}
   257  			}
   258  			// If at end of buffer, store any error, if present
   259  			if a.cur.isEmpty() && a.cur.err != nil {
   260  				a.err = a.cur.err
   261  			}
   262  			return true
   263  		}
   264  		if a.cur.err != nil {
   265  			a.err = a.cur.err
   266  			return false
   267  		}
   268  	}
   269  }
   270  
   271  // Abandon will ensure that the underlying async reader is shut down.
   272  // It will NOT close the input supplied on New.
   273  func (a *AsyncReader) Abandon() {
   274  	select {
   275  	case <-a.exit:
   276  		// Do nothing if reader routine already exited
   277  		return
   278  	default:
   279  	}
   280  	// Close and wait for go routine
   281  	close(a.exit)
   282  	<-a.exited
   283  	// take the lock to wait for Read/WriteTo to complete
   284  	a.mu.Lock()
   285  	defer a.mu.Unlock()
   286  	// Return any outstanding buffers to the Pool
   287  	if a.cur != nil {
   288  		a.putBuffer(a.cur)
   289  		a.cur = nil
   290  	}
   291  	for b := range a.ready {
   292  		a.putBuffer(b)
   293  	}
   294  }
   295  
   296  // Close will ensure that the underlying async reader is shut down.
   297  // It will also close the input supplied on New.
   298  func (a *AsyncReader) Close() (err error) {
   299  	a.Abandon()
   300  	if a.closed {
   301  		return nil
   302  	}
   303  	a.closed = true
   304  	return a.in.Close()
   305  }
   306  
   307  // Internal buffer
   308  // If an error is present, it must be returned
   309  // once all buffer content has been served.
   310  type buffer struct {
   311  	buf    []byte
   312  	err    error
   313  	offset int
   314  }
   315  
   316  // isEmpty returns true is offset is at end of
   317  // buffer, or
   318  func (b *buffer) isEmpty() bool {
   319  	if b == nil {
   320  		return true
   321  	}
   322  	if len(b.buf)-b.offset <= 0 {
   323  		return true
   324  	}
   325  	return false
   326  }
   327  
   328  // read into start of the buffer from the supplied reader,
   329  // resets the offset and updates the size of the buffer.
   330  // Any error encountered during the read is returned.
   331  func (b *buffer) read(rd io.Reader) error {
   332  	var n int
   333  	n, b.err = readers.ReadFill(rd, b.buf)
   334  	b.buf = b.buf[0:n]
   335  	b.offset = 0
   336  	return b.err
   337  }
   338  
   339  // Return the buffer at current offset
   340  func (b *buffer) buffer() []byte {
   341  	return b.buf[b.offset:]
   342  }
   343  
   344  // increment the offset
   345  func (b *buffer) increment(n int) {
   346  	b.offset += n
   347  }