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