github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/soliton/chunk/list_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package chunk
    15  
    16  import (
    17  	"math"
    18  	"math/rand"
    19  	"strconv"
    20  	"strings"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/cznic/mathutil"
    25  	"github.com/whtcorpsinc/check"
    26  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    27  	"github.com/whtcorpsinc/milevadb/types"
    28  	"github.com/whtcorpsinc/milevadb/types/json"
    29  )
    30  
    31  func (s *testChunkSuite) TestList(c *check.C) {
    32  	fields := []*types.FieldType{
    33  		types.NewFieldType(allegrosql.TypeLonglong),
    34  	}
    35  	l := NewList(fields, 2, 2)
    36  	srcChunk := NewChunkWithCapacity(fields, 32)
    37  	srcChunk.AppendInt64(0, 1)
    38  	srcRow := srcChunk.GetRow(0)
    39  
    40  	// Test basic append.
    41  	for i := 0; i < 5; i++ {
    42  		l.AppendRow(srcRow)
    43  	}
    44  	c.Assert(l.NumChunks(), check.Equals, 3)
    45  	c.Assert(l.Len(), check.Equals, 5)
    46  	c.Assert(len(l.freelist), check.Equals, 0)
    47  
    48  	// Test chunk reuse.
    49  	l.Reset()
    50  	c.Assert(len(l.freelist), check.Equals, 3)
    51  
    52  	for i := 0; i < 5; i++ {
    53  		l.AppendRow(srcRow)
    54  	}
    55  	c.Assert(len(l.freelist), check.Equals, 0)
    56  
    57  	// Test add chunk then append event.
    58  	l.Reset()
    59  	nChunk := NewChunkWithCapacity(fields, 32)
    60  	nChunk.AppendNull(0)
    61  	l.Add(nChunk)
    62  	ptr := l.AppendRow(srcRow)
    63  	c.Assert(l.NumChunks(), check.Equals, 2)
    64  	c.Assert(ptr.ChkIdx, check.Equals, uint32(1))
    65  	c.Assert(ptr.RowIdx, check.Equals, uint32(0))
    66  	event := l.GetRow(ptr)
    67  	c.Assert(event.GetInt64(0), check.Equals, int64(1))
    68  
    69  	// Test iteration.
    70  	l.Reset()
    71  	for i := 0; i < 5; i++ {
    72  		tmp := NewChunkWithCapacity(fields, 32)
    73  		tmp.AppendInt64(0, int64(i))
    74  		l.AppendRow(tmp.GetRow(0))
    75  	}
    76  	expected := []int64{0, 1, 2, 3, 4}
    77  	var results []int64
    78  	err := l.Walk(func(r Row) error {
    79  		results = append(results, r.GetInt64(0))
    80  		return nil
    81  	})
    82  	c.Assert(err, check.IsNil)
    83  	c.Assert(results, check.DeepEquals, expected)
    84  }
    85  
    86  func (s *testChunkSuite) TestListMemoryUsage(c *check.C) {
    87  	fieldTypes := make([]*types.FieldType, 0, 5)
    88  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeFloat})
    89  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeVarchar})
    90  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeJSON})
    91  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeDatetime})
    92  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeDuration})
    93  
    94  	jsonObj, err := json.ParseBinaryFromString("1")
    95  	c.Assert(err, check.IsNil)
    96  	timeObj := types.NewTime(types.FromGoTime(time.Now()), allegrosql.TypeDatetime, 0)
    97  	durationObj := types.Duration{Duration: math.MaxInt64, Fsp: 0}
    98  
    99  	maxChunkSize := 2
   100  	srcChk := NewChunkWithCapacity(fieldTypes, maxChunkSize)
   101  	srcChk.AppendFloat32(0, 12.4)
   102  	srcChk.AppendString(1, "123")
   103  	srcChk.AppendJSON(2, jsonObj)
   104  	srcChk.AppendTime(3, timeObj)
   105  	srcChk.AppendDuration(4, durationObj)
   106  
   107  	list := NewList(fieldTypes, maxChunkSize, maxChunkSize*2)
   108  	c.Assert(list.GetMemTracker().BytesConsumed(), check.Equals, int64(0))
   109  
   110  	list.AppendRow(srcChk.GetRow(0))
   111  	c.Assert(list.GetMemTracker().BytesConsumed(), check.Equals, int64(0))
   112  
   113  	memUsage := list.chunks[0].MemoryUsage()
   114  	list.Reset()
   115  	c.Assert(list.GetMemTracker().BytesConsumed(), check.Equals, memUsage)
   116  
   117  	list.Add(srcChk)
   118  	c.Assert(list.GetMemTracker().BytesConsumed(), check.Equals, memUsage+srcChk.MemoryUsage())
   119  }
   120  
   121  func (s *testChunkSuite) TestListPrePreAlloc4RowAndInsert(c *check.C) {
   122  	fieldTypes := make([]*types.FieldType, 0, 4)
   123  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeFloat})
   124  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeLonglong})
   125  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeNewDecimal})
   126  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeVarchar})
   127  
   128  	srcChk := NewChunkWithCapacity(fieldTypes, 10)
   129  	for i := int64(0); i < 10; i++ {
   130  		srcChk.AppendFloat32(0, float32(i))
   131  		srcChk.AppendInt64(1, i)
   132  		srcChk.AppendMyDecimal(2, types.NewDecFromInt(i))
   133  		srcChk.AppendString(3, strings.Repeat(strconv.FormatInt(i, 10), int(i)))
   134  	}
   135  
   136  	srcList := NewList(fieldTypes, 3, 3)
   137  	destList := NewList(fieldTypes, 5, 5)
   138  	destRowPtr := make([]RowPtr, srcChk.NumRows())
   139  	for i := 0; i < srcChk.NumRows(); i++ {
   140  		srcList.AppendRow(srcChk.GetRow(i))
   141  		destRowPtr[i] = destList.preAlloc4Row(srcChk.GetRow(i))
   142  	}
   143  
   144  	c.Assert(srcList.NumChunks(), check.Equals, 4)
   145  	c.Assert(destList.NumChunks(), check.Equals, 2)
   146  
   147  	iter4Src := NewIterator4List(srcList)
   148  	for event, i := iter4Src.Begin(), 0; event != iter4Src.End(); event, i = iter4Src.Next(), i+1 {
   149  		destList.Insert(destRowPtr[i], event)
   150  	}
   151  
   152  	iter4Dest := NewIterator4List(destList)
   153  	srcRow, destRow := iter4Src.Begin(), iter4Dest.Begin()
   154  	for ; srcRow != iter4Src.End(); srcRow, destRow = iter4Src.Next(), iter4Dest.Next() {
   155  		c.Assert(srcRow.GetFloat32(0), check.Equals, destRow.GetFloat32(0))
   156  		c.Assert(srcRow.GetInt64(1), check.Equals, destRow.GetInt64(1))
   157  		c.Assert(srcRow.GetMyDecimal(2).Compare(destRow.GetMyDecimal(2)) == 0, check.IsTrue)
   158  		c.Assert(srcRow.GetString(3), check.Equals, destRow.GetString(3))
   159  	}
   160  }
   161  
   162  func BenchmarkListMemoryUsage(b *testing.B) {
   163  	fieldTypes := make([]*types.FieldType, 0, 4)
   164  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeFloat})
   165  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeVarchar})
   166  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeDatetime})
   167  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeDuration})
   168  
   169  	chk := NewChunkWithCapacity(fieldTypes, 2)
   170  	timeObj := types.NewTime(types.FromGoTime(time.Now()), allegrosql.TypeDatetime, 0)
   171  	durationObj := types.Duration{Duration: math.MaxInt64, Fsp: 0}
   172  	chk.AppendFloat64(0, 123.123)
   173  	chk.AppendString(1, "123")
   174  	chk.AppendTime(2, timeObj)
   175  	chk.AppendDuration(3, durationObj)
   176  	event := chk.GetRow(0)
   177  
   178  	initCap := 50
   179  	list := NewList(fieldTypes, 2, 8)
   180  	for i := 0; i < initCap; i++ {
   181  		list.AppendRow(event)
   182  	}
   183  	b.ResetTimer()
   184  	for i := 0; i < b.N; i++ {
   185  		list.GetMemTracker().BytesConsumed()
   186  	}
   187  }
   188  
   189  func BenchmarkPreAllocList(b *testing.B) {
   190  	fieldTypes := make([]*types.FieldType, 0, 1)
   191  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeLonglong})
   192  	chk := NewChunkWithCapacity(fieldTypes, 1)
   193  	chk.AppendInt64(0, 1)
   194  	event := chk.GetRow(0)
   195  
   196  	b.ResetTimer()
   197  	list := NewList(fieldTypes, 1024, 1024)
   198  	for i := 0; i < b.N; i++ {
   199  		list.Reset()
   200  		// 32768 indicates the number of int64 rows to fill 256KB L2 cache.
   201  		for j := 0; j < 32768; j++ {
   202  			list.preAlloc4Row(event)
   203  		}
   204  	}
   205  }
   206  
   207  func BenchmarkPreAllocChunk(b *testing.B) {
   208  	fieldTypes := make([]*types.FieldType, 0, 1)
   209  	fieldTypes = append(fieldTypes, &types.FieldType{Tp: allegrosql.TypeLonglong})
   210  	chk := NewChunkWithCapacity(fieldTypes, 1)
   211  	chk.AppendInt64(0, 1)
   212  	event := chk.GetRow(0)
   213  
   214  	b.ResetTimer()
   215  	finalChk := New(fieldTypes, 33000, 1024)
   216  	for i := 0; i < b.N; i++ {
   217  		finalChk.Reset()
   218  		for j := 0; j < 32768; j++ {
   219  			finalChk.preAlloc(event)
   220  		}
   221  	}
   222  }
   223  
   224  func BenchmarkListAdd(b *testing.B) {
   225  	numChk, numRow := 1, 2
   226  	chks, fields := initChunks(numChk, numRow)
   227  	chk := chks[0]
   228  	l := NewList(fields, numRow, numRow)
   229  
   230  	b.ResetTimer()
   231  	for i := 0; i < b.N; i++ {
   232  		l.Add(chk)
   233  	}
   234  }
   235  
   236  func BenchmarkListGetRow(b *testing.B) {
   237  	numChk, numRow := 10000, 2
   238  	chks, fields := initChunks(numChk, numRow)
   239  	l := NewList(fields, numRow, numRow)
   240  	for _, chk := range chks {
   241  		l.Add(chk)
   242  	}
   243  	rand.Seed(0)
   244  	ptrs := make([]RowPtr, 0, b.N)
   245  	for i := 0; i < mathutil.Min(b.N, 10000); i++ {
   246  		ptrs = append(ptrs, RowPtr{
   247  			ChkIdx: rand.Uint32() % uint32(numChk),
   248  			RowIdx: rand.Uint32() % uint32(numRow),
   249  		})
   250  	}
   251  	for i := 10000; i < cap(ptrs); i++ {
   252  		ptrs = append(ptrs, ptrs[i%10000])
   253  	}
   254  	b.ResetTimer()
   255  	for i := 0; i < b.N; i++ {
   256  		l.GetRow(ptrs[i])
   257  	}
   258  }