github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/chunk/disk_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  	"fmt"
    18  	"io"
    19  	"io/ioutil"
    20  	"math/rand"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/cznic/mathutil"
    28  	"github.com/whtcorpsinc/check"
    29  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    30  	"github.com/whtcorpsinc/milevadb/config"
    31  	"github.com/whtcorpsinc/milevadb/types"
    32  	"github.com/whtcorpsinc/milevadb/types/json"
    33  )
    34  
    35  func initChunks(numChk, numRow int) ([]*Chunk, []*types.FieldType) {
    36  	fields := []*types.FieldType{
    37  		types.NewFieldType(allegrosql.TypeVarString),
    38  		types.NewFieldType(allegrosql.TypeLonglong),
    39  		types.NewFieldType(allegrosql.TypeVarString),
    40  		types.NewFieldType(allegrosql.TypeLonglong),
    41  		types.NewFieldType(allegrosql.TypeJSON),
    42  	}
    43  
    44  	chks := make([]*Chunk, 0, numChk)
    45  	for chkIdx := 0; chkIdx < numChk; chkIdx++ {
    46  		chk := NewChunkWithCapacity(fields, numRow)
    47  		for rowIdx := 0; rowIdx < numRow; rowIdx++ {
    48  			data := int64(chkIdx*numRow + rowIdx)
    49  			chk.AppendString(0, fmt.Sprint(data))
    50  			chk.AppendNull(1)
    51  			chk.AppendNull(2)
    52  			chk.AppendInt64(3, data)
    53  			if chkIdx%2 == 0 {
    54  				chk.AppendJSON(4, json.CreateBinary(fmt.Sprint(data)))
    55  			} else {
    56  				chk.AppendNull(4)
    57  			}
    58  		}
    59  		chks = append(chks, chk)
    60  	}
    61  	return chks, fields
    62  }
    63  
    64  func (s *testChunkSuite) TestListInDisk(c *check.C) {
    65  	numChk, numRow := 2, 2
    66  	chks, fields := initChunks(numChk, numRow)
    67  	l := NewListInDisk(fields)
    68  	defer func() {
    69  		err := l.Close()
    70  		c.Check(err, check.IsNil)
    71  		c.Check(l.disk, check.NotNil)
    72  		_, err = os.Stat(l.disk.Name())
    73  		c.Check(os.IsNotExist(err), check.IsTrue)
    74  	}()
    75  	for _, chk := range chks {
    76  		err := l.Add(chk)
    77  		c.Check(err, check.IsNil)
    78  	}
    79  	c.Assert(strings.HasPrefix(l.disk.Name(), filepath.Join(os.TemFIDelir(), "oom-use-tmp-storage")), check.Equals, true)
    80  	c.Check(l.NumChunks(), check.Equals, numChk)
    81  	c.Check(l.GetDiskTracker().BytesConsumed() > 0, check.IsTrue)
    82  
    83  	for chkIdx := 0; chkIdx < numChk; chkIdx++ {
    84  		for rowIdx := 0; rowIdx < numRow; rowIdx++ {
    85  			event, err := l.GetRow(RowPtr{ChkIdx: uint32(chkIdx), RowIdx: uint32(rowIdx)})
    86  			c.Check(err, check.IsNil)
    87  			c.Check(event.GetCausetRow(fields), check.DeepEquals, chks[chkIdx].GetRow(rowIdx).GetCausetRow(fields))
    88  		}
    89  	}
    90  }
    91  
    92  func BenchmarkListInDiskAdd(b *testing.B) {
    93  	numChk, numRow := 1, 2
    94  	chks, fields := initChunks(numChk, numRow)
    95  	chk := chks[0]
    96  	l := NewListInDisk(fields)
    97  	defer l.Close()
    98  
    99  	b.ResetTimer()
   100  	for i := 0; i < b.N; i++ {
   101  		err := l.Add(chk)
   102  		if err != nil {
   103  			b.Fatal(err)
   104  		}
   105  	}
   106  }
   107  
   108  func BenchmarkListInDiskGetRow(b *testing.B) {
   109  	numChk, numRow := 10000, 2
   110  	chks, fields := initChunks(numChk, numRow)
   111  	l := NewListInDisk(fields)
   112  	defer l.Close()
   113  	for _, chk := range chks {
   114  		err := l.Add(chk)
   115  		if err != nil {
   116  			b.Fatal(err)
   117  		}
   118  	}
   119  	rand.Seed(0)
   120  	ptrs := make([]RowPtr, 0, b.N)
   121  	for i := 0; i < mathutil.Min(b.N, 10000); i++ {
   122  		ptrs = append(ptrs, RowPtr{
   123  			ChkIdx: rand.Uint32() % uint32(numChk),
   124  			RowIdx: rand.Uint32() % uint32(numRow),
   125  		})
   126  	}
   127  	for i := 10000; i < cap(ptrs); i++ {
   128  		ptrs = append(ptrs, ptrs[i%10000])
   129  	}
   130  	b.ResetTimer()
   131  	for i := 0; i < b.N; i++ {
   132  		_, err := l.GetRow(ptrs[i])
   133  		if err != nil {
   134  			b.Fatal(err)
   135  		}
   136  	}
   137  }
   138  
   139  type listInDiskWriteDisk struct {
   140  	ListInDisk
   141  }
   142  
   143  func newListInDiskWriteDisk(fieldTypes []*types.FieldType) (*listInDiskWriteDisk, error) {
   144  	l := listInDiskWriteDisk{*NewListInDisk(fieldTypes)}
   145  	disk, err := ioutil.TempFile(config.GetGlobalConfig().TempStoragePath, strconv.Itoa(l.diskTracker.Label()))
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	l.disk = disk
   150  	l.w = disk
   151  	return &l, nil
   152  }
   153  
   154  func (l *listInDiskWriteDisk) GetRow(ptr RowPtr) (event Row, err error) {
   155  	err = l.flush()
   156  	if err != nil {
   157  		return
   158  	}
   159  	off := l.offsets[ptr.ChkIdx][ptr.RowIdx]
   160  
   161  	r := io.NewSectionReader(l.disk, off, l.offWrite-off)
   162  	format := rowInDisk{numDefCaus: len(l.fieldTypes)}
   163  	_, err = format.ReadFrom(r)
   164  	if err != nil {
   165  		return event, err
   166  	}
   167  	event = format.toMutRow(l.fieldTypes).ToRow()
   168  	return event, err
   169  }
   170  
   171  func checkRow(c *check.C, row1, row2 Row) {
   172  	c.Assert(row1.GetString(0), check.Equals, row2.GetString(0))
   173  	c.Assert(row1.GetInt64(1), check.Equals, row2.GetInt64(1))
   174  	c.Assert(row1.GetString(2), check.Equals, row2.GetString(2))
   175  	c.Assert(row1.GetInt64(3), check.Equals, row2.GetInt64(3))
   176  	if !row1.IsNull(4) {
   177  		c.Assert(row1.GetJSON(4).String(), check.Equals, row2.GetJSON(4).String())
   178  	}
   179  }
   180  
   181  func testListInDisk(c *check.C) {
   182  	numChk, numRow := 10, 1000
   183  	chks, fields := initChunks(numChk, numRow)
   184  	lChecksum := NewListInDisk(fields)
   185  	defer lChecksum.Close()
   186  	lDisk, err := newListInDiskWriteDisk(fields)
   187  	c.Assert(err, check.IsNil)
   188  	defer lDisk.Close()
   189  	for _, chk := range chks {
   190  		err := lChecksum.Add(chk)
   191  		c.Assert(err, check.IsNil)
   192  		err = lDisk.Add(chk)
   193  		c.Assert(err, check.IsNil)
   194  	}
   195  
   196  	var ptrs []RowPtr
   197  	for i := 0; i < numChk; i++ {
   198  		for j := 0; j < numRow; j++ {
   199  			ptrs = append(ptrs, RowPtr{
   200  				ChkIdx: uint32(i),
   201  				RowIdx: uint32(j),
   202  			})
   203  		}
   204  	}
   205  
   206  	for _, rowPtr := range ptrs {
   207  		row1, err := lChecksum.GetRow(rowPtr)
   208  		c.Assert(err, check.IsNil)
   209  		row2, err := lDisk.GetRow(rowPtr)
   210  		c.Assert(err, check.IsNil)
   211  		checkRow(c, row1, row2)
   212  	}
   213  }
   214  
   215  func (s *testChunkSuite) TestListInDiskWithChecksum(c *check.C) {
   216  	defer config.RestoreFunc()()
   217  	config.UFIDelateGlobal(func(conf *config.Config) {
   218  		conf.Security.SpilledFileEncryptionMethod = config.SpilledFileEncryptionMethodPlaintext
   219  	})
   220  	testListInDisk(c)
   221  
   222  }
   223  
   224  func (s *testChunkSuite) TestListInDiskWithChecksumAndEncrypt(c *check.C) {
   225  	defer config.RestoreFunc()()
   226  	config.UFIDelateGlobal(func(conf *config.Config) {
   227  		conf.Security.SpilledFileEncryptionMethod = config.SpilledFileEncryptionMethodAES128CTR
   228  	})
   229  	testListInDisk(c)
   230  }