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 }