github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/index/zm_test.go (about) 1 // Copyright 2021 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package index 16 17 import ( 18 "bytes" 19 "testing" 20 21 "github.com/matrixorigin/matrixone/pkg/common/mpool" 22 "github.com/matrixorigin/matrixone/pkg/container/types" 23 "github.com/matrixorigin/matrixone/pkg/container/vector" 24 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 25 "github.com/stretchr/testify/require" 26 ) 27 28 type testArithRes struct { 29 zm ZM 30 ok bool 31 } 32 33 type testCase struct { 34 v1 ZM 35 v2 ZM 36 37 // gt,lt,ge,le,inter,and,or, 38 expects [][2]bool 39 // +,-,* 40 arithExpects []*testArithRes 41 idx int 42 } 43 44 var testCases = []*testCase{ 45 { 46 v1: makeZM(types.T_int64, 0, int64(-10), int64(10)), 47 v2: makeZM(types.T_int32, 0, int32(-10), int32(-10)), 48 expects: [][2]bool{ 49 {false, false}, {false, false}, {false, false}, {false, false}, 50 {false, false}, {false, false}, {false, false}, 51 }, 52 arithExpects: []*testArithRes{ 53 {ZM{}, false}, {ZM{}, false}, {ZM{}, false}, 54 }, 55 idx: 0, 56 }, 57 { 58 v1: makeZM(types.T_int32, 0, int32(-10), int32(10)), 59 v2: makeZM(types.T_int32, 0, int32(5), int32(20)), 60 expects: [][2]bool{ 61 {true, true}, {true, true}, {true, true}, {true, true}, 62 {true, true}, {false, false}, {false, false}, 63 }, 64 arithExpects: []*testArithRes{ 65 {makeZM(types.T_int32, 0, int32(-5), int32(30)), true}, 66 {makeZM(types.T_int32, 0, int32(-30), int32(5)), true}, 67 {makeZM(types.T_int32, 0, int32(-200), int32(200)), true}, 68 }, 69 idx: 1, 70 }, 71 { 72 v1: makeZM(types.T_int16, 0, int16(-10), int16(10)), 73 v2: makeZM(types.T_int16, 0, int16(10), int16(20)), 74 expects: [][2]bool{ 75 {false, true}, {true, true}, {true, true}, {true, true}, 76 {true, true}, {false, false}, {false, false}, 77 }, 78 arithExpects: []*testArithRes{ 79 {makeZM(types.T_int16, 0, int16(0), int16(30)), true}, 80 {makeZM(types.T_int16, 0, int16(-30), int16(0)), true}, 81 {makeZM(types.T_int16, 0, int16(-200), int16(200)), true}, 82 }, 83 idx: 2, 84 }, 85 { 86 v1: makeZM(types.T_decimal128, 5, types.Decimal128{B0_63: 3, B64_127: 0}, types.Decimal128{B0_63: 20, B64_127: 0}), 87 v2: makeZM(types.T_decimal128, 8, types.Decimal128{B0_63: 1, B64_127: 0}, types.Decimal128{B0_63: 4, B64_127: 0}), 88 expects: [][2]bool{ 89 {true, true}, {false, true}, {true, true}, {false, true}, 90 {false, true}, {false, false}, {false, false}, 91 }, 92 arithExpects: []*testArithRes{ 93 {makeZM(types.T_decimal128, 8, types.Decimal128{B0_63: 3001, B64_127: 0}, types.Decimal128{B0_63: 20004, B64_127: 0}), true}, 94 {makeZM(types.T_decimal128, 8, types.Decimal128{B0_63: 2996, B64_127: 0}, types.Decimal128{B0_63: 19999, B64_127: 0}), true}, 95 {makeZM(types.T_decimal128, 12, types.Decimal128{B0_63: 0, B64_127: 0}, types.Decimal128{B0_63: 8, B64_127: 0}), true}, 96 }, 97 idx: 3, 98 }, 99 { 100 v1: makeZM(types.T_decimal64, 5, types.Decimal64(3), types.Decimal64(20)), 101 v2: makeZM(types.T_decimal64, 8, types.Decimal64(1), types.Decimal64(4)), 102 expects: [][2]bool{ 103 {true, true}, {false, true}, {true, true}, {false, true}, 104 {false, true}, {false, false}, {false, false}, 105 }, 106 arithExpects: []*testArithRes{ 107 {makeZM(types.T_decimal64, 8, types.Decimal64(3001), types.Decimal64(20004)), true}, 108 {makeZM(types.T_decimal64, 8, types.Decimal64(2996), types.Decimal64(19999)), true}, 109 {makeZM(types.T_decimal64, 12, types.Decimal64(3), types.Decimal64(80)), true}, 110 }, 111 idx: 4, 112 }, 113 } 114 115 func makeZM(t types.T, scale int32, minv, maxv any) ZM { 116 zm := NewZM(t, scale) 117 zm.Update(minv) 118 zm.Update(maxv) 119 return zm 120 } 121 122 func runCompare(tc *testCase) [][2]bool { 123 r := make([][2]bool, 0) 124 125 res, ok := tc.v1.AnyGT(tc.v2) 126 r = append(r, [2]bool{res, ok}) 127 res, ok = tc.v1.AnyLT(tc.v2) 128 r = append(r, [2]bool{res, ok}) 129 res, ok = tc.v1.AnyGE(tc.v2) 130 r = append(r, [2]bool{res, ok}) 131 res, ok = tc.v1.AnyLE(tc.v2) 132 r = append(r, [2]bool{res, ok}) 133 res, ok = tc.v1.Intersect(tc.v2) 134 r = append(r, [2]bool{res, ok}) 135 res, ok = tc.v1.And(tc.v2) 136 r = append(r, [2]bool{res, ok}) 137 res, ok = tc.v1.Or(tc.v2) 138 r = append(r, [2]bool{res, ok}) 139 140 return r 141 } 142 143 func runArith(tc *testCase) []*testArithRes { 144 r := make([]*testArithRes, 0) 145 res := ZMPlus(tc.v1, tc.v2, nil) 146 r = append(r, &testArithRes{res, res.IsInited()}) 147 res = ZMMinus(tc.v1, tc.v2, nil) 148 r = append(r, &testArithRes{res, res.IsInited()}) 149 res = ZMMulti(tc.v1, tc.v2, nil) 150 r = append(r, &testArithRes{res, res.IsInited()}) 151 return r 152 } 153 154 func TestZMOp(t *testing.T) { 155 for _, tc := range testCases[0:5] { 156 res1 := runCompare(tc) 157 for i := range tc.expects { 158 require.Equalf(t, tc.expects[i], res1[i], "[%d]compare-%d", tc.idx, i) 159 } 160 res2 := runArith(tc) 161 for i := range tc.arithExpects { 162 expect, actual := tc.arithExpects[i], res2[i] 163 if expect.ok { 164 require.Truef(t, actual.ok, "[%d]arith-%d", tc.idx, i) 165 t.Log(expect.zm.String()) 166 t.Log(actual.zm.String()) 167 require.Equalf(t, expect.zm, actual.zm, "[%d]arith-%d", tc.idx, i) 168 } else { 169 require.Falsef(t, actual.ok, "[%d]arith-%d", tc.idx, i) 170 } 171 } 172 } 173 } 174 175 func TestVectorZM(t *testing.T) { 176 m := mpool.MustNewNoFixed(t.Name()) 177 zm := NewZM(types.T_uint32, 0) 178 zm.Update(uint32(12)) 179 zm.Update(uint32(22)) 180 181 vec, err := ZMToVector(zm, nil, m) 182 require.NoError(t, err) 183 require.Equal(t, 2, vec.Length()) 184 require.False(t, vec.IsConst()) 185 require.False(t, vec.GetNulls().Any()) 186 require.Equal(t, uint32(12), vector.GetFixedAt[uint32](vec, 0)) 187 require.Equal(t, uint32(22), vector.GetFixedAt[uint32](vec, 1)) 188 189 zm2 := VectorToZM(vec, nil) 190 require.Equal(t, zm, zm2) 191 vec.Free(m) 192 193 zm = NewZM(types.T_char, 0) 194 zm.Update([]byte("abc")) 195 zm.Update([]byte("xyz")) 196 197 vec, err = ZMToVector(zm, nil, m) 198 require.NoError(t, err) 199 require.Equal(t, 2, vec.Length()) 200 require.False(t, vec.IsConst()) 201 require.False(t, vec.GetNulls().Any()) 202 require.Equal(t, []byte("abc"), vec.GetBytesAt(0)) 203 require.Equal(t, []byte("xyz"), vec.GetBytesAt(1)) 204 205 zm2 = VectorToZM(vec, nil) 206 require.Equal(t, zm, zm2) 207 vec.Free(m) 208 209 zm.Update(MaxBytesValue) 210 require.True(t, zm.MaxTruncated()) 211 212 vec, err = ZMToVector(zm, nil, m) 213 require.NoError(t, err) 214 require.Equal(t, 2, vec.Length()) 215 require.False(t, vec.IsConst()) 216 require.False(t, vec.GetNulls().Contains(0)) 217 require.True(t, vec.GetNulls().Contains(1)) 218 require.Equal(t, []byte("abc"), vec.GetBytesAt(0)) 219 220 zm2 = VectorToZM(vec, nil) 221 require.True(t, zm2.MaxTruncated()) 222 require.Equal(t, []byte("abc"), zm2.GetMinBuf()) 223 require.Equal(t, zm, zm2) 224 225 vec.Free(m) 226 227 zm = NewZM(types.T_uint16, 0) 228 vec, err = ZMToVector(zm, vec, m) 229 230 require.NoError(t, err) 231 require.Equal(t, 2, vec.Length()) 232 require.True(t, vec.IsConstNull()) 233 234 zm2 = VectorToZM(vec, nil) 235 require.False(t, zm2.IsInited()) 236 237 vec.Free(m) 238 239 require.Zero(t, m.CurrNB()) 240 } 241 242 func TestZMArray(t *testing.T) { 243 zm := NewZM(types.T_array_float32, 0) 244 zm.Update(types.ArrayToBytes[float32]([]float32{1, 1, 1})) 245 zm.Update(types.ArrayToBytes[float32]([]float32{5, 5, 5})) 246 247 require.True(t, zm.IsArray()) 248 require.False(t, zm.IsInited()) 249 250 require.Nil(t, zm.GetMin()) 251 require.Nil(t, zm.GetMax()) 252 253 require.Equal(t, 0, len(zm.GetMinBuf())) 254 require.Equal(t, 0, len(zm.GetMaxBuf())) 255 256 require.False(t, zm.ContainsKey(types.ArrayToBytes[float32]([]float32{1, 1, 1}))) 257 require.False(t, zm.ContainsKey(types.ArrayToBytes[float32]([]float32{5, 5, 5}))) 258 require.False(t, zm.ContainsKey(types.ArrayToBytes[float32]([]float32{3, 3, 3}))) 259 } 260 261 func TestZMNull(t *testing.T) { 262 zm := NewZM(types.T_int64, 0) 263 x := zm.GetMin() 264 require.Nil(t, x) 265 y := zm.GetMax() 266 require.Nil(t, y) 267 268 require.Equal(t, 8, len(zm.GetMinBuf())) 269 require.Equal(t, 8, len(zm.GetMaxBuf())) 270 271 require.False(t, zm.Contains(int64(-1))) 272 require.False(t, zm.Contains(int64(0))) 273 require.False(t, zm.Contains(int64(1))) 274 } 275 276 func TestZmStringCompose(t *testing.T) { 277 packer := types.NewPacker(mpool.MustNewNoFixed("TestZmCompose")) 278 packer.EncodeStringType([]byte("0123456789.0123456789.0123456789.")) 279 packer.EncodeInt32(42) 280 281 zm1 := BuildZM(types.T_varchar, packer.Bytes()) 282 require.NotPanics(t, func() { 283 t.Log(zm1.StringForCompose()) 284 }) 285 286 packer.Reset() 287 288 packer.EncodeStringType([]byte("0123456789.")) 289 packer.EncodeInt32(42) 290 291 zm2 := BuildZM(types.T_varchar, packer.Bytes()) 292 require.NotPanics(t, func() { 293 t.Log(zm2.StringForCompose()) 294 }) 295 296 } 297 298 func TestZM(t *testing.T) { 299 int64v := int64(100) 300 zm1 := BuildZM(types.T_int64, types.EncodeInt64(&int64v)) 301 require.Equal(t, int64v, zm1.GetMin()) 302 require.Equal(t, int64v, zm1.GetMax()) 303 304 i64l := int64v - 200 305 i64h := int64v + 100 306 require.True(t, zm1.ContainsKey(types.EncodeInt64(&int64v))) 307 require.False(t, zm1.ContainsKey(types.EncodeInt64(&i64l))) 308 require.False(t, zm1.ContainsKey(types.EncodeInt64(&i64h))) 309 310 UpdateZMAny(zm1, i64l) 311 t.Log(zm1.String()) 312 require.True(t, zm1.ContainsKey(types.EncodeInt64(&int64v))) 313 require.True(t, zm1.ContainsKey(types.EncodeInt64(&i64l))) 314 require.False(t, zm1.ContainsKey(types.EncodeInt64(&i64h))) 315 316 UpdateZMAny(zm1, i64h) 317 t.Log(zm1.String()) 318 require.True(t, zm1.ContainsKey(types.EncodeInt64(&int64v))) 319 require.True(t, zm1.ContainsKey(types.EncodeInt64(&i64l))) 320 require.True(t, zm1.ContainsKey(types.EncodeInt64(&i64h))) 321 322 minv := bytes.Repeat([]byte{0x00}, 31) 323 maxv := bytes.Repeat([]byte{0xff}, 31) 324 maxv[3] = 0x00 325 326 v2 := bytes.Repeat([]byte{0x00}, 29) 327 v3 := bytes.Repeat([]byte{0x00}, 30) 328 329 zm2 := BuildZM(types.T_varchar, minv) 330 require.False(t, zm2.ContainsKey([]byte(""))) 331 require.False(t, zm2.ContainsKey(v2)) 332 require.True(t, zm2.ContainsKey(v3)) 333 334 UpdateZM(zm2, maxv) 335 require.False(t, zm2.MaxTruncated()) 336 t.Log(zm2.String()) 337 require.True(t, zm2.ContainsKey(maxv)) 338 339 maxv[3] = 0xff 340 UpdateZM(zm2, maxv) 341 t.Log(zm2.String()) 342 require.True(t, zm2.MaxTruncated()) 343 344 v4 := bytes.Repeat([]byte{0xff}, 100) 345 require.True(t, zm2.ContainsKey(v4)) 346 347 buf, _ := zm2.Marshal() 348 zm3 := DecodeZM(buf) 349 t.Log(zm3.String()) 350 require.Equal(t, zm2.GetMinBuf(), zm3.GetMinBuf()) 351 require.Equal(t, zm2.GetMaxBuf(), zm3.GetMaxBuf()) 352 require.True(t, zm3.MaxTruncated()) 353 354 { // bit 355 v := uint64(500) 356 zm := BuildZM(types.T_bit, types.EncodeUint64(&v)) 357 require.Equal(t, v, zm.GetMin()) 358 require.Equal(t, v, zm.GetMax()) 359 360 vMin := v - 200 361 vMax := v + 100 362 require.True(t, zm.ContainsKey(types.EncodeUint64(&v))) 363 require.False(t, zm.ContainsKey(types.EncodeUint64(&vMin))) 364 require.False(t, zm.ContainsKey(types.EncodeUint64(&vMax))) 365 366 UpdateZMAny(zm, vMin) 367 t.Log(zm.String()) 368 require.True(t, zm.ContainsKey(types.EncodeUint64(&v))) 369 require.True(t, zm.ContainsKey(types.EncodeUint64(&vMin))) 370 require.False(t, zm.ContainsKey(types.EncodeUint64(&vMax))) 371 372 UpdateZMAny(zm, vMax) 373 t.Log(zm.String()) 374 require.True(t, zm.ContainsKey(types.EncodeUint64(&v))) 375 require.True(t, zm.ContainsKey(types.EncodeUint64(&vMin))) 376 require.True(t, zm.ContainsKey(types.EncodeUint64(&vMax))) 377 378 require.Equal(t, vMin, zm.GetMin()) 379 require.Equal(t, vMax, zm.GetMax()) 380 } 381 } 382 383 func TestZMSum(t *testing.T) { 384 testIntSum(t, types.T_int8) 385 testIntSum(t, types.T_int16) 386 testIntSum(t, types.T_int32) 387 testIntSum(t, types.T_int64) 388 testUIntSum(t, types.T_uint8) 389 testUIntSum(t, types.T_uint16) 390 testUIntSum(t, types.T_uint32) 391 testUIntSum(t, types.T_uint64) 392 testUIntSum(t, types.T_bit) 393 testFloatSum(t, types.T_float32) 394 testFloatSum(t, types.T_float64) 395 testDecimal64Sum(t) 396 } 397 398 func testIntSum(t *testing.T, zmType types.T) { 399 zm := NewZM(zmType, 0) 400 zm.setInited() 401 require.Equal(t, int64(0), zm.GetSum()) 402 sum := int64(100) 403 zm.SetSum(types.EncodeFixed(sum)) 404 require.Equal(t, sum, zm.GetSum()) 405 } 406 407 func testUIntSum(t *testing.T, zmType types.T) { 408 zm := NewZM(zmType, 0) 409 zm.setInited() 410 require.Equal(t, uint64(0), zm.GetSum()) 411 sum := uint64(100) 412 zm.SetSum(types.EncodeFixed(sum)) 413 require.Equal(t, sum, zm.GetSum()) 414 } 415 416 func testFloatSum(t *testing.T, zmType types.T) { 417 zm := NewZM(zmType, 0) 418 zm.setInited() 419 require.Equal(t, float64(0), zm.GetSum()) 420 sum := float64(100) 421 zm.SetSum(types.EncodeFixed(sum)) 422 require.Equal(t, sum, zm.GetSum()) 423 } 424 425 func testDecimal64Sum(t *testing.T) { 426 zm := NewZM(types.T_decimal64, 0) 427 zm.setInited() 428 require.Equal(t, types.Decimal64(0), zm.GetSum()) 429 sum := types.Decimal64(100) 430 zm.SetSum(types.EncodeFixed(sum)) 431 require.Equal(t, sum, zm.GetSum()) 432 } 433 434 func BenchmarkZM(b *testing.B) { 435 vec := containers.MockVector(types.T_char.ToType(), 10000, true, nil) 436 defer vec.Close() 437 var bs [][]byte 438 for i := 0; i < vec.Length(); i++ { 439 bs = append(bs, vec.Get(i).([]byte)) 440 } 441 442 zm := NewZM(vec.GetType().Oid, 0) 443 b.Run("build-bytes-zm", func(b *testing.B) { 444 b.ResetTimer() 445 for i := 0; i < b.N; i++ { 446 UpdateZM(zm, bs[i%vec.Length()]) 447 } 448 }) 449 b.Run("get-bytes-zm", func(b *testing.B) { 450 b.ResetTimer() 451 for i := 0; i < b.N; i++ { 452 zm.GetMin() 453 } 454 }) 455 456 vec = containers.MockVector(types.T_float64.ToType(), 10000, true, nil) 457 defer vec.Close() 458 var vs []float64 459 for i := 0; i < vec.Length(); i++ { 460 vs = append(vs, vec.Get(i).(float64)) 461 } 462 463 zm = NewZM(vec.GetType().Oid, 0) 464 b.Run("build-f64-zm", func(b *testing.B) { 465 b.ResetTimer() 466 for i := 0; i < b.N*5; i++ { 467 k := types.EncodeFloat64(&vs[i%vec.Length()]) 468 UpdateZM(zm, k) 469 } 470 }) 471 b.Run("get-f64-zm", func(b *testing.B) { 472 b.ResetTimer() 473 for i := 0; i < b.N*5; i++ { 474 zm.GetMax() 475 } 476 }) 477 } 478 479 func BenchmarkUpdateZMVector(b *testing.B) { 480 zm := NewZM(types.T_int64, 0) 481 tnVec := containers.MockVector(types.T_int64.ToType(), 10000, false, nil) 482 defer tnVec.Close() 483 vec := tnVec.GetDownstreamVector() 484 485 b.Run("update-vector", func(b *testing.B) { 486 b.ResetTimer() 487 for i := 0; i < b.N; i++ { 488 BatchUpdateZM(zm, vec) 489 } 490 }) 491 }