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 }