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 }