go-hep.org/x/hep@v0.38.1/groot/rtree/bkreader.go (about)

     1  // Copyright ©2020 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 rtree
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"runtime"
    11  
    12  	"go-hep.org/x/hep/groot/riofs"
    13  )
    14  
    15  // bkreader is a read-ahead basket reader.
    16  type bkreader struct {
    17  	f     *riofs.File
    18  	spans []rspan
    19  
    20  	beg    int64         // first event to process
    21  	end    int64         // last-1 event to process (ie: [beg,end) half-open interval of entries to process)
    22  	ready  chan bkReq    // baskets ready to be handed to the reader
    23  	reuse  chan bkReq    // baskets to reuse for input reading
    24  	exit   chan struct{} // closes when finished
    25  	n      int           // number of in-flight baskets
    26  	cur    *rbasket      // current buffer being served
    27  	closed chan struct{} // channel is closed when the async reader shuts down
    28  
    29  	name string
    30  }
    31  
    32  type bkReq struct {
    33  	bkt *rbasket
    34  	err error
    35  }
    36  
    37  func newBkReader(b Branch, n int, beg, end int64) *bkreader {
    38  	if n < 0 {
    39  		n = runtime.NumCPU() + 1
    40  	}
    41  	if n == 0 {
    42  		n = 1
    43  	}
    44  	base := asBranch(b)
    45  	if m := len(base.basketSeek); n > m && m != 0 {
    46  		n = m
    47  	}
    48  	bkr := &bkreader{
    49  		f:      b.getTree().f,
    50  		spans:  make([]rspan, len(base.basketSeek)),
    51  		beg:    beg,
    52  		end:    end,
    53  		ready:  make(chan bkReq, n),
    54  		reuse:  make(chan bkReq, n),
    55  		exit:   make(chan struct{}),
    56  		n:      n,
    57  		closed: make(chan struct{}),
    58  		name:   b.Name(),
    59  	}
    60  
    61  	if len(base.basketEntry) == len(base.basketSeek) {
    62  		numBaskets := 0
    63  		for i, v := range base.basketSeek {
    64  			if v == 0 || i == base.writeBasket {
    65  				break
    66  			}
    67  			numBaskets++
    68  		}
    69  		if numBaskets > 0 {
    70  			base.basketSeek = base.basketSeek[:numBaskets]
    71  			bkr.spans = bkr.spans[:len(base.basketSeek)]
    72  		}
    73  
    74  		// prepare for recover basket mode.
    75  		base.basketEntry = append(base.basketEntry, 0)
    76  		bkr.spans[0] = rspan{
    77  			pos: base.basketSeek[0],
    78  			sz:  base.basketBytes[0],
    79  			beg: base.basketEntry[0],
    80  			end: base.basketEntry[0+1],
    81  		}
    82  	} else {
    83  		for i, seek := range base.basketSeek {
    84  			bkr.spans[i] = rspan{
    85  				pos: seek,
    86  				sz:  base.basketBytes[i],
    87  				beg: base.basketEntry[i],
    88  				end: base.basketEntry[i+1],
    89  			}
    90  		}
    91  	}
    92  
    93  	for range n {
    94  		bkr.reuse <- bkReq{bkt: new(rbasket), err: nil}
    95  	}
    96  
    97  	switch {
    98  	case base.entries == base.basketEntry[len(base.basketSeek)]:
    99  		if len(bkr.spans) == 0 && base.entries == 0 {
   100  			bkr.spans = append(bkr.spans, rspan{
   101  				beg: 0,
   102  				end: -1,
   103  			})
   104  		}
   105  	default: // recover baskets
   106  		var beg int64
   107  		if len(bkr.spans) > 0 {
   108  			beg = bkr.spans[len(bkr.spans)-1].end
   109  		}
   110  		for i := range base.baskets {
   111  			bkt := &base.baskets[i]
   112  			span := rspan{
   113  				pos: 0,
   114  				beg: beg,
   115  				end: beg + int64(bkt.nevbuf),
   116  				bkt: bkt,
   117  			}
   118  			bkr.spans = append(bkr.spans, span)
   119  			beg = span.end
   120  		}
   121  	}
   122  
   123  	all := rspan{
   124  		beg: bkr.spans[0].beg,
   125  		end: bkr.spans[len(bkr.spans)-1].end,
   126  	}
   127  
   128  	if beg >= all.end {
   129  		// empty range: no need to run prefetch loop.
   130  		defer close(bkr.closed)
   131  		defer close(bkr.ready)
   132  		return bkr
   133  	}
   134  
   135  	ibeg, iend := bkr.findBaskets(beg, end)
   136  	if ibeg < 0 || iend < 0 {
   137  		panic(fmt.Errorf(
   138  			"rtree: could not find basket index for span [%d, %d): [%d, %d), spans: %#v",
   139  			beg, end, ibeg, iend, bkr.spans,
   140  		))
   141  	}
   142  
   143  	go bkr.run(base.entryOffsetLen, ibeg, iend)
   144  
   145  	return bkr
   146  }
   147  
   148  func (bkr *bkreader) findBaskets(beg, end int64) (int, int) {
   149  	var (
   150  		ibeg = -1
   151  		iend = -1
   152  	)
   153  	for i, v := range bkr.spans {
   154  		if ibeg < 0 && (v.beg <= beg && beg < v.end) {
   155  			ibeg = i
   156  		}
   157  		if iend < 0 && (end <= v.end) {
   158  			iend = i + 1
   159  		}
   160  	}
   161  	if iend < 0 {
   162  		iend = len(bkr.spans)
   163  	}
   164  
   165  	return ibeg, iend
   166  }
   167  
   168  func (bkr *bkreader) run(eoff, beg, end int) {
   169  	defer close(bkr.closed)
   170  	defer close(bkr.ready)
   171  	for i, span := range bkr.spans[beg:end] {
   172  		select {
   173  		case tok := <-bkr.reuse:
   174  			tok.err = tok.bkt.inflate(bkr.name, beg+i, span, eoff, bkr.f)
   175  			bkr.ready <- tok
   176  		case <-bkr.exit:
   177  			return
   178  		}
   179  	}
   180  }
   181  
   182  func (bkr *bkreader) read() (*rbasket, error) {
   183  	if bkr.cur != nil {
   184  		bkr.cur.reset()
   185  		bkr.reuse <- bkReq{bkt: bkr.cur, err: nil}
   186  		bkr.cur = nil
   187  	}
   188  	tok, ok := <-bkr.ready
   189  	if !ok {
   190  		return nil, io.EOF
   191  	}
   192  	bkr.cur = tok.bkt
   193  
   194  	return bkr.cur, tok.err
   195  }
   196  
   197  func (bkr *bkreader) close() {
   198  	select {
   199  	case <-bkr.closed:
   200  	case bkr.exit <- struct{}{}:
   201  		<-bkr.closed
   202  	}
   203  }
   204  
   205  type rspan struct {
   206  	beg int64 // first entry
   207  	end int64 // last entry
   208  
   209  	pos int64 // span location on-disk
   210  	sz  int32 // basket size
   211  
   212  	// for recovered baskets
   213  	bkt *Basket
   214  }