github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/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/ncw/rclone/fs" 11 "github.com/ncw/rclone/lib/pool" 12 "github.com/ncw/rclone/lib/readers" 13 "github.com/pkg/errors" 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 != nil { 178 return n, err 179 } 180 n2, err := w.Write(a.cur.buffer()) 181 a.cur.increment(n2) 182 n += int64(n2) 183 if err != nil { 184 return n, err 185 } 186 if a.cur.err != nil { 187 a.err = a.cur.err 188 return n, a.cur.err 189 } 190 } 191 } 192 193 // SkipBytes will try to seek 'skip' bytes relative to the current position. 194 // On success it returns true. If 'skip' is outside the current buffer data or 195 // an error occurs, Abandon is called and false is returned. 196 func (a *AsyncReader) SkipBytes(skip int) (ok bool) { 197 a.mu.Lock() 198 defer func() { 199 a.mu.Unlock() 200 if !ok { 201 a.Abandon() 202 } 203 }() 204 205 if a.err != nil { 206 return false 207 } 208 if skip < 0 { 209 // seek backwards if skip is inside current buffer 210 if a.cur != nil && a.cur.offset+skip >= 0 { 211 a.cur.offset += skip 212 return true 213 } 214 return false 215 } 216 // early return if skip is past the maximum buffer capacity 217 if skip >= (len(a.ready)+1)*BufferSize { 218 return false 219 } 220 221 refillTokens := 0 222 for { 223 if a.cur.isEmpty() { 224 if a.cur != nil { 225 a.putBuffer(a.cur) 226 refillTokens++ 227 a.cur = nil 228 } 229 select { 230 case b, ok := <-a.ready: 231 if !ok { 232 return false 233 } 234 a.cur = b 235 default: 236 return false 237 } 238 } 239 240 n := len(a.cur.buffer()) 241 if n > skip { 242 n = skip 243 } 244 a.cur.increment(n) 245 skip -= n 246 if skip == 0 { 247 for ; refillTokens > 0; refillTokens-- { 248 a.token <- struct{}{} 249 } 250 // If at end of buffer, store any error, if present 251 if a.cur.isEmpty() && a.cur.err != nil { 252 a.err = a.cur.err 253 } 254 return true 255 } 256 if a.cur.err != nil { 257 a.err = a.cur.err 258 return false 259 } 260 } 261 } 262 263 // Abandon will ensure that the underlying async reader is shut down. 264 // It will NOT close the input supplied on New. 265 func (a *AsyncReader) Abandon() { 266 select { 267 case <-a.exit: 268 // Do nothing if reader routine already exited 269 return 270 default: 271 } 272 // Close and wait for go routine 273 close(a.exit) 274 <-a.exited 275 // take the lock to wait for Read/WriteTo to complete 276 a.mu.Lock() 277 defer a.mu.Unlock() 278 // Return any outstanding buffers to the Pool 279 if a.cur != nil { 280 a.putBuffer(a.cur) 281 a.cur = nil 282 } 283 for b := range a.ready { 284 a.putBuffer(b) 285 } 286 } 287 288 // Close will ensure that the underlying async reader is shut down. 289 // It will also close the input supplied on New. 290 func (a *AsyncReader) Close() (err error) { 291 a.Abandon() 292 if a.closed { 293 return nil 294 } 295 a.closed = true 296 return a.in.Close() 297 } 298 299 // Internal buffer 300 // If an error is present, it must be returned 301 // once all buffer content has been served. 302 type buffer struct { 303 buf []byte 304 err error 305 offset int 306 } 307 308 // isEmpty returns true is offset is at end of 309 // buffer, or 310 func (b *buffer) isEmpty() bool { 311 if b == nil { 312 return true 313 } 314 if len(b.buf)-b.offset <= 0 { 315 return true 316 } 317 return false 318 } 319 320 // read into start of the buffer from the supplied reader, 321 // resets the offset and updates the size of the buffer. 322 // Any error encountered during the read is returned. 323 func (b *buffer) read(rd io.Reader) error { 324 var n int 325 n, b.err = readers.ReadFill(rd, b.buf) 326 b.buf = b.buf[0:n] 327 b.offset = 0 328 return b.err 329 } 330 331 // Return the buffer at current offset 332 func (b *buffer) buffer() []byte { 333 return b.buf[b.offset:] 334 } 335 336 // increment the offset 337 func (b *buffer) increment(n int) { 338 b.offset += n 339 }