Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

executor: support semi join #57658

Merged
merged 139 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 134 commits
Commits
Show all changes
139 commits
Select commit Hold shift + click to select a range
715e03f
save
xzhangxian1008 Sep 5, 2024
acef9a7
Merge branch 'master' into hash-join-spill-v2
xzhangxian1008 Sep 5, 2024
2b382c5
save
xzhangxian1008 Sep 5, 2024
287e2f9
fix ut
xzhangxian1008 Sep 5, 2024
b032126
add test and fix
xzhangxian1008 Sep 6, 2024
37a08c6
add more codes
xzhangxian1008 Sep 6, 2024
9f994a8
fix bugs
xzhangxian1008 Sep 6, 2024
3c6eaf7
fix bugs
xzhangxian1008 Sep 9, 2024
08ef531
fix bugs and add tests
xzhangxian1008 Sep 9, 2024
4fb8494
update bazel
xzhangxian1008 Sep 9, 2024
47bf0e7
merge
xzhangxian1008 Sep 9, 2024
12047df
rename
xzhangxian1008 Sep 10, 2024
6753db4
rename
xzhangxian1008 Sep 10, 2024
b152d87
fix
xzhangxian1008 Sep 11, 2024
d59ccaa
remove useless function
xzhangxian1008 Sep 11, 2024
56018b6
address some comments
xzhangxian1008 Sep 13, 2024
397bfd8
address comments
xzhangxian1008 Sep 13, 2024
7cc6f4d
tweaking
xzhangxian1008 Sep 14, 2024
ae866e0
address some comments
xzhangxian1008 Sep 14, 2024
9a7a934
address comments
xzhangxian1008 Sep 18, 2024
2c3ede3
tweaking
xzhangxian1008 Sep 18, 2024
f275846
add quick exit
xzhangxian1008 Sep 18, 2024
c93632b
tweaking
xzhangxian1008 Sep 19, 2024
1cb701f
fix gc crash bug
xzhangxian1008 Sep 19, 2024
645d6e3
check chk.Sel()
xzhangxian1008 Sep 19, 2024
80d863f
Merge branch 'master' into hash-join-spill-v2
xzhangxian1008 Sep 20, 2024
d233d06
the tweaking of fallback action
xzhangxian1008 Sep 20, 2024
47ba38d
fix bug
xzhangxian1008 Sep 20, 2024
2509a40
address comments
xzhangxian1008 Sep 23, 2024
e017c8c
fix ci
xzhangxian1008 Sep 23, 2024
e4f12e9
fix uint64
xzhangxian1008 Sep 23, 2024
18453f8
remove pool
xzhangxian1008 Sep 23, 2024
28f79bc
fix ci
xzhangxian1008 Sep 23, 2024
bbcf02c
fix ut
xzhangxian1008 Sep 23, 2024
da359e4
add test
xzhangxian1008 Sep 23, 2024
1035ee6
fix ci
xzhangxian1008 Sep 23, 2024
47c9644
remove useless test
xzhangxian1008 Sep 23, 2024
27c5118
remove useless test result
xzhangxian1008 Sep 23, 2024
d9d7dc9
tweaking
xzhangxian1008 Sep 23, 2024
f40b9fe
fix test
xzhangxian1008 Sep 23, 2024
d11c63f
tweaking
xzhangxian1008 Sep 24, 2024
38a3b26
fix
xzhangxian1008 Sep 24, 2024
e3934b1
move test to ut
xzhangxian1008 Sep 24, 2024
080ef8c
update bazel
xzhangxian1008 Sep 24, 2024
d77b37a
rename
xzhangxian1008 Sep 24, 2024
546060a
address comments
xzhangxian1008 Sep 25, 2024
846fedf
fix ci
xzhangxian1008 Sep 25, 2024
3328492
add
xzhangxian1008 Sep 25, 2024
e50ed2c
merge
xzhangxian1008 Sep 25, 2024
bb3edb6
enable v2
xzhangxian1008 Sep 25, 2024
0cce782
fix ci
xzhangxian1008 Sep 25, 2024
978cd1e
fix
xzhangxian1008 Sep 25, 2024
a4627bb
tweaking
xzhangxian1008 Sep 25, 2024
c4f2497
tweaking
xzhangxian1008 Sep 25, 2024
d2c5445
fix
xzhangxian1008 Sep 25, 2024
35088ae
fix test
xzhangxian1008 Sep 26, 2024
6b23b74
comment
xzhangxian1008 Sep 27, 2024
1dbd75b
resolve comment
xzhangxian1008 Oct 12, 2024
128d6eb
Merge branch 'master' into hash-join-spill-v2
xzhangxian1008 Oct 12, 2024
7d575ad
add comment
xzhangxian1008 Oct 12, 2024
20566d4
add semi join, need tests
xzhangxian1008 Oct 15, 2024
c1d78fe
create test file
xzhangxian1008 Oct 16, 2024
4c178c0
Merge branch 'master' into hash-join-spill-v2
xzhangxian1008 Oct 16, 2024
44d39da
Merge branch 'hash-join-spill-v2' into semi-join
xzhangxian1008 Oct 16, 2024
037d671
add left side build no other condition test
xzhangxian1008 Oct 16, 2024
89c11bb
add right side build no other condition test
xzhangxian1008 Oct 16, 2024
bbb2500
add tests
xzhangxian1008 Oct 16, 2024
95ab33c
add todo
xzhangxian1008 Oct 16, 2024
0de8dea
save
xzhangxian1008 Oct 17, 2024
81236c8
fix left side build with other condition
xzhangxian1008 Oct 17, 2024
ff76307
refine test
xzhangxian1008 Oct 18, 2024
9b81d6b
add tests
xzhangxian1008 Oct 18, 2024
4a21f20
update bazel
xzhangxian1008 Oct 18, 2024
ab2e4ef
add test
xzhangxian1008 Oct 21, 2024
4f87bb2
add anti-semi
xzhangxian1008 Oct 22, 2024
a4ddb58
save
xzhangxian1008 Oct 22, 2024
5061288
finish anti codes, need tests
xzhangxian1008 Oct 22, 2024
9de8062
add anti semi join tests, bugs need fix
xzhangxian1008 Oct 22, 2024
8ad1fb1
merge
xzhangxian1008 Oct 23, 2024
4f6a4fc
fix
xzhangxian1008 Oct 23, 2024
1793e06
tweaking
xzhangxian1008 Oct 23, 2024
bdd8737
tweaking
xzhangxian1008 Oct 23, 2024
17faad6
fix bugs
xzhangxian1008 Oct 23, 2024
f95c966
fix, need test
xzhangxian1008 Oct 31, 2024
35174ff
fix bugs and add tests
xzhangxian1008 Nov 4, 2024
6dfb89c
tweaking
xzhangxian1008 Nov 4, 2024
a797eca
extract codes
xzhangxian1008 Nov 4, 2024
f636e14
refine and fix bugs
xzhangxian1008 Nov 5, 2024
8097246
tweaking
xzhangxian1008 Nov 5, 2024
b476908
fix
xzhangxian1008 Nov 5, 2024
05cb23a
refine test
xzhangxian1008 Nov 5, 2024
3a0c4e2
add todo
xzhangxian1008 Nov 5, 2024
36a856c
fix bug
xzhangxian1008 Nov 5, 2024
f40c4bd
fix bugs and add anti tests
xzhangxian1008 Nov 6, 2024
880ed9f
tweaking
xzhangxian1008 Nov 6, 2024
2fe8ce3
add ft
xzhangxian1008 Nov 6, 2024
c397923
fix ci
xzhangxian1008 Nov 6, 2024
3c299ff
fix ci
xzhangxian1008 Nov 6, 2024
9a62dc3
update bazel
xzhangxian1008 Nov 6, 2024
9f00e2b
fix
xzhangxian1008 Nov 7, 2024
7502d25
save
xzhangxian1008 Nov 8, 2024
415637b
save
xzhangxian1008 Nov 8, 2024
a31753a
fix ut
xzhangxian1008 Nov 8, 2024
c15b3f0
fix spill bugs
xzhangxian1008 Nov 8, 2024
57852b6
tweaking
xzhangxian1008 Nov 11, 2024
b3cc676
merge
xzhangxian1008 Nov 15, 2024
7759111
refine some
xzhangxian1008 Nov 15, 2024
91a5437
successfully merge
xzhangxian1008 Nov 15, 2024
3c580d2
fix ci
xzhangxian1008 Nov 17, 2024
89a8061
Merge branch 'master' into semi-join
xzhangxian1008 Nov 25, 2024
799ce1c
remove anti
xzhangxian1008 Nov 25, 2024
2db2a9c
tweaking
xzhangxian1008 Nov 26, 2024
15b43e1
address comments
xzhangxian1008 Nov 27, 2024
7ea9e7c
address comments
xzhangxian1008 Nov 27, 2024
4f2c60c
fix ci
xzhangxian1008 Nov 28, 2024
02da55f
address comments
xzhangxian1008 Nov 28, 2024
903ed8f
address comments
xzhangxian1008 Nov 28, 2024
acb658b
refine
xzhangxian1008 Nov 28, 2024
1915ee0
address comments
xzhangxian1008 Nov 28, 2024
2e1e5af
refine
xzhangxian1008 Nov 28, 2024
ea66ae3
tweaking
xzhangxian1008 Nov 28, 2024
51c8f0c
remove useless
xzhangxian1008 Nov 28, 2024
3ae81d7
change init cap
xzhangxian1008 Nov 29, 2024
6b4da1a
resize
xzhangxian1008 Nov 29, 2024
5955fd5
tweaking
xzhangxian1008 Nov 29, 2024
7c61194
tweaking
xzhangxian1008 Nov 29, 2024
3254bc5
add comment
xzhangxian1008 Nov 29, 2024
1da8715
tweaking
xzhangxian1008 Nov 29, 2024
722964f
remove useless codes
xzhangxian1008 Nov 29, 2024
adfe457
address comments
xzhangxian1008 Nov 29, 2024
6dee33e
tweaking
xzhangxian1008 Nov 29, 2024
bb3760b
fix ci
xzhangxian1008 Nov 29, 2024
c432bbc
Merge branch 'master' into semi
xzhangxian1008 Dec 2, 2024
be0a2d0
address comments
xzhangxian1008 Dec 3, 2024
d70b60f
address comments
xzhangxian1008 Dec 3, 2024
e5b4c25
refine
xzhangxian1008 Dec 3, 2024
01b43fe
rename
xzhangxian1008 Dec 3, 2024
b70a864
rename
xzhangxian1008 Dec 3, 2024
423ea3e
tweaking
xzhangxian1008 Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions pkg/executor/internal/testutil/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type MockDataSourceParameters struct {
// and he can save provided test data at here.
Datums [][]any

Nulls [][]bool

Rows int
HasSel bool
}
Expand Down Expand Up @@ -80,6 +82,10 @@ func (mds *MockDataSource) GenColDatums(col int) (results []any) {
}
results = make([]any, 0, rows)

// ndv > 0: generate n rows with random value with `nvd` distinct value
// ndv == 0: generate n rows with random value
// ndv == -1: generate n rows with value provided by user and with `nvd` distinct value
// ndv == -2: use rows provided by user
if ndv == 0 {
if mds.P.GenDataFunc == nil {
for i := 0; i < rows; i++ {
Expand All @@ -90,11 +96,19 @@ func (mds *MockDataSource) GenColDatums(col int) (results []any) {
results = append(results, mds.P.GenDataFunc(i, typ))
}
}
} else if ndv == -2 {
xzhangxian1008 marked this conversation as resolved.
Show resolved Hide resolved
// Use data provided by user
if mds.P.Datums[col] == nil {
panic("need to provide data")
}

results = mds.P.Datums[col]
} else {
// Use nvd base data provided by user
datums := make([]any, 0, max(ndv, 0))
if ndv == -1 {
if mds.P.Datums[col] == nil {
panic("need to provid data")
panic("need to provide data")
}

datums = mds.P.Datums[col]
Expand Down Expand Up @@ -257,8 +271,9 @@ func BuildMockDataSource(opt MockDataSourceParameters) *MockDataSource {
Chunks: nil,
}
rTypes := exec.RetTypes(m)
colData := make([][]any, len(rTypes))
for i := 0; i < len(rTypes); i++ {
colNum := len(rTypes)
colData := make([][]any, colNum)
for i := 0; i < colNum; i++ {
colData[i] = m.GenColDatums(i)
}

Expand All @@ -267,10 +282,26 @@ func BuildMockDataSource(opt MockDataSourceParameters) *MockDataSource {
m.GenData[i] = chunk.NewChunkWithCapacity(exec.RetTypes(m), m.MaxChunkSize())
}

nulls := opt.Nulls
if nulls == nil {
nulls = make([][]bool, colNum)
for i := range colNum {
nulls[i] = make([]bool, m.P.Rows)
for j := range m.P.Rows {
nulls[i][j] = false
}
}
}

for i := 0; i < m.P.Rows; i++ {
idx := i / m.MaxChunkSize()
retTypes := exec.RetTypes(m)
for colIdx := 0; colIdx < len(rTypes); colIdx++ {
for colIdx := 0; colIdx < colNum; colIdx++ {
if nulls[colIdx][i] {
m.GenData[idx].AppendNull(colIdx)
continue
}

switch retTypes[colIdx].GetType() {
case mysql.TypeLong, mysql.TypeLonglong:
m.GenData[idx].AppendInt64(colIdx, colData[colIdx][i].(int64))
Expand Down
3 changes: 3 additions & 0 deletions pkg/executor/join/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "join",
srcs = [
"base_join_probe.go",
"base_semi_join.go",
"concurrent_map.go",
"hash_join_base.go",
"hash_join_spill.go",
Expand All @@ -24,6 +25,7 @@ go_library(
"merge_join.go",
"outer_join_probe.go",
"row_table_builder.go",
"semi_join_probe.go",
"tagged_ptr.go",
],
importpath = "github.com/pingcap/tidb/pkg/executor/join",
Expand Down Expand Up @@ -93,6 +95,7 @@ go_test(
"outer_join_spill_test.go",
"right_outer_join_probe_test.go",
"row_table_builder_test.go",
"semi_join_probe_test.go",
"tagged_ptr_test.go",
],
embed = [":join"],
Expand Down
26 changes: 25 additions & 1 deletion pkg/executor/join/base_join_probe.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ func (j *baseJoinProbe) prepareForProbe(chk *chunk.Chunk) (joinedChk *chunk.Chun
j.nextCachedBuildRowIndex = 0
j.matchedRowsForCurrentProbeRow = 0
joinedChk = chk
if j.ctx.OtherCondition != nil {
if j.ctx.hasOtherCondition() {
j.tmpChk.Reset()
j.rowIndexInfos = j.rowIndexInfos[:0]
j.selected = j.selected[:0]
Expand Down Expand Up @@ -693,6 +693,22 @@ func isKeyMatched(keyMode keyMode, serializedKey []byte, rowStart unsafe.Pointer
}
}

func commonInitForScanRowTable(base *baseJoinProbe) *rowIter {
totalRowCount := base.ctx.hashTableContext.hashTable.totalRowCount()
concurrency := base.ctx.Concurrency
workID := uint64(base.workID)
avgRowPerWorker := totalRowCount / uint64(concurrency)
startIndex := workID * avgRowPerWorker
endIndex := (workID + 1) * avgRowPerWorker
if workID == uint64(concurrency-1) {
endIndex = totalRowCount
}
if endIndex > totalRowCount {
endIndex = totalRowCount
}
return base.ctx.hashTableContext.hashTable.createRowIter(startIndex, endIndex)
}

// NewJoinProbe create a join probe used for hash join v2
func NewJoinProbe(ctx *HashJoinCtxV2, workID uint, joinType logicalop.JoinType, keyIndex []int, joinedColumnTypes, probeKeyTypes []*types.FieldType, rightAsBuildSide bool) ProbeV2 {
base := baseJoinProbe{
Expand Down Expand Up @@ -747,7 +763,15 @@ func NewJoinProbe(ctx *HashJoinCtxV2, workID uint, joinType logicalop.JoinType,
return newOuterJoinProbe(base, !rightAsBuildSide, rightAsBuildSide)
case logicalop.RightOuterJoin:
return newOuterJoinProbe(base, rightAsBuildSide, rightAsBuildSide)
case logicalop.SemiJoin:
xzhangxian1008 marked this conversation as resolved.
Show resolved Hide resolved
if len(base.rUsed) != 0 {
panic("len(base.rUsed) != 0 for semi join")
}
return newSemiJoinProbe(base, !rightAsBuildSide)
case logicalop.LeftOuterSemiJoin:
if len(base.rUsed) != 0 {
panic("len(base.rUsed) != 0 for left outer semi join")
}
if rightAsBuildSide {
return newLeftOuterSemiJoinProbe(base)
}
Expand Down
131 changes: 131 additions & 0 deletions pkg/executor/join/base_semi_join.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2024 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package join

import (
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/pingcap/tidb/pkg/util/queue"
"github.com/pingcap/tidb/pkg/util/sqlkiller"
)

// The following described case has other condition.
// During the probe, when a probe matches one build row, we need to put the probe and build rows
// together and generate a new row. If one probe row could match n build row, then we will get
// n new rows. If n is very big, there will generate too much rows. In order to avoid this case
// we need to limit the max generated row number. This variable describe this max number.
// NOTE: Suppose probe chunk has n rows and n*maxMatchedRowNum << chunkRemainingCapacity.
// We will keep on join probe rows that have been matched before with build rows, though
// probe row with idx i may have produced `maxMatchedRowNum` number rows before. So that
// we can process as many rows as possible.
var maxMatchedRowNum = 4

type baseSemiJoin struct {
baseJoinProbe
isLeftSideBuild bool

// isMatchedRows marks whether the left side row is matched
xzhangxian1008 marked this conversation as resolved.
Show resolved Hide resolved
// It's used only when right side is build side.
isMatchedRows []bool

isNulls []bool
xzhangxian1008 marked this conversation as resolved.
Show resolved Hide resolved

// used when left side is build side
rowIter *rowIter

// used in other condition to record which rows need to be processed
unFinishedProbeRowIdxQueue *queue.Queue[int]
}

func newBaseSemiJoin(base baseJoinProbe, isLeftSideBuild bool) *baseSemiJoin {
ret := &baseSemiJoin{
baseJoinProbe: base,
isLeftSideBuild: isLeftSideBuild,
isNulls: make([]bool, 0),
}

return ret
}

func (b *baseSemiJoin) resetProbeState() {
if !b.isLeftSideBuild {
b.isMatchedRows = b.isMatchedRows[:0]
for i := 0; i < b.chunkRows; i++ {
b.isMatchedRows = append(b.isMatchedRows, false)
}
}
xzhangxian1008 marked this conversation as resolved.
Show resolved Hide resolved

if b.ctx.hasOtherCondition() {
if b.unFinishedProbeRowIdxQueue == nil {
b.unFinishedProbeRowIdxQueue = queue.NewQueue[int](b.chunkRows)
} else {
b.unFinishedProbeRowIdxQueue.ClearAndExpandIfNeed(b.chunkRows)
}

for i := 0; i < b.chunkRows; i++ {
if b.matchedRowsHeaders[i] != 0 {
b.unFinishedProbeRowIdxQueue.Push(i)
}
}
}
}

func (b *baseSemiJoin) matchMultiBuildRows(joinedChk *chunk.Chunk, joinedChkRemainCap *int, isRightSideBuild bool) {
tagHelper := b.ctx.hashTableContext.tagHelper
meta := b.ctx.hashTableMeta
for b.matchedRowsHeaders[b.currentProbeRow] != 0 && *joinedChkRemainCap > 0 && b.matchedRowsForCurrentProbeRow < maxMatchedRowNum {
candidateRow := tagHelper.toUnsafePointer(b.matchedRowsHeaders[b.currentProbeRow])
if isRightSideBuild || !meta.isCurrentRowUsedWithAtomic(candidateRow) {
if isKeyMatched(meta.keyMode, b.serializedKeys[b.currentProbeRow], candidateRow, meta) {
b.appendBuildRowToCachedBuildRowsV1(b.currentProbeRow, candidateRow, joinedChk, 0, true)
b.matchedRowsForCurrentProbeRow++
*joinedChkRemainCap--
} else {
b.probeCollision++
}
}

b.matchedRowsHeaders[b.currentProbeRow] = getNextRowAddress(candidateRow, tagHelper, b.matchedRowsHashValue[b.currentProbeRow])
}

b.finishLookupCurrentProbeRow()
}

func (b *baseSemiJoin) concatenateProbeAndBuildRows(joinedChk *chunk.Chunk, sqlKiller *sqlkiller.SQLKiller, isRightSideBuild bool) error {
joinedChkRemainCap := joinedChk.Capacity()

for joinedChkRemainCap > 0 && !b.unFinishedProbeRowIdxQueue.IsEmpty() {
probeRowIdx := b.unFinishedProbeRowIdxQueue.Pop()
if isRightSideBuild && b.isMatchedRows[probeRowIdx] {
continue
}

b.currentProbeRow = probeRowIdx
b.matchMultiBuildRows(joinedChk, &joinedChkRemainCap, isRightSideBuild)

if b.matchedRowsHeaders[probeRowIdx] == 0 {
continue
}

b.unFinishedProbeRowIdxQueue.Push(probeRowIdx)
}

err := checkSQLKiller(sqlKiller, "killedDuringProbe")
if err != nil {
return err
}

b.finishCurrentLookupLoop(joinedChk)
return nil
}
6 changes: 5 additions & 1 deletion pkg/executor/join/inner_join_probe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,11 @@ func testJoinProbe(t *testing.T, withSel bool, leftKeyIndex []int, rightKeyIndex
checkChunksEqual(t, expectedChunks, resultChunks, resultTypes)
case logicalop.LeftOuterSemiJoin:
expectedChunks := genLeftOuterSemiJoinResult(t, hashJoinCtx.SessCtx, leftFilter, leftChunks, rightChunks, leftKeyIndex, rightKeyIndex, leftTypes,
rightTypes, leftKeyTypes, rightKeyTypes, leftUsed, rightUsed, otherCondition, resultTypes)
rightTypes, leftKeyTypes, rightKeyTypes, leftUsed, otherCondition, resultTypes)
checkChunksEqual(t, expectedChunks, resultChunks, resultTypes)
case logicalop.SemiJoin:
expectedChunks := genSemiJoinResult(t, hashJoinCtx.SessCtx, leftFilter, leftChunks, rightChunks, leftKeyIndex, rightKeyIndex, leftTypes,
rightTypes, leftKeyTypes, rightKeyTypes, leftUsed, otherCondition, resultTypes)
checkChunksEqual(t, expectedChunks, resultChunks, resultTypes)
default:
require.NoError(t, errors.New("not supported join type"))
Expand Down
6 changes: 6 additions & 0 deletions pkg/executor/join/join_table_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ func (*joinTableMeta) isCurrentRowUsed(rowStart unsafe.Pointer) bool {
return (*(*uint32)(unsafe.Add(rowStart, sizeOfNextPtr)) & usedFlagMask) == usedFlagMask
}

func (*joinTableMeta) isCurrentRowUsedWithAtomic(rowStart unsafe.Pointer) bool {
addr := (*uint32)(unsafe.Add(rowStart, sizeOfNextPtr))
value := atomic.LoadUint32(addr)
return (value & usedFlagMask) == usedFlagMask
}

type keyProp struct {
canBeInlined bool
keyLength int
Expand Down
Loading