github.com/zeebo/mon@v0.0.0-20211012163247-13d39bdb54fa/floathist/serialize.go (about)

     1  package floathist
     2  
     3  import (
     4  	"encoding/binary"
     5  	"sync/atomic"
     6  
     7  	"github.com/zeebo/errs"
     8  	"github.com/zeebo/mon/internal/buffer"
     9  )
    10  
    11  func (h *Histogram) Serialize(mem []byte) []byte {
    12  	le := binary.LittleEndian
    13  
    14  	if cap(mem) < 64 {
    15  		mem = make([]byte, 0, 64)
    16  	}
    17  	buf := buffer.Of(mem)
    18  
    19  	bm := h.l0.bm.Clone()
    20  
    21  	buf = buf.Grow()
    22  	le.PutUint32(buf.Front4()[:], bm.UnsafeUint32())
    23  	buf = buf.Advance(4)
    24  
    25  	for {
    26  		i, ok := bm.Next()
    27  		if !ok {
    28  			break
    29  		}
    30  		l1 := (*level1)(atomic.LoadPointer((*ptr)(ptr(&h.l0.l1[i]))))
    31  
    32  		bm := l1.bm.Clone()
    33  
    34  		buf = buf.Grow()
    35  		le.PutUint32(buf.Front4()[:], bm.UnsafeUint32())
    36  		buf = buf.Advance(4)
    37  
    38  		for {
    39  			i, ok := bm.Next()
    40  			if !ok {
    41  				break
    42  			}
    43  
    44  			l2 := (*level2)(atomic.LoadPointer((*ptr)(ptr(&l1.l2[i]))))
    45  			var bm b32
    46  
    47  			buf = buf.Grow()
    48  			pos := buf.Pos()
    49  			buf = buf.Advance(4)
    50  
    51  			for i := 0; i < levelSize; i++ {
    52  				val := atomic.LoadUint64(&l2[i])
    53  				if val == 0 {
    54  					continue
    55  				}
    56  
    57  				bm.UnsafeSet(uint(i))
    58  
    59  				buf = buf.Grow()
    60  				nbytes := varintAppend(buf.Front9(), val)
    61  				buf = buf.Advance(nbytes)
    62  			}
    63  
    64  			le.PutUint32(buf.Index4(pos)[:], bm.UnsafeUint32())
    65  
    66  		}
    67  	}
    68  
    69  	return buf.Prefix()
    70  }
    71  
    72  func (h *Histogram) Load(data []byte) (err error) {
    73  	le := binary.LittleEndian
    74  	buf := buffer.OfLen(data)
    75  
    76  	var bm0 b32
    77  	var bm1 b32
    78  	var bm2 b32
    79  
    80  	if buf.Remaining() < 4 {
    81  		err = errs.New("buffer too short")
    82  		goto done
    83  	}
    84  
    85  	h.l0.bm.UnsafeSetUint32(le.Uint32(buf.Front4()[:]))
    86  	buf = buf.Advance(4)
    87  
    88  	bm0 = h.l0.bm.UnsafeClone()
    89  
    90  	for {
    91  		i, ok := bm0.Next()
    92  		if !ok {
    93  			break
    94  		}
    95  
    96  		l1 := new(level1)
    97  		h.l0.l1[i] = l1
    98  
    99  		if buf.Remaining() < 4 {
   100  			err = errs.New("buffer too short")
   101  			goto done
   102  		}
   103  
   104  		l1.bm.UnsafeSetUint32(le.Uint32(buf.Front4()[:]))
   105  		buf = buf.Advance(4)
   106  
   107  		bm1 = l1.bm.UnsafeClone()
   108  
   109  		for {
   110  			i, ok := bm1.Next()
   111  			if !ok {
   112  				break
   113  			}
   114  
   115  			l2 := new(level2)
   116  			l1.l2[i] = l2
   117  
   118  			if buf.Remaining() < 4 {
   119  				err = errs.New("buffer too short")
   120  				goto done
   121  			}
   122  
   123  			bm2.UnsafeSetUint32(le.Uint32(buf.Front4()[:]))
   124  			buf = buf.Advance(4)
   125  
   126  			for {
   127  				i, ok := bm2.Next()
   128  				if !ok {
   129  					break
   130  				}
   131  
   132  				if rem := buf.Remaining(); rem >= 9 {
   133  					var nbytes uintptr
   134  					nbytes, l2[i] = fastVarintConsume(buf.Front9())
   135  					if nbytes > rem {
   136  						err = errs.New("invalid varint data")
   137  						goto done
   138  					}
   139  					buf = buf.Advance(nbytes)
   140  
   141  				} else {
   142  					l2[i], buf, ok = safeVarintConsume(buf)
   143  					if !ok {
   144  						err = errs.New("invalid varint data")
   145  						goto done
   146  					}
   147  				}
   148  			}
   149  		}
   150  	}
   151  
   152  done:
   153  	return err
   154  }