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 }