go-hep.org/x/hep@v0.38.1/groot/riofs/plugin/http/preader.go (about) 1 // Copyright ©2022 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http 6 7 import ( 8 "sync" 9 10 "go-hep.org/x/hep/groot/riofs" 11 ) 12 13 type preader struct { 14 r reader 15 n int // number of workers 16 } 17 18 var ( 19 _ riofs.Reader = (*preader)(nil) 20 ) 21 22 const blkSize = 1 * 1024 * 1024 // TODO(sbinet): adjust size for multiple payloads? 23 24 func (r *preader) Close() error { 25 return r.r.Close() 26 } 27 28 func (r *preader) Read(p []byte) (int, error) { 29 return r.r.Read(p) 30 } 31 32 func (r *preader) ReadAt(p []byte, off int64) (int, error) { 33 switch sz := len(p); { 34 default: 35 return r.r.ReadAt(p, off) 36 case sz > blkSize: 37 return r.pread(p, off) 38 } 39 } 40 41 func (r *preader) pread(p []byte, off int64) (int, error) { 42 nblks := len(p) / blkSize 43 sps := make([]span, 0, nblks+1) 44 beg := off 45 end := off + int64(len(p)) 46 for beg < end { 47 len := int64(blkSize) 48 if beg+len > end { 49 len = end - beg 50 } 51 sps = append(sps, span{ 52 off: beg, 53 len: len, 54 }) 55 beg += blkSize 56 } 57 out := make([]pread, len(sps)) 58 wrk := make(chan int, r.n) 59 go func() { 60 defer close(wrk) 61 for i := range sps { 62 wrk <- i 63 } 64 }() 65 66 var wg sync.WaitGroup 67 wg.Add(r.n) 68 for range r.n { 69 go func() { 70 defer wg.Done() 71 for i := range wrk { 72 spn := sps[i] 73 beg := int64(i) * blkSize 74 end := beg + spn.len 75 out[i].n, out[i].err = r.r.ReadAt(p[beg:end], spn.off) 76 } 77 }() 78 } 79 80 wg.Wait() 81 82 var ( 83 n int 84 err error 85 ) 86 for _, o := range out { 87 n += o.n 88 if o.err != nil { 89 err = o.err 90 } 91 } 92 return n, err 93 } 94 95 type pread struct { 96 n int 97 err error 98 }