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  }