diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3ed6c1fd9..d9c87d217 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.17.x, 1.20.x, 1.21.x] + go-version: [1.20.x, 1.21.x] os: [ubuntu, windows, macOS] env: OS: ${{ matrix.os }}-latest @@ -44,7 +44,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.17.x, 1.20.x, 1.21.x] + go-version: [1.20.x, 1.21.x] ydb-version: [22.5, 23.1, 23.2, 23.3] services: ydb: diff --git a/CHANGELOG.md b/CHANGELOG.md index 82b67ff4d..7a0cbfe09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ * Refactored `internal/value/intervalValue.Yql()` +* The minimum version of Go in `ydb-go-sdk` has been raised to `go1.20` ## v3.54.3 * Added per message metadata support for topic api diff --git a/README.md b/README.md index 47740b7ac..eb51ff130 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ Supports `table`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripti `YDB` is an open-source Distributed SQL Database that combines high availability and scalability with strict consistency and [ACID](https://en.wikipedia.org/wiki/ACID) transactions. `YDB` was created primarily for [OLTP](https://en.wikipedia.org/wiki/Online_transaction_processing) workloads and supports some [OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing) scenarious. +## Supported Go Versions + +`ydb-go-sdk` supports all Go versions supported by the official [Go Release Policy](https://go.dev/doc/devel/release#policy). +That is, the two most recent releases of Go. + ## Installation ```sh diff --git a/internal/allocator/allocator.go b/internal/allocator/allocator.go index f08282ad0..2c8c7b176 100644 --- a/internal/allocator/allocator.go +++ b/internal/allocator/allocator.go @@ -1,191 +1,922 @@ -//go:build !go1.18 -// +build !go1.18 - package allocator import ( + "sync" + "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" ) type ( - Allocator struct{} + Allocator struct { + valueAllocator + typeAllocator + typedValueAllocator + boolAllocator + typeDecimalAllocator + typeListAllocator + typeEmptyListAllocator + typeEmptyDictAllocator + typeTupleAllocator + typeStructAllocator + typeDictAllocator + decimalAllocator + listAllocator + tupleAllocator + structAllocator + dictAllocator + structMemberAllocator + typeOptionalAllocator + optionalAllocator + bytesAllocator + textAllocator + uint32Allocator + int32Allocator + low128Allocator + uint64Allocator + int64Allocator + floatAllocator + doubleAllocator + nestedAllocator + pairAllocator + nullFlagAllocator + variantAllocator + typeVariantAllocator + variantStructItemsAllocator + variantTupleItemsAllocator + tableExecuteQueryResultAllocator + tableExecuteQueryRequestAllocator + tableQueryCachePolicyAllocator + tableQueryAllocator + tableQueryYqlTextAllocator + tableQueryIDAllocator + } ) func New() (v *Allocator) { - return &Allocator{} + return allocatorPool.Get() +} + +func (a *Allocator) Free() { + a.valueAllocator.free() + a.typeAllocator.free() + a.typedValueAllocator.free() + a.boolAllocator.free() + a.typeDecimalAllocator.free() + a.typeListAllocator.free() + a.typeEmptyListAllocator.free() + a.typeEmptyDictAllocator.free() + a.typeTupleAllocator.free() + a.typeStructAllocator.free() + a.typeDictAllocator.free() + a.decimalAllocator.free() + a.listAllocator.free() + a.tupleAllocator.free() + a.structAllocator.free() + a.dictAllocator.free() + a.structMemberAllocator.free() + a.typeOptionalAllocator.free() + a.optionalAllocator.free() + a.bytesAllocator.free() + a.textAllocator.free() + a.uint32Allocator.free() + a.int32Allocator.free() + a.low128Allocator.free() + a.uint64Allocator.free() + a.int64Allocator.free() + a.floatAllocator.free() + a.doubleAllocator.free() + a.nestedAllocator.free() + a.pairAllocator.free() + a.nullFlagAllocator.free() + a.variantAllocator.free() + a.typeVariantAllocator.free() + a.variantStructItemsAllocator.free() + a.variantTupleItemsAllocator.free() + a.tableExecuteQueryRequestAllocator.free() + a.tableExecuteQueryResultAllocator.free() + a.tableQueryCachePolicyAllocator.free() + a.tableQueryAllocator.free() + a.tableQueryYqlTextAllocator.free() + a.tableQueryIDAllocator.free() + + allocatorPool.Put(a) +} + +type boolAllocator struct { + allocations []*Ydb.Value_BoolValue +} + +func (a *boolAllocator) Bool() (v *Ydb.Value_BoolValue) { + v = boolPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *boolAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_BoolValue{} + boolPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type bytesAllocator struct { + allocations []*Ydb.Value_BytesValue +} + +func (a *bytesAllocator) Bytes() (v *Ydb.Value_BytesValue) { + v = bytesPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *bytesAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_BytesValue{} + bytesPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type decimalAllocator struct { + allocations []*Ydb.DecimalType +} + +func (a *decimalAllocator) Decimal() (v *Ydb.DecimalType) { + v = decimalPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *decimalAllocator) free() { + for _, v := range a.allocations { + v.Reset() + decimalPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type dictAllocator struct { + allocations []*Ydb.DictType +} + +func (a *dictAllocator) Dict() (v *Ydb.DictType) { + v = dictPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *dictAllocator) free() { + for _, v := range a.allocations { + v.Reset() + dictPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type doubleAllocator struct { + allocations []*Ydb.Value_DoubleValue +} + +func (a *doubleAllocator) Double() (v *Ydb.Value_DoubleValue) { + v = doublePool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *doubleAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_DoubleValue{} + doublePool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type floatAllocator struct { + allocations []*Ydb.Value_FloatValue +} + +func (a *floatAllocator) Float() (v *Ydb.Value_FloatValue) { + v = floatPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *floatAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_FloatValue{} + floatPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type int32Allocator struct { + allocations []*Ydb.Value_Int32Value +} + +func (a *int32Allocator) Int32() (v *Ydb.Value_Int32Value) { + v = int32Pool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *int32Allocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_Int32Value{} + int32Pool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type int64Allocator struct { + allocations []*Ydb.Value_Int64Value +} + +func (a *int64Allocator) Int64() (v *Ydb.Value_Int64Value) { + v = int64Pool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *int64Allocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_Int64Value{} + int64Pool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type listAllocator struct { + allocations []*Ydb.ListType +} + +func (a *listAllocator) List() (v *Ydb.ListType) { + v = listPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *listAllocator) free() { + for _, v := range a.allocations { + v.Reset() + listPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type low128Allocator struct { + allocations []*Ydb.Value_Low_128 +} + +func (a *low128Allocator) Low128() (v *Ydb.Value_Low_128) { + v = low128Pool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *low128Allocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_Low_128{} + low128Pool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type nestedAllocator struct { + allocations []*Ydb.Value_NestedValue +} + +func (a *nestedAllocator) Nested() (v *Ydb.Value_NestedValue) { + v = nestedPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *nestedAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_NestedValue{} + nestedPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type nullFlagAllocator struct { + allocations []*Ydb.Value_NullFlagValue +} + +func (a *nullFlagAllocator) NullFlag() (v *Ydb.Value_NullFlagValue) { + v = nullFlagPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *nullFlagAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_NullFlagValue{} + nullFlagPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type optionalAllocator struct { + allocations []*Ydb.OptionalType +} + +func (a *optionalAllocator) Optional() (v *Ydb.OptionalType) { + v = optionalPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *optionalAllocator) free() { + for _, v := range a.allocations { + v.Reset() + optionalPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type pairAllocator struct { + allocations []*Ydb.ValuePair +} + +func (a *pairAllocator) Pair() (v *Ydb.ValuePair) { + v = pairPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *pairAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.ValuePair{} + pairPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type structAllocator struct { + allocations []*Ydb.StructType +} + +func (a *structAllocator) Struct() (v *Ydb.StructType) { + v = structPool.Get() + if cap(v.Members) <= 0 { + v.Members = make([]*Ydb.StructMember, 0, 10) + } + a.allocations = append(a.allocations, v) + return v +} + +func (a *structAllocator) free() { + for _, v := range a.allocations { + members := v.Members + for i := range members { + members[i] = nil + } + v.Reset() + v.Members = members[:0] + structPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type structMemberAllocator struct { + allocations []*Ydb.StructMember +} + +func (a *structMemberAllocator) StructMember() (v *Ydb.StructMember) { + v = structMemberPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *structMemberAllocator) free() { + for _, v := range a.allocations { + v.Reset() + structMemberPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type textAllocator struct { + allocations []*Ydb.Value_TextValue +} + +func (a *textAllocator) Text() (v *Ydb.Value_TextValue) { + v = textPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *textAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_TextValue{} + textPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type tupleAllocator struct { + allocations []*Ydb.TupleType +} + +func (a *tupleAllocator) Tuple() (v *Ydb.TupleType) { + v = tuplePool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *tupleAllocator) free() { + for _, v := range a.allocations { + elements := v.Elements + for i := range elements { + elements[i] = nil + } + v.Reset() + v.Elements = elements[:0] + tuplePool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeDecimalAllocator struct { + allocations []*Ydb.Type_DecimalType +} + +func (a *typeDecimalAllocator) TypeDecimal() (v *Ydb.Type_DecimalType) { + v = typeDecimalPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeDecimalAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_DecimalType{} + typeDecimalPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeDictAllocator struct { + allocations []*Ydb.Type_DictType +} + +func (a *typeDictAllocator) TypeDict() (v *Ydb.Type_DictType) { + v = typeDictPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeDictAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_DictType{} + typeDictPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeEmptyListAllocator struct { + allocations []*Ydb.Type_EmptyListType +} + +func (a *typeEmptyListAllocator) TypeEmptyList() (v *Ydb.Type_EmptyListType) { + v = typeEmptyListPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeEmptyListAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_EmptyListType{} + typeEmptyListPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeEmptyDictAllocator struct { + allocations []*Ydb.Type_EmptyDictType +} + +func (a *typeEmptyDictAllocator) TypeEmptyDict() (v *Ydb.Type_EmptyDictType) { + v = typeEmptyDictPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeEmptyDictAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_EmptyDictType{} + typeEmptyDictPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Free() {} +type typeAllocator struct { + allocations []*Ydb.Type +} + +func (a *typeAllocator) Type() (v *Ydb.Type) { + v = typePool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeAllocator) free() { + for _, v := range a.allocations { + v.Reset() + typePool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeListAllocator struct { + allocations []*Ydb.Type_ListType +} + +func (a *typeListAllocator) TypeList() (v *Ydb.Type_ListType) { + v = typeListPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeListAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_ListType{} + typeListPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeOptionalAllocator struct { + allocations []*Ydb.Type_OptionalType +} + +func (a *typeOptionalAllocator) TypeOptional() (v *Ydb.Type_OptionalType) { + v = typeOptionalPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeOptionalAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_OptionalType{} + typeOptionalPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type typeStructAllocator struct { + allocations []*Ydb.Type_StructType +} + +func (a *typeStructAllocator) TypeStruct() (v *Ydb.Type_StructType) { + v = typeStructPool.Get() + a.allocations = append(a.allocations, v) + return v +} + +func (a *typeStructAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_StructType{} + typeStructPool.Put(v) + } + a.allocations = a.allocations[:0] +} -func (a *Allocator) Value() (v *Ydb.Value) { - return new(Ydb.Value) +type typeTupleAllocator struct { + allocations []*Ydb.Type_TupleType } -func (a *Allocator) TypedValue() (v *Ydb.TypedValue) { - return new(Ydb.TypedValue) +func (a *typeTupleAllocator) TypeTuple() (v *Ydb.Type_TupleType) { + v = typeTuplePool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Type() (v *Ydb.Type) { - return new(Ydb.Type) +func (a *typeTupleAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_TupleType{} + typeTuplePool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) TypePrimitive() (v *Ydb.Type_TypeId) { - return new(Ydb.Type_TypeId) +type typeVariantAllocator struct { + allocations []*Ydb.Type_VariantType } -func (a *Allocator) Decimal() (v *Ydb.DecimalType) { - return new(Ydb.DecimalType) +func (a *typeVariantAllocator) TypeVariant() (v *Ydb.Type_VariantType) { + v = typeVariantPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) List() (v *Ydb.ListType) { - return new(Ydb.ListType) +func (a *typeVariantAllocator) free() { + for _, v := range a.allocations { + *v = Ydb.Type_VariantType{} + typeVariantPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Tuple() (v *Ydb.TupleType) { - return new(Ydb.TupleType) +type typedValueAllocator struct { + allocations []*Ydb.TypedValue } -func (a *Allocator) TypeDecimal() (v *Ydb.Type_DecimalType) { - return new(Ydb.Type_DecimalType) +func (a *typedValueAllocator) TypedValue() (v *Ydb.TypedValue) { + v = typedValuePool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) TypeList() (v *Ydb.Type_ListType) { - return new(Ydb.Type_ListType) +func (a *typedValueAllocator) free() { + for _, v := range a.allocations { + v.Reset() + typedValuePool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) TypeTuple() (v *Ydb.Type_TupleType) { - return new(Ydb.Type_TupleType) +type uint32Allocator struct { + allocations []*Ydb.Value_Uint32Value } -func (a *Allocator) TypeEmptyList() (v *Ydb.Type_EmptyListType) { - return new(Ydb.Type_EmptyListType) +func (a *uint32Allocator) Uint32() (v *Ydb.Value_Uint32Value) { + v = uint32Pool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) TypeEmptyDict() (v *Ydb.Type_EmptyDictType) { - return new(Ydb.Type_EmptyDictType) +func (a *uint32Allocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_Uint32Value{} + uint32Pool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) TypeOptional() (v *Ydb.Type_OptionalType) { - return new(Ydb.Type_OptionalType) +type uint64Allocator struct { + allocations []*Ydb.Value_Uint64Value } -func (a *Allocator) Bool() (v *Ydb.Value_BoolValue) { - return new(Ydb.Value_BoolValue) +func (a *uint64Allocator) Uint64() (v *Ydb.Value_Uint64Value) { + v = uint64Pool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Bytes() (v *Ydb.Value_BytesValue) { - return new(Ydb.Value_BytesValue) +func (a *uint64Allocator) free() { + for _, v := range a.allocations { + *v = Ydb.Value_Uint64Value{} + uint64Pool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Int32() (v *Ydb.Value_Int32Value) { - return new(Ydb.Value_Int32Value) +type valueAllocator struct { + allocations []*Ydb.Value } -func (a *Allocator) Int64() (v *Ydb.Value_Int64Value) { - return new(Ydb.Value_Int64Value) +func (a *valueAllocator) Value() (v *Ydb.Value) { + v = valuePool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Uint32() (v *Ydb.Value_Uint32Value) { - return new(Ydb.Value_Uint32Value) +func (a *valueAllocator) free() { + for _, v := range a.allocations { + items := v.Items + pairs := v.Pairs + for i := range items { + items[i] = nil + } + for i := range pairs { + pairs[i] = nil + } + v.Reset() + v.Items = items[:0] + v.Pairs = pairs[:0] + valuePool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Float() (v *Ydb.Value_FloatValue) { - return new(Ydb.Value_FloatValue) +type variantAllocator struct { + allocations []*Ydb.VariantType } -func (a *Allocator) Double() (v *Ydb.Value_DoubleValue) { - return new(Ydb.Value_DoubleValue) +func (a *variantAllocator) Variant() (v *Ydb.VariantType) { + v = variantPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Uint64() (v *Ydb.Value_Uint64Value) { - return new(Ydb.Value_Uint64Value) +func (a *variantAllocator) free() { + for _, v := range a.allocations { + variantPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Text() (v *Ydb.Value_TextValue) { - return new(Ydb.Value_TextValue) +type variantStructItemsAllocator struct { + allocations []*Ydb.VariantType_StructItems } -func (a *Allocator) Low128() (v *Ydb.Value_Low_128) { - return new(Ydb.Value_Low_128) +func (a *variantStructItemsAllocator) VariantStructItems() (v *Ydb.VariantType_StructItems) { + v = variantStructItemsPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Struct() (v *Ydb.StructType) { - return new(Ydb.StructType) +func (a *variantStructItemsAllocator) free() { + for _, v := range a.allocations { + variantStructItemsPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) StructMember() (v *Ydb.StructMember) { - return new(Ydb.StructMember) +type variantTupleItemsAllocator struct { + allocations []*Ydb.VariantType_TupleItems } -func (a *Allocator) Optional() (v *Ydb.OptionalType) { - return new(Ydb.OptionalType) +func (a *variantTupleItemsAllocator) VariantTupleItems() (v *Ydb.VariantType_TupleItems) { + v = variantTupleItemsPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) TypeStruct() (v *Ydb.Type_StructType) { - return new(Ydb.Type_StructType) +func (a *variantTupleItemsAllocator) free() { + for _, v := range a.allocations { + variantTupleItemsPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Nested() (v *Ydb.Value_NestedValue) { - return new(Ydb.Value_NestedValue) +type tableExecuteQueryResultAllocator struct { + allocations []*Ydb_Table.ExecuteQueryResult } -func (a *Allocator) TypeDict() (v *Ydb.Type_DictType) { - return new(Ydb.Type_DictType) +func (a *tableExecuteQueryResultAllocator) TableExecuteQueryResult() (v *Ydb_Table.ExecuteQueryResult) { + v = tableExecuteQueryResultPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) Dict() (v *Ydb.DictType) { - return new(Ydb.DictType) +func (a *tableExecuteQueryResultAllocator) free() { + for _, v := range a.allocations { + v.Reset() + tableExecuteQueryResultPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) Pair() (v *Ydb.ValuePair) { - return new(Ydb.ValuePair) +type tableExecuteQueryRequestAllocator struct { + allocations []*Ydb_Table.ExecuteDataQueryRequest } -func (a *Allocator) NullFlag() (v *Ydb.Value_NullFlagValue) { - return new(Ydb.Value_NullFlagValue) +func (a *tableExecuteQueryRequestAllocator) TableExecuteDataQueryRequest() (v *Ydb_Table.ExecuteDataQueryRequest) { + v = tableExecuteDataQueryRequestPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) VariantStructItems() (v *Ydb.VariantType_StructItems) { - return new(Ydb.VariantType_StructItems) +func (a *tableExecuteQueryRequestAllocator) free() { + for _, v := range a.allocations { + v.Reset() + tableExecuteDataQueryRequestPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) TypeVariant() (v *Ydb.Type_VariantType) { - return new(Ydb.Type_VariantType) +type tableQueryCachePolicyAllocator struct { + allocations []*Ydb_Table.QueryCachePolicy } -func (a *Allocator) Variant() (v *Ydb.VariantType) { - return new(Ydb.VariantType) +func (a *tableQueryCachePolicyAllocator) TableQueryCachePolicy() (v *Ydb_Table.QueryCachePolicy) { + v = tableQueryCachePolicyPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) VariantTupleItems() (v *Ydb.VariantType_TupleItems) { - return new(Ydb.VariantType_TupleItems) +func (a *tableQueryCachePolicyAllocator) free() { + for _, v := range a.allocations { + v.Reset() + tableQueryCachePolicyPool.Put(v) + } + a.allocations = a.allocations[:0] +} + +type tableQueryAllocator struct { + allocations []*Ydb_Table.Query } -func (a *Allocator) TableExecuteQueryResult() (v *Ydb_Table.ExecuteQueryResult) { - return new(Ydb_Table.ExecuteQueryResult) +func (a *tableQueryAllocator) TableQuery() (v *Ydb_Table.Query) { + v = tableQueryPool.Get() + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) TableExecuteDataQueryRequest() (v *Ydb_Table.ExecuteDataQueryRequest) { - return new(Ydb_Table.ExecuteDataQueryRequest) +func (a *tableQueryAllocator) free() { + for _, v := range a.allocations { + v.Reset() + tableQueryPool.Put(v) + } + a.allocations = a.allocations[:0] } -func (a *Allocator) TableQueryCachePolicy() (v *Ydb_Table.QueryCachePolicy) { - return new(Ydb_Table.QueryCachePolicy) +type tableQueryYqlTextAllocator struct { + allocations []*Ydb_Table.Query_YqlText } -func (a *Allocator) TableQuery() (v *Ydb_Table.Query) { - return new(Ydb_Table.Query) +func (a *tableQueryYqlTextAllocator) TableQueryYqlText(s string) (v *Ydb_Table.Query_YqlText) { + v = tableQueryYqlTextPool.Get() + v.YqlText = s + a.allocations = append(a.allocations, v) + return v } -func (a *Allocator) TableQueryYqlText(s string) (v *Ydb_Table.Query_YqlText) { - return &Ydb_Table.Query_YqlText{ - YqlText: s, +func (a *tableQueryYqlTextAllocator) free() { + for _, v := range a.allocations { + tableQueryYqlTextPool.Put(v) } + a.allocations = a.allocations[:0] +} + +type tableQueryIDAllocator struct { + allocations []*Ydb_Table.Query_Id } -func (a *Allocator) TableQueryID(id string) (v *Ydb_Table.Query_Id) { - return &Ydb_Table.Query_Id{ - Id: id, +func (a *tableQueryIDAllocator) TableQueryID(id string) (v *Ydb_Table.Query_Id) { + v = tableQueryIDPool.Get() + v.Id = id + a.allocations = append(a.allocations, v) + return v +} + +func (a *tableQueryIDAllocator) free() { + for _, v := range a.allocations { + tableQueryIDPool.Put(v) } + a.allocations = a.allocations[:0] } + +type Pool[T any] sync.Pool + +func (p *Pool[T]) Get() *T { + v := (*sync.Pool)(p).Get() + if v == nil { + var zero T + v = &zero + } + return v.(*T) +} + +func (p *Pool[T]) Put(t *T) { + (*sync.Pool)(p).Put(t) +} + +var ( + allocatorPool Pool[Allocator] + valuePool Pool[Ydb.Value] + typePool Pool[Ydb.Type] + typeDecimalPool Pool[Ydb.Type_DecimalType] + typeListPool Pool[Ydb.Type_ListType] + typeEmptyListPool Pool[Ydb.Type_EmptyListType] + typeEmptyDictPool Pool[Ydb.Type_EmptyDictType] + typeTuplePool Pool[Ydb.Type_TupleType] + typeStructPool Pool[Ydb.Type_StructType] + typeDictPool Pool[Ydb.Type_DictType] + typeVariantPool Pool[Ydb.Type_VariantType] + decimalPool Pool[Ydb.DecimalType] + listPool Pool[Ydb.ListType] + tuplePool Pool[Ydb.TupleType] + structPool Pool[Ydb.StructType] + dictPool Pool[Ydb.DictType] + variantPool Pool[Ydb.VariantType] + variantTupleItemsPool Pool[Ydb.VariantType_TupleItems] + variantStructItemsPool Pool[Ydb.VariantType_StructItems] + structMemberPool Pool[Ydb.StructMember] + typeOptionalPool Pool[Ydb.Type_OptionalType] + optionalPool Pool[Ydb.OptionalType] + typedValuePool Pool[Ydb.TypedValue] + boolPool Pool[Ydb.Value_BoolValue] + bytesPool Pool[Ydb.Value_BytesValue] + textPool Pool[Ydb.Value_TextValue] + int32Pool Pool[Ydb.Value_Int32Value] + uint32Pool Pool[Ydb.Value_Uint32Value] + low128Pool Pool[Ydb.Value_Low_128] + int64Pool Pool[Ydb.Value_Int64Value] + uint64Pool Pool[Ydb.Value_Uint64Value] + floatPool Pool[Ydb.Value_FloatValue] + doublePool Pool[Ydb.Value_DoubleValue] + nestedPool Pool[Ydb.Value_NestedValue] + nullFlagPool Pool[Ydb.Value_NullFlagValue] + pairPool Pool[Ydb.ValuePair] + tableExecuteQueryResultPool Pool[Ydb_Table.ExecuteQueryResult] + tableExecuteDataQueryRequestPool Pool[Ydb_Table.ExecuteDataQueryRequest] + tableQueryCachePolicyPool Pool[Ydb_Table.QueryCachePolicy] + tableQueryPool Pool[Ydb_Table.Query] + tableQueryYqlTextPool Pool[Ydb_Table.Query_YqlText] + tableQueryIDPool Pool[Ydb_Table.Query_Id] +) diff --git a/internal/allocator/allocator_go1.18.go b/internal/allocator/allocator_go1.18.go deleted file mode 100644 index aff3a6571..000000000 --- a/internal/allocator/allocator_go1.18.go +++ /dev/null @@ -1,925 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package allocator - -import ( - "sync" - - "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" - "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" -) - -type ( - Allocator struct { - valueAllocator - typeAllocator - typedValueAllocator - boolAllocator - typeDecimalAllocator - typeListAllocator - typeEmptyListAllocator - typeEmptyDictAllocator - typeTupleAllocator - typeStructAllocator - typeDictAllocator - decimalAllocator - listAllocator - tupleAllocator - structAllocator - dictAllocator - structMemberAllocator - typeOptionalAllocator - optionalAllocator - bytesAllocator - textAllocator - uint32Allocator - int32Allocator - low128Allocator - uint64Allocator - int64Allocator - floatAllocator - doubleAllocator - nestedAllocator - pairAllocator - nullFlagAllocator - variantAllocator - typeVariantAllocator - variantStructItemsAllocator - variantTupleItemsAllocator - tableExecuteQueryResultAllocator - tableExecuteQueryRequestAllocator - tableQueryCachePolicyAllocator - tableQueryAllocator - tableQueryYqlTextAllocator - tableQueryIDAllocator - } -) - -func New() (v *Allocator) { - return allocatorPool.Get() -} - -func (a *Allocator) Free() { - a.valueAllocator.free() - a.typeAllocator.free() - a.typedValueAllocator.free() - a.boolAllocator.free() - a.typeDecimalAllocator.free() - a.typeListAllocator.free() - a.typeEmptyListAllocator.free() - a.typeEmptyDictAllocator.free() - a.typeTupleAllocator.free() - a.typeStructAllocator.free() - a.typeDictAllocator.free() - a.decimalAllocator.free() - a.listAllocator.free() - a.tupleAllocator.free() - a.structAllocator.free() - a.dictAllocator.free() - a.structMemberAllocator.free() - a.typeOptionalAllocator.free() - a.optionalAllocator.free() - a.bytesAllocator.free() - a.textAllocator.free() - a.uint32Allocator.free() - a.int32Allocator.free() - a.low128Allocator.free() - a.uint64Allocator.free() - a.int64Allocator.free() - a.floatAllocator.free() - a.doubleAllocator.free() - a.nestedAllocator.free() - a.pairAllocator.free() - a.nullFlagAllocator.free() - a.variantAllocator.free() - a.typeVariantAllocator.free() - a.variantStructItemsAllocator.free() - a.variantTupleItemsAllocator.free() - a.tableExecuteQueryRequestAllocator.free() - a.tableExecuteQueryResultAllocator.free() - a.tableQueryCachePolicyAllocator.free() - a.tableQueryAllocator.free() - a.tableQueryYqlTextAllocator.free() - a.tableQueryIDAllocator.free() - - allocatorPool.Put(a) -} - -type boolAllocator struct { - allocations []*Ydb.Value_BoolValue -} - -func (a *boolAllocator) Bool() (v *Ydb.Value_BoolValue) { - v = boolPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *boolAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_BoolValue{} - boolPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type bytesAllocator struct { - allocations []*Ydb.Value_BytesValue -} - -func (a *bytesAllocator) Bytes() (v *Ydb.Value_BytesValue) { - v = bytesPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *bytesAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_BytesValue{} - bytesPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type decimalAllocator struct { - allocations []*Ydb.DecimalType -} - -func (a *decimalAllocator) Decimal() (v *Ydb.DecimalType) { - v = decimalPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *decimalAllocator) free() { - for _, v := range a.allocations { - v.Reset() - decimalPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type dictAllocator struct { - allocations []*Ydb.DictType -} - -func (a *dictAllocator) Dict() (v *Ydb.DictType) { - v = dictPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *dictAllocator) free() { - for _, v := range a.allocations { - v.Reset() - dictPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type doubleAllocator struct { - allocations []*Ydb.Value_DoubleValue -} - -func (a *doubleAllocator) Double() (v *Ydb.Value_DoubleValue) { - v = doublePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *doubleAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_DoubleValue{} - doublePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type floatAllocator struct { - allocations []*Ydb.Value_FloatValue -} - -func (a *floatAllocator) Float() (v *Ydb.Value_FloatValue) { - v = floatPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *floatAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_FloatValue{} - floatPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type int32Allocator struct { - allocations []*Ydb.Value_Int32Value -} - -func (a *int32Allocator) Int32() (v *Ydb.Value_Int32Value) { - v = int32Pool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *int32Allocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_Int32Value{} - int32Pool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type int64Allocator struct { - allocations []*Ydb.Value_Int64Value -} - -func (a *int64Allocator) Int64() (v *Ydb.Value_Int64Value) { - v = int64Pool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *int64Allocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_Int64Value{} - int64Pool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type listAllocator struct { - allocations []*Ydb.ListType -} - -func (a *listAllocator) List() (v *Ydb.ListType) { - v = listPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *listAllocator) free() { - for _, v := range a.allocations { - v.Reset() - listPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type low128Allocator struct { - allocations []*Ydb.Value_Low_128 -} - -func (a *low128Allocator) Low128() (v *Ydb.Value_Low_128) { - v = low128Pool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *low128Allocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_Low_128{} - low128Pool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type nestedAllocator struct { - allocations []*Ydb.Value_NestedValue -} - -func (a *nestedAllocator) Nested() (v *Ydb.Value_NestedValue) { - v = nestedPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *nestedAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_NestedValue{} - nestedPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type nullFlagAllocator struct { - allocations []*Ydb.Value_NullFlagValue -} - -func (a *nullFlagAllocator) NullFlag() (v *Ydb.Value_NullFlagValue) { - v = nullFlagPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *nullFlagAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_NullFlagValue{} - nullFlagPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type optionalAllocator struct { - allocations []*Ydb.OptionalType -} - -func (a *optionalAllocator) Optional() (v *Ydb.OptionalType) { - v = optionalPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *optionalAllocator) free() { - for _, v := range a.allocations { - v.Reset() - optionalPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type pairAllocator struct { - allocations []*Ydb.ValuePair -} - -func (a *pairAllocator) Pair() (v *Ydb.ValuePair) { - v = pairPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *pairAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.ValuePair{} - pairPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type structAllocator struct { - allocations []*Ydb.StructType -} - -func (a *structAllocator) Struct() (v *Ydb.StructType) { - v = structPool.Get() - if cap(v.Members) <= 0 { - v.Members = make([]*Ydb.StructMember, 0, 10) - } - a.allocations = append(a.allocations, v) - return v -} - -func (a *structAllocator) free() { - for _, v := range a.allocations { - members := v.Members - for i := range members { - members[i] = nil - } - v.Reset() - v.Members = members[:0] - structPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type structMemberAllocator struct { - allocations []*Ydb.StructMember -} - -func (a *structMemberAllocator) StructMember() (v *Ydb.StructMember) { - v = structMemberPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *structMemberAllocator) free() { - for _, v := range a.allocations { - v.Reset() - structMemberPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type textAllocator struct { - allocations []*Ydb.Value_TextValue -} - -func (a *textAllocator) Text() (v *Ydb.Value_TextValue) { - v = textPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *textAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_TextValue{} - textPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tupleAllocator struct { - allocations []*Ydb.TupleType -} - -func (a *tupleAllocator) Tuple() (v *Ydb.TupleType) { - v = tuplePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *tupleAllocator) free() { - for _, v := range a.allocations { - elements := v.Elements - for i := range elements { - elements[i] = nil - } - v.Reset() - v.Elements = elements[:0] - tuplePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeDecimalAllocator struct { - allocations []*Ydb.Type_DecimalType -} - -func (a *typeDecimalAllocator) TypeDecimal() (v *Ydb.Type_DecimalType) { - v = typeDecimalPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeDecimalAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_DecimalType{} - typeDecimalPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeDictAllocator struct { - allocations []*Ydb.Type_DictType -} - -func (a *typeDictAllocator) TypeDict() (v *Ydb.Type_DictType) { - v = typeDictPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeDictAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_DictType{} - typeDictPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeEmptyListAllocator struct { - allocations []*Ydb.Type_EmptyListType -} - -func (a *typeEmptyListAllocator) TypeEmptyList() (v *Ydb.Type_EmptyListType) { - v = typeEmptyListPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeEmptyListAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_EmptyListType{} - typeEmptyListPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeEmptyDictAllocator struct { - allocations []*Ydb.Type_EmptyDictType -} - -func (a *typeEmptyDictAllocator) TypeEmptyDict() (v *Ydb.Type_EmptyDictType) { - v = typeEmptyDictPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeEmptyDictAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_EmptyDictType{} - typeEmptyDictPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeAllocator struct { - allocations []*Ydb.Type -} - -func (a *typeAllocator) Type() (v *Ydb.Type) { - v = typePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeAllocator) free() { - for _, v := range a.allocations { - v.Reset() - typePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeListAllocator struct { - allocations []*Ydb.Type_ListType -} - -func (a *typeListAllocator) TypeList() (v *Ydb.Type_ListType) { - v = typeListPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeListAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_ListType{} - typeListPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeOptionalAllocator struct { - allocations []*Ydb.Type_OptionalType -} - -func (a *typeOptionalAllocator) TypeOptional() (v *Ydb.Type_OptionalType) { - v = typeOptionalPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeOptionalAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_OptionalType{} - typeOptionalPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeStructAllocator struct { - allocations []*Ydb.Type_StructType -} - -func (a *typeStructAllocator) TypeStruct() (v *Ydb.Type_StructType) { - v = typeStructPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeStructAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_StructType{} - typeStructPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeTupleAllocator struct { - allocations []*Ydb.Type_TupleType -} - -func (a *typeTupleAllocator) TypeTuple() (v *Ydb.Type_TupleType) { - v = typeTuplePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeTupleAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_TupleType{} - typeTuplePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typeVariantAllocator struct { - allocations []*Ydb.Type_VariantType -} - -func (a *typeVariantAllocator) TypeVariant() (v *Ydb.Type_VariantType) { - v = typeVariantPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typeVariantAllocator) free() { - for _, v := range a.allocations { - *v = Ydb.Type_VariantType{} - typeVariantPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type typedValueAllocator struct { - allocations []*Ydb.TypedValue -} - -func (a *typedValueAllocator) TypedValue() (v *Ydb.TypedValue) { - v = typedValuePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *typedValueAllocator) free() { - for _, v := range a.allocations { - v.Reset() - typedValuePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type uint32Allocator struct { - allocations []*Ydb.Value_Uint32Value -} - -func (a *uint32Allocator) Uint32() (v *Ydb.Value_Uint32Value) { - v = uint32Pool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *uint32Allocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_Uint32Value{} - uint32Pool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type uint64Allocator struct { - allocations []*Ydb.Value_Uint64Value -} - -func (a *uint64Allocator) Uint64() (v *Ydb.Value_Uint64Value) { - v = uint64Pool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *uint64Allocator) free() { - for _, v := range a.allocations { - *v = Ydb.Value_Uint64Value{} - uint64Pool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type valueAllocator struct { - allocations []*Ydb.Value -} - -func (a *valueAllocator) Value() (v *Ydb.Value) { - v = valuePool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *valueAllocator) free() { - for _, v := range a.allocations { - items := v.Items - pairs := v.Pairs - for i := range items { - items[i] = nil - } - for i := range pairs { - pairs[i] = nil - } - v.Reset() - v.Items = items[:0] - v.Pairs = pairs[:0] - valuePool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type variantAllocator struct { - allocations []*Ydb.VariantType -} - -func (a *variantAllocator) Variant() (v *Ydb.VariantType) { - v = variantPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *variantAllocator) free() { - for _, v := range a.allocations { - variantPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type variantStructItemsAllocator struct { - allocations []*Ydb.VariantType_StructItems -} - -func (a *variantStructItemsAllocator) VariantStructItems() (v *Ydb.VariantType_StructItems) { - v = variantStructItemsPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *variantStructItemsAllocator) free() { - for _, v := range a.allocations { - variantStructItemsPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type variantTupleItemsAllocator struct { - allocations []*Ydb.VariantType_TupleItems -} - -func (a *variantTupleItemsAllocator) VariantTupleItems() (v *Ydb.VariantType_TupleItems) { - v = variantTupleItemsPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *variantTupleItemsAllocator) free() { - for _, v := range a.allocations { - variantTupleItemsPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableExecuteQueryResultAllocator struct { - allocations []*Ydb_Table.ExecuteQueryResult -} - -func (a *tableExecuteQueryResultAllocator) TableExecuteQueryResult() (v *Ydb_Table.ExecuteQueryResult) { - v = tableExecuteQueryResultPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableExecuteQueryResultAllocator) free() { - for _, v := range a.allocations { - v.Reset() - tableExecuteQueryResultPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableExecuteQueryRequestAllocator struct { - allocations []*Ydb_Table.ExecuteDataQueryRequest -} - -func (a *tableExecuteQueryRequestAllocator) TableExecuteDataQueryRequest() (v *Ydb_Table.ExecuteDataQueryRequest) { - v = tableExecuteDataQueryRequestPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableExecuteQueryRequestAllocator) free() { - for _, v := range a.allocations { - v.Reset() - tableExecuteDataQueryRequestPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableQueryCachePolicyAllocator struct { - allocations []*Ydb_Table.QueryCachePolicy -} - -func (a *tableQueryCachePolicyAllocator) TableQueryCachePolicy() (v *Ydb_Table.QueryCachePolicy) { - v = tableQueryCachePolicyPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableQueryCachePolicyAllocator) free() { - for _, v := range a.allocations { - v.Reset() - tableQueryCachePolicyPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableQueryAllocator struct { - allocations []*Ydb_Table.Query -} - -func (a *tableQueryAllocator) TableQuery() (v *Ydb_Table.Query) { - v = tableQueryPool.Get() - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableQueryAllocator) free() { - for _, v := range a.allocations { - v.Reset() - tableQueryPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableQueryYqlTextAllocator struct { - allocations []*Ydb_Table.Query_YqlText -} - -func (a *tableQueryYqlTextAllocator) TableQueryYqlText(s string) (v *Ydb_Table.Query_YqlText) { - v = tableQueryYqlTextPool.Get() - v.YqlText = s - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableQueryYqlTextAllocator) free() { - for _, v := range a.allocations { - tableQueryYqlTextPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type tableQueryIDAllocator struct { - allocations []*Ydb_Table.Query_Id -} - -func (a *tableQueryIDAllocator) TableQueryID(id string) (v *Ydb_Table.Query_Id) { - v = tableQueryIDPool.Get() - v.Id = id - a.allocations = append(a.allocations, v) - return v -} - -func (a *tableQueryIDAllocator) free() { - for _, v := range a.allocations { - tableQueryIDPool.Put(v) - } - a.allocations = a.allocations[:0] -} - -type Pool[T any] sync.Pool - -func (p *Pool[T]) Get() *T { - v := (*sync.Pool)(p).Get() - if v == nil { - var zero T - v = &zero - } - return v.(*T) -} - -func (p *Pool[T]) Put(t *T) { - (*sync.Pool)(p).Put(t) -} - -var ( - allocatorPool Pool[Allocator] - valuePool Pool[Ydb.Value] - typePool Pool[Ydb.Type] - typeDecimalPool Pool[Ydb.Type_DecimalType] - typeListPool Pool[Ydb.Type_ListType] - typeEmptyListPool Pool[Ydb.Type_EmptyListType] - typeEmptyDictPool Pool[Ydb.Type_EmptyDictType] - typeTuplePool Pool[Ydb.Type_TupleType] - typeStructPool Pool[Ydb.Type_StructType] - typeDictPool Pool[Ydb.Type_DictType] - typeVariantPool Pool[Ydb.Type_VariantType] - decimalPool Pool[Ydb.DecimalType] - listPool Pool[Ydb.ListType] - tuplePool Pool[Ydb.TupleType] - structPool Pool[Ydb.StructType] - dictPool Pool[Ydb.DictType] - variantPool Pool[Ydb.VariantType] - variantTupleItemsPool Pool[Ydb.VariantType_TupleItems] - variantStructItemsPool Pool[Ydb.VariantType_StructItems] - structMemberPool Pool[Ydb.StructMember] - typeOptionalPool Pool[Ydb.Type_OptionalType] - optionalPool Pool[Ydb.OptionalType] - typedValuePool Pool[Ydb.TypedValue] - boolPool Pool[Ydb.Value_BoolValue] - bytesPool Pool[Ydb.Value_BytesValue] - textPool Pool[Ydb.Value_TextValue] - int32Pool Pool[Ydb.Value_Int32Value] - uint32Pool Pool[Ydb.Value_Uint32Value] - low128Pool Pool[Ydb.Value_Low_128] - int64Pool Pool[Ydb.Value_Int64Value] - uint64Pool Pool[Ydb.Value_Uint64Value] - floatPool Pool[Ydb.Value_FloatValue] - doublePool Pool[Ydb.Value_DoubleValue] - nestedPool Pool[Ydb.Value_NestedValue] - nullFlagPool Pool[Ydb.Value_NullFlagValue] - pairPool Pool[Ydb.ValuePair] - tableExecuteQueryResultPool Pool[Ydb_Table.ExecuteQueryResult] - tableExecuteDataQueryRequestPool Pool[Ydb_Table.ExecuteDataQueryRequest] - tableQueryCachePolicyPool Pool[Ydb_Table.QueryCachePolicy] - tableQueryPool Pool[Ydb_Table.Query] - tableQueryYqlTextPool Pool[Ydb_Table.Query_YqlText] - tableQueryIDPool Pool[Ydb_Table.Query_Id] -) diff --git a/internal/xatomic/type.go b/internal/xatomic/type.go index a77de524a..0ce078b19 100644 --- a/internal/xatomic/type.go +++ b/internal/xatomic/type.go @@ -1,126 +1,10 @@ -//go:build !go1.19 -// +build !go1.19 - package xatomic -// the file contains types, copied from go 1.19 atomic/type for use in older go - import "sync/atomic" -// A Bool is an atomic boolean value. -// The zero value is false. -type Bool struct { - _ noCopy - v uint32 -} - -// Load atomically loads and returns the value stored in x. -func (x *Bool) Load() bool { return atomic.LoadUint32(&x.v) != 0 } - -// Store atomically stores val into x. -func (x *Bool) Store(val bool) { atomic.StoreUint32(&x.v, b32(val)) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Bool) Swap(new bool) (old bool) { return atomic.SwapUint32(&x.v, b32(new)) != 0 } - -// CompareAndSwap executes the compare-and-swap operation for the boolean value x. -func (x *Bool) CompareAndSwap(old, new bool) (swapped bool) { - return atomic.CompareAndSwapUint32(&x.v, b32(old), b32(new)) -} - -// An Int64 is an atomic int64. The zero value is zero. -type Int64 struct { - _ noCopy - _ align64 - v int64 -} - -// Load atomically loads and returns the value stored in x. -func (x *Int64) Load() int64 { return atomic.LoadInt64(&x.v) } - -// Store atomically stores val into x. -func (x *Int64) Store(val int64) { atomic.StoreInt64(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Int64) Swap(new int64) (old int64) { return atomic.SwapInt64(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) { - return atomic.CompareAndSwapInt64(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Int64) Add(delta int64) (new int64) { return atomic.AddInt64(&x.v, delta) } - -// An Uint32 is an atomic uint32. The zero value is zero. -type Uint32 struct { - _ noCopy - v uint32 -} - -// Load atomically loads and returns the value stored in x. -func (x *Uint32) Load() uint32 { return atomic.LoadUint32(&x.v) } - -// Store atomically stores val into x. -func (x *Uint32) Store(val uint32) { atomic.StoreUint32(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Uint32) Swap(new uint32) (old uint32) { return atomic.SwapUint32(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) { - return atomic.CompareAndSwapUint32(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Uint32) Add(delta uint32) (new uint32) { return atomic.AddUint32(&x.v, delta) } - -// An Uint64 is an atomic uint64. The zero value is zero. -type Uint64 struct { - _ noCopy - _ align64 - v uint64 -} - -// Load atomically loads and returns the value stored in x. -func (x *Uint64) Load() uint64 { return atomic.LoadUint64(&x.v) } - -// Store atomically stores val into x. -func (x *Uint64) Store(val uint64) { atomic.StoreUint64(&x.v, val) } - -// Swap atomically stores new into x and returns the previous value. -func (x *Uint64) Swap(new uint64) (old uint64) { return atomic.SwapUint64(&x.v, new) } - -// CompareAndSwap executes the compare-and-swap operation for x. -func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) { - return atomic.CompareAndSwapUint64(&x.v, old, new) -} - -// Add atomically adds delta to x and returns the new value. -func (x *Uint64) Add(delta uint64) (new uint64) { return atomic.AddUint64(&x.v, delta) } - -// b32 returns a uint32 0 or 1 representing b. -func b32(b bool) uint32 { - if b { - return 1 - } - return 0 -} - -// noCopy may be added to structs which must not be copied -// after the first use. -// -// See https://golang.org/issues/8005#issuecomment-190753527 -// for details. -// -// Note that it must not be embedded, due to the Lock and Unlock methods. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} -func (*noCopy) Unlock() {} - -// align64 may be added to structs that must be 64-bit aligned. -// This struct is recognized by a special case in the compiler -// and will not work if copied to any other package. -type align64 struct{} +type ( + Bool = atomic.Bool + Int64 = atomic.Int64 + Uint32 = atomic.Uint32 + Uint64 = atomic.Uint64 +) diff --git a/internal/xatomic/type_go1.19.go b/internal/xatomic/type_go1.19.go deleted file mode 100644 index 4f50a900f..000000000 --- a/internal/xatomic/type_go1.19.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build go1.19 -// +build go1.19 - -package xatomic - -import "sync/atomic" - -type ( - Bool = atomic.Bool - Int64 = atomic.Int64 - Uint32 = atomic.Uint32 - Uint64 = atomic.Uint64 -) diff --git a/internal/xbytes/clone.go b/internal/xbytes/clone.go index 2b923e742..0b471be25 100644 --- a/internal/xbytes/clone.go +++ b/internal/xbytes/clone.go @@ -1,14 +1,10 @@ -//go:build !go1.20 -// +build !go1.20 - package xbytes +import "bytes" + // Clone returns a copy of b[:len(b)]. // The result may have additional unused capacity. // Clone(nil) returns nil. func Clone(b []byte) []byte { - if b == nil { - return nil - } - return append([]byte{}, b...) + return bytes.Clone(b) } diff --git a/internal/xbytes/clone_go1.20.go b/internal/xbytes/clone_go1.20.go deleted file mode 100644 index fd6df4ae8..000000000 --- a/internal/xbytes/clone_go1.20.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build go1.20 -// +build go1.20 - -package xbytes - -import "bytes" - -// Clone returns a copy of b[:len(b)]. -// The result may have additional unused capacity. -// Clone(nil) returns nil. -func Clone(b []byte) []byte { - return bytes.Clone(b) -} diff --git a/internal/xsql/badconn/badconn.go b/internal/xsql/badconn/badconn.go index 63b8f50da..620c674a2 100644 --- a/internal/xsql/badconn/badconn.go +++ b/internal/xsql/badconn/badconn.go @@ -1,6 +1,3 @@ -//go:build !go1.18 -// +build !go1.18 - package badconn import ( @@ -10,14 +7,43 @@ import ( "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" ) +type Error struct { + err error +} + +func (e Error) Origin() error { + return e.err +} + +func (e Error) Error() string { + return e.err.Error() +} + +func (e Error) Is(err error) bool { + //nolint:nolintlint + if err == driver.ErrBadConn { //nolint:errorlint + return true + } + return xerrors.Is(e.err, err) +} + +func (e Error) As(target interface{}) bool { + switch target.(type) { + case Error, *Error: + return true + default: + return xerrors.As(e.err, target) + } +} + func Map(err error) error { switch { case err == nil: return nil case xerrors.Is(err, io.EOF): return io.EOF - case xerrors.Is(err, driver.ErrBadConn), xerrors.MustDeleteSession(err): - return driver.ErrBadConn + case xerrors.MustDeleteSession(err): + return Error{err: err} default: return err } diff --git a/internal/xsql/badconn/badconn_go1.18.go b/internal/xsql/badconn/badconn_go1.18.go deleted file mode 100644 index 8256f195b..000000000 --- a/internal/xsql/badconn/badconn_go1.18.go +++ /dev/null @@ -1,53 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package badconn - -import ( - "database/sql/driver" - "io" - - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" -) - -type Error struct { - err error -} - -func (e Error) Origin() error { - return e.err -} - -func (e Error) Error() string { - return e.err.Error() -} - -func (e Error) Is(err error) bool { - //nolint:nolintlint - if err == driver.ErrBadConn { //nolint:errorlint - return true - } - return xerrors.Is(e.err, err) -} - -func (e Error) As(target interface{}) bool { - switch target.(type) { - case Error, *Error: - return true - default: - return xerrors.As(e.err, target) - } -} - -func Map(err error) error { - switch { - case err == nil: - return nil - case xerrors.Is(err, io.EOF): - return io.EOF - case xerrors.MustDeleteSession(err): - return Error{err: err} - default: - return err - } -} diff --git a/internal/xsql/badconn/badconn_go1.18_test.go b/internal/xsql/badconn/badconn_test.go similarity index 99% rename from internal/xsql/badconn/badconn_go1.18_test.go rename to internal/xsql/badconn/badconn_test.go index 4557563ab..1d252c051 100644 --- a/internal/xsql/badconn/badconn_go1.18_test.go +++ b/internal/xsql/badconn/badconn_test.go @@ -1,6 +1,3 @@ -//go:build go1.18 -// +build go1.18 - package badconn import ( diff --git a/internal/xsql/unwrap.go b/internal/xsql/unwrap.go index 79a1e1f47..39755e50e 100644 --- a/internal/xsql/unwrap.go +++ b/internal/xsql/unwrap.go @@ -1,10 +1,6 @@ -//go:build !go1.18 -// +build !go1.18 - package xsql import ( - "context" "database/sql" "fmt" @@ -12,19 +8,26 @@ import ( "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn" ) -func Unwrap(db *sql.DB) (connector *Connector, err error) { - c, err := db.Conn(context.Background()) - if err != nil { - return nil, badconn.Map(xerrors.WithStackTrace(err)) - } - if err = c.Raw(func(driverConn interface{}) error { - if cc, ok := driverConn.(*conn); ok { - connector = cc.connector - return nil +func Unwrap[T *sql.DB | *sql.Conn](v T) (connector *Connector, err error) { + switch vv := any(v).(type) { + case *sql.DB: + d := vv.Driver() + if dw, ok := d.(*driverWrapper); ok { + return dw.c, nil + } + return nil, xerrors.WithStackTrace(fmt.Errorf("%T is not a *driverWrapper", d)) + case *sql.Conn: + if err = vv.Raw(func(driverConn interface{}) error { + if cc, ok := driverConn.(*conn); ok { + connector = cc.connector + return nil + } + return xerrors.WithStackTrace(fmt.Errorf("%T is not a *conn", driverConn)) + }); err != nil { + return nil, badconn.Map(xerrors.WithStackTrace(err)) } - return xerrors.WithStackTrace(badconn.Map(fmt.Errorf("%+v is not a *conn", driverConn))) - }); err != nil { - return nil, badconn.Map(xerrors.WithStackTrace(err)) + return connector, nil + default: + return nil, xerrors.WithStackTrace(fmt.Errorf("unknown type %T for Unwrap", vv)) } - return connector, nil } diff --git a/internal/xsql/unwrap_go1.18.go b/internal/xsql/unwrap_go1.18.go deleted file mode 100644 index 3fc4550a9..000000000 --- a/internal/xsql/unwrap_go1.18.go +++ /dev/null @@ -1,36 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package xsql - -import ( - "database/sql" - "fmt" - - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn" -) - -func Unwrap[T *sql.DB | *sql.Conn](v T) (connector *Connector, err error) { - switch vv := any(v).(type) { - case *sql.DB: - d := vv.Driver() - if dw, ok := d.(*driverWrapper); ok { - return dw.c, nil - } - return nil, xerrors.WithStackTrace(fmt.Errorf("%T is not a *driverWrapper", d)) - case *sql.Conn: - if err = vv.Raw(func(driverConn interface{}) error { - if cc, ok := driverConn.(*conn); ok { - connector = cc.connector - return nil - } - return xerrors.WithStackTrace(fmt.Errorf("%T is not a *conn", driverConn)) - }); err != nil { - return nil, badconn.Map(xerrors.WithStackTrace(err)) - } - return connector, nil - default: - return nil, xerrors.WithStackTrace(fmt.Errorf("unknown type %T for Unwrap", vv)) - } -} diff --git a/internal/xstring/convert.go b/internal/xstring/convert.go index 49bd824a2..7881a16cb 100644 --- a/internal/xstring/convert.go +++ b/internal/xstring/convert.go @@ -1,23 +1,22 @@ -//go:build !go1.20 -// +build !go1.20 - package xstring import ( - "reflect" "unsafe" ) func FromBytes(b []byte) string { - return *(*string)(unsafe.Pointer(&b)) + if len(b) == 0 { + return "" + } + if len(b) == 0 { + return "" + } + return unsafe.String(&b[0], len(b)) } func ToBytes(s string) (b []byte) { - pb := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - ps := (*reflect.StringHeader)(unsafe.Pointer(&s)) - pb.Data = ps.Data - pb.Len = ps.Len - pb.Cap = ps.Len - - return b + if s == "" { + return nil + } + return unsafe.Slice(unsafe.StringData(s), len(s)) } diff --git a/internal/xstring/convert_go1.20.go b/internal/xstring/convert_go1.20.go deleted file mode 100644 index 9d6d040b3..000000000 --- a/internal/xstring/convert_go1.20.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build go1.20 -// +build go1.20 - -package xstring - -import ( - "unsafe" -) - -func FromBytes(b []byte) string { - if len(b) == 0 { - return "" - } - return unsafe.String(unsafe.SliceData(b), len(b)) -} - -func ToBytes(s string) (b []byte) { - if s == "" { - return nil - } - return unsafe.Slice(unsafe.StringData(s), len(s)) -} diff --git a/retry/errors.go b/retry/errors.go index 4137b6477..ed540018f 100644 --- a/retry/errors.go +++ b/retry/errors.go @@ -1,20 +1,14 @@ -//go:build !go1.18 -// +build !go1.18 - package retry import ( - "database/sql/driver" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn" ) func unwrapErrBadConn(err error) error { - if xerrors.Is(err, driver.ErrBadConn) { - return xerrors.Retryable(err, - xerrors.WithName("unwrapErrBadConn"), - xerrors.WithDeleteSession(), - ) + var e *badconn.Error + if xerrors.As(err, &e) { + return e.Origin() } return err } diff --git a/retry/errors_go1.18.go b/retry/errors_go1.18.go deleted file mode 100644 index ef880af22..000000000 --- a/retry/errors_go1.18.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package retry - -import ( - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn" -) - -func unwrapErrBadConn(err error) error { - var e *badconn.Error - if xerrors.As(err, &e) { - return e.Origin() - } - return err -} diff --git a/retry/sql_test.go b/retry/sql_test.go index 2fd0f197e..d4a6c3d5f 100644 --- a/retry/sql_test.go +++ b/retry/sql_test.go @@ -1,6 +1,3 @@ -//go:build go1.18 -// +build go1.18 - package retry import ( diff --git a/sql_unwrap.go b/sql_unwrap.go index 8fd07e1f8..86703a8ca 100644 --- a/sql_unwrap.go +++ b/sql_unwrap.go @@ -1,6 +1,3 @@ -//go:build !go1.18 -// +build !go1.18 - package ydb import ( @@ -10,8 +7,8 @@ import ( "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql" ) -func Unwrap(db *sql.DB) (*Driver, error) { - c, err := xsql.Unwrap(db) +func Unwrap[T *sql.DB | *sql.Conn](v T) (*Driver, error) { + c, err := xsql.Unwrap(v) if err != nil { return nil, xerrors.WithStackTrace(err) } diff --git a/sql_unwrap_go1.18.go b/sql_unwrap_go1.18.go deleted file mode 100644 index b5ea788c0..000000000 --- a/sql_unwrap_go1.18.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package ydb - -import ( - "database/sql" - - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql" -) - -func Unwrap[T *sql.DB | *sql.Conn](v T) (*Driver, error) { - c, err := xsql.Unwrap(v) - if err != nil { - return nil, xerrors.WithStackTrace(err) - } - d.connectorsMtx.RLock() - defer d.connectorsMtx.RUnlock() - - return d.connectors[c], nil -} diff --git a/sugar/params.go b/sugar/params.go index ee9ed504d..e8d6691b1 100644 --- a/sugar/params.go +++ b/sugar/params.go @@ -1,16 +1,52 @@ -//go:build !go1.18 -// +build !go1.18 - package sugar import ( + "database/sql" + "fmt" + + "github.com/ydb-platform/ydb-go-sdk/v3/internal/bind" internal "github.com/ydb-platform/ydb-go-sdk/v3/internal/table" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" "github.com/ydb-platform/ydb-go-sdk/v3/table" ) // GenerateDeclareSection generates DECLARE section text in YQL query by params // // Deprecated: use testutil.QueryBind(ydb.WithAutoDeclare()) helper -func GenerateDeclareSection(params *table.QueryParameters) (string, error) { - return internal.GenerateDeclareSection(params) +func GenerateDeclareSection[T *table.QueryParameters | []table.ParameterOption | []sql.NamedArg]( + params T, +) (string, error) { + switch v := any(params).(type) { + case *table.QueryParameters: + return internal.GenerateDeclareSection(v) + case []table.ParameterOption: + return internal.GenerateDeclareSection(table.NewQueryParameters(v...)) + case []sql.NamedArg: + values, err := bind.Params(func() (newArgs []interface{}) { + for i := range v { + newArgs = append(newArgs, v[i]) + } + return newArgs + }()...) + if err != nil { + return "", xerrors.WithStackTrace(err) + } + return internal.GenerateDeclareSection(table.NewQueryParameters(values...)) + default: + return "", xerrors.WithStackTrace(fmt.Errorf("unsupported type: %T", v)) + } +} + +// ToYdbParam converts +// +// Deprecated: use testutil/QueryBind helper +func ToYdbParam(param sql.NamedArg) (table.ParameterOption, error) { + params, err := bind.Params(param) + if err != nil { + return nil, xerrors.WithStackTrace(err) + } + if len(params) != 1 { + return nil, xerrors.WithStackTrace(fmt.Errorf("internal error: wrong parameters count: %v", params)) + } + return params[0], nil } diff --git a/sugar/params_go1.18.go b/sugar/params_go1.18.go deleted file mode 100644 index 2fc73d6cb..000000000 --- a/sugar/params_go1.18.go +++ /dev/null @@ -1,55 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package sugar - -import ( - "database/sql" - "fmt" - - "github.com/ydb-platform/ydb-go-sdk/v3/internal/bind" - internal "github.com/ydb-platform/ydb-go-sdk/v3/internal/table" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" - "github.com/ydb-platform/ydb-go-sdk/v3/table" -) - -// GenerateDeclareSection generates DECLARE section text in YQL query by params -// -// Deprecated: use testutil.QueryBind(ydb.WithAutoDeclare()) helper -func GenerateDeclareSection[T *table.QueryParameters | []table.ParameterOption | []sql.NamedArg]( - params T, -) (string, error) { - switch v := any(params).(type) { - case *table.QueryParameters: - return internal.GenerateDeclareSection(v) - case []table.ParameterOption: - return internal.GenerateDeclareSection(table.NewQueryParameters(v...)) - case []sql.NamedArg: - values, err := bind.Params(func() (newArgs []interface{}) { - for i := range v { - newArgs = append(newArgs, v[i]) - } - return newArgs - }()...) - if err != nil { - return "", xerrors.WithStackTrace(err) - } - return internal.GenerateDeclareSection(table.NewQueryParameters(values...)) - default: - return "", xerrors.WithStackTrace(fmt.Errorf("unsupported type: %T", v)) - } -} - -// ToYdbParam converts -// -// Deprecated: use testutil/QueryBind helper -func ToYdbParam(param sql.NamedArg) (table.ParameterOption, error) { - params, err := bind.Params(param) - if err != nil { - return nil, xerrors.WithStackTrace(err) - } - if len(params) != 1 { - return nil, xerrors.WithStackTrace(fmt.Errorf("internal error: wrong parameters count: %v", params)) - } - return params[0], nil -} diff --git a/sugar/params_go1.18_test.go b/sugar/params_go1.18_test.go deleted file mode 100644 index 14a71fb59..000000000 --- a/sugar/params_go1.18_test.go +++ /dev/null @@ -1,319 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -package sugar - -import ( - "database/sql" - "sort" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/ydb-platform/ydb-go-sdk/v3/internal/bind" - "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" - "github.com/ydb-platform/ydb-go-sdk/v3/table" - "github.com/ydb-platform/ydb-go-sdk/v3/table/types" - "github.com/ydb-platform/ydb-go-sdk/v3/testutil" -) - -func TestGenerateDeclareSection_ParameterOption(t *testing.T) { - b := testutil.QueryBind(bind.AutoDeclare{}) - getDeclares := func(declaresSection string) (declares []string) { - for _, s := range strings.Split(declaresSection, "\n") { - s = strings.TrimSpace(s) - if s != "" && !strings.HasPrefix(s, "--") { - declares = append(declares, strings.TrimRight(s, ";")) - } - } - sort.Strings(declares) - return declares - } - for _, tt := range []struct { - params []interface{} - declares []string - }{ - { - params: []interface{}{ - table.ValueParam( - "$values", - types.ListValue( - types.Uint64Value(1), - types.Uint64Value(2), - types.Uint64Value(3), - types.Uint64Value(4), - types.Uint64Value(5), - ), - ), - }, - declares: []string{ - "DECLARE $values AS List", - }, - }, - { - params: []interface{}{ - table.ValueParam( - "$delta", - types.IntervalValueFromDuration(time.Hour), - ), - }, - declares: []string{ - "DECLARE $delta AS Interval", - }, - }, - { - params: []interface{}{ - table.ValueParam( - "$ts", - types.TimestampValueFromTime(time.Now()), - ), - }, - declares: []string{ - "DECLARE $ts AS Timestamp", - }, - }, - { - params: []interface{}{ - table.ValueParam( - "$a", - types.BoolValue(true), - ), - table.ValueParam( - "$b", - types.Int64Value(123), - ), - table.ValueParam( - "$c", - types.OptionalValue(types.TextValue("test")), - ), - }, - declares: []string{ - "DECLARE $a AS Bool", - "DECLARE $b AS Int64", - "DECLARE $c AS Optional", - }, - }, - { - params: []interface{}{ - table.ValueParam( - "$a", - types.BoolValue(true), - ), - table.ValueParam( - "b", - types.Int64Value(123), - ), - table.ValueParam( - "c", - types.OptionalValue(types.TextValue("test")), - ), - }, - declares: []string{ - "DECLARE $a AS Bool", - "DECLARE $b AS Int64", - "DECLARE $c AS Optional", - }, - }, - } { - t.Run("", func(t *testing.T) { - yql, _, err := b.RewriteQuery("", tt.params...) - require.NoError(t, err) - require.Equal(t, tt.declares, getDeclares(yql)) - }) - } -} - -func TestGenerateDeclareSection_NamedArg(t *testing.T) { - b := testutil.QueryBind(bind.AutoDeclare{}) - getDeclares := func(declaresSection string) (declares []string) { - for _, s := range strings.Split(declaresSection, "\n") { - s = strings.TrimSpace(s) - if s != "" && !strings.HasPrefix(s, "--") { - declares = append(declares, strings.TrimRight(s, ";")) - } - } - sort.Strings(declares) - return declares - } - for _, tt := range []struct { - params []interface{} - declares []string - }{ - { - params: []interface{}{ - sql.Named( - "values", - types.ListValue( - types.Uint64Value(1), - types.Uint64Value(2), - types.Uint64Value(3), - types.Uint64Value(4), - types.Uint64Value(5), - ), - ), - }, - declares: []string{ - "DECLARE $values AS List", - }, - }, - { - params: []interface{}{ - sql.Named( - "delta", - types.IntervalValueFromDuration(time.Hour), - ), - }, - declares: []string{ - "DECLARE $delta AS Interval", - }, - }, - { - params: []interface{}{ - sql.Named( - "ts", - types.TimestampValueFromTime(time.Now()), - ), - }, - declares: []string{ - "DECLARE $ts AS Timestamp", - }, - }, - { - params: []interface{}{ - sql.Named( - "a", - types.BoolValue(true), - ), - sql.Named( - "b", - types.Int64Value(123), - ), - sql.Named( - "c", - types.OptionalValue(types.TextValue("test")), - ), - }, - declares: []string{ - "DECLARE $a AS Bool", - "DECLARE $b AS Int64", - "DECLARE $c AS Optional", - }, - }, - { - params: []interface{}{ - sql.Named( - "a", - types.BoolValue(true), - ), - sql.Named( - "b", - types.Int64Value(123), - ), - sql.Named( - "c", - types.OptionalValue(types.TextValue("test")), - ), - }, - declares: []string{ - "DECLARE $a AS Bool", - "DECLARE $b AS Int64", - "DECLARE $c AS Optional", - }, - }, - - { - params: []interface{}{ - sql.Named("delta", time.Hour), - }, - declares: []string{ - "DECLARE $delta AS Interval", - }, - }, - { - params: []interface{}{ - sql.Named("ts", time.Now()), - }, - declares: []string{ - "DECLARE $ts AS Timestamp", - }, - }, - { - params: []interface{}{ - sql.Named("$a", true), - sql.Named("$b", int64(123)), - sql.Named("$c", func(s string) *string { return &s }("test")), - }, - declares: []string{ - "DECLARE $a AS Bool", - "DECLARE $b AS Int64", - "DECLARE $c AS Optional", - }, - }, - { - params: []interface{}{ - sql.Named("$a", func(b bool) *bool { return &b }(true)), - sql.Named("b", func(i int64) *int64 { return &i }(123)), - sql.Named("c", func(s string) *string { return &s }("test")), - }, - declares: []string{ - "DECLARE $a AS Optional", - "DECLARE $b AS Optional", - "DECLARE $c AS Optional", - }, - }, - } { - t.Run("", func(t *testing.T) { - yql, _, err := b.RewriteQuery("", tt.params...) - require.NoError(t, err) - require.Equal(t, tt.declares, getDeclares(yql)) - }) - } -} - -func TestToYdbParam(t *testing.T) { - for _, tt := range []struct { - name string - param sql.NamedArg - ydbParam table.ParameterOption - err error - }{ - { - name: xtest.CurrentFileLine(), - param: sql.Named("a", "b"), - ydbParam: table.ValueParam("$a", types.TextValue("b")), - err: nil, - }, - { - name: xtest.CurrentFileLine(), - param: sql.Named("a", 123), - ydbParam: table.ValueParam("$a", types.Int32Value(123)), - err: nil, - }, - { - name: xtest.CurrentFileLine(), - param: sql.Named("a", types.OptionalValue(types.TupleValue( - types.BytesValue([]byte("test")), - types.TextValue("test"), - types.Uint64Value(123), - ))), - ydbParam: table.ValueParam("$a", types.OptionalValue(types.TupleValue( - types.BytesValue([]byte("test")), - types.TextValue("test"), - types.Uint64Value(123), - ))), - err: nil, - }, - } { - t.Run(tt.name, func(t *testing.T) { - ydbParam, err := ToYdbParam(tt.param) - if tt.err != nil { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.ydbParam, ydbParam) - } - }) - } -} diff --git a/sugar/params_test.go b/sugar/params_test.go index 10dc9fbd5..b3a6ee10c 100644 --- a/sugar/params_test.go +++ b/sugar/params_test.go @@ -1,6 +1,7 @@ package sugar import ( + "database/sql" "sort" "strings" "testing" @@ -8,8 +9,11 @@ import ( "github.com/stretchr/testify/require" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/bind" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" "github.com/ydb-platform/ydb-go-sdk/v3/table" "github.com/ydb-platform/ydb-go-sdk/v3/table/types" + "github.com/ydb-platform/ydb-go-sdk/v3/testutil" ) func TestGenerateDeclareSection(t *testing.T) { @@ -109,3 +113,302 @@ func TestGenerateDeclareSection(t *testing.T) { }) } } + +func TestGenerateDeclareSection_ParameterOption(t *testing.T) { + b := testutil.QueryBind(bind.AutoDeclare{}) + getDeclares := func(declaresSection string) (declares []string) { + for _, s := range strings.Split(declaresSection, "\n") { + s = strings.TrimSpace(s) + if s != "" && !strings.HasPrefix(s, "--") { + declares = append(declares, strings.TrimRight(s, ";")) + } + } + sort.Strings(declares) + return declares + } + for _, tt := range []struct { + params []interface{} + declares []string + }{ + { + params: []interface{}{ + table.ValueParam( + "$values", + types.ListValue( + types.Uint64Value(1), + types.Uint64Value(2), + types.Uint64Value(3), + types.Uint64Value(4), + types.Uint64Value(5), + ), + ), + }, + declares: []string{ + "DECLARE $values AS List", + }, + }, + { + params: []interface{}{ + table.ValueParam( + "$delta", + types.IntervalValueFromDuration(time.Hour), + ), + }, + declares: []string{ + "DECLARE $delta AS Interval", + }, + }, + { + params: []interface{}{ + table.ValueParam( + "$ts", + types.TimestampValueFromTime(time.Now()), + ), + }, + declares: []string{ + "DECLARE $ts AS Timestamp", + }, + }, + { + params: []interface{}{ + table.ValueParam( + "$a", + types.BoolValue(true), + ), + table.ValueParam( + "$b", + types.Int64Value(123), + ), + table.ValueParam( + "$c", + types.OptionalValue(types.TextValue("test")), + ), + }, + declares: []string{ + "DECLARE $a AS Bool", + "DECLARE $b AS Int64", + "DECLARE $c AS Optional", + }, + }, + { + params: []interface{}{ + table.ValueParam( + "$a", + types.BoolValue(true), + ), + table.ValueParam( + "b", + types.Int64Value(123), + ), + table.ValueParam( + "c", + types.OptionalValue(types.TextValue("test")), + ), + }, + declares: []string{ + "DECLARE $a AS Bool", + "DECLARE $b AS Int64", + "DECLARE $c AS Optional", + }, + }, + } { + t.Run("", func(t *testing.T) { + yql, _, err := b.RewriteQuery("", tt.params...) + require.NoError(t, err) + require.Equal(t, tt.declares, getDeclares(yql)) + }) + } +} + +func TestGenerateDeclareSection_NamedArg(t *testing.T) { + b := testutil.QueryBind(bind.AutoDeclare{}) + getDeclares := func(declaresSection string) (declares []string) { + for _, s := range strings.Split(declaresSection, "\n") { + s = strings.TrimSpace(s) + if s != "" && !strings.HasPrefix(s, "--") { + declares = append(declares, strings.TrimRight(s, ";")) + } + } + sort.Strings(declares) + return declares + } + for _, tt := range []struct { + params []interface{} + declares []string + }{ + { + params: []interface{}{ + sql.Named( + "values", + types.ListValue( + types.Uint64Value(1), + types.Uint64Value(2), + types.Uint64Value(3), + types.Uint64Value(4), + types.Uint64Value(5), + ), + ), + }, + declares: []string{ + "DECLARE $values AS List", + }, + }, + { + params: []interface{}{ + sql.Named( + "delta", + types.IntervalValueFromDuration(time.Hour), + ), + }, + declares: []string{ + "DECLARE $delta AS Interval", + }, + }, + { + params: []interface{}{ + sql.Named( + "ts", + types.TimestampValueFromTime(time.Now()), + ), + }, + declares: []string{ + "DECLARE $ts AS Timestamp", + }, + }, + { + params: []interface{}{ + sql.Named( + "a", + types.BoolValue(true), + ), + sql.Named( + "b", + types.Int64Value(123), + ), + sql.Named( + "c", + types.OptionalValue(types.TextValue("test")), + ), + }, + declares: []string{ + "DECLARE $a AS Bool", + "DECLARE $b AS Int64", + "DECLARE $c AS Optional", + }, + }, + { + params: []interface{}{ + sql.Named( + "a", + types.BoolValue(true), + ), + sql.Named( + "b", + types.Int64Value(123), + ), + sql.Named( + "c", + types.OptionalValue(types.TextValue("test")), + ), + }, + declares: []string{ + "DECLARE $a AS Bool", + "DECLARE $b AS Int64", + "DECLARE $c AS Optional", + }, + }, + + { + params: []interface{}{ + sql.Named("delta", time.Hour), + }, + declares: []string{ + "DECLARE $delta AS Interval", + }, + }, + { + params: []interface{}{ + sql.Named("ts", time.Now()), + }, + declares: []string{ + "DECLARE $ts AS Timestamp", + }, + }, + { + params: []interface{}{ + sql.Named("$a", true), + sql.Named("$b", int64(123)), + sql.Named("$c", func(s string) *string { return &s }("test")), + }, + declares: []string{ + "DECLARE $a AS Bool", + "DECLARE $b AS Int64", + "DECLARE $c AS Optional", + }, + }, + { + params: []interface{}{ + sql.Named("$a", func(b bool) *bool { return &b }(true)), + sql.Named("b", func(i int64) *int64 { return &i }(123)), + sql.Named("c", func(s string) *string { return &s }("test")), + }, + declares: []string{ + "DECLARE $a AS Optional", + "DECLARE $b AS Optional", + "DECLARE $c AS Optional", + }, + }, + } { + t.Run("", func(t *testing.T) { + yql, _, err := b.RewriteQuery("", tt.params...) + require.NoError(t, err) + require.Equal(t, tt.declares, getDeclares(yql)) + }) + } +} + +func TestToYdbParam(t *testing.T) { + for _, tt := range []struct { + name string + param sql.NamedArg + ydbParam table.ParameterOption + err error + }{ + { + name: xtest.CurrentFileLine(), + param: sql.Named("a", "b"), + ydbParam: table.ValueParam("$a", types.TextValue("b")), + err: nil, + }, + { + name: xtest.CurrentFileLine(), + param: sql.Named("a", 123), + ydbParam: table.ValueParam("$a", types.Int32Value(123)), + err: nil, + }, + { + name: xtest.CurrentFileLine(), + param: sql.Named("a", types.OptionalValue(types.TupleValue( + types.BytesValue([]byte("test")), + types.TextValue("test"), + types.Uint64Value(123), + ))), + ydbParam: table.ValueParam("$a", types.OptionalValue(types.TupleValue( + types.BytesValue([]byte("test")), + types.TextValue("test"), + types.Uint64Value(123), + ))), + err: nil, + }, + } { + t.Run(tt.name, func(t *testing.T) { + ydbParam, err := ToYdbParam(tt.param) + if tt.err != nil { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.ydbParam, ydbParam) + } + }) + } +} diff --git a/tests/integration/metrics_registry_go1.18_test.go b/tests/integration/metrics_registry_go1.18_test.go deleted file mode 100644 index 40155dbf5..000000000 --- a/tests/integration/metrics_registry_go1.18_test.go +++ /dev/null @@ -1,504 +0,0 @@ -//go:build integration && go1.18 -// +build integration,go1.18 - -package integration - -import ( - "bytes" - "fmt" - "sort" - "strconv" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ydb-platform/ydb-go-sdk/v3" - "github.com/ydb-platform/ydb-go-sdk/v3/metrics" - "github.com/ydb-platform/ydb-go-sdk/v3/trace" -) - -func movingAverage[T interface { - time.Duration | float64 -}]( - oldValue T, newValue T, α float64, -) T { - return T(α*float64(newValue) + (1-α)*float64(oldValue)) -} - -func nameLabelValuesToString(name string, labelValues map[string]string) string { - var buffer bytes.Buffer - fmt.Fprintf(&buffer, name) - fmt.Fprintf(&buffer, "{") - labels := make([]string, 0, len(labelValues)) - for k := range labelValues { - labels = append(labels, k) - } - sort.Strings(labels) - for i, l := range labels { - if i != 0 { - fmt.Fprintf(&buffer, ",") - } - fmt.Fprintf(&buffer, "%s=%s", l, labelValues[l]) - } - fmt.Fprintf(&buffer, "}") - return buffer.String() -} - -func nameLabelNamesToString(name string, labelNames []string) string { - var buffer bytes.Buffer - fmt.Fprintf(&buffer, name) - fmt.Fprintf(&buffer, "{") - sort.Strings(labelNames) - for i, name := range labelNames { - if i != 0 { - fmt.Fprintf(&buffer, ",") - } - fmt.Fprintf(&buffer, name) - } - fmt.Fprintf(&buffer, "}") - return buffer.String() -} - -type counter struct { - name string - value uint64 - m sync.RWMutex -} - -func (c *counter) Inc() { - c.m.Lock() - defer c.m.Unlock() - c.value += 1 -} - -func (c *counter) Name() string { - return c.name -} - -func (c *counter) Value() string { - c.m.RLock() - defer c.m.RUnlock() - return fmt.Sprintf("%d", c.value) -} - -// define custom counterVec -type counterVec struct { - name string - labelNames []string - counters map[string]*counter - m sync.RWMutex -} - -func (vec *counterVec) With(labels map[string]string) metrics.Counter { - name := nameLabelValuesToString(vec.name, labels) - vec.m.RLock() - c, has := vec.counters[name] - vec.m.RUnlock() - if has { - return c - } - if has { - return c - } - c = &counter{ - name: name, - } - vec.m.Lock() - vec.counters[name] = c - vec.m.Unlock() - return c -} - -func (vec *counterVec) Name() string { - return vec.name -} - -func (vec *counterVec) Values() (values []string) { - vec.m.RLock() - defer vec.m.RUnlock() - for _, g := range vec.counters { - values = append(values, fmt.Sprintf("%s = %s", g.Name(), g.Value())) - } - return values -} - -type timer struct { - name string - value time.Duration - m sync.RWMutex -} - -func (t *timer) Record(value time.Duration) { - t.m.Lock() - defer t.m.Unlock() - t.value = movingAverage(t.value, value, 0.9) -} - -func (t *timer) Name() string { - return t.name -} - -func (t *timer) Value() string { - t.m.RLock() - defer t.m.RUnlock() - return fmt.Sprintf("%v", t.value) -} - -// define custom timerVec -type timerVec struct { - name string - labelNames []string - timers map[string]*timer - m sync.RWMutex -} - -func (vec *timerVec) With(labels map[string]string) metrics.Timer { - name := nameLabelValuesToString(vec.name, labels) - vec.m.RLock() - t, has := vec.timers[name] - vec.m.RUnlock() - if has { - return t - } - t = &timer{ - name: name, - } - vec.m.Lock() - vec.timers[name] = t - vec.m.Unlock() - return t -} - -func (vec *timerVec) Name() string { - return vec.name -} - -func (vec *timerVec) Values() (values []string) { - vec.m.RLock() - defer vec.m.RUnlock() - for _, t := range vec.timers { - values = append(values, fmt.Sprintf("%s = %s", t.Name(), t.Value())) - } - return values -} - -type bin struct { - value float64 // left corner of bucket - count uint64 -} - -type histogram struct { - name string - buckets []*bin - m sync.RWMutex -} - -func (h *histogram) Record(value float64) { - h.m.Lock() - defer h.m.Unlock() - for i := len(h.buckets) - 1; i >= 0; i-- { - if h.buckets[i].value < value { - atomic.AddUint64(&h.buckets[i].count, 1) - return - } - } -} - -func (h *histogram) Name() string { - return h.name -} - -func (h *histogram) Value() string { - var buffer bytes.Buffer - h.m.RLock() - defer h.m.RUnlock() - buffer.WriteByte('[') - for i := 0; i < len(h.buckets); i++ { - if i > 0 { - buffer.WriteByte(',') - } - buffer.WriteByte('[') - buffer.WriteString(strconv.FormatFloat(h.buckets[i].value, 'f', -1, 64)) - buffer.WriteString("..") - if i == len(h.buckets)-1 { - buffer.WriteString(".") - } else { - buffer.WriteString(strconv.FormatFloat(h.buckets[i+1].value, 'f', -1, 64)) - } - buffer.WriteString("]:") - buffer.WriteString(strconv.FormatUint(atomic.LoadUint64(&h.buckets[i].count), 10)) - } - buffer.WriteByte(']') - return buffer.String() -} - -// define custom histogramVec -type histogramVec struct { - name string - labelNames []string - histograms map[string]*histogram - buckets []float64 - m sync.RWMutex -} - -func (vec *histogramVec) With(labels map[string]string) metrics.Histogram { - name := nameLabelValuesToString(vec.name, labels) - vec.m.RLock() - h, has := vec.histograms[name] - vec.m.RUnlock() - if has { - return h - } - h = &histogram{ - name: name, - buckets: make([]*bin, len(vec.buckets)), - } - for i, v := range vec.buckets { - h.buckets[i] = &bin{ - value: v, - } - } - vec.m.Lock() - vec.histograms[name] = h - vec.m.Unlock() - return h -} - -func (vec *histogramVec) Name() string { - return vec.name -} - -func (vec *histogramVec) Values() (values []string) { - vec.m.RLock() - defer vec.m.RUnlock() - for _, t := range vec.histograms { - values = append(values, fmt.Sprintf("%s = %s", t.Name(), t.Value())) - } - return values -} - -// define custom gaugeVec -type gaugeVec struct { - name string - labelNames []string - gauges map[string]*gauge - m sync.RWMutex -} - -type gauge struct { - name string - value float64 - m sync.RWMutex -} - -func (g *gauge) Name() string { - return g.name -} - -func (g *gauge) Value() string { - g.m.RLock() - defer g.m.RUnlock() - return fmt.Sprintf("%f", g.value) -} - -func (vec *gaugeVec) With(labels map[string]string) metrics.Gauge { - name := nameLabelValuesToString(vec.name, labels) - vec.m.RLock() - g, has := vec.gauges[name] - vec.m.RUnlock() - if has { - return g - } - g = &gauge{ - name: name, - } - vec.m.Lock() - vec.gauges[name] = g - vec.m.Unlock() - return g -} - -func (g *gauge) Add(value float64) { - g.m.Lock() - defer g.m.Unlock() - g.value += value -} - -func (g *gauge) Set(value float64) { - g.m.Lock() - defer g.m.Unlock() - g.value = value -} - -func (vec *gaugeVec) Name() string { - return vec.name -} - -func (vec *gaugeVec) Values() (values []string) { - vec.m.RLock() - defer vec.m.RUnlock() - for _, g := range vec.gauges { - values = append(values, fmt.Sprintf("%s = %s", g.Name(), g.Value())) - } - return values -} - -type vec[T any] struct { - mtx sync.RWMutex - data map[string]*T -} - -func newVec[T any]() *vec[T] { - return &vec[T]{ - data: make(map[string]*T, 0), - } -} - -func (v *vec[T]) add(key string, element *T) *T { - v.mtx.Lock() - defer v.mtx.Unlock() - if _, has := v.data[key]; has { - panic(fmt.Sprintf("key = %s already exists", key)) - } - v.data[key] = element - return element -} - -func (v *vec[T]) iterate(f func(element *T)) { - v.mtx.RLock() - defer v.mtx.RUnlock() - for _, element := range v.data { - f(element) - } -} - -// define custom registryConfig -type registryConfig struct { - prefix string - details trace.Details - gauges *vec[gaugeVec] - counters *vec[counterVec] - timers *vec[timerVec] - histograms *vec[histogramVec] -} - -func (registry *registryConfig) CounterVec(name string, labelNames ...string) metrics.CounterVec { - return registry.counters.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &counterVec{ - name: registry.prefix + "." + name, - labelNames: labelNames, - counters: make(map[string]*counter), - }) -} - -func (registry *registryConfig) GaugeVec(name string, labelNames ...string) metrics.GaugeVec { - return registry.gauges.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &gaugeVec{ - name: registry.prefix + "." + name, - labelNames: labelNames, - gauges: make(map[string]*gauge), - }) -} - -func (registry *registryConfig) TimerVec(name string, labelNames ...string) metrics.TimerVec { - return registry.timers.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &timerVec{ - name: registry.prefix + "." + name, - labelNames: labelNames, - timers: make(map[string]*timer), - }) -} - -func (registry *registryConfig) HistogramVec(name string, buckets []float64, labelNames ...string) metrics.HistogramVec { - return registry.histograms.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &histogramVec{ - name: registry.prefix + "." + name, - labelNames: labelNames, - histograms: make(map[string]*histogram), - buckets: buckets, - }) -} - -func (registry *registryConfig) WithSystem(subsystem string) metrics.Config { - copy := *registry - if len(copy.prefix) == 0 { - copy.prefix = subsystem - } else { - copy.prefix = registry.prefix + "." + subsystem - } - return © -} - -func (registry *registryConfig) Details() trace.Details { - return registry.details -} - -func withMetrics(t *testing.T, details trace.Details, interval time.Duration) ydb.Option { - registry := ®istryConfig{ - details: details, - gauges: newVec[gaugeVec](), - counters: newVec[counterVec](), - timers: newVec[timerVec](), - histograms: newVec[histogramVec](), - } - var ( - done = make(chan struct{}) - printState = func(log func(format string, args ...interface{}), header string) { - log(time.Now().Format("[2006-01-02 15:04:05] ") + header + ":\n") - var ( - gaugesOnce sync.Once - countersOnce sync.Once - timersOnce sync.Once - histogramsOnce sync.Once - ) - registry.gauges.iterate(func(element *gaugeVec) { - for _, v := range element.Values() { - gaugesOnce.Do(func() { - log("- gauges:\n") - }) - log(" - %s\n", v) - } - }) - registry.counters.iterate(func(element *counterVec) { - for _, v := range element.Values() { - countersOnce.Do(func() { - log("- counters:\n") - }) - log(" - %s\n", v) - } - }) - registry.timers.iterate(func(element *timerVec) { - for _, v := range element.Values() { - timersOnce.Do(func() { - log("- timers:\n") - }) - log(" - %s\n", v) - } - }) - registry.histograms.iterate(func(element *histogramVec) { - for _, v := range element.Values() { - histogramsOnce.Do(func() { - log("- histograms:\n") - }) - log(" - %s\n", v) - } - }) - } - ) - if interval > 0 { - go func() { - for { - select { - case <-done: - return - case <-time.After(interval): - printState(t.Logf, "registry state") - } - } - }() - } - t.Cleanup(func() { - close(done) - printState(func(format string, args ...interface{}) { - _, _ = fmt.Printf(format, args...) - }, "final registry state") - }) - return metrics.WithTraces(registry) -} diff --git a/tests/integration/metrics_registry_test.go b/tests/integration/metrics_registry_test.go index 20095cbe1..eaa481694 100644 --- a/tests/integration/metrics_registry_test.go +++ b/tests/integration/metrics_registry_test.go @@ -1,16 +1,504 @@ -//go:build integration && !go1.18 -// +build integration,!go1.18 +//go:build integration +// +build integration package integration import ( + "bytes" + "fmt" + "sort" + "strconv" + "sync" + "sync/atomic" "testing" "time" "github.com/ydb-platform/ydb-go-sdk/v3" + "github.com/ydb-platform/ydb-go-sdk/v3/metrics" "github.com/ydb-platform/ydb-go-sdk/v3/trace" ) +func movingAverage[T interface { + time.Duration | float64 +}]( + oldValue T, newValue T, α float64, +) T { + return T(α*float64(newValue) + (1-α)*float64(oldValue)) +} + +func nameLabelValuesToString(name string, labelValues map[string]string) string { + var buffer bytes.Buffer + fmt.Fprintf(&buffer, name) + fmt.Fprintf(&buffer, "{") + labels := make([]string, 0, len(labelValues)) + for k := range labelValues { + labels = append(labels, k) + } + sort.Strings(labels) + for i, l := range labels { + if i != 0 { + fmt.Fprintf(&buffer, ",") + } + fmt.Fprintf(&buffer, "%s=%s", l, labelValues[l]) + } + fmt.Fprintf(&buffer, "}") + return buffer.String() +} + +func nameLabelNamesToString(name string, labelNames []string) string { + var buffer bytes.Buffer + fmt.Fprintf(&buffer, name) + fmt.Fprintf(&buffer, "{") + sort.Strings(labelNames) + for i, name := range labelNames { + if i != 0 { + fmt.Fprintf(&buffer, ",") + } + fmt.Fprintf(&buffer, name) + } + fmt.Fprintf(&buffer, "}") + return buffer.String() +} + +type counter struct { + name string + value uint64 + m sync.RWMutex +} + +func (c *counter) Inc() { + c.m.Lock() + defer c.m.Unlock() + c.value += 1 +} + +func (c *counter) Name() string { + return c.name +} + +func (c *counter) Value() string { + c.m.RLock() + defer c.m.RUnlock() + return fmt.Sprintf("%d", c.value) +} + +// define custom counterVec +type counterVec struct { + name string + labelNames []string + counters map[string]*counter + m sync.RWMutex +} + +func (vec *counterVec) With(labels map[string]string) metrics.Counter { + name := nameLabelValuesToString(vec.name, labels) + vec.m.RLock() + c, has := vec.counters[name] + vec.m.RUnlock() + if has { + return c + } + if has { + return c + } + c = &counter{ + name: name, + } + vec.m.Lock() + vec.counters[name] = c + vec.m.Unlock() + return c +} + +func (vec *counterVec) Name() string { + return vec.name +} + +func (vec *counterVec) Values() (values []string) { + vec.m.RLock() + defer vec.m.RUnlock() + for _, g := range vec.counters { + values = append(values, fmt.Sprintf("%s = %s", g.Name(), g.Value())) + } + return values +} + +type timer struct { + name string + value time.Duration + m sync.RWMutex +} + +func (t *timer) Record(value time.Duration) { + t.m.Lock() + defer t.m.Unlock() + t.value = movingAverage(t.value, value, 0.9) +} + +func (t *timer) Name() string { + return t.name +} + +func (t *timer) Value() string { + t.m.RLock() + defer t.m.RUnlock() + return fmt.Sprintf("%v", t.value) +} + +// define custom timerVec +type timerVec struct { + name string + labelNames []string + timers map[string]*timer + m sync.RWMutex +} + +func (vec *timerVec) With(labels map[string]string) metrics.Timer { + name := nameLabelValuesToString(vec.name, labels) + vec.m.RLock() + t, has := vec.timers[name] + vec.m.RUnlock() + if has { + return t + } + t = &timer{ + name: name, + } + vec.m.Lock() + vec.timers[name] = t + vec.m.Unlock() + return t +} + +func (vec *timerVec) Name() string { + return vec.name +} + +func (vec *timerVec) Values() (values []string) { + vec.m.RLock() + defer vec.m.RUnlock() + for _, t := range vec.timers { + values = append(values, fmt.Sprintf("%s = %s", t.Name(), t.Value())) + } + return values +} + +type bin struct { + value float64 // left corner of bucket + count uint64 +} + +type histogram struct { + name string + buckets []*bin + m sync.RWMutex +} + +func (h *histogram) Record(value float64) { + h.m.Lock() + defer h.m.Unlock() + for i := len(h.buckets) - 1; i >= 0; i-- { + if h.buckets[i].value < value { + atomic.AddUint64(&h.buckets[i].count, 1) + return + } + } +} + +func (h *histogram) Name() string { + return h.name +} + +func (h *histogram) Value() string { + var buffer bytes.Buffer + h.m.RLock() + defer h.m.RUnlock() + buffer.WriteByte('[') + for i := 0; i < len(h.buckets); i++ { + if i > 0 { + buffer.WriteByte(',') + } + buffer.WriteByte('[') + buffer.WriteString(strconv.FormatFloat(h.buckets[i].value, 'f', -1, 64)) + buffer.WriteString("..") + if i == len(h.buckets)-1 { + buffer.WriteString(".") + } else { + buffer.WriteString(strconv.FormatFloat(h.buckets[i+1].value, 'f', -1, 64)) + } + buffer.WriteString("]:") + buffer.WriteString(strconv.FormatUint(atomic.LoadUint64(&h.buckets[i].count), 10)) + } + buffer.WriteByte(']') + return buffer.String() +} + +// define custom histogramVec +type histogramVec struct { + name string + labelNames []string + histograms map[string]*histogram + buckets []float64 + m sync.RWMutex +} + +func (vec *histogramVec) With(labels map[string]string) metrics.Histogram { + name := nameLabelValuesToString(vec.name, labels) + vec.m.RLock() + h, has := vec.histograms[name] + vec.m.RUnlock() + if has { + return h + } + h = &histogram{ + name: name, + buckets: make([]*bin, len(vec.buckets)), + } + for i, v := range vec.buckets { + h.buckets[i] = &bin{ + value: v, + } + } + vec.m.Lock() + vec.histograms[name] = h + vec.m.Unlock() + return h +} + +func (vec *histogramVec) Name() string { + return vec.name +} + +func (vec *histogramVec) Values() (values []string) { + vec.m.RLock() + defer vec.m.RUnlock() + for _, t := range vec.histograms { + values = append(values, fmt.Sprintf("%s = %s", t.Name(), t.Value())) + } + return values +} + +// define custom gaugeVec +type gaugeVec struct { + name string + labelNames []string + gauges map[string]*gauge + m sync.RWMutex +} + +type gauge struct { + name string + value float64 + m sync.RWMutex +} + +func (g *gauge) Name() string { + return g.name +} + +func (g *gauge) Value() string { + g.m.RLock() + defer g.m.RUnlock() + return fmt.Sprintf("%f", g.value) +} + +func (vec *gaugeVec) With(labels map[string]string) metrics.Gauge { + name := nameLabelValuesToString(vec.name, labels) + vec.m.RLock() + g, has := vec.gauges[name] + vec.m.RUnlock() + if has { + return g + } + g = &gauge{ + name: name, + } + vec.m.Lock() + vec.gauges[name] = g + vec.m.Unlock() + return g +} + +func (g *gauge) Add(value float64) { + g.m.Lock() + defer g.m.Unlock() + g.value += value +} + +func (g *gauge) Set(value float64) { + g.m.Lock() + defer g.m.Unlock() + g.value = value +} + +func (vec *gaugeVec) Name() string { + return vec.name +} + +func (vec *gaugeVec) Values() (values []string) { + vec.m.RLock() + defer vec.m.RUnlock() + for _, g := range vec.gauges { + values = append(values, fmt.Sprintf("%s = %s", g.Name(), g.Value())) + } + return values +} + +type vec[T any] struct { + mtx sync.RWMutex + data map[string]*T +} + +func newVec[T any]() *vec[T] { + return &vec[T]{ + data: make(map[string]*T, 0), + } +} + +func (v *vec[T]) add(key string, element *T) *T { + v.mtx.Lock() + defer v.mtx.Unlock() + if _, has := v.data[key]; has { + panic(fmt.Sprintf("key = %s already exists", key)) + } + v.data[key] = element + return element +} + +func (v *vec[T]) iterate(f func(element *T)) { + v.mtx.RLock() + defer v.mtx.RUnlock() + for _, element := range v.data { + f(element) + } +} + +// define custom registryConfig +type registryConfig struct { + prefix string + details trace.Details + gauges *vec[gaugeVec] + counters *vec[counterVec] + timers *vec[timerVec] + histograms *vec[histogramVec] +} + +func (registry *registryConfig) CounterVec(name string, labelNames ...string) metrics.CounterVec { + return registry.counters.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &counterVec{ + name: registry.prefix + "." + name, + labelNames: labelNames, + counters: make(map[string]*counter), + }) +} + +func (registry *registryConfig) GaugeVec(name string, labelNames ...string) metrics.GaugeVec { + return registry.gauges.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &gaugeVec{ + name: registry.prefix + "." + name, + labelNames: labelNames, + gauges: make(map[string]*gauge), + }) +} + +func (registry *registryConfig) TimerVec(name string, labelNames ...string) metrics.TimerVec { + return registry.timers.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &timerVec{ + name: registry.prefix + "." + name, + labelNames: labelNames, + timers: make(map[string]*timer), + }) +} + +func (registry *registryConfig) HistogramVec(name string, buckets []float64, labelNames ...string) metrics.HistogramVec { + return registry.histograms.add(nameLabelNamesToString(registry.prefix+"."+name, labelNames), &histogramVec{ + name: registry.prefix + "." + name, + labelNames: labelNames, + histograms: make(map[string]*histogram), + buckets: buckets, + }) +} + +func (registry *registryConfig) WithSystem(subsystem string) metrics.Config { + copy := *registry + if len(copy.prefix) == 0 { + copy.prefix = subsystem + } else { + copy.prefix = registry.prefix + "." + subsystem + } + return © +} + +func (registry *registryConfig) Details() trace.Details { + return registry.details +} + func withMetrics(t *testing.T, details trace.Details, interval time.Duration) ydb.Option { - return nil // nop + registry := ®istryConfig{ + details: details, + gauges: newVec[gaugeVec](), + counters: newVec[counterVec](), + timers: newVec[timerVec](), + histograms: newVec[histogramVec](), + } + var ( + done = make(chan struct{}) + printState = func(log func(format string, args ...interface{}), header string) { + log(time.Now().Format("[2006-01-02 15:04:05] ") + header + ":\n") + var ( + gaugesOnce sync.Once + countersOnce sync.Once + timersOnce sync.Once + histogramsOnce sync.Once + ) + registry.gauges.iterate(func(element *gaugeVec) { + for _, v := range element.Values() { + gaugesOnce.Do(func() { + log("- gauges:\n") + }) + log(" - %s\n", v) + } + }) + registry.counters.iterate(func(element *counterVec) { + for _, v := range element.Values() { + countersOnce.Do(func() { + log("- counters:\n") + }) + log(" - %s\n", v) + } + }) + registry.timers.iterate(func(element *timerVec) { + for _, v := range element.Values() { + timersOnce.Do(func() { + log("- timers:\n") + }) + log(" - %s\n", v) + } + }) + registry.histograms.iterate(func(element *histogramVec) { + for _, v := range element.Values() { + histogramsOnce.Do(func() { + log("- histograms:\n") + }) + log(" - %s\n", v) + } + }) + } + ) + if interval > 0 { + go func() { + for { + select { + case <-done: + return + case <-time.After(interval): + printState(t.Logf, "registry state") + } + } + }() + } + t.Cleanup(func() { + close(done) + printState(func(format string, args ...interface{}) { + _, _ = fmt.Printf(format, args...) + }, "final registry state") + }) + return metrics.WithTraces(registry) }