github.com/GuanceCloud/cliutils@v1.1.21/point/encode_v2.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package point 7 8 // EncodeV2 set points to be encoded. 9 func (e *Encoder) EncodeV2(pts []*Point) { 10 e.pts = pts 11 } 12 13 // Next is a iterator that return encoded data in prepared buf. 14 // If all points encoded done, return false. 15 // If any error occurred, we can get the error by call e.LastErr(). 16 func (e *Encoder) Next(buf []byte) ([]byte, bool) { 17 switch e.enc { 18 case Protobuf: 19 return e.doEncodeProtobuf(buf) 20 case LineProtocol: 21 return e.doEncodeLineProtocol(buf) 22 case JSON: 23 return e.doEncodeJSON(buf) 24 case PBJSON: 25 return e.doEncodePBJSON(buf) 26 default: // TODO: json 27 return nil, false 28 } 29 } 30 31 func (e *Encoder) doEncodeProtobuf(buf []byte) ([]byte, bool) { 32 var ( 33 curSize, 34 pbptsSize int 35 trimmed = 1 36 ) 37 38 for _, pt := range e.pts[e.lastPtsIdx:] { 39 if pt == nil { 40 continue 41 } 42 43 curSize += pt.Size() 44 45 // e.pbpts size larger than buf, we must trim some of points 46 // until size fit ok or MarshalTo will panic. 47 if curSize >= len(buf) { 48 if len(e.pbpts.Arr) <= 1 { // nothing to trim 49 e.lastErr = errTooSmallBuffer 50 return nil, false 51 } 52 53 for { 54 if pbptsSize = e.pbpts.Size(); pbptsSize > len(buf) { 55 e.pbpts.Arr = e.pbpts.Arr[:len(e.pbpts.Arr)-trimmed] 56 e.lastPtsIdx -= trimmed 57 trimmed *= 2 58 } else { 59 goto __doEncode 60 } 61 } 62 } else { 63 e.pbpts.Arr = append(e.pbpts.Arr, pt.pt) 64 e.lastPtsIdx++ 65 } 66 } 67 68 __doEncode: 69 e.trimmed = trimmed 70 71 if len(e.pbpts.Arr) == 0 { 72 return nil, false 73 } 74 75 defer func() { 76 e.pbpts.Arr = e.pbpts.Arr[:0] 77 }() 78 79 if n, err := e.pbpts.MarshalTo(buf); err != nil { 80 e.lastErr = err 81 return nil, false 82 } else { 83 if e.fn != nil { 84 if err := e.fn(len(e.pbpts.Arr), buf[:n]); err != nil { 85 e.lastErr = err 86 return nil, false 87 } 88 } 89 90 e.parts++ 91 return buf[:n], true 92 } 93 } 94 95 func (e *Encoder) doEncodeLineProtocol(buf []byte) ([]byte, bool) { 96 curSize := 0 97 npts := 0 98 99 for _, pt := range e.pts[e.lastPtsIdx:] { 100 if pt == nil { 101 continue 102 } 103 104 lppt, err := pt.LPPoint() 105 if err != nil { 106 e.lastErr = err 107 continue 108 } 109 110 ptsize := lppt.StringSize() 111 112 if curSize+ptsize+1 > len(buf) { // extra +1 used to store the last '\n' 113 if curSize == 0 { // nothing added 114 e.lastErr = errTooSmallBuffer 115 return nil, false 116 } 117 118 if e.fn != nil { 119 if err := e.fn(npts, buf[:curSize]); err != nil { 120 e.lastErr = err 121 return nil, false 122 } 123 } 124 e.parts++ 125 return buf[:curSize], true 126 } else { 127 e.lpPointBuf = lppt.AppendString(e.lpPointBuf) 128 129 copy(buf[curSize:], e.lpPointBuf[:ptsize]) 130 131 // Always add '\n' to the end of current point, this may 132 // cause a _unneeded_ '\n' to the end of buf, it's ok for 133 // line-protocol parsing. 134 buf[curSize+ptsize] = '\n' 135 curSize += (ptsize + 1) 136 137 // clean buffer, next time AppendString() append from byte 0 138 e.lpPointBuf = e.lpPointBuf[:0] 139 e.lastPtsIdx++ 140 npts++ 141 } 142 } 143 144 if curSize > 0 { 145 e.parts++ 146 if e.fn != nil { // NOTE: encode callback error will terminate encode 147 if err := e.fn(npts, buf[:curSize]); err != nil { 148 e.lastErr = err 149 return nil, false 150 } 151 } 152 return buf[:curSize], true 153 } else { 154 return nil, false 155 } 156 } 157 158 func (e *Encoder) doEncodeJSON(buf []byte) ([]byte, bool) { 159 return nil, false 160 } 161 162 func (e *Encoder) doEncodePBJSON(buf []byte) ([]byte, bool) { 163 return nil, false 164 }