github.com/matrixorigin/matrixone@v1.2.0/pkg/incrservice/column_cache_test.go (about)

     1  // Copyright 2023 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 incrservice
    16  
    17  import (
    18  	"context"
    19  	"math"
    20  	"sync"
    21  	"sync/atomic"
    22  	"testing"
    23  
    24  	"github.com/lni/goutils/leaktest"
    25  	"github.com/matrixorigin/matrixone/pkg/catalog"
    26  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    27  	"github.com/matrixorigin/matrixone/pkg/common/runtime"
    28  	"github.com/matrixorigin/matrixone/pkg/container/types"
    29  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    30  	"github.com/matrixorigin/matrixone/pkg/defines"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  	"golang.org/x/exp/constraints"
    34  )
    35  
    36  func TestNewColumnCache(t *testing.T) {
    37  	defer leaktest.AfterTest(t)()
    38  	runColumnCacheTests(
    39  		t,
    40  		100,
    41  		1,
    42  		func(
    43  			ctx context.Context,
    44  			c *columnCache) {
    45  			c.Lock()
    46  			defer c.Unlock()
    47  			require.NoError(t, c.waitPrevAllocatingLocked(ctx))
    48  			assert.Equal(t, 100, c.ranges.left())
    49  		},
    50  	)
    51  }
    52  
    53  func TestColumnCacheAllocate(t *testing.T) {
    54  	defer leaktest.AfterTest(t)()
    55  	runColumnCacheTests(
    56  		t,
    57  		100,
    58  		1,
    59  		func(
    60  			ctx context.Context,
    61  			c *columnCache) {
    62  			c.Lock()
    63  			require.NoError(t, c.waitPrevAllocatingLocked(ctx))
    64  			require.NoError(t, c.allocateLocked(ctx, 0, 200, 0, nil))
    65  			c.Unlock()
    66  
    67  			c.Lock()
    68  			defer c.Unlock()
    69  			assert.Equal(t, 300, c.ranges.left())
    70  		},
    71  	)
    72  }
    73  
    74  func TestColumnCacheInsert(t *testing.T) {
    75  	defer leaktest.AfterTest(t)()
    76  	runColumnCacheTests(
    77  		t,
    78  		100,
    79  		1,
    80  		func(
    81  			ctx context.Context,
    82  			c *columnCache) {
    83  			c.Lock()
    84  			require.NoError(t, c.waitPrevAllocatingLocked(ctx))
    85  			require.NoError(t, c.allocateLocked(ctx, 0, 200, 0, nil))
    86  			c.Unlock()
    87  
    88  			c.Lock()
    89  			defer c.Unlock()
    90  			assert.Equal(t, 300, c.ranges.left())
    91  		},
    92  	)
    93  }
    94  
    95  func TestInsertInt8(t *testing.T) {
    96  	fillValues := []int8{1, 2, 3, 4, 5, 6, 7, 8}
    97  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
    98  	testColumnCacheInsert[int8](
    99  		t,
   100  		8,
   101  		8,
   102  		newTestVector[int8](8, types.New(types.T_int8, 0, 0), nil, nil),
   103  		newTestVector(8, types.New(types.T_int8, 0, 0), fillValues, fillRows),
   104  	)
   105  }
   106  
   107  func TestInsertInt8WithManual(t *testing.T) {
   108  	manualValues := []int8{6, 9}
   109  	manualRows := []int{0, 1}
   110  
   111  	fillValues := []int8{6, 9, 10, 11, 12, 13, 14, 15}
   112  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   113  	testColumnCacheInsert[int8](
   114  		t,
   115  		8,
   116  		15,
   117  		newTestVector(8, types.New(types.T_int8, 0, 0), manualValues, manualRows),
   118  		newTestVector(8, types.New(types.T_int8, 0, 0), fillValues, fillRows),
   119  	)
   120  }
   121  
   122  func TestInsertInt16(t *testing.T) {
   123  	fillValues := []int16{1, 2, 3, 4, 5, 6, 7, 8}
   124  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   125  	testColumnCacheInsert[int16](
   126  		t,
   127  		8,
   128  		8,
   129  		newTestVector[int16](8, types.New(types.T_int16, 0, 0), nil, nil),
   130  		newTestVector(8, types.New(types.T_int16, 0, 0), fillValues, fillRows),
   131  	)
   132  }
   133  
   134  func TestInsertInt16WithManual(t *testing.T) {
   135  	manualValues := []int16{6, 9}
   136  	manualRows := []int{0, 1}
   137  
   138  	fillValues := []int16{6, 9, 10, 11, 12, 13, 14, 15}
   139  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   140  	testColumnCacheInsert[int16](
   141  		t,
   142  		8,
   143  		15,
   144  		newTestVector(8, types.New(types.T_int16, 0, 0), manualValues, manualRows),
   145  		newTestVector(8, types.New(types.T_int16, 0, 0), fillValues, fillRows),
   146  	)
   147  }
   148  
   149  func TestInsertInt32(t *testing.T) {
   150  	fillValues := []int32{1, 2, 3, 4, 5, 6, 7, 8}
   151  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   152  	testColumnCacheInsert[int32](
   153  		t,
   154  		8,
   155  		8,
   156  		newTestVector[int32](8, types.New(types.T_int32, 0, 0), nil, nil),
   157  		newTestVector(8, types.New(types.T_int32, 0, 0), fillValues, fillRows),
   158  	)
   159  }
   160  
   161  func TestInsertInt32WithManual(t *testing.T) {
   162  	manualValues := []int32{6, 9}
   163  	manualRows := []int{0, 1}
   164  
   165  	fillValues := []int32{6, 9, 10, 11, 12, 13, 14, 15}
   166  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   167  	testColumnCacheInsert[int32](
   168  		t,
   169  		8,
   170  		15,
   171  		newTestVector(8, types.New(types.T_int32, 0, 0), manualValues, manualRows),
   172  		newTestVector(8, types.New(types.T_int32, 0, 0), fillValues, fillRows),
   173  	)
   174  }
   175  
   176  func TestInsertInt64(t *testing.T) {
   177  	fillValues := []int64{1, 2, 3, 4, 5, 6, 7, 8}
   178  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   179  	testColumnCacheInsert[int64](
   180  		t,
   181  		8,
   182  		8,
   183  		newTestVector[int64](8, types.New(types.T_int64, 0, 0), nil, nil),
   184  		newTestVector(8, types.New(types.T_int64, 0, 0), fillValues, fillRows),
   185  	)
   186  }
   187  
   188  func TestInsertInt64WithManual(t *testing.T) {
   189  	manualValues := []int64{6, 9}
   190  	manualRows := []int{0, 1}
   191  
   192  	fillValues := []int64{6, 9, 10, 11, 12, 13, 14, 15}
   193  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   194  	testColumnCacheInsert[int64](
   195  		t,
   196  		8,
   197  		15,
   198  		newTestVector(8, types.New(types.T_int64, 0, 0), manualValues, manualRows),
   199  		newTestVector(8, types.New(types.T_int64, 0, 0), fillValues, fillRows),
   200  	)
   201  }
   202  
   203  func TestInsertUint8(t *testing.T) {
   204  	fillValues := []uint8{1, 2, 3, 4, 5, 6, 7, 8}
   205  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   206  	testColumnCacheInsert[uint8](
   207  		t,
   208  		8,
   209  		8,
   210  		newTestVector[uint8](8, types.New(types.T_uint8, 0, 0), nil, nil),
   211  		newTestVector(8, types.New(types.T_uint8, 0, 0), fillValues, fillRows),
   212  	)
   213  }
   214  
   215  func TestInsertUint8WithManual(t *testing.T) {
   216  	manualValues := []uint8{6, 9}
   217  	manualRows := []int{0, 1}
   218  
   219  	fillValues := []uint8{6, 9, 10, 11, 12, 13, 14, 15}
   220  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   221  	testColumnCacheInsert[uint8](
   222  		t,
   223  		8,
   224  		15,
   225  		newTestVector(8, types.New(types.T_uint8, 0, 0), manualValues, manualRows),
   226  		newTestVector(8, types.New(types.T_uint8, 0, 0), fillValues, fillRows),
   227  	)
   228  }
   229  
   230  func TestInsertUint16(t *testing.T) {
   231  	fillValues := []uint16{1, 2, 3, 4, 5, 6, 7, 8}
   232  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   233  	testColumnCacheInsert[uint16](
   234  		t,
   235  		8,
   236  		8,
   237  		newTestVector[uint16](8, types.New(types.T_uint16, 0, 0), nil, nil),
   238  		newTestVector(8, types.New(types.T_uint16, 0, 0), fillValues, fillRows),
   239  	)
   240  }
   241  
   242  func TestInsertUint16WithManual(t *testing.T) {
   243  	manualValues := []uint16{6, 9}
   244  	manualRows := []int{0, 1}
   245  
   246  	fillValues := []uint16{6, 9, 10, 11, 12, 13, 14, 15}
   247  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   248  	testColumnCacheInsert[uint16](
   249  		t,
   250  		8,
   251  		15,
   252  		newTestVector(8, types.New(types.T_uint16, 0, 0), manualValues, manualRows),
   253  		newTestVector(8, types.New(types.T_uint16, 0, 0), fillValues, fillRows),
   254  	)
   255  }
   256  
   257  func TestInsertUint32(t *testing.T) {
   258  	fillValues := []uint32{1, 2, 3, 4, 5, 6, 7, 8}
   259  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   260  	testColumnCacheInsert[uint32](
   261  		t,
   262  		8,
   263  		8,
   264  		newTestVector[uint32](8, types.New(types.T_uint32, 0, 0), nil, nil),
   265  		newTestVector(8, types.New(types.T_uint32, 0, 0), fillValues, fillRows),
   266  	)
   267  }
   268  
   269  func TestInsertUint32WithManual(t *testing.T) {
   270  	manualValues := []uint32{6, 9}
   271  	manualRows := []int{0, 1}
   272  
   273  	fillValues := []uint32{6, 9, 10, 11, 12, 13, 14, 15}
   274  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   275  	testColumnCacheInsert[uint32](
   276  		t,
   277  		8,
   278  		15,
   279  		newTestVector(8, types.New(types.T_uint32, 0, 0), manualValues, manualRows),
   280  		newTestVector(8, types.New(types.T_uint32, 0, 0), fillValues, fillRows),
   281  	)
   282  }
   283  
   284  func TestInsertUint64(t *testing.T) {
   285  	fillValues := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
   286  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   287  	testColumnCacheInsert[uint64](
   288  		t,
   289  		8,
   290  		8,
   291  		newTestVector[uint64](8, types.New(types.T_uint64, 0, 0), nil, nil),
   292  		newTestVector(8, types.New(types.T_uint64, 0, 0), fillValues, fillRows),
   293  	)
   294  }
   295  
   296  func TestInsertUint64WithManual(t *testing.T) {
   297  	manualValues := []uint64{6, 9}
   298  	manualRows := []int{0, 1}
   299  
   300  	fillValues := []uint64{6, 9, 10, 11, 12, 13, 14, 15}
   301  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   302  	testColumnCacheInsert[uint64](
   303  		t,
   304  		8,
   305  		15,
   306  		newTestVector(8, types.New(types.T_uint64, 0, 0), manualValues, manualRows),
   307  		newTestVector(8, types.New(types.T_uint64, 0, 0), fillValues, fillRows),
   308  	)
   309  }
   310  
   311  func TestInsertWithManualMixed(t *testing.T) {
   312  	manualValues := []uint64{3, 6}
   313  	manualRows := []int{1, 3}
   314  
   315  	fillValues := []uint64{1, 3, 4, 6, 7, 8, 9, 10}
   316  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   317  	testColumnCacheInsert[uint64](
   318  		t,
   319  		8,
   320  		10,
   321  		newTestVector(8, types.New(types.T_uint64, 0, 0), manualValues, manualRows),
   322  		newTestVector(8, types.New(types.T_uint64, 0, 0), fillValues, fillRows),
   323  	)
   324  }
   325  
   326  func TestLastInsertValueWithNoAutoInserted(t *testing.T) {
   327  	manualValues := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
   328  	manualRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   329  	testColumnCacheInsert[uint64](
   330  		t,
   331  		8,
   332  		0,
   333  		newTestVector(8, types.New(types.T_uint64, 0, 0), manualValues, manualRows),
   334  		newTestVector(8, types.New(types.T_uint64, 0, 0), manualValues, manualRows),
   335  	)
   336  }
   337  
   338  func TestOverflow(t *testing.T) {
   339  	runColumnCacheTests(
   340  		t,
   341  		1,
   342  		1,
   343  		func(
   344  			ctx context.Context,
   345  			cc *columnCache) {
   346  			require.NoError(t, cc.updateTo(ctx, 0, math.MaxUint64, nil))
   347  			require.True(t, cc.overflow)
   348  
   349  			require.NoError(t,
   350  				cc.applyAutoValues(
   351  					ctx,
   352  					0,
   353  					1,
   354  					nil,
   355  					func(i int) bool { return false },
   356  					func(i int, u uint64) error {
   357  						require.Equal(t, uint64(0), u)
   358  						return nil
   359  					},
   360  					nil))
   361  		},
   362  	)
   363  }
   364  
   365  func TestOverflowWithInit(t *testing.T) {
   366  	runColumnCacheTestsWithInitOffset(
   367  		t,
   368  		1,
   369  		1,
   370  		math.MaxUint64,
   371  		func(
   372  			ctx context.Context,
   373  			cc *columnCache) {
   374  			require.True(t, cc.overflow)
   375  
   376  			require.NoError(t,
   377  				cc.applyAutoValues(
   378  					ctx,
   379  					0,
   380  					1,
   381  					nil,
   382  					func(i int) bool { return false },
   383  					func(i int, u uint64) error {
   384  						require.Equal(t, uint64(0), u)
   385  						return nil
   386  					},
   387  					nil))
   388  		},
   389  	)
   390  }
   391  
   392  func TestMergeAllocate(t *testing.T) {
   393  	total := 3600000
   394  	goroutines := 60
   395  	batch := 6000
   396  	rowsPerGoroutine := total / goroutines
   397  	var added atomic.Uint64
   398  	capacity := 10000
   399  	runColumnCacheTests(
   400  		t,
   401  		capacity,
   402  		1,
   403  		func(
   404  			ctx context.Context,
   405  			cc *columnCache) {
   406  			var wg sync.WaitGroup
   407  			for i := 0; i < goroutines; i++ {
   408  				wg.Add(1)
   409  				go func() {
   410  					defer wg.Done()
   411  					n := rowsPerGoroutine / batch
   412  					for i := 0; i < n; i++ {
   413  						cc.applyAutoValues(
   414  							ctx,
   415  							0,
   416  							batch,
   417  							nil,
   418  							func(i int) bool { return false },
   419  							func(i int, u uint64) error {
   420  								added.Add(1)
   421  								return nil
   422  							},
   423  							nil)
   424  					}
   425  				}()
   426  			}
   427  
   428  			wg.Wait()
   429  			assert.Equal(t, uint64(total), added.Load())
   430  			assert.True(t, cc.allocateCount.Load() < 360)
   431  		},
   432  	)
   433  }
   434  
   435  func TestIssue9840(t *testing.T) {
   436  	fillValues := []uint64{1, 2, 3, 4, 5, 6, 7, 8}
   437  	fillRows := []int{0, 1, 2, 3, 4, 5, 6, 7}
   438  	input := newTestVector[uint64](8, types.New(types.T_uint64, 0, 0), nil, nil)
   439  	// index 0 is manual, others is null, but index 1 has a invalid value
   440  	vector.SetFixedAt[uint64](input, 0, 1)
   441  	vector.SetFixedAt[uint64](input, 1, 5)
   442  	input.GetNulls().Del(0)
   443  	testColumnCacheInsert[uint64](
   444  		t,
   445  		8,
   446  		8,
   447  		input,
   448  		newTestVector(8, types.New(types.T_uint64, 0, 0), fillValues, fillRows),
   449  	)
   450  }
   451  
   452  func testColumnCacheInsert[T constraints.Integer](
   453  	t *testing.T,
   454  	rows int,
   455  	expectLastInsertValue uint64,
   456  	input *vector.Vector,
   457  	expect *vector.Vector) {
   458  	runColumnCacheTests(
   459  		t,
   460  		10,
   461  		1,
   462  		func(
   463  			ctx context.Context,
   464  			c *columnCache) {
   465  			lastInsertValue, err := c.insertAutoValues(ctx, 0, input, rows, nil)
   466  			require.NoError(t, err)
   467  			assert.Equal(t, expectLastInsertValue, lastInsertValue)
   468  			assert.Equal(t,
   469  				vector.MustFixedCol[T](expect),
   470  				vector.MustFixedCol[T](input))
   471  		},
   472  	)
   473  }
   474  
   475  func newTestVector[T constraints.Integer](
   476  	rows int,
   477  	vecType types.Type,
   478  	fillValues []T,
   479  	fillRows []int) *vector.Vector {
   480  	fillMap := make(map[int]T)
   481  	for i, v := range fillRows {
   482  		fillMap[v] = fillValues[i]
   483  	}
   484  
   485  	vec := vector.NewVec(vecType)
   486  	for i := 0; i < rows; i++ {
   487  		if v, ok := fillMap[i]; ok {
   488  			vector.AppendFixed(vec, v, false, mpool.MustNew("test"))
   489  		} else {
   490  			vector.AppendFixed[T](vec, 0, true, mpool.MustNew("test"))
   491  		}
   492  	}
   493  	return vec
   494  }
   495  
   496  func runColumnCacheTests(
   497  	t *testing.T,
   498  	capacity int,
   499  	step int,
   500  	fn func(context.Context, *columnCache),
   501  ) {
   502  	runColumnCacheTestsWithInitOffset(
   503  		t,
   504  		capacity,
   505  		step,
   506  		0,
   507  		fn)
   508  }
   509  
   510  func runColumnCacheTestsWithInitOffset(
   511  	t *testing.T,
   512  	capacity int,
   513  	step int,
   514  	offset uint64,
   515  	fn func(context.Context, *columnCache),
   516  ) {
   517  	defer leaktest.AfterTest(t)()
   518  	runtime.SetupProcessLevelRuntime(runtime.DefaultRuntime())
   519  	runAllocatorTests(
   520  		t,
   521  		func(a valueAllocator) {
   522  			ctx, cancel := context.WithCancel(defines.AttachAccountId(context.Background(), catalog.System_Account))
   523  			defer cancel()
   524  			col := AutoColumn{
   525  				ColName: "k1",
   526  				Offset:  offset,
   527  				Step:    uint64(step),
   528  			}
   529  			a.(*allocator).store.Create(
   530  				ctx,
   531  				0,
   532  				[]AutoColumn{col},
   533  				nil)
   534  			cc, err := newColumnCache(ctx, 0, col, Config{CountPerAllocate: capacity}, true, a, nil)
   535  			require.NoError(t, err)
   536  			fn(ctx, cc)
   537  		},
   538  	)
   539  }