From 343d44e7898f514ff924315638d172e71eea9f85 Mon Sep 17 00:00:00 2001 From: Aleksey Myasnikov Date: Mon, 23 Oct 2023 10:49:19 +0300 Subject: [PATCH] refactored `internal/stack` --- internal/stack/record.go | 154 +++++++++++++++++++++-- internal/stack/record_test.go | 227 +++++++++++++++++++++++++++++++++- internal/table/retry.go | 12 +- 3 files changed, 375 insertions(+), 18 deletions(-) diff --git a/internal/stack/record.go b/internal/stack/record.go index 8b1482b5c..403f7f396 100644 --- a/internal/stack/record.go +++ b/internal/stack/record.go @@ -1,21 +1,157 @@ package stack import ( + "fmt" "runtime" - "strconv" "strings" + + "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator" ) -func Record(depth int) string { +type recordOptions struct { + packagePath bool + packageName bool + structName bool + functionName bool + fileName bool + line bool + lambdas bool +} + +type recordOption func(opts *recordOptions) + +func PackageName(b bool) recordOption { + return func(opts *recordOptions) { + opts.packageName = b + } +} + +func FunctionName(b bool) recordOption { + return func(opts *recordOptions) { + opts.functionName = b + } +} + +func FileName(b bool) recordOption { + return func(opts *recordOptions) { + opts.fileName = b + } +} + +func Line(b bool) recordOption { + return func(opts *recordOptions) { + opts.line = b + } +} + +func StructName(b bool) recordOption { + return func(opts *recordOptions) { + opts.structName = b + } +} + +func Lambda(b bool) recordOption { + return func(opts *recordOptions) { + opts.lambdas = b + } +} + +func PackagePath(b bool) recordOption { + return func(opts *recordOptions) { + opts.packagePath = b + } +} + +func Record(depth int, opts ...recordOption) string { + optionsHolder := recordOptions{ + packagePath: true, + packageName: true, + structName: true, + functionName: true, + fileName: true, + line: true, + lambdas: true, + } + for _, opt := range opts { + opt(&optionsHolder) + } function, file, line, _ := runtime.Caller(depth + 1) name := runtime.FuncForPC(function).Name() - return name + "(" + fileName(file) + ":" + strconv.Itoa(line) + ")" -} + var ( + pkgPath string + pkgName string + structName string + funcName string + ) + if i := strings.LastIndex(file, "/"); i > -1 { + file = file[i+1:] + } + if i := strings.LastIndex(name, "/"); i > -1 { + pkgPath, name = name[:i], name[i+1:] + } + split := strings.Split(name, ".") + lambdas := make([]string, 0, len(split)) + for i := range split { + elem := split[len(split)-i-1] + if !strings.HasPrefix(elem, "func") { + break + } + lambdas = append(lambdas, elem) + } + split = split[:len(split)-len(lambdas)] + if len(split) > 0 { + pkgName = split[0] + } + if len(split) > 1 { + funcName = split[len(split)-1] + } + if len(split) > 2 { + structName = split[1] + } -func fileName(original string) string { - i := strings.LastIndex(original, "/") - if i == -1 { - return original + buffer := allocator.Buffers.Get() + defer allocator.Buffers.Put(buffer) + if optionsHolder.packagePath { + buffer.WriteString(pkgPath) + } + if optionsHolder.packageName { + if buffer.Len() > 0 { + buffer.WriteByte('/') + } + buffer.WriteString(pkgName) + } + if optionsHolder.structName && len(structName) > 0 { + if buffer.Len() > 0 { + buffer.WriteByte('.') + } + buffer.WriteString(structName) + } + if optionsHolder.functionName { + if buffer.Len() > 0 { + buffer.WriteByte('.') + } + buffer.WriteString(funcName) + if optionsHolder.lambdas { + for i := range lambdas { + buffer.WriteByte('.') + buffer.WriteString(lambdas[len(lambdas)-i-1]) + } + } + } + if optionsHolder.fileName { + var closeBrace bool + if buffer.Len() > 0 { + buffer.WriteByte('(') + closeBrace = true + } + buffer.WriteString(file) + if optionsHolder.line { + buffer.WriteByte(':') + fmt.Fprintf(buffer, "%d", line) + } + if closeBrace { + buffer.WriteByte(')') + } } - return original[i+1:] + return buffer.String() } diff --git a/internal/stack/record_test.go b/internal/stack/record_test.go index 273bff226..7baee43b3 100644 --- a/internal/stack/record_test.go +++ b/internal/stack/record_test.go @@ -6,6 +6,23 @@ import ( "github.com/stretchr/testify/require" ) +type testStruct struct { + depth int + opts []recordOption +} + +func (s testStruct) TestFunc() string { + return func() string { + return Record(s.depth, s.opts...) + }() +} + +func (s *testStruct) TestPointerFunc() string { + return func() string { + return Record(s.depth, s.opts...) + }() +} + func TestRecord(t *testing.T) { for _, tt := range []struct { act string @@ -13,13 +30,13 @@ func TestRecord(t *testing.T) { }{ { act: Record(0), - exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:15)", + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:32)", }, { act: func() string { return Record(1) }(), - exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:21)", + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:38)", }, { act: func() string { @@ -27,7 +44,211 @@ func TestRecord(t *testing.T) { return Record(2) }() }(), - exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:29)", + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.TestRecord(record_test.go:46)", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + // PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "stack", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + // StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "testStruct", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + // FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "TestFunc", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + // Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + // FunctionName(false), + // Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "TestFunc.func1", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + // FileName(false), + Line(false), + }}.TestFunc(), + exp: "record_test.go", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + // Line(false), + }}.TestFunc(), + exp: "", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + PackagePath(false), + PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + // FileName(false), + // Line(false), + }}.TestFunc(), + exp: "record_test.go:16", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.testStruct", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + // FunctionName(false), + Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.testStruct.TestFunc", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + // FunctionName(false), + // Lambda(false), + FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.testStruct.TestFunc.func1", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + // FunctionName(false), + // Lambda(false), + // FileName(false), + Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.testStruct.TestFunc.func1(record_test.go)", + }, + { + act: testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + // FunctionName(false), + // Lambda(false), + // FileName(false), + // Line(false), + }}.TestFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.testStruct.TestFunc.func1(record_test.go:16)", + }, + { + act: (&testStruct{depth: 0, opts: []recordOption{ + // PackagePath(false), + // PackageName(false), + // StructName(false), + // FunctionName(false), + // Lambda(false), + // FileName(false), + // Line(false), + }}).TestPointerFunc(), + exp: "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.(*testStruct).TestPointerFunc.func1(record_test.go:22)", }, } { t.Run("", func(t *testing.T) { diff --git a/internal/table/retry.go b/internal/table/retry.go index f5ad6f93a..764764bd6 100644 --- a/internal/table/retry.go +++ b/internal/table/retry.go @@ -3,6 +3,7 @@ package table import ( "context" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack" "github.com/ydb-platform/ydb-go-sdk/v3/internal/table/config" "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" "github.com/ydb-platform/ydb-go-sdk/v3/retry" @@ -161,8 +162,8 @@ func retryBackoff( p SessionProvider, op table.Operation, opts ...retry.Option, -) (err error) { - err = retry.Retry(markRetryCall(ctx), +) error { + return retry.Retry(markRetryCall(ctx), func(ctx context.Context) (err error) { var s *session @@ -185,10 +186,6 @@ func retryBackoff( }, opts..., ) - if err != nil { - return xerrors.WithStackTrace(err) - } - return nil } func retryOptions(trace *trace.Table, opts ...table.Option) *table.Options { @@ -197,6 +194,9 @@ func retryOptions(trace *trace.Table, opts ...table.Option) *table.Options { TxSettings: table.TxSettings( table.WithSerializableReadWrite(), ), + RetryOptions: []retry.Option{ + retry.WithID(stack.Record(1, stack.Lambda(false), stack.FileName(false))), + }, } for _, opt := range opts { if opt != nil {