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  )