github.com/m3db/m3@v1.5.0/src/dbnode/encoding/proto/int_encoder_iterator.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package proto 22 23 import ( 24 "fmt" 25 26 "github.com/m3db/m3/src/dbnode/encoding" 27 "github.com/m3db/m3/src/dbnode/encoding/m3tsz" 28 ) 29 30 type intEncoderAndIterator struct { 31 prevIntBits uint64 32 intSigBitsTracker m3tsz.IntSigBitsTracker 33 unsigned bool 34 hasEncodedFirst bool 35 } 36 37 func (eit *intEncoderAndIterator) encodeSignedIntValue(stream encoding.OStream, v int64) { 38 if eit.hasEncodedFirst { 39 eit.encodeNextSignedIntValue(stream, v) 40 } else { 41 eit.encodeFirstSignedIntValue(stream, v) 42 eit.hasEncodedFirst = true 43 } 44 } 45 46 func (eit *intEncoderAndIterator) encodeUnsignedIntValue(stream encoding.OStream, v uint64) { 47 if eit.hasEncodedFirst { 48 eit.encodeNextUnsignedIntValue(stream, v) 49 } else { 50 eit.encodeFirstUnsignedIntValue(stream, v) 51 eit.hasEncodedFirst = true 52 } 53 } 54 55 func (eit *intEncoderAndIterator) encodeFirstSignedIntValue(stream encoding.OStream, v int64) { 56 neg := false 57 eit.prevIntBits = uint64(v) 58 if v < 0 { 59 neg = true 60 v = -1 * v 61 } 62 63 vBits := uint64(v) 64 numSig := encoding.NumSig(vBits) 65 66 eit.intSigBitsTracker.WriteIntSig(stream, numSig) 67 eit.encodeIntValDiff(stream, vBits, neg, numSig) 68 } 69 70 func (eit *intEncoderAndIterator) encodeFirstUnsignedIntValue(stream encoding.OStream, v uint64) { 71 eit.prevIntBits = v 72 73 numSig := encoding.NumSig(v) 74 eit.intSigBitsTracker.WriteIntSig(stream, numSig) 75 eit.encodeIntValDiff(stream, v, false, numSig) 76 } 77 78 func (eit *intEncoderAndIterator) encodeNextSignedIntValue(stream encoding.OStream, next int64) { 79 prev := int64(eit.prevIntBits) 80 diff := next - prev 81 if diff == 0 { 82 stream.WriteBit(opCodeNoChange) 83 return 84 } 85 86 stream.WriteBit(opCodeChange) 87 88 neg := false 89 if diff < 0 { 90 neg = true 91 diff = -1 * diff 92 } 93 94 var ( 95 diffBits = uint64(diff) 96 numSig = encoding.NumSig(diffBits) 97 newSig = eit.intSigBitsTracker.TrackNewSig(numSig) 98 ) 99 100 eit.intSigBitsTracker.WriteIntSig(stream, newSig) 101 eit.encodeIntValDiff(stream, diffBits, neg, newSig) 102 eit.prevIntBits = uint64(next) 103 } 104 105 func (eit *intEncoderAndIterator) encodeNextUnsignedIntValue(stream encoding.OStream, next uint64) { 106 var ( 107 neg = false 108 prev = eit.prevIntBits 109 diff uint64 110 ) 111 112 // Avoid overflows. 113 if next > prev { 114 diff = next - prev 115 } else { 116 neg = true 117 diff = prev - next 118 } 119 120 if diff == 0 { 121 stream.WriteBit(opCodeNoChange) 122 return 123 } 124 125 stream.WriteBit(opCodeChange) 126 127 numSig := encoding.NumSig(diff) 128 newSig := eit.intSigBitsTracker.TrackNewSig(numSig) 129 130 eit.intSigBitsTracker.WriteIntSig(stream, newSig) 131 eit.encodeIntValDiff(stream, diff, neg, newSig) 132 eit.prevIntBits = next 133 } 134 135 func (eit *intEncoderAndIterator) encodeIntValDiff(stream encoding.OStream, valBits uint64, neg bool, numSig uint8) { 136 if neg { 137 // opCodeNegative 138 stream.WriteBit(opCodeIntDeltaNegative) 139 } else { 140 // opCodePositive 141 stream.WriteBit(opCodeIntDeltaPositive) 142 } 143 144 stream.WriteBits(valBits, int(numSig)) 145 } 146 147 func (eit *intEncoderAndIterator) readIntValue(stream *encoding.IStream) error { 148 if eit.hasEncodedFirst { 149 changeExistsControlBit, err := stream.ReadBit() 150 if err != nil { 151 return fmt.Errorf( 152 "%s: error trying to read int change exists control bit: %v", 153 itErrPrefix, err) 154 } 155 156 if changeExistsControlBit == opCodeNoChange { 157 // No change. 158 return nil 159 } 160 } 161 162 if err := eit.readIntSig(stream); err != nil { 163 return fmt.Errorf( 164 "%s error trying to read number of significant digits: %v", 165 itErrPrefix, err) 166 } 167 168 if err := eit.readIntValDiff(stream); err != nil { 169 return fmt.Errorf( 170 "%s error trying to read int diff: %v", 171 itErrPrefix, err) 172 } 173 174 if !eit.hasEncodedFirst { 175 eit.hasEncodedFirst = true 176 } 177 178 return nil 179 } 180 181 func (eit *intEncoderAndIterator) readIntSig(stream *encoding.IStream) error { 182 updateControlBit, err := stream.ReadBit() 183 if err != nil { 184 return fmt.Errorf( 185 "%s error reading int significant digits update control bit: %v", 186 itErrPrefix, err) 187 } 188 if updateControlBit == opCodeNoChange { 189 // No change. 190 return nil 191 } 192 193 sigDigitsControlBit, err := stream.ReadBit() 194 if err != nil { 195 return fmt.Errorf( 196 "%s error reading zero significant digits control bit: %v", 197 itErrPrefix, err) 198 } 199 if sigDigitsControlBit == m3tsz.OpcodeZeroSig { 200 eit.intSigBitsTracker.NumSig = 0 201 } else { 202 numSigBits, err := stream.ReadBits(6) 203 if err != nil { 204 return fmt.Errorf( 205 "%s error reading number of significant digits: %v", 206 itErrPrefix, err) 207 } 208 209 eit.intSigBitsTracker.NumSig = uint8(numSigBits) + 1 210 } 211 212 return nil 213 } 214 215 func (eit *intEncoderAndIterator) readIntValDiff(stream *encoding.IStream) error { 216 negativeControlBit, err := stream.ReadBit() 217 if err != nil { 218 return fmt.Errorf( 219 "%s error reading negative control bit: %v", 220 itErrPrefix, err) 221 } 222 223 numSig := eit.intSigBitsTracker.NumSig 224 diffSigBits, err := stream.ReadBits(numSig) 225 if err != nil { 226 return fmt.Errorf( 227 "%s error reading significant digits: %v", 228 itErrPrefix, err) 229 } 230 231 if eit.unsigned { 232 diff := diffSigBits 233 shouldSubtract := false 234 if negativeControlBit == opCodeIntDeltaNegative { 235 shouldSubtract = true 236 } 237 238 prev := eit.prevIntBits 239 if shouldSubtract { 240 eit.prevIntBits = prev - diff 241 } else { 242 eit.prevIntBits = prev + diff 243 } 244 } else { 245 diff := int64(diffSigBits) 246 sign := int64(1) 247 if negativeControlBit == opCodeIntDeltaNegative { 248 sign = -1.0 249 } 250 251 prev := int64(eit.prevIntBits) 252 eit.prevIntBits = uint64(prev + (sign * diff)) 253 } 254 255 return nil 256 }