go-hep.org/x/hep@v0.38.1/groot/rtree/basket.go (about) 1 // Copyright ©2017 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 "reflect" 11 12 "go-hep.org/x/hep/groot/rbytes" 13 "go-hep.org/x/hep/groot/riofs" 14 "go-hep.org/x/hep/groot/root" 15 "go-hep.org/x/hep/groot/rtypes" 16 "go-hep.org/x/hep/groot/rvers" 17 ) 18 19 const ( 20 kGenerateOffsetMap = 0 21 ) 22 23 type Basket struct { 24 key riofs.Key 25 26 bufsize int // length in bytes 27 nevsize int // length in int_t or fixed length of each entry 28 nevbuf int // number of entries in basket 29 last int // pointer to last used byte in basket 30 31 header bool // true when only the basket header must be read/written 32 iobits tioFeatures // IO feature flags 33 displ []int32 // displacement of entries in key.buffer 34 offsets []int32 // offset of entries in key.buffer 35 36 rbuf *rbytes.RBuffer 37 wbuf *rbytes.WBuffer 38 39 branch Branch // basket support branch 40 } 41 42 func newBasketFrom(t Tree, b Branch, cycle int16, bufsize, eoffsetLen int) Basket { 43 var ( 44 f = FileOf(t) 45 name = b.Name() 46 title = t.Name() 47 class = "TBasket" 48 ) 49 50 bkt := Basket{ 51 key: riofs.NewKeyForBasketInternal(f, name, title, class, cycle), 52 bufsize: bufsize, 53 nevsize: eoffsetLen, 54 wbuf: rbytes.NewWBuffer(nil, nil, 0, nil), 55 header: true, // FIXME(sbinet): ROOT default is "false" 56 branch: b, 57 } 58 59 bkt.offsets = rbytes.ResizeI32(bkt.offsets, bkt.nevsize) 60 return bkt 61 } 62 63 func (b *Basket) Name() string { 64 return b.key.Name() 65 } 66 67 func (b *Basket) Title() string { 68 return b.key.Title() 69 } 70 71 func (*Basket) RVersion() int16 { 72 return rvers.Basket 73 } 74 75 func (b *Basket) Class() string { 76 return "TBasket" 77 } 78 79 func (b *Basket) MarshalROOT(w *rbytes.WBuffer) (int, error) { 80 if w.Err() != nil { 81 return 0, w.Err() 82 } 83 84 beg := w.Pos() 85 86 w.WriteObject(&b.key) 87 w.WriteI16(b.RVersion()) 88 w.WriteI32(int32(b.bufsize)) 89 switch { 90 case b.iobits != 0: 91 w.WriteI32(int32(-b.nevsize)) 92 w.WriteObject(&b.iobits) 93 default: 94 w.WriteI32(int32(b.nevsize)) 95 } 96 w.WriteI32(int32(b.nevbuf)) 97 w.WriteI32(int32(b.last)) 98 99 mustGenOffsets := (len(b.offsets) > 0 && b.nevbuf > 0 && 100 (b.iobits&kGenerateOffsetMap != 0) && 101 b.canGenerateOffsetArray()) 102 103 if mustGenOffsets && len(b.displ) > 0 { 104 panic("rtree: impossible basket serialization case") 105 } 106 107 var flag byte 108 switch { 109 case b.header: 110 if mustGenOffsets { 111 flag = 80 112 } 113 w.WriteU8(flag) 114 115 default: 116 if b.nevbuf > 0 { 117 b.computeEntryOffsets() 118 } 119 flag = 1 120 if b.nevbuf <= 0 || len(b.offsets) == 0 { 121 flag = 2 122 } 123 if b.wbuf != nil { 124 flag += 10 125 } 126 127 if len(b.displ) > 0 { 128 flag += 40 129 } 130 131 if mustGenOffsets { 132 flag += 80 133 } 134 w.WriteU8(flag) 135 136 if !mustGenOffsets && len(b.offsets) > 0 && b.nevbuf > 0 { 137 w.WriteI32(int32(b.nevbuf)) 138 w.WriteArrayI32(b.offsets[:b.nevbuf]) 139 if len(b.displ) > 0 { 140 w.WriteI32(int32(b.nevbuf)) 141 w.WriteArrayI32(b.displ) 142 } 143 } 144 if b.wbuf != nil && b.wbuf.Len() > 0 { 145 raw := b.wbuf.Bytes() 146 n := min(len(raw), b.last) 147 _, err := w.Write(raw[:n]) 148 if err != nil { 149 return int(w.Pos() - beg), err 150 } 151 } 152 } 153 154 n := w.Pos() - beg 155 return int(n), w.Err() 156 } 157 158 func (b *Basket) UnmarshalROOT(r *rbytes.RBuffer) error { 159 if r.Err() != nil { 160 return r.Err() 161 } 162 163 r.ReadObject(&b.key) 164 if b.Class() != "TBasket" { 165 return fmt.Errorf("rtree: Key is not a Basket") 166 } 167 168 vers := r.ReadI16() 169 if vers > rvers.Basket { 170 return fmt.Errorf("rtree: unknown Basket version (got = %d > %d)", vers, rvers.Basket) 171 } 172 173 b.bufsize = int(r.ReadI32()) 174 b.nevsize = int(r.ReadI32()) 175 176 if b.nevsize < 0 { 177 b.nevsize = -b.nevsize 178 if err := b.iobits.UnmarshalROOT(r); err != nil { 179 r.SetErr(fmt.Errorf("rtree: could not read basket I/O bits: %w", err)) 180 return r.Err() 181 } 182 } 183 184 b.nevbuf = int(r.ReadI32()) 185 b.last = int(r.ReadI32()) 186 187 flag := r.ReadU8() 188 189 if b.last > b.bufsize { 190 b.bufsize = b.last 191 } 192 193 mustGenOffsets := false 194 if flag >= 80 { 195 mustGenOffsets = true 196 flag -= 80 197 } 198 199 switch { 200 case !mustGenOffsets && flag != 0 && (flag%10 != 2): 201 if b.nevbuf > 0 { 202 n := int(r.ReadI32()) 203 b.offsets = rbytes.ResizeI32(b.offsets, n) 204 r.ReadArrayI32(b.offsets) 205 if 20 < flag && flag < 40 { 206 for i, v := range b.offsets { 207 b.offsets[i] = int32(uint32(v) &^ rbytes.DisplacementMask) 208 } 209 } 210 } 211 if flag > 40 { 212 n := int(r.ReadI32()) 213 b.displ = rbytes.ResizeI32(b.displ, n) 214 r.ReadArrayI32(b.displ) 215 } 216 case mustGenOffsets: 217 b.offsets = nil 218 if flag <= 40 { 219 panic(fmt.Errorf("rtree: invalid basket[%s] state (flag=%v <= 40)", b.Name(), flag)) 220 } 221 } 222 223 if flag == 1 || flag > 10 { 224 // reading raw data 225 var sz = int32(b.last) 226 if vers <= 1 { 227 sz = r.ReadI32() 228 } 229 buf := make([]byte, int(sz)) 230 _, err := io.ReadFull(r, buf) 231 if err != nil { 232 r.SetErr(err) 233 return r.Err() 234 } 235 b.key.SetBuffer(buf) 236 } 237 238 return r.Err() 239 } 240 241 func (b *Basket) loadLeaf(entry int64, leaf Leaf) error { 242 var offset int64 243 if len(b.offsets) == 0 { 244 offset = entry*int64(b.nevsize) + int64(leaf.Offset()) + int64(b.key.KeyLen()) 245 } else { 246 offset = int64(b.offsets[int(entry)]) + int64(leaf.Offset()) 247 } 248 b.rbuf.SetPos(offset) 249 return leaf.readFromBuffer(b.rbuf) 250 } 251 252 func (b *Basket) computeEntryOffsets() { 253 if b.offsets != nil { 254 return 255 } 256 257 if b.branch == nil { 258 panic("rtree: basket with no associated branch") 259 } 260 261 if len(b.branch.Leaves()) != 1 { 262 panic("rtree: basket's associated branch contains multiple leaves") 263 } 264 265 leaf := b.branch.Leaves()[0] 266 b.offsets = leaf.computeOffsetArray(int(b.key.KeyLen()), b.nevbuf) 267 } 268 269 func (b *Basket) canGenerateOffsetArray() bool { 270 if len(b.branch.Leaves()) != 1 { 271 return false 272 } 273 leaf := b.branch.Leaves()[0] 274 return leaf.canGenerateOffsetArray() 275 } 276 277 func (b *Basket) update(offset int64) { 278 offset += int64(b.key.KeyLen()) 279 if len(b.offsets) > 0 { 280 if b.nevbuf+1 >= b.nevsize { 281 nevsize := max(10, 2*b.nevsize) 282 b.nevsize = nevsize 283 delta := len(b.offsets) - nevsize 284 if delta < 0 { 285 delta = -delta 286 } 287 b.offsets = append(b.offsets, make([]int32, delta)...) 288 } 289 b.offsets[b.nevbuf] = int32(offset) 290 } 291 b.nevbuf++ 292 } 293 294 func (b *Basket) grow(n int) { 295 b.nevsize = n 296 delta := len(b.offsets) - n 297 if delta < 0 { 298 delta = -delta 299 } 300 b.offsets = append(b.offsets, make([]int32, delta)...) 301 } 302 303 func (b *Basket) writeFile(f *riofs.File, compr int32) (totBytes int64, zipBytes int64, err error) { 304 header := b.header 305 b.header = true 306 defer func() { 307 b.header = header 308 }() 309 310 // we need to handle the case for a basket being created 311 // while the file was small, and *then* being flushed while 312 // the file is big. 313 // ie: the TKey structure switched to 64b offsets, and add an 314 // extra 8bytes. 315 // we need to propagate to the 'offsets' and 'last' fields. 316 adjust := !(b.key.RVersion() > 1000) && f.IsBigFile() 317 318 b.last = int(int64(b.key.KeyLen()) + b.wbuf.Len()) 319 if b.offsets != nil { 320 if adjust { 321 for i, v := range b.offsets { 322 b.offsets[i] = v + 8 323 } 324 } 325 b.wbuf.WriteI32(int32(b.nevbuf + 1)) 326 b.wbuf.WriteArrayI32(b.offsets[:b.nevbuf]) 327 b.wbuf.WriteI32(0) 328 } 329 b.key, err = riofs.NewKey(nil, b.key.Name(), b.key.Title(), b.Class(), int16(b.key.Cycle()), b.wbuf.Bytes(), f, riofs.WithKeyCompression(compr)) 330 if err != nil { 331 return 0, 0, fmt.Errorf("rtree: could not create basket-key: %w", err) 332 } 333 if adjust { 334 b.last += 8 335 } 336 337 nbytes := b.key.KeyLen() + b.key.ObjLen() 338 buf := rbytes.NewWBuffer(make([]byte, nbytes), nil, uint32(b.key.KeyLen()), f) 339 _, err = b.MarshalROOT(buf) 340 if err != nil { 341 return 0, 0, err 342 } 343 344 n, err := f.WriteAt(buf.Bytes(), b.key.SeekKey()) 345 if err != nil { 346 return int64(n), int64(n), err 347 } 348 nn, err := f.WriteAt(b.key.Buffer(), b.key.SeekKey()+int64(b.key.KeyLen())) 349 n += nn 350 if err != nil { 351 return int64(n), int64(n), err 352 } 353 b.wbuf = nil 354 b.key.SetBuffer(nil) 355 356 return int64(nbytes), int64(b.key.Nbytes()), nil 357 } 358 359 func init() { 360 f := func() reflect.Value { 361 o := &Basket{} 362 return reflect.ValueOf(o) 363 } 364 rtypes.Factory.Add("TBasket", f) 365 } 366 367 var ( 368 _ root.Object = (*Basket)(nil) 369 _ root.Named = (*Basket)(nil) 370 _ rbytes.Marshaler = (*Basket)(nil) 371 _ rbytes.Unmarshaler = (*Basket)(nil) 372 )