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  }