github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/sink/codec/craft/buffer.go (about)

     1  // Copyright 2021 PingCAP, 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.orglicensesLICENSE-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 craft
    15  
    16  // Utility functions for buffer allocation
    17  func newBufferSize(oldSize int) int {
    18  	var newSize int
    19  	if oldSize > 128 {
    20  		newSize = oldSize + 128
    21  	} else {
    22  		if oldSize > 0 {
    23  			newSize = oldSize * 2
    24  		} else {
    25  			newSize = 8
    26  		}
    27  	}
    28  	return newSize
    29  }
    30  
    31  // generic slice allocator
    32  type sliceAllocator[T any] struct {
    33  	buffer []T
    34  	offset int
    35  }
    36  
    37  //nolint:unused
    38  func (b *sliceAllocator[T]) realloc(old []T, newSize int) []T {
    39  	n := b.alloc(newSize)
    40  	copy(n, old)
    41  	return n
    42  }
    43  
    44  func (b *sliceAllocator[T]) alloc(size int) []T {
    45  	if len(b.buffer)-b.offset < size {
    46  		if size > len(b.buffer)/4 {
    47  			// large allocation
    48  			return make([]T, size)
    49  		}
    50  		b.buffer = make([]T, len(b.buffer))
    51  		b.offset = 0
    52  	}
    53  	result := b.buffer[b.offset : b.offset+size]
    54  	b.offset += size
    55  	return result
    56  }
    57  
    58  //nolint:unused
    59  func (b *sliceAllocator[T]) one(x T) []T {
    60  	r := b.alloc(1)
    61  	r[0] = x
    62  	return r
    63  }
    64  
    65  func newGenericSliceAllocator[T any](batchSize int) *sliceAllocator[T] {
    66  	return &sliceAllocator[T]{buffer: make([]T, batchSize)}
    67  }
    68  
    69  // SliceAllocator for different slice types
    70  type SliceAllocator struct {
    71  	intAllocator             *sliceAllocator[int]
    72  	int64Allocator           *sliceAllocator[int64]
    73  	uint64Allocator          *sliceAllocator[uint64]
    74  	stringAllocator          *sliceAllocator[string]
    75  	nullableStringAllocator  *sliceAllocator[*string]
    76  	byteAllocator            *sliceAllocator[byte]
    77  	bytesAllocator           *sliceAllocator[[]byte]
    78  	columnGroupAllocator     *sliceAllocator[*columnGroup]
    79  	rowChangedEventAllocator *sliceAllocator[rowChangedEvent]
    80  }
    81  
    82  // NewSliceAllocator creates a new slice allocator with given batch allocation size.
    83  func NewSliceAllocator(batchSize int) *SliceAllocator {
    84  	return &SliceAllocator{
    85  		intAllocator:             newGenericSliceAllocator[int](batchSize),
    86  		int64Allocator:           newGenericSliceAllocator[int64](batchSize),
    87  		uint64Allocator:          newGenericSliceAllocator[uint64](batchSize),
    88  		stringAllocator:          newGenericSliceAllocator[string](batchSize),
    89  		nullableStringAllocator:  newGenericSliceAllocator[*string](batchSize),
    90  		byteAllocator:            newGenericSliceAllocator[byte](batchSize),
    91  		bytesAllocator:           newGenericSliceAllocator[[]byte](batchSize),
    92  		columnGroupAllocator:     newGenericSliceAllocator[*columnGroup](batchSize),
    93  		rowChangedEventAllocator: newGenericSliceAllocator[rowChangedEvent](batchSize),
    94  	}
    95  }
    96  
    97  func (b *SliceAllocator) intSlice(size int) []int {
    98  	return b.intAllocator.alloc(size)
    99  }
   100  
   101  //nolint:unused
   102  func (b *SliceAllocator) oneIntSlice(x int) []int {
   103  	return b.intAllocator.one(x)
   104  }
   105  
   106  //nolint:unused
   107  func (b *SliceAllocator) resizeIntSlice(old []int, newSize int) []int {
   108  	return b.intAllocator.realloc(old, newSize)
   109  }
   110  
   111  func (b *SliceAllocator) int64Slice(size int) []int64 {
   112  	return b.int64Allocator.alloc(size)
   113  }
   114  
   115  //nolint:unused
   116  func (b *SliceAllocator) oneInt64Slice(x int64) []int64 {
   117  	return b.int64Allocator.one(x)
   118  }
   119  
   120  func (b *SliceAllocator) resizeInt64Slice(old []int64, newSize int) []int64 {
   121  	return b.int64Allocator.realloc(old, newSize)
   122  }
   123  
   124  func (b *SliceAllocator) uint64Slice(size int) []uint64 {
   125  	return b.uint64Allocator.alloc(size)
   126  }
   127  
   128  func (b *SliceAllocator) oneUint64Slice(x uint64) []uint64 {
   129  	return b.uint64Allocator.one(x)
   130  }
   131  
   132  func (b *SliceAllocator) resizeUint64Slice(old []uint64, newSize int) []uint64 {
   133  	return b.uint64Allocator.realloc(old, newSize)
   134  }
   135  
   136  func (b *SliceAllocator) stringSlice(size int) []string {
   137  	return b.stringAllocator.alloc(size)
   138  }
   139  
   140  //nolint:unused
   141  func (b *SliceAllocator) oneStringSlice(x string) []string {
   142  	return b.stringAllocator.one(x)
   143  }
   144  
   145  //nolint:unused
   146  func (b *SliceAllocator) resizeStringSlice(old []string, newSize int) []string {
   147  	return b.stringAllocator.realloc(old, newSize)
   148  }
   149  
   150  func (b *SliceAllocator) nullableStringSlice(size int) []*string {
   151  	return b.nullableStringAllocator.alloc(size)
   152  }
   153  
   154  func (b *SliceAllocator) oneNullableStringSlice(x *string) []*string {
   155  	return b.nullableStringAllocator.one(x)
   156  }
   157  
   158  func (b *SliceAllocator) resizeNullableStringSlice(old []*string, newSize int) []*string {
   159  	return b.nullableStringAllocator.realloc(old, newSize)
   160  }
   161  
   162  func (b *SliceAllocator) byteSlice(size int) []byte {
   163  	return b.byteAllocator.alloc(size)
   164  }
   165  
   166  //nolint:unused
   167  func (b *SliceAllocator) oneByteSlice(x byte) []byte {
   168  	return b.byteAllocator.one(x)
   169  }
   170  
   171  //nolint:unused
   172  func (b *SliceAllocator) resizeByteSlice(old []byte, newSize int) []byte {
   173  	return b.byteAllocator.realloc(old, newSize)
   174  }
   175  
   176  func (b *SliceAllocator) bytesSlice(size int) [][]byte {
   177  	return b.bytesAllocator.alloc(size)
   178  }
   179  
   180  //nolint:unused
   181  func (b *SliceAllocator) oneBytesSlice(x []byte) [][]byte {
   182  	return b.bytesAllocator.one(x)
   183  }
   184  
   185  //nolint:unused
   186  func (b *SliceAllocator) resizeBytesSlice(old [][]byte, newSize int) [][]byte {
   187  	return b.bytesAllocator.realloc(old, newSize)
   188  }
   189  
   190  func (b *SliceAllocator) columnGroupSlice(size int) []*columnGroup {
   191  	return b.columnGroupAllocator.alloc(size)
   192  }
   193  
   194  //nolint:unused
   195  func (b *SliceAllocator) oneColumnGroupSlice(x *columnGroup) []*columnGroup {
   196  	return b.columnGroupAllocator.one(x)
   197  }
   198  
   199  //nolint:unused
   200  func (b *SliceAllocator) resizeColumnGroupSlice(old []*columnGroup, newSize int) []*columnGroup {
   201  	return b.columnGroupAllocator.realloc(old, newSize)
   202  }
   203  
   204  //nolint:unused
   205  func (b *SliceAllocator) rowChangedEventSlice(size int) []rowChangedEvent {
   206  	return b.rowChangedEventAllocator.alloc(size)
   207  }
   208  
   209  //nolint:unused
   210  func (b *SliceAllocator) oneRowChangedEventSlice(x rowChangedEvent) []rowChangedEvent {
   211  	return b.rowChangedEventAllocator.one(x)
   212  }
   213  
   214  func (b *SliceAllocator) resizeRowChangedEventSlice(old []rowChangedEvent, newSize int) []rowChangedEvent {
   215  	return b.rowChangedEventAllocator.realloc(old, newSize)
   216  }