diff --git a/.github/workflows/breaking.yml b/.github/workflows/breaking.yml
index cbfa052c8..7594b1f82 100644
--- a/.github/workflows/breaking.yml
+++ b/.github/workflows/breaking.yml
@@ -12,18 +12,21 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-latest
permissions:
- pull-requests: write
+ pull-requests: write
+ contents: read
steps:
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: "1.21"
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install gorelease
run: test -e ~/go/bin/gorelease || go install golang.org/x/exp/cmd/gorelease@latest
- name: Check broken API changes
run: gorelease -base=$GITHUB_BASE_REF 2>&1 > changes.txt | true
+ - name: Print API changes
+ run: cat changes.txt
- name: Comment Report
if: always()
uses: marocchino/sticky-pull-request-comment@v2
diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml
index 5c3508bd1..65f19da5b 100644
--- a/.github/workflows/changelog.yml
+++ b/.github/workflows/changelog.yml
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout sources
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Changelog updated
uses: Zomzog/changelog-checker@v1.3.0
diff --git a/.github/workflows/check-codegen.yml b/.github/workflows/check-codegen.yml
index 6ef0f1ed1..8d9f701e3 100644
--- a/.github/workflows/check-codegen.yml
+++ b/.github/workflows/check-codegen.yml
@@ -18,10 +18,10 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
@@ -32,6 +32,7 @@ jobs:
- name: Build
run: |
go install ./internal/cmd/gtrace
+ go install ./internal/cmd/gstack
go install go.uber.org/mock/mockgen@v0.4.0
- name: Clean and re-generate *_gtrace.go files
@@ -40,5 +41,9 @@ jobs:
go generate ./trace
go generate ./...
+ - name: Re-generate stack.FunctionID calls
+ run: |
+ gstack .
+
- name: Check repository diff
run: bash ./.github/scripts/check-work-copy-equals-to-committed.sh "code-generation not equal with committed"
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 678e69070..f37a6b49c 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -45,11 +45,11 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -63,7 +63,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# âšī¸ Command-line programs to run using the OS shell.
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -76,4 +76,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml
index 745864a37..4eca7b4b2 100644
--- a/.github/workflows/examples.yml
+++ b/.github/workflows/examples.yml
@@ -38,9 +38,9 @@ jobs:
YDB_VERSION: ${{ matrix.ydb-version }}
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
cache: true
- name: Run basic example ${{ matrix.application }}
@@ -74,9 +74,9 @@ jobs:
POSTGRES_CONNECTION_STRING: postgres://postgres:postgres@localhost:5432/basic?sslmode=disable
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
cache: true
- name: Run basic example ${{ matrix.application }} with postgres
@@ -97,9 +97,9 @@ jobs:
SQLITE_CONNECTION_STRING: ${{ matrix.application }}.db
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
cache: true
- name: Run basic example ${{ matrix.application }} with sqlite
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index c4b89aa7a..e922c39e2 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -16,9 +16,9 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: golangci-lint
- uses: golangci/golangci-lint-action@v3
+ uses: golangci/golangci-lint-action@v4
with:
version: ${{ env.GOLANGCI_LINT_VERSION }}
args: --timeout=5m
@@ -29,11 +29,11 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: generate examples golangci-lint config
run: sed 's/github.com\/ydb-platform\/ydb-go-sdk\/v3/examples/g' .golangci.yml > examples/.golangci.yml
- name: golangci-lint
- uses: golangci/golangci-lint-action@v3
+ uses: golangci/golangci-lint-action@v4
with:
version: ${{ env.GOLANGCI_LINT_VERSION }}
args: --timeout=5m
@@ -45,11 +45,11 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: generate slo golangci-lint config
run: sed 's/github.com\/ydb-platform\/ydb-go-sdk\/v3/slo/g' .golangci.yml > tests/slo/.golangci.yml
- name: golangci-lint
- uses: golangci/golangci-lint-action@v3
+ uses: golangci/golangci-lint-action@v4
with:
version: ${{ env.GOLANGCI_LINT_VERSION }}
args: --timeout=5m
@@ -61,9 +61,9 @@ jobs:
cancel-in-progress: true
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: "1.21"
- name: Install utilities
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 61361f822..64f30b640 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -28,7 +28,7 @@ jobs:
CHANGELOG_FILE: CHANGELOG.md
GITHUB_TOKEN: ${{ secrets.YDB_PLATFORM_BOT_TOKEN_REPO }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
token: ${{ secrets.YDB_PLATFORM_BOT_TOKEN_REPO }}
fetch-depth: 0
diff --git a/.github/workflows/slo.yml b/.github/workflows/slo.yml
index d1922303e..bc63cacbe 100644
--- a/.github/workflows/slo.yml
+++ b/.github/workflows/slo.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Run SLO
uses: ydb-platform/slo-tests@js-version
@@ -73,7 +73,7 @@ jobs:
workload_build_context4: ../..
workload_build_options4: -f Dockerfile --build-arg SRC_PATH=xorm --build-arg JOB_NAME=workload-xorm
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
if: always()
with:
name: slo-logs
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 756b2fd38..55e6629fe 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -22,16 +22,16 @@ jobs:
runs-on: ${{ matrix.os }}-latest
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
- name: Test
run: go test -race -coverprofile unit.txt -covermode atomic ./...
- name: Upload coverage report to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
with:
file: ./unit.txt
flags: unit,${{ matrix.os }},go-${{ matrix.go-version }}
@@ -71,16 +71,16 @@ jobs:
HIDE_APPLICATION_OUTPUT: 1
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Install Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
- name: Integration test
run: go test -race -tags integration -coverpkg=./... -coverprofile integration-secure.txt -covermode atomic ./tests/integration
- name: Upload Test secure connection coverage report to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
with:
file: ./integration-secure.txt
flags: integration,${{ matrix.os }},go-${{ matrix.go-version }},ydb-${{ matrix.ydb-version }}
diff --git a/.golangci.yml b/.golangci.yml
index b373a0322..85915e7b9 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -227,21 +227,18 @@ linters:
- exhaustivestruct
- exhaustruct
- forbidigo
- - forcetypeassert
- funlen
- gochecknoglobals
- gocognit
- godot
- goerr113
- golint
- - gomnd
- ifshort
- interfacebloat
- ireturn
- maintidx
- nonamedreturns
- paralleltest
- - scopelint
- structcheck
- testableexamples
- testpackage
@@ -295,6 +292,8 @@ issues:
- predeclared
- path: _test\.go
linters:
+ - scopelint
+ - funlen
- unused
- unparam
- gocritic
@@ -303,6 +302,9 @@ issues:
- staticcheck
- path: _test\.go
text: "ydb.Connection is deprecated"
+ - path: examples
+ linters:
+ - gomnd
# Allow underscore and capital camel case for readability
# Examples: Type_PRIMITIVE_TYPE_ID_UNSPECIFIED, Ydb_Discovery_V1, _voidValue
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d36d2f2dd..6a4a61efc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,58 @@
+## v3.65.0
+* Supported OAuth 2.0 Token Exchange credentials provider
+
+## v3.64.0
+* Supported `table.Session.RenameTables` method
+* Fixed out of range panic if next query result set part is empty
+* Updated the indirect dependencies `golang.org/x/net` to `v0.17.0` and `golang.org/x/sys` to `v0.13.0` due to vulnerability issue
+
+## v3.63.0
+* Added versioning policy
+
+## v3.62.0
+* Restored `WithSessionPoolKeepAliveMinSize` and `WithSessionPoolKeepAliveTimeout` for backward compatibility.
+* Fixed leak timers
+* Changed default StartTime (time of retries for connect to server) for topic writer from 1 minute to infinite (can be overrided by WithWriterStartTimeout topic option)
+* Added `Struct` support for `Variant` in `ydb.ParamsBuilder()`
+* Added `go` with anonymous function case in `gstack`
+
+## v3.61.2
+* Changed default transaction control to `NoTx` for execute query through query service client
+
+## v3.61.1
+* Renamed `db.Coordination().CreateSession()` to `db.Coordination().Session()` for compatibility with protos
+
+## v3.61.0
+* Added `Tuple` support for `Variant` in `ydb.ParamsBuilder()`
+
+## v3.60.1
+* Added additional traces for coordination service client internals
+
+## v3.60.0
+* Added experimental support of semaphores over coordination service client
+
+## v3.59.3
+* Fixed `gstack` logic for parsing `ast.BlockStmt`
+
+## v3.59.2
+* Added internal `gstack` codegen tool for filling `stack.FunctionID` with value from call stack
+
+## v3.59.1
+* Fixed updating last usage timestamp for smart parking of the conns
+
+## v3.59.0
+* Added `Struct` support for `ydb.ParamsBuilder()`
* Added support of `TzDate`,`TzDateTime`,`TzTimestamp` types in `ydb.ParamsBuilder()`
* Added `trace.Query.OnTransactionExecute` event
* Added query pool metrics
* Fixed logic of query session pool
* Changed initialization of internal driver clients to lazy
-* Disabled the logic of background grpc-connection parking
+* Removed `ydb.WithSessionPoolSizeLimit()` option
+* Added async put session into pool if external context is done
+* Dropped intermediate callbacks from `trace.{Table,Retry,Query}` events
+* Wrapped errors from `internal/pool.Pool.getItem` as retryable
+* Disabled the logic of background grpc-connection parking
+* Improved stringification for postgres types
## v3.58.2
* Added `trace.Query.OnSessionBegin` event
@@ -27,6 +76,7 @@
* Updated `google.golang.org/protobuf` from `v1.31.0` to `v.33.0`
* Added `ydb.ParamsBuilder().Pg().{Value,Int4,Int8,Unknown}` for postgres arguments
* Added `Tuple` support for `ydb.ParamsBuilder()`
+* Added type assertion checks to enhance type safety and prevent unexpected panics in critical sections of the codebase
## v3.57.4
* Added client pid to each gRPC requests to YDB over header `x-ydb-client-pid`
@@ -51,7 +101,7 @@
* Fixed sometime panic on topic writer closing
* Added experimental query parameters builder `ydb.ParamsBuilder()`
* Changed types of `table/table.{QueryParameters,ParameterOption}` to aliases on `internal/params.{Parameters,NamedValue}`
-* Fixed bug with optional decimal serialization
+* Fixed bug with optional decimal serialization
## v3.56.2
* Fixed return private error for commit to stopped partition in topic reader.
diff --git a/README.md b/README.md
index eb51ff130..ef0c47e06 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
[![WebSite](https://img.shields.io/badge/website-ydb.tech-blue.svg)](https://ydb.tech)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/ydb-platform/ydb-go-sdk/blob/master/CONTRIBUTING.md)
-Supports `table`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripting` and `topic` clients for [YDB](https://ydb.tech).
+Supports `table`, `query`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripting` and `topic` clients for [YDB](https://ydb.tech).
`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.
@@ -22,6 +22,10 @@ Supports `table`, `discovery`, `coordination`, `ratelimiter`, `scheme`, `scripti
`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.
+## Versioning Policy
+
+`ydb-go-sdk` comply to guidelines from [SemVer2.0.0](https://semver.org/) with an several [exceptions](VERSIONING.md).
+
## Installation
```sh
@@ -31,19 +35,20 @@ go get -u github.com/ydb-platform/ydb-go-sdk/v3
## Example Usage
* connect to YDB
-```golang
+```go
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
log.Fatal(err)
}
```
-* execute `SELECT` query
- ```golang
-const query = `SELECT 42 as id, "myStr" as myStr;`
-
+* execute `SELECT` query over `Table` service client
+ ```go
// Do retry operation on errors with best effort
-queryErr := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
- _, res, err := s.Execute(ctx, table.DefaultTxControl(), query, nil)
+err := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err error) {
+ _, res, err := s.Execute(ctx, table.DefaultTxControl(),
+ `SELECT 42 as id, "myStr" as myStr;`,
+ nil, // empty parameters
+ )
if err != nil {
return err
}
@@ -62,12 +67,61 @@ queryErr := db.Table().Do(ctx, func(ctx context.Context, s table.Session) (err e
}
return res.Err() // for driver retry if not nil
})
-if queryErr != nil {
- log.Fatal(queryErr)
+if err != nil {
+ log.Fatal(err)
+}
+```
+* execute `SELECT` query over `Query` service client
+ ```go
+// Do retry operation on errors with best effort
+err := db.Query().Do( // Do retry operation on errors with best effort
+ ctx, // context manage exiting from Do
+ func(ctx context.Context, s query.Session) (err error) { // retry operation
+ _, res, err := s.Execute(ctx, `SELECT 42 as id, "myStr" as myStr;`))
+ if err != nil {
+ return err // for auto-retry with driver
+ }
+ defer func() { _ = res.Close(ctx) }() // cleanup resources
+ for { // iterate over result sets
+ rs, err := res.NextResultSet(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ for { // iterate over rows
+ row, err := rs.NextRow(ctx)
+ if err != nil {
+ if errors.Is(err, io.EOF) {
+ break
+ }
+
+ return err
+ }
+ type myStruct struct {
+ id uint64 `sql:"id"`
+ str string `sql:"myStr"`
+ }
+ var s myStruct
+ if err = row.ScanStruct(&s); err != nil {
+ return err // generally scan error not retryable, return it for driver check error
+ }
+ }
+ }
+
+ return res.Err() // return finally result error for auto-retry with driver
+ },
+ query.WithIdempotent(),
+)
+if err != nil {
+ log.Fatal(err)
}
```
+
* usage with `database/sql` (see additional docs in [SQL.md](SQL.md) )
-```golang
+```go
import (
"context"
"database/sql"
@@ -96,7 +150,7 @@ log.Printf("id = %d, myStr = \"%s\"", id, myStr)
```
-More examples of usage placed in [examples](https://github.com/ydb-platform/ydb-go-examples) repository.
+More examples of usage placed in [examples](./examples) directory.
## Credentials
@@ -124,8 +178,7 @@ Next packages provide debug tooling:
| [ydb-go-sdk-zap](https://github.com/ydb-platform/ydb-go-sdk-zap) | logging | logging ydb-go-sdk events with `zap` package | [ydbZap.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-zap/blob/master/internal/cmd/bench/main.go#L64) |
| [ydb-go-sdk-zerolog](https://github.com/ydb-platform/ydb-go-sdk-zerolog) | logging | logging ydb-go-sdk events with `zerolog` package | [ydbZerolog.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-zerolog/blob/master/internal/cmd/bench/main.go#L47) |
| [ydb-go-sdk-logrus](https://github.com/ydb-platform/ydb-go-sdk-logrus) | logging | logging ydb-go-sdk events with `logrus` package | [ydbLogrus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-logrus/blob/master/internal/cmd/bench/main.go#L48) |
-| [ydb-go-sdk-metrics](https://github.com/ydb-platform/ydb-go-sdk-metrics) | metrics | common metrics of ydb-go-sdk. Package declare interfaces such as `Registry`, `GaugeVec` and `Gauge` and use it for traces | |
-| [ydb-go-sdk-prometheus](https://github.com/ydb-platform/ydb-go-sdk-prometheus) | metrics | prometheus wrapper over [ydb-go-sdk-metrics](https://github.com/ydb-platform/ydb-go-sdk-metrics) | [ydbPrometheus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-prometheus/blob/master/internal/cmd/bench/main.go#L56) |
+| [ydb-go-sdk-prometheus](https://github.com/ydb-platform/ydb-go-sdk-prometheus/v2) | metrics | prometheus wrapper over [ydb-go-sdk/v3/metrics](https://github.com/ydb-platform/ydb-go-sdk/tree/master/metrics) | [ydbPrometheus.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-prometheus/blob/master/internal/cmd/bench/main.go#L56) |
| [ydb-go-sdk-opentracing](https://github.com/ydb-platform/ydb-go-sdk-opentracing) | tracing | OpenTracing plugin for trace internal ydb-go-sdk calls | [ydbOpentracing.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-opentracing/blob/master/internal/cmd/bench/main.go#L86) |
| [ydb-go-sdk-otel](https://github.com/ydb-platform/ydb-go-sdk-otel) | tracing | OpenTelemetry plugin for trace internal ydb-go-sdk calls | [ydbOtel.WithTraces](https://github.com/ydb-platform/ydb-go-sdk-otel/blob/master/internal/cmd/bench/main.go#L98) |
diff --git a/VERSIONING.md b/VERSIONING.md
new file mode 100644
index 000000000..40cb9171c
--- /dev/null
+++ b/VERSIONING.md
@@ -0,0 +1,24 @@
+# YDB-Go-SDK Versioning Policy
+
+By adhering to these guidelines and exceptions, we aim to provide a stable and reliable development experience for our users (aka [LTS](https://en.wikipedia.org/wiki/Long-term_support)) while still allowing for innovation and improvement.
+
+We endeavor to adhere to versioning guidelines as defined by [SemVer2.0.0](https://semver.org/).
+
+We making the following exceptions to those guidelines:
+## Experimental
+ - We use the `// Experimental` comment for new features in the `ydb-go-sdk`.
+ - Early adopters of newest feature can report bugs and imperfections in functionality.
+ - For fix this issues we can make broken changes in experimental API.
+ - We reserve the right to remove or modify these experimental features at any time without increase of major part of version.
+ - We want to make experimental API as stable in the future
+## Deprecated
+ - We use the `// Deprecated` comment for deprecated features in the `ydb-go-sdk`.
+ - Usage of some entity marked with `// Deprecated` can be detected with linters such as [check-deprecated](https://github.com/black-06/check-deprecated), [staticcheck](https://github.com/dominikh/go-tools/tree/master/cmd/staticcheck) or [go-critic](https://github.com/go-critic/go-critic).
+ - This helps to our users to soft decline to use the deprecated feature without any impact on their code.
+ - Deprecated features will not be removed or changed for a minimum period of **six months** since the mark added.
+ - We reserve the right to remove or modify these deprecated features without increase of major part of version.
+## Internals
+ - Some public API of `ydb-go-sdk` relate to the internals.
+ - We use the `// Internals` comment for public internals in the `ydb-go-sdk`.
+ - `ydb-go-sdk` internals can be changed at any time without increase of major part of version.
+ - Internals will never marked as stable
diff --git a/balancers/balancers.go b/balancers/balancers.go
index c73c8f503..2fe525a53 100644
--- a/balancers/balancers.go
+++ b/balancers/balancers.go
@@ -9,7 +9,9 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
-// Deprecated: RoundRobin is RandomChoice now
+// Deprecated: RoundRobin is an alias to RandomChoice now
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func RoundRobin() *balancerConfig.Config {
return &balancerConfig.Config{}
}
@@ -115,6 +117,8 @@ type Endpoint interface {
// Deprecated: LocalDC check "local" by compare endpoint location with discovery "selflocation" field.
// It work good only if connection url always point to local dc.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
LocalDC() bool
}
diff --git a/config/config.go b/config/config.go
index 47d3b8cc1..28ffd0f90 100644
--- a/config/config.go
+++ b/config/config.go
@@ -21,6 +21,7 @@ type Config struct {
trace *trace.Driver
dialTimeout time.Duration
+ connectionTTL time.Duration
balancerConfig *balancerConfig.Config
secure bool
endpoint string
@@ -56,6 +57,13 @@ func (c *Config) Meta() *meta.Meta {
return c.meta
}
+// ConnectionTTL defines interval for parking grpc connections.
+//
+// If ConnectionTTL is zero - connections are not park.
+func (c *Config) ConnectionTTL() time.Duration {
+ return c.connectionTTL
+}
+
// Secure is a flag for secure connection
func (c *Config) Secure() bool {
return c.secure
@@ -99,7 +107,9 @@ type Option func(c *Config)
// WithInternalDNSResolver
//
-// Deprecated: always used internal dns-resolver
+// Deprecated: always used internal dns-resolver.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithInternalDNSResolver() Option {
return func(c *Config) {}
}
@@ -162,13 +172,21 @@ func WithApplicationName(applicationName string) Option {
// WithUserAgent add provided user agent to all api requests
//
-// Deprecated: use WithApplicationName instead
+// Deprecated: use WithApplicationName instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithUserAgent(userAgent string) Option {
return func(c *Config) {
c.metaOptions = append(c.metaOptions, meta.WithApplicationNameOption(userAgent))
}
}
+func WithConnectionTTL(ttl time.Duration) Option {
+ return func(c *Config) {
+ c.connectionTTL = ttl
+ }
+}
+
func WithCredentials(credentials credentials.Credentials) Option {
return func(c *Config) {
c.credentials = credentials
diff --git a/connection.go b/connection.go
index 9bff94e31..14adc7470 100644
--- a/connection.go
+++ b/connection.go
@@ -16,10 +16,10 @@ import (
// Connection interface provide access to YDB service clients
// Interface and list of clients may be changed in the future
//
-// Deprecated: use directly *Driver type from ydb.Open instead
-//
-//nolint:interfacebloat
-type Connection interface {
+// Deprecated: use Driver instance instead.
+// Will be removed at next major release.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+type Connection interface { //nolint:interfacebloat
// Endpoint returns initial endpoint
Endpoint() string
@@ -37,9 +37,7 @@ type Connection interface {
// Query returns query client
//
- // # Experimental
- //
- // Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+ // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
Query() query.Client
// Scheme returns scheme client
diff --git a/coordination/coordination.go b/coordination/coordination.go
index 7bd9f6dbf..b0ff0c011 100644
--- a/coordination/coordination.go
+++ b/coordination/coordination.go
@@ -2,7 +2,11 @@ package coordination
import (
"context"
+ "fmt"
+ "math"
+ "time"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
)
@@ -11,4 +15,185 @@ type Client interface {
AlterNode(ctx context.Context, path string, config NodeConfig) (err error)
DropNode(ctx context.Context, path string) (err error)
DescribeNode(ctx context.Context, path string) (_ *scheme.Entry, _ *NodeConfig, err error)
+
+ // Session starts a new session. This method blocks until the server session is created. The context provided
+ // may be used to cancel the invocation. If the method completes successfully, the session remains alive even if
+ // the context is canceled.
+ //
+ // To ensure resources are not leaked, one of the following actions must be performed:
+ //
+ // - call Close on the Session,
+ // - close the Client which the session was created with,
+ // - call any method of the Session until the ErrSessionClosed is returned.
+ //
+ // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
+ Session(ctx context.Context, path string, opts ...options.SessionOption) (Session, error)
+}
+
+const (
+ // MaxSemaphoreLimit defines the maximum value of the limit parameter in the Session.CreateSemaphore method.
+ MaxSemaphoreLimit = math.MaxUint64
+
+ // Exclusive is just a shortcut for the maximum semaphore limit value. You can use this to acquire a semaphore in
+ // the exclusive mode if it was created with the limit value of MaxSemaphoreLimit, which is always true for
+ // ephemeral semaphores.
+ Exclusive = math.MaxUint64
+
+ // Shared is just a shortcut for the minimum semaphore limit value (1). You can use this to acquire a semaphore in
+ // the shared mode if it was created with the limit value of MaxSemaphoreLimit, which is always true for ephemeral
+ // semaphores.
+ Shared = 1
+)
+
+// Session defines a coordination service backed session.
+//
+// In general, Session API is concurrency-friendly, you can safely access all of its methods concurrently.
+//
+// The client guarantees that sequential calls of the methods are sent to the server in the same order. However, the
+// session client may reorder and suspend some of the requests without violating correctness of the execution. This also
+// applies to the situations when the underlying gRPC stream has been recreated due to network or server issues.
+//
+// The client automatically keeps the underlying gRPC stream alive by sending keep-alive (ping-pong) requests. If the
+// client can no longer consider the session alive, it immediately cancels the session context which also leads to
+// cancellation of contexts of all semaphore leases created by this session.
+type Session interface {
+ // Close closes the coordination service session. It cancels all active requests on the server and notifies every
+ // pending or waiting for response request on the client side. It also cancels the session context and tries to
+ // stop the session gracefully on the server. If the ctx is canceled, this will not wait for the server session to
+ // become stopped and returns immediately with an error. Once this function returns with no error, all subsequent
+ // calls will be noop.
+ Close(ctx context.Context) error
+
+ // Context returns the context of the session. It is canceled when the underlying server session is over or if the
+ // client could not get any successful response from the server before the session timeout (see
+ // options.WithSessionTimeout).
+ Context() context.Context
+
+ // CreateSemaphore creates a new semaphore. This method waits until the server successfully creates a new semaphore
+ // or returns an error.
+ //
+ // This method is not idempotent. If the request has been sent to the server but no reply has been received, it
+ // returns the ErrOperationStatusUnknown error.
+ CreateSemaphore(ctx context.Context, name string, limit uint64, opts ...options.CreateSemaphoreOption) error
+
+ // UpdateSemaphore changes semaphore data. This method waits until the server successfully updates the semaphore or
+ // returns an error.
+ //
+ // This method is not idempotent. The client will automatically retry in the case of network or server failure
+ // unless it leaves the client state inconsistent.
+ UpdateSemaphore(ctx context.Context, name string, opts ...options.UpdateSemaphoreOption) error
+
+ // DeleteSemaphore deletes an existing semaphore. This method waits until the server successfully deletes the
+ // semaphore or returns an error.
+ //
+ // This method is not idempotent. If the request has been sent to the server but no reply has been received, it
+ // returns the ErrOperationStatusUnknown error.
+ DeleteSemaphore(ctx context.Context, name string, opts ...options.DeleteSemaphoreOption) error
+
+ // DescribeSemaphore returns the state of the semaphore.
+ //
+ // This method is idempotent. The client will automatically retry in the case of network or server failure.
+ DescribeSemaphore(
+ ctx context.Context,
+ name string,
+ opts ...options.DescribeSemaphoreOption,
+ ) (*SemaphoreDescription, error)
+
+ // AcquireSemaphore acquires the semaphore. If you acquire an ephemeral semaphore (see options.WithEphemeral), its
+ // limit will be set to MaxSemaphoreLimit. Later requests override previous operations with the same semaphore, e.g.
+ // to reduce acquired count, change timeout or attached data.
+ //
+ // This method blocks until the semaphore is acquired, an error is returned from the server or the session is
+ // closed. If the operation context was canceled but the server replied that the semaphore was actually acquired,
+ // the client will automatically release the semaphore.
+ //
+ // Semaphore waiting is fair: the semaphore guarantees that other sessions invoking the AcquireSemaphore method
+ // acquire permits in the order which they were called (FIFO). If a session invokes the AcquireSemaphore method
+ // multiple times while the first invocation is still in process, the position in the queue remains unchanged.
+ //
+ // This method is idempotent. The client will automatically retry in the case of network or server failure.
+ AcquireSemaphore(
+ ctx context.Context,
+ name string,
+ count uint64,
+ opts ...options.AcquireSemaphoreOption,
+ ) (Lease, error)
+
+ // SessionID returns a server-generated identifier of the session. This value is permanent and unique within the
+ // coordination service node.
+ SessionID() uint64
+
+ // Reconnect forcibly shuts down the underlying gRPC stream and initiates a new one. This method is highly unlikely
+ // to be of use in a typical application but is extremely useful for testing an API implementation.
+ Reconnect()
+}
+
+// Lease is the object which defines the rights of the session to the acquired semaphore. Lease is alive until its
+// context is not canceled. This may happen implicitly, when the associated session becomes lost or closed, or
+// explicitly, if someone calls the Release method of the lease.
+type Lease interface {
+ // Context returns the context of the lease. It is canceled when the session it was created by was lost or closed,
+ // or if the lease was released by calling the Release method.
+ Context() context.Context
+
+ // Release releases the acquired lease to the semaphore. It also cancels the context of the lease. This method does
+ // not take a ctx argument, but you can cancel the execution of it by closing the session or canceling its context.
+ Release() error
+
+ // Session returns the session which this lease was created by.
+ Session() Session
+}
+
+// SemaphoreDescription describes the state of a semaphore.
+type SemaphoreDescription struct {
+ // Name is the name of the semaphore.
+ Name string
+
+ // Limit is the maximum number of tokens that may be acquired.
+ Limit uint64
+
+ // Count is the number of tokens currently acquired by its owners.
+ Count uint64
+
+ // Ephemeral semaphores are deleted when there are no owners and waiters left.
+ Ephemeral bool
+
+ // Data is user-defined data attached to the semaphore.
+ Data []byte
+
+ // Owner is the list of current owners of the semaphore.
+ Owners []*SemaphoreSession
+
+ // Waiter is the list of current waiters of the semaphore.
+ Waiters []*SemaphoreSession
+}
+
+// SemaphoreSession describes an owner or a waiter of this semaphore.
+type SemaphoreSession struct {
+ // SessionID is the id of the session which tried to acquire the semaphore.
+ SessionID uint64
+
+ // Count is the number of tokens for the acquire operation.
+ Count uint64
+
+ // OrderId is a monotonically increasing id which determines locking order.
+ OrderID uint64
+
+ // Data is user-defined data attached to the acquire operation.
+ Data []byte
+
+ // Timeout is the timeout for the operation in the waiter queue. If this is time.Duration(math.MaxInt64) the session
+ // will wait for the semaphore until the operation is canceled.
+ Timeout time.Duration
+}
+
+func (d *SemaphoreDescription) String() string {
+ return fmt.Sprintf(
+ "{Name: %q Limit: %d Count: %d Ephemeral: %t Data: %q Owners: %s Waiters: %s}",
+ d.Name, d.Limit, d.Count, d.Ephemeral, d.Data, d.Owners, d.Waiters)
+}
+
+func (s *SemaphoreSession) String() string {
+ return fmt.Sprintf("{SessionID: %d Count: %d OrderID: %d Data: %q TimeoutMillis: %v}",
+ s.SessionID, s.Count, s.OrderID, s.Data, s.Timeout)
}
diff --git a/coordination/errors.go b/coordination/errors.go
new file mode 100644
index 000000000..2f10cd557
--- /dev/null
+++ b/coordination/errors.go
@@ -0,0 +1,18 @@
+package coordination
+
+import "errors"
+
+var (
+ // ErrOperationStatusUnknown indicates that the request has been sent to the server but no reply has been received.
+ // The client usually automatically retries calls of that kind, but there are cases when it is not possible:
+ // - the request is not idempotent, non-idempotent requests are never retried,
+ // - the session was lost and its context is canceled.
+ ErrOperationStatusUnknown = errors.New("operation status is unknown")
+
+ // ErrSessionClosed indicates that the Session object is closed.
+ ErrSessionClosed = errors.New("session is closed")
+
+ // ErrAcquireTimeout indicates that the Session.AcquireSemaphore method could not acquire the semaphore before the
+ // operation timeout (see options.WithAcquireTimeout).
+ ErrAcquireTimeout = errors.New("acquire semaphore timeout")
+)
diff --git a/coordination/example_test.go b/coordination/example_test.go
index 57657d779..20ca57852 100644
--- a/coordination/example_test.go
+++ b/coordination/example_test.go
@@ -6,10 +6,11 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3"
"github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
)
//nolint:errcheck
-func Example() {
+func Example_createDropNode() {
ctx := context.TODO()
db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
if err != nil {
@@ -41,3 +42,106 @@ func Example() {
}
fmt.Printf("node description: %+v\nnode config: %+v\n", e, c)
}
+
+func Example_semaphore() {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx, "grpc://localhost:2136/local")
+ if err != nil {
+ fmt.Printf("failed to connect: %v", err)
+
+ return
+ }
+ defer db.Close(ctx) // cleanup resources
+ // create node
+ err = db.Coordination().CreateNode(ctx, "/local/test", coordination.NodeConfig{
+ Path: "",
+ SelfCheckPeriodMillis: 1000,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: coordination.ConsistencyModeStrict,
+ AttachConsistencyMode: coordination.ConsistencyModeStrict,
+ RatelimiterCountersMode: coordination.RatelimiterCountersModeDetailed,
+ })
+ if err != nil {
+ fmt.Printf("failed to create node: %v", err)
+
+ return
+ }
+ defer func() {
+ dropNodeErr := db.Coordination().DropNode(ctx, "/local/test")
+ if dropNodeErr != nil {
+ fmt.Printf("failed to drop node: %v\n", dropNodeErr)
+ }
+ }()
+
+ e, c, err := db.Coordination().DescribeNode(ctx, "/local/test")
+ if err != nil {
+ fmt.Printf("failed to describe node: %v\n", err)
+
+ return
+ }
+ fmt.Printf("node description: %+v\nnode config: %+v\n", e, c)
+
+ s, err := db.Coordination().Session(ctx, "/local/test")
+ if err != nil {
+ fmt.Printf("failed to create session: %v\n", err)
+
+ return
+ }
+ defer s.Close(ctx)
+ fmt.Printf("session 1 created, id: %d\n", s.SessionID())
+
+ err = s.CreateSemaphore(ctx, "my-semaphore", 20, options.WithCreateData([]byte{1, 2, 3}))
+ if err != nil {
+ fmt.Printf("failed to create semaphore: %v", err)
+
+ return
+ }
+ fmt.Printf("semaphore my-semaphore created\n")
+
+ lease, err := s.AcquireSemaphore(ctx, "my-semaphore", 10)
+ if err != nil {
+ fmt.Printf("failed to acquire semaphore: %v", err)
+
+ return
+ }
+ defer func() {
+ releaseErr := lease.Release()
+ if releaseErr != nil {
+ fmt.Printf("failed to release lease: %v", releaseErr)
+ }
+ }()
+
+ fmt.Printf("session 1 acquired semaphore 10\n")
+
+ s.Reconnect()
+ fmt.Printf("session 1 reconnected\n")
+
+ desc, err := s.DescribeSemaphore(
+ ctx,
+ "my-semaphore",
+ options.WithDescribeOwners(true),
+ options.WithDescribeWaiters(true),
+ )
+ if err != nil {
+ fmt.Printf("failed to describe semaphore: %v", err)
+
+ return
+ }
+ fmt.Printf("session 1 described semaphore %v\n", desc)
+
+ err = lease.Release()
+ if err != nil {
+ fmt.Printf("failed to release semaphore: %v", err)
+
+ return
+ }
+ fmt.Printf("session 1 released semaphore my-semaphore\n")
+
+ err = s.DeleteSemaphore(ctx, "my-semaphore", options.WithForceDelete(true))
+ if err != nil {
+ fmt.Printf("failed to delete semaphore: %v", err)
+
+ return
+ }
+ fmt.Printf("deleted semaphore my-semaphore\n")
+}
diff --git a/coordination/options/options.go b/coordination/options/options.go
new file mode 100644
index 000000000..e156bc068
--- /dev/null
+++ b/coordination/options/options.go
@@ -0,0 +1,173 @@
+package options
+
+import (
+ "math"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+)
+
+// WithDescription returns an SessionOption that specifies a user-defined description that may be used to describe
+// the client.
+func WithDescription(description string) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.Description = description
+ }
+}
+
+// WithSessionTimeout returns an SessionOption that specifies the timeout during which client may restore a
+// detached session. The client is forced to terminate the session if the last successful session request occurred
+// earlier than this time.
+//
+// If this is not set, the client uses the default 5 seconds.
+func WithSessionTimeout(timeout time.Duration) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.SessionTimeout = timeout
+ }
+}
+
+// WithSessionStartTimeout returns an SessionOption that specifies the time that the client should wait for a
+// response to the StartSession request from the server before it terminates the gRPC stream and tries to reconnect.
+//
+// If this is not set, the client uses the default time 1 second.
+func WithSessionStartTimeout(timeout time.Duration) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.SessionStartTimeout = timeout
+ }
+}
+
+// WithSessionStopTimeout returns an SessionOption that specifies the time that the client should wait for a
+// response to the StopSession request from the server before it terminates the gRPC stream and tries to reconnect.
+//
+// If this is not set, the client uses the default time 1 second.
+func WithSessionStopTimeout(timeout time.Duration) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.SessionStartTimeout = timeout
+ }
+}
+
+// WithSessionKeepAliveTimeout returns an SessionOption that specifies the time that the client will wait before
+// it terminates the gRPC stream and tries to reconnect if no successful responses have been received from the server.
+//
+// If this is not set, the client uses the default time 10 seconds.
+func WithSessionKeepAliveTimeout(timeout time.Duration) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.SessionKeepAliveTimeout = timeout
+ }
+}
+
+// WithSessionReconnectDelay returns an SessionOption that specifies the time that the client will wait before it
+// tries to reconnect the underlying gRPC stream in case of error.
+//
+// If this is not set, the client uses the default time 500 milliseconds.
+func WithSessionReconnectDelay(delay time.Duration) SessionOption {
+ return func(c *CreateSessionOptions) {
+ c.SessionReconnectDelay = delay
+ }
+}
+
+// SessionOption configures how we create a new session.
+type SessionOption func(c *CreateSessionOptions)
+
+// CreateSessionOptions configure an Session call. CreateSessionOptions are set by the SessionOption values
+// passed to the Session function.
+type CreateSessionOptions struct {
+ Description string
+ SessionTimeout time.Duration
+ SessionStartTimeout time.Duration
+ SessionStopTimeout time.Duration
+ SessionKeepAliveTimeout time.Duration
+ SessionReconnectDelay time.Duration
+}
+
+// WithEphemeral returns an AcquireSemaphoreOption that causes to create an ephemeral semaphore.
+//
+// Ephemeral semaphores are created with the first acquire operation and automatically deleted with the last release
+// operation. Ephemeral semaphore are always created with the limit of coordination.MaxSemaphoreLimit.
+func WithEphemeral(ephemeral bool) AcquireSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_AcquireSemaphore) {
+ c.Ephemeral = ephemeral
+ }
+}
+
+// WithAcquireTimeout returns an AcquireSemaphoreOption which sets the timeout after which the operation fails if it
+// is still waiting in the queue. Use 0 to make the AcquireSemaphore method fail immediately if the semaphore is already
+// acquired by another session.
+//
+// If this is not set, the client waits for the acquire operation result until the operation or session context is done.
+// You can reset the default value of this timeout by calling the WithAcquireInfiniteTimeout method.
+func WithAcquireTimeout(timeout time.Duration) AcquireSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_AcquireSemaphore) {
+ c.TimeoutMillis = uint64(timeout.Milliseconds())
+ }
+}
+
+// WithAcquireInfiniteTimeout returns an AcquireSemaphoreOption which disables the timeout after which the operation
+// fails if it is still waiting in the queue.
+//
+// This is the default behavior. You can set the specific timeout by calling the WithAcquireTimeout method.
+func WithAcquireInfiniteTimeout() AcquireSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_AcquireSemaphore) {
+ c.TimeoutMillis = math.MaxUint64
+ }
+}
+
+// WithAcquireData returns an AcquireSemaphoreOption which attaches user-defined data to the operation.
+func WithAcquireData(data []byte) AcquireSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_AcquireSemaphore) {
+ c.Data = data
+ }
+}
+
+// AcquireSemaphoreOption configures how we acquire a semaphore.
+type AcquireSemaphoreOption func(c *Ydb_Coordination.SessionRequest_AcquireSemaphore)
+
+// WithForceDelete return a DeleteSemaphoreOption which allows to delete a semaphore even if it is currently acquired
+// by other sessions.
+func WithForceDelete(force bool) DeleteSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_DeleteSemaphore) {
+ c.Force = force
+ }
+}
+
+// DeleteSemaphoreOption configures how we delete a semaphore.
+type DeleteSemaphoreOption func(c *Ydb_Coordination.SessionRequest_DeleteSemaphore)
+
+// WithCreateData return a CreateSemaphoreOption which attaches user-defined data to the semaphore.
+func WithCreateData(data []byte) CreateSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_CreateSemaphore) {
+ c.Data = data
+ }
+}
+
+// CreateSemaphoreOption configures how we create a semaphore.
+type CreateSemaphoreOption func(c *Ydb_Coordination.SessionRequest_CreateSemaphore)
+
+// WithUpdateData return a UpdateSemaphoreOption which changes user-defined data in the semaphore.
+func WithUpdateData(data []byte) UpdateSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_UpdateSemaphore) {
+ c.Data = data
+ }
+}
+
+// UpdateSemaphoreOption configures how we update a semaphore.
+type UpdateSemaphoreOption func(c *Ydb_Coordination.SessionRequest_UpdateSemaphore)
+
+// WithDescribeOwners return a DescribeSemaphoreOption which causes server send the list of owners in the response
+// to the DescribeSemaphore request.
+func WithDescribeOwners(describeOwners bool) DescribeSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_DescribeSemaphore) {
+ c.IncludeOwners = describeOwners
+ }
+}
+
+// WithDescribeWaiters return a DescribeSemaphoreOption which causes server send the list of waiters in the response
+// to the DescribeSemaphore request.
+func WithDescribeWaiters(describeWaiters bool) DescribeSemaphoreOption {
+ return func(c *Ydb_Coordination.SessionRequest_DescribeSemaphore) {
+ c.IncludeWaiters = describeWaiters
+ }
+}
+
+// DescribeSemaphoreOption configures how we update a semaphore.
+type DescribeSemaphoreOption func(c *Ydb_Coordination.SessionRequest_DescribeSemaphore)
diff --git a/credentials/credentials.go b/credentials/credentials.go
index 8829eb973..b11106414 100644
--- a/credentials/credentials.go
+++ b/credentials/credentials.go
@@ -34,3 +34,21 @@ func NewStaticCredentials(
) *credentials.Static {
return credentials.NewStaticCredentials(user, password, authEndpoint, opts...)
}
+
+// NewOauth2TokenExchangeCredentials makes OAuth 2.0 token exchange protocol credentials object
+// https://www.rfc-editor.org/rfc/rfc8693
+func NewOauth2TokenExchangeCredentials(
+ opts ...credentials.Oauth2TokenExchangeCredentialsOption,
+) (Credentials, error) {
+ return credentials.NewOauth2TokenExchangeCredentials(opts...)
+}
+
+// NewJWTTokenSource makes JWT token source for OAuth 2.0 token exchange credentials
+func NewJWTTokenSource(opts ...credentials.JWTTokenSourceOption) (credentials.TokenSource, error) {
+ return credentials.NewJWTTokenSource(opts...)
+}
+
+// NewFixedTokenSource makes fixed token source for OAuth 2.0 token exchange credentials
+func NewFixedTokenSource(token, tokenType string) credentials.TokenSource {
+ return credentials.NewFixedTokenSource(token, tokenType)
+}
diff --git a/credentials/options.go b/credentials/options.go
index 9da142092..5d944dae6 100644
--- a/credentials/options.go
+++ b/credentials/options.go
@@ -1,11 +1,20 @@
package credentials
import (
+ "time"
+
+ "github.com/golang-jwt/jwt/v4"
"google.golang.org/grpc"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/credentials"
)
+type Oauth2TokenExchangeCredentialsOption = credentials.Oauth2TokenExchangeCredentialsOption
+
+type TokenSource = credentials.TokenSource
+
+type Token = credentials.Token
+
// WithSourceInfo option append to credentials object the source info for reporting source info details on error case
func WithSourceInfo(sourceInfo string) credentials.SourceInfoOption {
return credentials.WithSourceInfo(sourceInfo)
@@ -15,3 +24,118 @@ func WithSourceInfo(sourceInfo string) credentials.SourceInfoOption {
func WithGrpcDialOptions(opts ...grpc.DialOption) credentials.StaticCredentialsOption {
return credentials.WithGrpcDialOptions(opts...)
}
+
+// TokenEndpoint
+func WithTokenEndpoint(endpoint string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithTokenEndpoint(endpoint)
+}
+
+// GrantType
+func WithGrantType(grantType string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithGrantType(grantType)
+}
+
+// Resource
+func WithResource(resource string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithResource(resource)
+}
+
+// RequestedTokenType
+func WithRequestedTokenType(requestedTokenType string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithRequestedTokenType(requestedTokenType)
+}
+
+// Scope
+func WithScope(scope ...string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithScope(scope...)
+}
+
+// RequestTimeout
+func WithRequestTimeout(timeout time.Duration) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithRequestTimeout(timeout)
+}
+
+// SubjectTokenSource
+func WithSubjectToken(subjectToken credentials.TokenSource) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithSubjectToken(subjectToken)
+}
+
+// SubjectTokenSource
+func WithFixedSubjectToken(token, tokenType string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithFixedSubjectToken(token, tokenType)
+}
+
+// SubjectTokenSource
+func WithJWTSubjectToken(opts ...credentials.JWTTokenSourceOption) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithJWTSubjectToken(opts...)
+}
+
+// ActorTokenSource
+func WithActorToken(actorToken credentials.TokenSource) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithActorToken(actorToken)
+}
+
+// ActorTokenSource
+func WithFixedActorToken(token, tokenType string) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithFixedActorToken(token, tokenType)
+}
+
+// ActorTokenSource
+func WithJWTActorToken(opts ...credentials.JWTTokenSourceOption) Oauth2TokenExchangeCredentialsOption {
+ return credentials.WithJWTActorToken(opts...)
+}
+
+// Audience
+type oauthCredentialsAndJWTCredentialsOption interface {
+ credentials.Oauth2TokenExchangeCredentialsOption
+ credentials.JWTTokenSourceOption
+}
+
+func WithAudience(audience ...string) oauthCredentialsAndJWTCredentialsOption {
+ return credentials.WithAudience(audience...)
+}
+
+// Issuer
+func WithIssuer(issuer string) credentials.JWTTokenSourceOption {
+ return credentials.WithIssuer(issuer)
+}
+
+// Subject
+func WithSubject(subject string) credentials.JWTTokenSourceOption {
+ return credentials.WithSubject(subject)
+}
+
+// ID
+func WithID(id string) credentials.JWTTokenSourceOption {
+ return credentials.WithID(id)
+}
+
+// TokenTTL
+func WithTokenTTL(ttl time.Duration) credentials.JWTTokenSourceOption {
+ return credentials.WithTokenTTL(ttl)
+}
+
+// SigningMethod
+func WithSigningMethod(method jwt.SigningMethod) credentials.JWTTokenSourceOption {
+ return credentials.WithSigningMethod(method)
+}
+
+// KeyID
+func WithKeyID(id string) credentials.JWTTokenSourceOption {
+ return credentials.WithKeyID(id)
+}
+
+// PrivateKey
+func WithPrivateKey(key interface{}) credentials.JWTTokenSourceOption {
+ return credentials.WithPrivateKey(key)
+}
+
+// PrivateKey
+func WithRSAPrivateKeyPEMContent(key []byte) credentials.JWTTokenSourceOption {
+ return credentials.WithRSAPrivateKeyPEMContent(key)
+}
+
+// PrivateKey
+func WithRSAPrivateKeyPEMFile(path string) credentials.JWTTokenSourceOption {
+ return credentials.WithRSAPrivateKeyPEMFile(path)
+}
diff --git a/driver.go b/driver.go
index 190254dce..592466443 100644
--- a/driver.go
+++ b/driver.go
@@ -115,7 +115,9 @@ func (d *Driver) trace() *trace.Driver {
//
//nolint:nonamedreturns
func (d *Driver) Close(ctx context.Context) (finalErr error) {
- onDone := trace.DriverOnClose(d.trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnClose(d.trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.(*Driver).Close"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -189,9 +191,7 @@ func (d *Driver) Table() table.Client {
// Query returns query client
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func (d *Driver) Query() query.Client {
return d.query.Get()
}
@@ -248,7 +248,7 @@ func Open(ctx context.Context, dsn string, opts ...Option) (_ *Driver, err error
onDone := trace.DriverOnInit(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.Open"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {
@@ -273,10 +273,12 @@ func MustOpen(ctx context.Context, dsn string, opts ...Option) *Driver {
// New connects to database and return driver runtime holder
//
-// Deprecated: use Open with required param connectionString instead
-//
-//nolint:nonamedreturns
-func New(ctx context.Context, opts ...Option) (_ *Driver, err error) {
+// Deprecated: use ydb.Open instead.
+// New func have no required arguments, such as connection string.
+// Thats why we recognize that New have wrong signature.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+func New(ctx context.Context, opts ...Option) (_ *Driver, err error) { //nolint:nonamedreturns
d, err := newConnectionFromOptions(ctx, opts...)
if err != nil {
return nil, xerrors.WithStackTrace(err)
@@ -284,7 +286,7 @@ func New(ctx context.Context, opts ...Option) (_ *Driver, err error) {
onDone := trace.DriverOnInit(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.New"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {
@@ -300,7 +302,7 @@ func New(ctx context.Context, opts ...Option) (_ *Driver, err error) {
//nolint:cyclop, nonamedreturns
func newConnectionFromOptions(ctx context.Context, opts ...Option) (_ *Driver, err error) {
- ctx, driverCtxCancel := xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ ctx, driverCtxCancel := xcontext.WithCancel(xcontext.ValueOnly(ctx))
defer func() {
if err != nil {
driverCtxCancel()
@@ -401,7 +403,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
}
d.table = xsync.OnceValue(func() *internalTable.Client {
- return internalTable.New(xcontext.WithoutDeadline(ctx),
+ return internalTable.New(xcontext.ValueOnly(ctx),
d.balancer,
tableConfig.New(
append(
@@ -416,7 +418,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.query = xsync.OnceValue(func() *internalQuery.Client {
- return internalQuery.New(xcontext.WithoutDeadline(ctx),
+ return internalQuery.New(xcontext.ValueOnly(ctx),
d.balancer,
queryConfig.New(
append(
@@ -434,7 +436,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
}
d.scheme = xsync.OnceValue(func() *internalScheme.Client {
- return internalScheme.New(xcontext.WithoutDeadline(ctx),
+ return internalScheme.New(xcontext.ValueOnly(ctx),
d.balancer,
schemeConfig.New(
append(
@@ -450,7 +452,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.coordination = xsync.OnceValue(func() *internalCoordination.Client {
- return internalCoordination.New(xcontext.WithoutDeadline(ctx),
+ return internalCoordination.New(xcontext.ValueOnly(ctx),
d.balancer,
coordinationConfig.New(
append(
@@ -465,7 +467,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.ratelimiter = xsync.OnceValue(func() *internalRatelimiter.Client {
- return internalRatelimiter.New(xcontext.WithoutDeadline(ctx),
+ return internalRatelimiter.New(xcontext.ValueOnly(ctx),
d.balancer,
ratelimiterConfig.New(
append(
@@ -480,7 +482,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.discovery = xsync.OnceValue(func() *internalDiscovery.Client {
- return internalDiscovery.New(xcontext.WithoutDeadline(ctx),
+ return internalDiscovery.New(xcontext.ValueOnly(ctx),
d.pool.Get(endpoint.New(d.config.Endpoint())),
discoveryConfig.New(
append(
@@ -499,7 +501,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.scripting = xsync.OnceValue(func() *internalScripting.Client {
- return internalScripting.New(xcontext.WithoutDeadline(ctx),
+ return internalScripting.New(xcontext.ValueOnly(ctx),
d.balancer,
scriptingConfig.New(
append(
@@ -514,7 +516,7 @@ func (d *Driver) connect(ctx context.Context) (err error) {
})
d.topic = xsync.OnceValue(func() *topicclientinternal.Client {
- return topicclientinternal.New(xcontext.WithoutDeadline(ctx),
+ return topicclientinternal.New(xcontext.ValueOnly(ctx),
d.balancer,
d.config.Credentials(),
append(
diff --git a/examples/auth/README.md b/examples/auth/README.md
index 273113372..e2b384488 100644
--- a/examples/auth/README.md
+++ b/examples/auth/README.md
@@ -4,6 +4,7 @@ Auth examples helps to understand YDB authentication:
* `access_token_credentials` - example of use access token credentials
* `anonymous_credentials` - example of use anonymous credentials
* `metadata_credentials` - example of use metadata credentials
+* `oauth2_token_exchange_credentials` - example of use oauth 2.0 token exchange credentials
* `service_account_credentials` - example of use service account key file credentials
* `static_credentials` - example of use static credentials
* `environ` - example of use environment variables to configure YDB authenticate
diff --git a/examples/auth/oauth2_token_exchange_credentials/README.md b/examples/auth/oauth2_token_exchange_credentials/README.md
new file mode 100644
index 000000000..a13adf8d8
--- /dev/null
+++ b/examples/auth/oauth2_token_exchange_credentials/README.md
@@ -0,0 +1,8 @@
+# Authenticate with oauth 2.0 token exchange credentials
+
+`oauth2_token_exchange_credentials` example provides code snippet for authentication to YDB with oauth 2.0 token exchange credentials
+
+## Runing code snippet
+```bash
+oauth2_token_exchange_credentials -ydb="grpcs://endpoint/?database=database" -token-endpoint="https://exchange.token.endpoint/oauth2/token/exchange" -key-id="123" -private-key-file="path/to/key/file" -audience="test-aud" -issuer="test-issuer" -subject="test-subject"
+```
diff --git a/examples/auth/oauth2_token_exchange_credentials/main.go b/examples/auth/oauth2_token_exchange_credentials/main.go
new file mode 100644
index 000000000..e20e8a882
--- /dev/null
+++ b/examples/auth/oauth2_token_exchange_credentials/main.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/golang-jwt/jwt/v4"
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/credentials"
+)
+
+var (
+ dsn string
+ tokenEndpoint string
+ keyID string
+ privateKeyFile string
+ audience string
+ issuer string
+ subject string
+)
+
+func init() { //nolint:gochecknoinits
+ required := []string{"ydb", "private-key-file", "key-id", "token-endpoint"}
+ flagSet := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+ flagSet.Usage = func() {
+ out := flagSet.Output()
+ _, _ = fmt.Fprintf(out, "Usage:\n%s [options]\n", os.Args[0])
+ _, _ = fmt.Fprintf(out, "\nOptions:\n")
+ flagSet.PrintDefaults()
+ }
+ flagSet.StringVar(&dsn,
+ "ydb", "",
+ "YDB connection string",
+ )
+ flagSet.StringVar(&tokenEndpoint,
+ "token-endpoint", "",
+ "oauth 2.0 token exchange endpoint",
+ )
+ flagSet.StringVar(&keyID,
+ "key-id", "",
+ "key id for jwt token",
+ )
+ flagSet.StringVar(&privateKeyFile,
+ "private-key-file", "",
+ "RSA private key file for jwt token in pem format",
+ )
+ flagSet.StringVar(&audience,
+ "audience", "",
+ "audience",
+ )
+ flagSet.StringVar(&issuer,
+ "issuer", "",
+ "jwt token issuer",
+ )
+ flagSet.StringVar(&subject,
+ "subject", "",
+ "jwt token subject",
+ )
+ if err := flagSet.Parse(os.Args[1:]); err != nil {
+ flagSet.Usage()
+ os.Exit(1)
+ }
+ flagSet.Visit(func(f *flag.Flag) {
+ for i, arg := range required {
+ if arg == f.Name {
+ required = append(required[:i], required[i+1:]...)
+ }
+ }
+ })
+ if len(required) > 0 {
+ fmt.Printf("\nSome required options not defined: %v\n\n", required)
+ flagSet.Usage()
+ os.Exit(1)
+ }
+}
+
+func main() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ db, err := ydb.Open(ctx, dsn,
+ ydb.WithOauth2TokenExchangeCredentials(
+ credentials.WithTokenEndpoint(tokenEndpoint),
+ credentials.WithAudience(audience),
+ credentials.WithJWTSubjectToken(
+ credentials.WithSigningMethod(jwt.SigningMethodRS256),
+ credentials.WithKeyID(keyID),
+ credentials.WithRSAPrivateKeyPEMFile(privateKeyFile),
+ credentials.WithIssuer(issuer),
+ credentials.WithSubject(subject),
+ credentials.WithAudience(audience),
+ ),
+ ),
+ )
+ if err != nil {
+ panic(err)
+ }
+ defer func() { _ = db.Close(ctx) }()
+
+ whoAmI, err := db.Discovery().WhoAmI(ctx)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println(whoAmI.String())
+}
diff --git a/examples/coordination/README.md b/examples/coordination/README.md
new file mode 100644
index 000000000..d5248aa99
--- /dev/null
+++ b/examples/coordination/README.md
@@ -0,0 +1,156 @@
+# Coordination Examples
+
+Coordination Examples demonstrate how to implement various distributed consistency primitives using the
+`coordination.Client` API.
+
+## Locks
+
+Strictly speaking, this is an implementation of a [lease](https://en.wikipedia.org/wiki/Lease_(computer_science)), not a
+lock in the traditional sense.
+
+Consider an application which is running a number of different instances. You want to ensure that some shared resource
+is accessed by only one instance at a time.
+
+The `lock` application is an example of that instance. When it starts, it waits until the distributed lock is acquired.
+When the application cannot consider the lock acquired anymore (for example, in the case of network issues) it stops
+working and tries to acquire the lock again.
+
+You may start any number of applications, only one of them will consider itself the holder of the lock at a time.
+
+Although we call it a lock, this mechanism **cannot be used to implement mutual exclusion by itself**. Session relies on
+physical time clocks. The server and the client clocks may be, and actually always are, out of sync. This results in a
+situation where for example the server releases the lease but the client still assumes it owns the lease. However,
+leases can be used as optimization in order to significantly reduce the possibility of resource contention.
+
+To start the application with the [YDB Docker database instance](https://ydb.tech/en/docs/getting_started/self_hosted/ydb_docker) run
+
+```bash
+$ go build
+$ YDB_ANONYMOUS_CREDENTIALS=1 ./lock -ydb grpc://localhost:2136/local --path /local/test --semaphore lock
+```
+
+When you stop the application which is currently holding the semaphore, another one should immediately acquire the lock
+and start doing its work.
+
+This example uses an ephemeral semaphore which is always acquired exclusive. The following pseudocode shows how it is
+used.
+
+```go
+for {
+ session, err := db.Coordination().OpenSession(ctx, path)
+ if err != nil {
+ // The context is canceled.
+ break
+ }
+
+ lease, err := session.AcquireSemaphore(ctx, semaphore, coordination.Exclusive, options.WithEphemeral(true))
+ if err != nil {
+ session.Close(ctx)
+ continue
+ }
+
+ // The lock is acquired.
+ go doWork(lease.Context())
+
+ // Wait until the lock is released.
+ <-lease.Context().Done():
+
+ // The lock is not acquired anymore.
+ cancelWork()
+}
+```
+
+## Workers
+
+This is an example of distributing long-running tasks among multiple workers. Consider there is a number of tasks that
+need to be processed simultaneously by a pool of workers. Each task is processed independently and the order of
+processing does not matter. A worker has a fixed capacity that defines how many tasks it is ready to process at a time.
+
+Any single task is associated with a Coordination Service semaphore. When the application starts, it grabs all task
+semaphores in order to acquire at least `capacity` of them. When it happens, it releases excessive ones and wait until
+the application finishes. Until then, it starts a new task for every acquired semaphore and waits until the number of
+running tasks becomes equal to the capacity of the worker.
+
+To start the application with the [YDB Docker database instance](https://ydb.tech/en/docs/getting_started/self_hosted/ydb_docker) run
+
+```bash
+$ go build
+$ YDB_ANONYMOUS_CREDENTIALS=1 ./lock -ydb grpc://localhost:2136/local -path /local/test --semaphore-prefix job- --tasks 10 --capacity 4
+```
+
+This example uses ephemeral semaphores which are always acquired exclusive. However, in a real application you may
+want to use persistent semaphores in order to store the state of workers in attached data. The following pseudocode
+shows how it is used.
+
+```go
+for {
+ session, err := db.Coordination().OpenSession(ctx, path)
+ if err != nil {
+ // The context is canceled.
+ break
+ }
+
+ semaphoreCtx, semaphoreCancel := context.WithCancel(ctx)
+ capacitySemaphore := semaphore.NewWeighted(capacity)
+ leaseChan := make(chan *coordination.Lease)
+ for _, name := range tasks {
+ go awaitSemaphore(semaphoreCtx, semaphoreCancel, session, name, capacitySemaphore, leaseChan)
+ }
+
+ tasksStarted := 0
+loop:
+ for {
+ lease := <-leaseChan
+
+ // Run a new task every time we acquire a semaphore.
+ go doWork(lease.Context())
+
+ tasksStarted++
+ if tasksStarted == capacity {
+ break
+ }
+ }
+
+ // The capacity is full, cancel all Acquire operations.
+ semaphoreCancel()
+
+ // Wait until the session is alive.
+ <-session.Context().Done()
+
+ // The tasks must be stopped since we do not own the semaphores anymore.
+ cancelTasks()
+}
+
+func awaitSemaphore(
+ ctx context.Context,
+ cancel context.CancelFunc,
+ session coordination.Session,
+ semaphoreName string,
+ capacitySemaphore *semaphore.Weighted,
+ leaseChan chan *coordination.Lease,
+) {
+ lease, err := session.AcquireSemaphore(
+ ctx,
+ semaphoreName,
+ coordination.Exclusive,
+ options.WithEphemeral(true),
+ )
+ if err != nil {
+ // Let the main loop know that something is wrong.
+ // ...
+ return
+ }
+
+ // If there is a need in tasks for the current worker, provide it with a new lease.
+ if capacitySemaphore.TryAcquire(1) {
+ leaseChan <- lease
+ } else {
+ // This may happen since we are waiting for all existing semaphores trying to grab the first available to us.
+ err := lease.Release()
+ if err != nil {
+ // Let the main loop know that something is wrong.
+ // ...
+ }
+ }
+}
+```
diff --git a/examples/coordination/lock/main.go b/examples/coordination/lock/main.go
new file mode 100644
index 000000000..905bb1e4b
--- /dev/null
+++ b/examples/coordination/lock/main.go
@@ -0,0 +1,144 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
+)
+
+var (
+ dsn string
+ path string
+ semaphore string
+)
+
+//nolint:gochecknoinits
+func init() {
+ required := []string{"ydb", "path", "semaphore"}
+ flagSet := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+ flagSet.Usage = func() {
+ out := flagSet.Output()
+ _, _ = fmt.Fprintf(out, "Usage:\n%s [options]\n", os.Args[0])
+ _, _ = fmt.Fprintf(out, "\nOptions:\n")
+ flagSet.PrintDefaults()
+ }
+ flagSet.StringVar(&dsn,
+ "ydb", "",
+ "YDB connection string",
+ )
+ flagSet.StringVar(&path,
+ "path", "",
+ "coordination node path",
+ )
+ flagSet.StringVar(&semaphore,
+ "semaphore", "",
+ "semaphore name",
+ )
+ if err := flagSet.Parse(os.Args[1:]); err != nil {
+ flagSet.Usage()
+ os.Exit(1)
+ }
+ flagSet.Visit(func(f *flag.Flag) {
+ for i, arg := range required {
+ if arg == f.Name {
+ required = append(required[:i], required[i+1:]...)
+ }
+ }
+ })
+ if len(required) > 0 {
+ fmt.Printf("\nSome required options not defined: %v\n\n", required)
+ flagSet.Usage()
+ os.Exit(1)
+ }
+}
+
+func main() {
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+ defer cancel()
+
+ db, err := ydb.Open(ctx, dsn,
+ environ.WithEnvironCredentials(ctx),
+ )
+ if err != nil {
+ panic(fmt.Errorf("connect error: %w", err))
+ }
+ defer func() { _ = db.Close(ctx) }()
+
+ err = db.Coordination().CreateNode(ctx, path, coordination.NodeConfig{
+ Path: "",
+ SelfCheckPeriodMillis: 1000,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: coordination.ConsistencyModeStrict,
+ AttachConsistencyMode: coordination.ConsistencyModeStrict,
+ RatelimiterCountersMode: coordination.RatelimiterCountersModeDetailed,
+ })
+ if err != nil {
+ fmt.Printf("failed to create coordination node: %v\n", err)
+
+ return
+ }
+
+ for {
+ fmt.Println("waiting for a lock...")
+
+ session, err := db.Coordination().Session(ctx, path)
+ if err != nil {
+ fmt.Println("failed to open session", err)
+
+ return
+ }
+
+ lease, err := session.AcquireSemaphore(ctx, semaphore, coordination.Exclusive, options.WithEphemeral(true))
+ if err != nil {
+ fmt.Printf("failed to acquire semaphore: %v\n", err)
+ _ = session.Close(ctx)
+
+ continue
+ }
+
+ fmt.Println("the lock is acquired")
+
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+ go doWork(lease.Context(), &wg)
+
+ select {
+ case <-ctx.Done():
+ fmt.Println("exiting")
+
+ return
+ case <-lease.Context().Done():
+ }
+
+ fmt.Println("the lock is released")
+ wg.Wait()
+ }
+}
+
+func doWork(ctx context.Context, wg *sync.WaitGroup) {
+ defer func() {
+ fmt.Println("suspending work")
+ wg.Done()
+ }()
+
+ fmt.Println("starting work")
+ for {
+ fmt.Println("work is in progress...")
+
+ select {
+ case <-ctx.Done():
+ return
+ case <-time.After(time.Second):
+ }
+ }
+}
diff --git a/examples/coordination/workers/main.go b/examples/coordination/workers/main.go
new file mode 100644
index 000000000..451336a7a
--- /dev/null
+++ b/examples/coordination/workers/main.go
@@ -0,0 +1,229 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "math/rand"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ environ "github.com/ydb-platform/ydb-go-sdk-auth-environ"
+ ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
+ "golang.org/x/sync/semaphore"
+)
+
+var (
+ dsn string
+ path string
+ semaphorePrefix string
+ taskCount int
+ capacity int
+)
+
+//nolint:gochecknoinits
+func init() {
+ required := []string{"ydb", "path"}
+ flagSet := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+ flagSet.Usage = func() {
+ out := flagSet.Output()
+ _, _ = fmt.Fprintf(out, "Usage:\n%s [options]\n", os.Args[0])
+ _, _ = fmt.Fprintf(out, "\nOptions:\n")
+ flagSet.PrintDefaults()
+ }
+ flagSet.StringVar(&dsn,
+ "ydb", "",
+ "YDB connection string",
+ )
+ flagSet.StringVar(&path,
+ "path", "",
+ "coordination node path",
+ )
+ flagSet.StringVar(&semaphorePrefix,
+ "semaphore-prefix", "job-",
+ "semaphore prefix",
+ )
+ flagSet.IntVar(&taskCount,
+ "tasks", 10,
+ "the number of tasks",
+ )
+ flagSet.IntVar(&capacity,
+ "capacity", 4,
+ "the maximum number of tasks a worker can run",
+ )
+ if err := flagSet.Parse(os.Args[1:]); err != nil {
+ flagSet.Usage()
+ os.Exit(1)
+ }
+ flagSet.Visit(func(f *flag.Flag) {
+ for i, arg := range required {
+ if arg == f.Name {
+ required = append(required[:i], required[i+1:]...)
+ }
+ }
+ })
+ if len(required) > 0 {
+ fmt.Printf("\nSome required options not defined: %v\n\n", required)
+ flagSet.Usage()
+ os.Exit(1)
+ }
+}
+
+func main() {
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+ defer cancel()
+
+ db, err := ydb.Open(ctx, dsn,
+ environ.WithEnvironCredentials(ctx),
+ )
+ if err != nil {
+ panic(fmt.Errorf("connect error: %w", err))
+ }
+ defer func() { _ = db.Close(ctx) }()
+
+ err = db.Coordination().CreateNode(ctx, path, coordination.NodeConfig{
+ Path: "",
+ SelfCheckPeriodMillis: 1000,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: coordination.ConsistencyModeStrict,
+ AttachConsistencyMode: coordination.ConsistencyModeStrict,
+ RatelimiterCountersMode: coordination.RatelimiterCountersModeDetailed,
+ })
+ if err != nil {
+ fmt.Printf("failed to create coordination node: %v\n", err)
+
+ return
+ }
+
+ tasks := make([]string, taskCount)
+ for i := 0; i < taskCount; i++ {
+ tasks[i] = fmt.Sprintf("%s%d", semaphorePrefix, i)
+ }
+ rand.Shuffle(taskCount, func(i int, j int) {
+ tasks[i], tasks[j] = tasks[j], tasks[i]
+ })
+
+ fmt.Println("starting tasks")
+ for {
+ session, err := db.Coordination().Session(ctx, path)
+ if err != nil {
+ fmt.Println("failed to open session", err)
+
+ return
+ }
+
+ semaphoreCtx, semaphoreCancel := context.WithCancel(ctx)
+ wg := sync.WaitGroup{}
+ wg.Add(taskCount)
+ leaseChan := make(chan *LeaseInfo)
+ sem := semaphore.NewWeighted(int64(capacity))
+
+ for _, name := range tasks {
+ go awaitSemaphore(semaphoreCtx, &wg, session, name, leaseChan, sem, semaphoreCancel)
+ }
+
+ tasksStarted := 0
+ loop:
+ for {
+ select {
+ case <-semaphoreCtx.Done():
+ break loop
+ case lease := <-leaseChan:
+ go doWork(lease.lease, lease.semaphoreName)
+ tasksStarted++
+ if tasksStarted == capacity {
+ break loop
+ }
+ case <-ctx.Done():
+ fmt.Println("exiting")
+
+ return
+ }
+ }
+
+ fmt.Println("all workers are started")
+
+ semaphoreCancel()
+ wg.Wait()
+
+ select {
+ case <-ctx.Done():
+ fmt.Println("exiting")
+
+ return
+ case <-session.Context().Done():
+ }
+ }
+}
+
+type LeaseInfo struct {
+ lease coordination.Lease
+ semaphoreName string
+}
+
+func awaitSemaphore(
+ ctx context.Context,
+ done *sync.WaitGroup,
+ session coordination.Session,
+ semaphoreName string,
+ leaseChan chan *LeaseInfo,
+ sem *semaphore.Weighted,
+ cancel context.CancelFunc,
+) {
+ defer done.Done()
+
+ lease, err := session.AcquireSemaphore(
+ ctx,
+ semaphoreName,
+ coordination.Exclusive,
+ options.WithEphemeral(true),
+ )
+ if err != nil {
+ if ctx.Err() != nil {
+ return
+ }
+
+ fmt.Println("failed to acquire semaphore", err)
+ cancel()
+
+ return
+ }
+
+ if sem.TryAcquire(1) {
+ leaseChan <- &LeaseInfo{lease: lease, semaphoreName: semaphoreName}
+ } else {
+ err := lease.Release()
+ if err != nil {
+ fmt.Println("failed to release semaphore", err)
+ cancel()
+ }
+ }
+}
+
+func doWork(
+ lease coordination.Lease,
+ name string,
+) {
+ fmt.Printf("worker %s: starting\n", name)
+
+ for {
+ select {
+ case <-lease.Context().Done():
+ fmt.Printf("worker %s: done\n", name)
+ err := lease.Release()
+ if err != nil {
+ fmt.Println("failed to release semaphore", err)
+ }
+
+ return
+ case <-time.After(time.Second):
+ }
+
+ fmt.Printf("worker %s: in progress\n", name)
+ }
+}
diff --git a/examples/go.mod b/examples/go.mod
index 4b8c940bb..8e4d692d8 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -12,6 +12,7 @@ require (
github.com/ydb-platform/ydb-go-sdk-prometheus/v2 v2.0.1
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.0
github.com/ydb-platform/ydb-go-yc v0.10.1
+ golang.org/x/sync v0.3.0
google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54
gorm.io/driver/postgres v1.5.0
gorm.io/driver/sqlite v1.5.0
@@ -54,8 +55,7 @@ require (
github.com/ydb-platform/ydb-go-yc-metadata v0.5.4 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/mod v0.11.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sync v0.3.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.7.0 // indirect
diff --git a/examples/go.sum b/examples/go.sum
index 79278f3b3..14380c891 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1269,7 +1269,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1401,8 +1401,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1551,7 +1551,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1565,7 +1565,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/examples/topic/topicreader/topicreader_advanced.go b/examples/topic/topicreader/topicreader_advanced.go
index 962f4700b..256d38494 100644
--- a/examples/topic/topicreader/topicreader_advanced.go
+++ b/examples/topic/topicreader/topicreader_advanced.go
@@ -50,14 +50,14 @@ func UnmarshalMessageContentToOwnType(ctx context.Context, reader *topicreader.R
// ProcessMessagesWithSyncCommit example about guarantee wait for commit accepted by server
func ProcessMessagesWithSyncCommit(ctx context.Context, db *ydb.Driver) {
reader, _ := db.Topic().StartReader("consumer", nil,
- topicoptions.WithCommitMode(topicoptions.CommitModeSync),
+ topicoptions.WithReaderCommitMode(topicoptions.CommitModeSync),
)
defer func() {
_ = reader.Close(ctx)
}()
for {
- batch, _ := reader.ReadMessageBatch(ctx)
+ batch, _ := reader.ReadMessagesBatch(ctx)
processBatch(batch.Context(), batch)
_ = reader.Commit(ctx, batch) // will wait response about commit from server
}
@@ -67,7 +67,7 @@ func ProcessMessagesWithSyncCommit(ctx context.Context, db *ydb.Driver) {
// commit messages to YDB
func OwnReadProgressStorage(ctx context.Context, db *ydb.Driver) {
reader, _ := db.Topic().StartReader("consumer", topicoptions.ReadTopic("asd"),
- topicoptions.WithGetPartitionStartOffset(
+ topicoptions.WithReaderGetPartitionStartOffset(
func(
ctx context.Context,
req topicoptions.GetPartitionStartOffsetRequest,
@@ -84,7 +84,7 @@ func OwnReadProgressStorage(ctx context.Context, db *ydb.Driver) {
)
for {
- batch, _ := reader.ReadMessageBatch(ctx)
+ batch, _ := reader.ReadMessagesBatch(ctx)
processBatch(batch.Context(), batch)
_ = externalSystemCommit(
diff --git a/examples/topic/topicreader/topicreader_simple.go b/examples/topic/topicreader/topicreader_simple.go
index 6fb568037..793485fbb 100644
--- a/examples/topic/topicreader/topicreader_simple.go
+++ b/examples/topic/topicreader/topicreader_simple.go
@@ -24,7 +24,7 @@ func PrintMessageContent(ctx context.Context, reader *topicreader.Reader) {
// ReadMessagesByBatch it is recommended way for process messages
func ReadMessagesByBatch(ctx context.Context, reader *topicreader.Reader) {
for {
- batch, _ := reader.ReadMessageBatch(ctx)
+ batch, _ := reader.ReadMessagesBatch(ctx)
processBatch(batch.Context(), batch)
_ = reader.Commit(batch.Context(), batch)
}
diff --git a/examples/topic/topicreader/topicreader_trace.go b/examples/topic/topicreader/topicreader_trace.go
index 28ab11427..b31390fb2 100644
--- a/examples/topic/topicreader/topicreader_trace.go
+++ b/examples/topic/topicreader/topicreader_trace.go
@@ -71,7 +71,7 @@ func ExplicitPartitionStartStopHandler(ctx context.Context, db *ydb.Driver) {
}()
for {
- batch, _ := reader.ReadMessageBatch(readContext)
+ batch, _ := reader.ReadMessagesBatch(readContext)
processBatch(batch.Context(), batch)
_ = externalSystemCommit(
@@ -129,8 +129,7 @@ func PartitionStartStopHandlerAndOwnReadProgressStorage(ctx context.Context, db
}
r, _ := db.Topic().StartReader("consumer", topicoptions.ReadTopic("asd"),
-
- topicoptions.WithGetPartitionStartOffset(readStartPosition),
+ topicoptions.WithReaderGetPartitionStartOffset(readStartPosition),
topicoptions.WithReaderTrace(
trace.Topic{
OnReaderPartitionReadStartResponse: onPartitionStart,
@@ -144,7 +143,7 @@ func PartitionStartStopHandlerAndOwnReadProgressStorage(ctx context.Context, db
}()
for {
- batch, _ := r.ReadMessageBatch(readContext)
+ batch, _ := r.ReadMessagesBatch(readContext)
processBatch(batch.Context(), batch)
_ = externalSystemCommit(batch.Context(), batch.Topic(), batch.PartitionID(), getEndOffset(batch))
diff --git a/examples/topic/topicwriter/topicwriter.go b/examples/topic/topicwriter/topicwriter.go
index a378f8a90..354d3f454 100644
--- a/examples/topic/topicwriter/topicwriter.go
+++ b/examples/topic/topicwriter/topicwriter.go
@@ -17,13 +17,13 @@ func ConnectSimple(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
}
func ConnectWithSyncWrite(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
- writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithSyncWrite(true))
+ writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithWriterWaitServerAck(true))
return writer
}
func ConnectSelectCodec(ctx context.Context, db *ydb.Driver) *topicwriter.Writer {
- writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithCodec(topictypes.CodecGzip))
+ writer, _ := db.Topic().StartWriter("topicName", topicoptions.WithWriterCodec(topictypes.CodecGzip))
return writer
}
diff --git a/examples/ttl/series.go b/examples/ttl/series.go
index a6e4753c3..67f7759dc 100644
--- a/examples/ttl/series.go
+++ b/examples/ttl/series.go
@@ -268,9 +268,10 @@ func createTables(ctx context.Context, c table.Client, prefix string) (err error
}
for i := 0; i < expirationQueueCount; i++ {
+ tableName := path.Join(prefix, fmt.Sprintf("expiration_queue_%v", i))
err = c.Do(ctx,
func(ctx context.Context, s table.Session) error {
- return s.CreateTable(ctx, path.Join(prefix, fmt.Sprintf("expiration_queue_%v", i)),
+ return s.CreateTable(ctx, tableName,
options.WithColumn("doc_id", types.Optional(types.TypeUint64)),
options.WithColumn("ts", types.Optional(types.TypeUint64)),
options.WithPrimaryKeyColumn("ts", "doc_id"),
diff --git a/go.mod b/go.mod
index 339491ffc..e531a3b47 100644
--- a/go.mod
+++ b/go.mod
@@ -24,8 +24,8 @@ require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
diff --git a/go.sum b/go.sum
index 4cfd88ee1..5af6dc2e2 100644
--- a/go.sum
+++ b/go.sum
@@ -84,8 +84,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -100,8 +100,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
diff --git a/internal/allocator/allocator.go b/internal/allocator/allocator.go
index 378e8d244..981780697 100644
--- a/internal/allocator/allocator.go
+++ b/internal/allocator/allocator.go
@@ -1,6 +1,7 @@
package allocator
import (
+ "fmt"
"sync"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
@@ -395,7 +396,7 @@ type structAllocator struct {
func (a *structAllocator) Struct() (v *Ydb.StructType) {
v = structPool.Get()
if cap(v.GetMembers()) <= 0 {
- v.Members = make([]*Ydb.StructMember, 0, 10)
+ v.Members = make([]*Ydb.StructMember, 0, 10) //nolint:gomnd
}
a.allocations = append(a.allocations, v)
@@ -1107,7 +1108,12 @@ func (p *Pool[T]) Get() *T {
v = &zero
}
- return v.(*T)
+ val, ok := v.(*T)
+ if !ok {
+ panic(fmt.Sprintf("assertion failed: expected type *T, got %T", v))
+ }
+
+ return val
}
func (p *Pool[T]) Put(t *T) {
diff --git a/internal/backoff/backoff.go b/internal/backoff/backoff.go
index c3a6902fe..d4b9cceeb 100644
--- a/internal/backoff/backoff.go
+++ b/internal/backoff/backoff.go
@@ -22,11 +22,11 @@ const (
var (
Fast = New(
WithSlotDuration(fastSlot),
- WithCeiling(6),
+ WithCeiling(6), //nolint:gomnd
)
Slow = New(
WithSlotDuration(slowSlot),
- WithCeiling(6),
+ WithCeiling(6), //nolint:gomnd
)
)
diff --git a/internal/balancer/balancer.go b/internal/balancer/balancer.go
index 9bd58b451..f69ec11e2 100644
--- a/internal/balancer/balancer.go
+++ b/internal/balancer/balancer.go
@@ -97,7 +97,8 @@ func (b *Balancer) clusterDiscoveryAttempt(ctx context.Context) (err error) {
address = "ydb:///" + b.driverConfig.Endpoint()
onDone = trace.DriverOnBalancerClusterDiscoveryAttempt(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).clusterDiscoveryAttempt"),
address,
)
endpoints []endpoint.Endpoint
@@ -173,7 +174,8 @@ func (b *Balancer) applyDiscoveredEndpoints(ctx context.Context, endpoints []end
var (
onDone = trace.DriverOnBalancerUpdate(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).applyDiscoveredEndpoints"),
b.config.DetectLocalDC,
)
previousConns []conn.Conn
@@ -211,7 +213,7 @@ func (b *Balancer) applyDiscoveredEndpoints(ctx context.Context, endpoints []end
func (b *Balancer) Close(ctx context.Context) (err error) {
onDone := trace.DriverOnBalancerClose(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).Close"),
)
defer func() {
onDone(err)
@@ -237,7 +239,7 @@ func New(
var (
onDone = trace.DriverOnBalancerInit(
driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.New"),
driverConfig.Balancer().String(),
)
discoveryConfig = discoveryConfig.New(append(opts,
@@ -280,7 +282,7 @@ func New(
}
// run background discovering
if d := discoveryConfig.Interval(); d > 0 {
- b.discoveryRepeater = repeater.New(xcontext.WithoutDeadline(ctx),
+ b.discoveryRepeater = repeater.New(xcontext.ValueOnly(ctx),
d, b.clusterDiscoveryAttempt,
repeater.WithName("discovery"),
repeater.WithTrace(b.driverConfig.Trace()),
@@ -371,7 +373,7 @@ func (b *Balancer) connections() *connectionsState {
func (b *Balancer) getConn(ctx context.Context) (c conn.Conn, err error) {
onDone := trace.DriverOnBalancerChooseEndpoint(
b.driverConfig.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/balancer.(*Balancer).getConn"),
)
defer func() {
if err == nil {
diff --git a/internal/balancer/local_dc.go b/internal/balancer/local_dc.go
index e764af7d8..b1ee2e086 100644
--- a/internal/balancer/local_dc.go
+++ b/internal/balancer/local_dc.go
@@ -69,7 +69,7 @@ func detectFastestEndpoint(ctx context.Context, endpoints []endpoint.Endpoint) (
var lastErr error
// common is 2 ip address for every fqdn: ipv4 + ipv6
- initialAddressToEndpointCapacity := len(endpoints) * 2
+ initialAddressToEndpointCapacity := len(endpoints) * 2 //nolint:gomnd
addressToEndpoint := make(map[string]endpoint.Endpoint, initialAddressToEndpointCapacity)
for _, ep := range endpoints {
host, port, err := extractHostPort(ep.Address())
diff --git a/internal/bind/numeric_args.go b/internal/bind/numeric_args.go
index 89c9c4ecc..6cb948906 100644
--- a/internal/bind/numeric_args.go
+++ b/internal/bind/numeric_args.go
@@ -5,6 +5,7 @@ import (
"strconv"
"unicode/utf8"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
"github.com/ydb-platform/ydb-go-sdk/v3/table"
@@ -16,9 +17,7 @@ func (m NumericArgs) blockID() blockID {
return blockYQL
}
-func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (
- yql string, newArgs []interface{}, err error,
-) {
+func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (yql string, newArgs []interface{}, err error) {
l := &sqlLexer{
src: sql,
stateFn: numericArgsStateFn,
@@ -29,14 +28,18 @@ func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (
l.stateFn = l.stateFn(l)
}
- var (
- buffer = xstring.Buffer()
- param table.ParameterOption
- )
+ buffer := xstring.Buffer()
defer buffer.Free()
if len(args) > 0 {
- newArgs = make([]interface{}, len(args))
+ parameters, err := parsePositionalParameters(args)
+ if err != nil {
+ return "", nil, err
+ }
+ newArgs = make([]interface{}, len(parameters))
+ for i, param := range parameters {
+ newArgs[i] = param
+ }
}
for _, p := range l.parts {
@@ -49,7 +52,7 @@ func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (
}
if int(p) > len(args) {
return "", nil, xerrors.WithStackTrace(
- fmt.Errorf("%w: $p%d, len(args) = %d", ErrInconsistentArgs, p, len(args)),
+ fmt.Errorf("%w: $%d, len(args) = %d", ErrInconsistentArgs, p, len(args)),
)
}
paramName := "$p" + strconv.Itoa(int(p-1)) //nolint:goconst
@@ -61,26 +64,21 @@ func (m NumericArgs) RewriteQuery(sql string, args ...interface{}) (
newArgs[p-1] = param
buffer.WriteString(param.Name())
} else {
- buffer.WriteString(newArgs[p-1].(table.ParameterOption).Name())
+ val, ok := newArgs[p-1].(table.ParameterOption)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to table.ParameterOption", val))
+ }
+ buffer.WriteString(val.Name())
}
}
}
- for i, p := range newArgs {
- if p == nil {
- return "", nil, xerrors.WithStackTrace(
- fmt.Errorf("%w: $p%d, len(args) = %d", ErrInconsistentArgs, i+1, len(args)),
- )
- }
- }
-
+ yql = buffer.String()
if len(newArgs) > 0 {
- const prefix = "-- origin query with numeric args replacement\n"
-
- return prefix + buffer.String(), newArgs, nil
+ yql = "-- origin query with numeric args replacement\n" + yql
}
- return buffer.String(), newArgs, nil
+ return yql, newArgs, nil
}
func numericArgsStateFn(l *sqlLexer) stateFn {
@@ -130,6 +128,20 @@ func numericArgsStateFn(l *sqlLexer) stateFn {
}
}
+func parsePositionalParameters(args []interface{}) ([]*params.Parameter, error) {
+ newArgs := make([]*params.Parameter, len(args))
+ for i, arg := range args {
+ paramName := fmt.Sprintf("$p%d", i)
+ param, err := toYdbParam(paramName, arg)
+ if err != nil {
+ return nil, err
+ }
+ newArgs[i] = param
+ }
+
+ return newArgs, nil
+}
+
func numericArgState(l *sqlLexer) stateFn {
numbers := ""
defer func() {
diff --git a/internal/bind/params.go b/internal/bind/params.go
index d0e6a82da..95653b996 100644
--- a/internal/bind/params.go
+++ b/internal/bind/params.go
@@ -21,7 +21,7 @@ var (
errMultipleQueryParameters = errors.New("only one query arg *table.QueryParameters allowed")
)
-//nolint:gocyclo
+//nolint:gocyclo,funlen
func toValue(v interface{}) (_ types.Value, err error) {
if valuer, ok := v.(driver.Valuer); ok {
v, err = valuer.Value()
@@ -174,58 +174,36 @@ func toYdbParam(name string, value interface{}) (*params.Parameter, error) {
return params.Named(name, v), nil
}
-func Params(args ...interface{}) (parameters []*params.Parameter, _ error) {
- parameters = make([]*params.Parameter, 0, len(args))
+func Params(args ...interface{}) ([]*params.Parameter, error) {
+ parameters := make([]*params.Parameter, 0, len(args))
for i, arg := range args {
+ var newParam *params.Parameter
+ var newParams []*params.Parameter
+ var err error
switch x := arg.(type) {
case driver.NamedValue:
- if x.Name == "" {
- switch xx := x.Value.(type) {
- case *params.Parameters:
- if len(args) > 1 {
- return nil, xerrors.WithStackTrace(errMultipleQueryParameters)
- }
- parameters = *xx
- case *params.Parameter:
- parameters = append(parameters, xx)
- default:
- x.Name = fmt.Sprintf("$p%d", i)
- param, err := toYdbParam(x.Name, x.Value)
- if err != nil {
- return nil, xerrors.WithStackTrace(err)
- }
- parameters = append(parameters, param)
- }
- } else {
- param, err := toYdbParam(x.Name, x.Value)
- if err != nil {
- return nil, xerrors.WithStackTrace(err)
- }
- parameters = append(parameters, param)
- }
+ newParams, err = paramHandleNamedValue(x, i, len(args))
case sql.NamedArg:
if x.Name == "" {
return nil, xerrors.WithStackTrace(errUnnamedParam)
}
- param, err := toYdbParam(x.Name, x.Value)
- if err != nil {
- return nil, xerrors.WithStackTrace(err)
- }
- parameters = append(parameters, param)
+ newParam, err = toYdbParam(x.Name, x.Value)
+ newParams = append(newParams, newParam)
case *params.Parameters:
if len(args) > 1 {
return nil, xerrors.WithStackTrace(errMultipleQueryParameters)
}
parameters = *x
case *params.Parameter:
- parameters = append(parameters, x)
+ newParams = append(newParams, x)
default:
- param, err := toYdbParam(fmt.Sprintf("$p%d", i), x)
- if err != nil {
- return nil, xerrors.WithStackTrace(err)
- }
- parameters = append(parameters, param)
+ newParam, err = toYdbParam(fmt.Sprintf("$p%d", i), x)
+ newParams = append(newParams, newParam)
+ }
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
}
+ parameters = append(parameters, newParams...)
}
sort.Slice(parameters, func(i, j int) bool {
return parameters[i].Name() < parameters[j].Name()
@@ -233,3 +211,33 @@ func Params(args ...interface{}) (parameters []*params.Parameter, _ error) {
return parameters, nil
}
+
+func paramHandleNamedValue(arg driver.NamedValue, paramNumber, argsLen int) ([]*params.Parameter, error) {
+ if arg.Name == "" {
+ switch x := arg.Value.(type) {
+ case *params.Parameters:
+ if argsLen > 1 {
+ return nil, xerrors.WithStackTrace(errMultipleQueryParameters)
+ }
+
+ return *x, nil
+ case *params.Parameter:
+ return []*params.Parameter{x}, nil
+ default:
+ arg.Name = fmt.Sprintf("$p%d", paramNumber)
+ param, err := toYdbParam(arg.Name, arg.Value)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return []*params.Parameter{param}, nil
+ }
+ } else {
+ param, err := toYdbParam(arg.Name, arg.Value)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return []*params.Parameter{param}, nil
+ }
+}
diff --git a/internal/cmd/gstack/main.go b/internal/cmd/gstack/main.go
new file mode 100644
index 000000000..10f3ed061
--- /dev/null
+++ b/internal/cmd/gstack/main.go
@@ -0,0 +1,228 @@
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/cmd/gstack/utils"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: gstack [path]\n")
+ flag.PrintDefaults()
+}
+
+func getCallExpressionsFromExpr(expr ast.Expr) (listOfCalls []*ast.CallExpr) {
+ switch expr := expr.(type) {
+ case *ast.SelectorExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.IndexExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.StarExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ case *ast.BinaryExpr:
+ listOfCalls = getCallExpressionsFromExpr(expr.X)
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Y)...)
+ case *ast.CallExpr:
+ listOfCalls = append(listOfCalls, expr)
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Fun)...)
+ for _, arg := range expr.Args {
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(arg)...)
+ }
+ case *ast.CompositeLit:
+ for _, elt := range expr.Elts {
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(elt)...)
+ }
+ case *ast.UnaryExpr:
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.X)...)
+ case *ast.KeyValueExpr:
+ listOfCalls = append(listOfCalls, getCallExpressionsFromExpr(expr.Value)...)
+ case *ast.FuncLit:
+ listOfCalls = append(listOfCalls, getListOfCallExpressionsFromBlockStmt(expr.Body)...)
+ }
+
+ return listOfCalls
+}
+
+func getExprFromDeclStmt(statement *ast.DeclStmt) (listOfExpressions []ast.Expr) {
+ decl, ok := statement.Decl.(*ast.GenDecl)
+ if !ok {
+ return listOfExpressions
+ }
+ for _, spec := range decl.Specs {
+ if spec, ok := spec.(*ast.ValueSpec); ok {
+ listOfExpressions = append(listOfExpressions, spec.Values...)
+ }
+ }
+
+ return listOfExpressions
+}
+
+func getCallExpressionsFromStmt(statement ast.Stmt) (listOfCallExpressions []*ast.CallExpr) {
+ var body *ast.BlockStmt
+ var listOfExpressions []ast.Expr
+ switch stmt := statement.(type) {
+ case *ast.IfStmt:
+ body = stmt.Body
+ case *ast.SwitchStmt:
+ body = stmt.Body
+ case *ast.TypeSwitchStmt:
+ body = stmt.Body
+ case *ast.SelectStmt:
+ body = stmt.Body
+ case *ast.ForStmt:
+ body = stmt.Body
+ case *ast.GoStmt:
+ if fun, ok := stmt.Call.Fun.(*ast.FuncLit); ok {
+ listOfCallExpressions = append(listOfCallExpressions, getListOfCallExpressionsFromBlockStmt(fun.Body)...)
+ } else {
+ listOfCallExpressions = append(listOfCallExpressions, stmt.Call)
+ }
+ case *ast.RangeStmt:
+ body = stmt.Body
+ case *ast.DeclStmt:
+ listOfExpressions = append(listOfExpressions, getExprFromDeclStmt(stmt)...)
+ for _, expr := range listOfExpressions {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(expr)...)
+ }
+ case *ast.CommClause:
+ stmts := stmt.Body
+ for _, stmt := range stmts {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromStmt(stmt)...)
+ }
+ case *ast.ExprStmt:
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(stmt.X)...)
+ case *ast.AssignStmt:
+ for _, rh := range stmt.Rhs {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(rh)...)
+ }
+ case *ast.ReturnStmt:
+ for _, result := range stmt.Results {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromExpr(result)...)
+ }
+ }
+ if body != nil {
+ listOfCallExpressions = append(
+ listOfCallExpressions,
+ getListOfCallExpressionsFromBlockStmt(body)...,
+ )
+ }
+
+ return listOfCallExpressions
+}
+
+func getListOfCallExpressionsFromBlockStmt(block *ast.BlockStmt) (listOfCallExpressions []*ast.CallExpr) {
+ for _, statement := range block.List {
+ listOfCallExpressions = append(listOfCallExpressions, getCallExpressionsFromStmt(statement)...)
+ }
+
+ return listOfCallExpressions
+}
+
+func format(src []byte, path string, fset *token.FileSet, file *ast.File) ([]byte, error) {
+ var listOfArgs []utils.FunctionIDArg
+ for _, f := range file.Decls {
+ var listOfCalls []*ast.CallExpr
+ fn, ok := f.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ listOfCalls = getListOfCallExpressionsFromBlockStmt(fn.Body)
+ for _, call := range listOfCalls {
+ if function, ok := call.Fun.(*ast.SelectorExpr); ok && function.Sel.Name == "FunctionID" {
+ pack, ok := function.X.(*ast.Ident)
+ if !ok {
+ continue
+ }
+ if pack.Name == "stack" && len(call.Args) == 1 {
+ listOfArgs = append(listOfArgs, utils.FunctionIDArg{
+ FuncDecl: fn,
+ ArgPos: call.Args[0].Pos(),
+ ArgEnd: call.Args[0].End(),
+ })
+ }
+ }
+ }
+ }
+ if len(listOfArgs) != 0 {
+ fixed, err := utils.FixSource(fset, path, src, listOfArgs)
+ if err != nil {
+ return nil, err
+ }
+
+ return fixed, nil
+ }
+
+ return src, nil
+}
+
+func processFile(src []byte, path string, fset *token.FileSet, file *ast.File, info os.FileInfo) error {
+ formatted, err := format(src, path, fset, file)
+ if err != nil {
+ return err
+ }
+ if !bytes.Equal(src, formatted) {
+ err = utils.WriteFile(path, formatted, info.Mode().Perm())
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+
+ if len(args) != 1 {
+ flag.Usage()
+
+ return
+ }
+ _, err := os.Stat(args[0])
+ if err != nil {
+ panic(err)
+ }
+
+ fileSystem := os.DirFS(args[0])
+
+ err = fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error {
+ fset := token.NewFileSet()
+ if err != nil {
+ return err
+ }
+ if d.IsDir() {
+ return nil
+ }
+ if filepath.Ext(path) == ".go" {
+ info, err := os.Stat(path)
+ if err != nil {
+ return err
+ }
+ src, err := utils.ReadFile(path, info)
+ if err != nil {
+ return err
+ }
+ file, err := parser.ParseFile(fset, path, nil, 0)
+ if err != nil {
+ return err
+ }
+
+ return processFile(src, path, fset, file, info)
+ }
+
+ return nil
+ })
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/internal/cmd/gstack/utils/utils.go b/internal/cmd/gstack/utils/utils.go
new file mode 100644
index 000000000..19b35512d
--- /dev/null
+++ b/internal/cmd/gstack/utils/utils.go
@@ -0,0 +1,135 @@
+package utils
+
+import (
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "io"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/version"
+)
+
+type FunctionIDArg struct {
+ FuncDecl *ast.FuncDecl
+ ArgPos token.Pos
+ ArgEnd token.Pos
+}
+
+func ReadFile(filename string, info fs.FileInfo) ([]byte, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ size := int(info.Size())
+ src := make([]byte, size)
+ n, err := io.ReadFull(f, src)
+ if err != nil {
+ return nil, err
+ }
+ if n < size {
+ return nil, fmt.Errorf("error: size of %q changed during reading (from %d to %d bytes)", filename, size, n)
+ } else if n > size {
+ return nil, fmt.Errorf("error: size of %q changed during reading (from %d to >=%d bytes)", filename, size, len(src))
+ }
+
+ return src, nil
+}
+
+func FixSource(fset *token.FileSet, path string, src []byte, listOfArgs []FunctionIDArg) ([]byte, error) {
+ var fixed []byte
+ var previousArgEnd int
+ for _, arg := range listOfArgs {
+ argPosOffset := fset.Position(arg.ArgPos).Offset
+ argEndOffset := fset.Position(arg.ArgEnd).Offset
+ argument, err := makeCall(fset, path, arg)
+ if err != nil {
+ return nil, err
+ }
+ fixed = append(fixed, src[previousArgEnd:argPosOffset]...)
+ fixed = append(fixed, fmt.Sprintf("%q", argument)...)
+ previousArgEnd = argEndOffset
+ }
+ fixed = append(fixed, src[previousArgEnd:]...)
+
+ return fixed, nil
+}
+
+func WriteFile(filename string, formatted []byte, perm fs.FileMode) error {
+ fout, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC, perm)
+ if err != nil {
+ return err
+ }
+
+ defer fout.Close()
+
+ _, err = fout.Write(formatted)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func makeCall(fset *token.FileSet, path string, arg FunctionIDArg) (string, error) {
+ basePath := filepath.Join("github.com", "ydb-platform", version.Prefix, version.Major, "")
+ packageName, err := getPackageName(fset, arg)
+ if err != nil {
+ return "", err
+ }
+ filePath := filepath.Dir(filepath.Dir(path))
+ funcName, err := getFuncName(arg.FuncDecl)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(basePath, filePath, packageName) + "." + funcName, nil
+}
+
+func getFuncName(funcDecl *ast.FuncDecl) (string, error) {
+ if funcDecl.Recv != nil {
+ recvType := funcDecl.Recv.List[0].Type
+ prefix, err := getIdentNameFromExpr(recvType)
+ if err != nil {
+ return "", err
+ }
+
+ return prefix + "." + funcDecl.Name.Name, nil
+ }
+
+ return funcDecl.Name.Name, nil
+}
+
+func getIdentNameFromExpr(expr ast.Expr) (string, error) {
+ switch expr := expr.(type) {
+ case *ast.Ident:
+ return expr.Name, nil
+ case *ast.StarExpr:
+ prefix, err := getIdentNameFromExpr(expr.X)
+ if err != nil {
+ return "", err
+ }
+
+ return "(*" + prefix + ")", nil
+ case *ast.IndexExpr:
+ return getIdentNameFromExpr(expr.X)
+ case *ast.IndexListExpr:
+ return getIdentNameFromExpr(expr.X)
+ default:
+ return "", fmt.Errorf("error during getting ident from expr")
+ }
+}
+
+func getPackageName(fset *token.FileSet, arg FunctionIDArg) (string, error) {
+ file := fset.File(arg.ArgPos)
+ parsedFile, err := parser.ParseFile(fset, file.Name(), nil, parser.PackageClauseOnly)
+ if err != nil {
+ return "", fmt.Errorf("error during get package name function")
+ }
+
+ return parsedFile.Name.Name, nil
+}
diff --git a/internal/cmd/gtrace/main.go b/internal/cmd/gtrace/main.go
index 99f2bf98a..84a16add4 100644
--- a/internal/cmd/gtrace/main.go
+++ b/internal/cmd/gtrace/main.go
@@ -67,7 +67,7 @@ func main() {
f, err = os.OpenFile(
filepath.Join(workDir, filepath.Clean(name)),
os.O_WRONLY|os.O_CREATE|os.O_TRUNC,
- 0o600,
+ 0o600, //nolint:gomnd
)
if err != nil {
log.Fatal(err)
diff --git a/internal/cmd/gtrace/writer.go b/internal/cmd/gtrace/writer.go
index fcc87a43e..3616f425f 100644
--- a/internal/cmd/gtrace/writer.go
+++ b/internal/cmd/gtrace/writer.go
@@ -86,7 +86,10 @@ func (w *Writer) init() {
}
func (w *Writer) mustDeclare(name string) {
- s := w.scope.Back().Value.(*scope)
+ s, ok := w.scope.Back().Value.(*scope)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to w.scope.Back()", s))
+ }
if !s.set(name) {
where := s.where(name)
panic(fmt.Sprintf(
@@ -100,7 +103,10 @@ func (w *Writer) declare(name string) string {
if isPredeclared(name) {
name = firstChar(name)
}
- s := w.scope.Back().Value.(*scope)
+ s, ok := w.scope.Back().Value.(*scope)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *scope", s))
+ }
for i := 0; ; i++ {
v := name
if i > 0 {
@@ -127,7 +133,10 @@ func (w *Writer) isGlobalScope() bool {
}
func (w *Writer) capture(vars ...string) {
- s := w.scope.Back().Value.(*scope)
+ s, ok := w.scope.Back().Value.(*scope)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *scope", s))
+ }
for _, v := range vars {
if !s.set(v) {
panic(fmt.Sprintf("can't capture variable %q", v))
@@ -324,6 +333,7 @@ func (w *Writer) compose(trace *Trace) {
w.line(`// Compose returns a new `, trace.Name, ` which has functional fields composed both from `,
t, ` and `, x, `.`,
)
+ w.line(`// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals`)
w.code(`func (`, t, ` *`, trace.Name, `) Compose(`, x, ` *`, trace.Name, `, opts ...`+trace.Name+`ComposeOption) `)
w.line(`*`, trace.Name, ` {`)
w.block(func() {
@@ -405,9 +415,9 @@ func (w *Writer) composeHookCall(fn *Func, h1, h2 string) {
w.line("if " + h + " != nil {")
w.block(func() {
if fn.HasResult() {
- w.code(rs[i], ` = `)
+ w.code(rs[i], ` = `) //nolint:scopelint
}
- w.code(h)
+ w.code(h) //nolint:scopelint
w.call(args)
})
w.line("}")
@@ -440,11 +450,13 @@ func (w *Writer) options(trace *Trace) {
})
w.newScope(func() {
w.line(fmt.Sprintf(`// %sOption specified %s compose option`, trace.Name, trace.Name))
+ w.line(`// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals`)
w.line(fmt.Sprintf(`type %sComposeOption func(o *%sComposeOptions)`, trace.Name, unexported(trace.Name)))
_ = w.bw.WriteByte('\n')
})
w.newScope(func() {
w.line(fmt.Sprintf(`// With%sPanicCallback specified behavior on panic`, trace.Name))
+ w.line(`// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals`)
w.line(fmt.Sprintf(`func With%sPanicCallback(cb func(e interface{})) %sComposeOption {`, trace.Name, trace.Name))
w.block(func() {
w.line(fmt.Sprintf(`return func(o *%sComposeOptions) {`, unexported(trace.Name)))
@@ -641,6 +653,7 @@ func (w *Writer) hookShortcut(trace *Trace, hook Hook) {
w.newScope(func() {
t := w.declare("t")
+ w.line(`// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals`)
w.code(`func `, name)
w.code(`(`)
var ctx string
@@ -1028,7 +1041,7 @@ func (s *scope) set(v string) bool {
if _, has := s.vars[v]; has {
return false
}
- _, file, line, _ := runtime.Caller(2)
+ _, file, line, _ := runtime.Caller(2) //nolint:gomnd
s.vars[v] = decl{
where: fmt.Sprintf("%s:%d", file, line),
}
diff --git a/internal/conn/config.go b/internal/conn/config.go
index 27a0603a1..df82f3a85 100644
--- a/internal/conn/config.go
+++ b/internal/conn/config.go
@@ -10,6 +10,7 @@ import (
type Config interface {
DialTimeout() time.Duration
+ ConnectionTTL() time.Duration
Trace() *trace.Driver
GrpcDialOptions() []grpc.DialOption
}
diff --git a/internal/conn/conn.go b/internal/conn/conn.go
index a754923bd..2fd03991e 100644
--- a/internal/conn/conn.go
+++ b/internal/conn/conn.go
@@ -19,6 +19,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
@@ -55,7 +56,8 @@ type conn struct {
endpoint endpoint.Endpoint // ro access
closed bool
state atomic.Uint32
- lastUsage time.Time
+ childStreams *xcontext.CancelsGuard
+ lastUsage xsync.LastUsage
onClose []func(*conn)
onTransportErrors []func(ctx context.Context, cc Conn, cause error)
}
@@ -80,7 +82,7 @@ func (c *conn) LastUsage() time.Time {
c.mtx.RLock()
defer c.mtx.RUnlock()
- return c.lastUsage
+ return c.lastUsage.Get()
}
func (c *conn) IsState(states ...State) bool {
@@ -102,6 +104,36 @@ func (c *conn) NodeID() uint32 {
return 0
}
+func (c *conn) park(ctx context.Context) (err error) {
+ onDone := trace.DriverOnConnPark(
+ c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).park"),
+ c.Endpoint(),
+ )
+ defer func() {
+ onDone(err)
+ }()
+
+ c.mtx.Lock()
+ defer c.mtx.Unlock()
+
+ if c.closed {
+ return nil
+ }
+
+ if c.cc == nil {
+ return nil
+ }
+
+ err = c.close(ctx)
+
+ if err != nil {
+ return c.wrapError(err)
+ }
+
+ return nil
+}
+
func (c *conn) Endpoint() endpoint.Endpoint {
if c != nil {
return c.endpoint
@@ -118,7 +150,7 @@ func (c *conn) setState(ctx context.Context, s State) State {
if state := State(c.state.Swap(uint32(s))); state != s {
trace.DriverOnConnStateChange(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).setState"),
c.endpoint.Copy(), state,
)(s)
}
@@ -166,7 +198,7 @@ func (c *conn) realConn(ctx context.Context) (cc *grpc.ClientConn, err error) {
onDone := trace.DriverOnConnDial(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).realConn"),
c.endpoint.Copy(),
)
defer func() {
@@ -183,6 +215,10 @@ func (c *conn) realConn(ctx context.Context) (cc *grpc.ClientConn, err error) {
}, c.config.GrpcDialOptions()...,
)...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -210,12 +246,6 @@ func (c *conn) onTransportError(ctx context.Context, cause error) {
}
}
-func (c *conn) touchLastUsage() {
- c.mtx.Lock()
- defer c.mtx.Unlock()
- c.lastUsage = time.Now()
-}
-
func isAvailable(raw *grpc.ClientConn) bool {
return raw != nil && raw.GetState() == connectivity.Ready
}
@@ -249,7 +279,7 @@ func (c *conn) Close(ctx context.Context) (err error) {
onDone := trace.DriverOnConnClose(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).Close"),
c.Endpoint(),
)
defer func() {
@@ -282,7 +312,7 @@ func (c *conn) Invoke(
useWrapping = UseWrapping(ctx)
onDone = trace.DriverOnConnInvoke(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).Invoke"),
c.endpoint, trace.Method(method),
)
cc *grpc.ClientConn
@@ -298,8 +328,8 @@ func (c *conn) Invoke(
return c.wrapError(err)
}
- c.touchLastUsage()
- defer c.touchLastUsage()
+ stop := c.lastUsage.Start()
+ defer stop()
ctx, traceID, err := meta.TraceID(ctx)
if err != nil {
@@ -310,6 +340,10 @@ func (c *conn) Invoke(
err = cc.Invoke(ctx, method, req, res, append(opts, grpc.Trailer(&md))...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -354,34 +388,33 @@ func (c *conn) Invoke(
return err
}
+//nolint:funlen
func (c *conn) NewStream(
ctx context.Context,
desc *grpc.StreamDesc,
method string,
opts ...grpc.CallOption,
-) (_ grpc.ClientStream, err error) {
+) (_ grpc.ClientStream, finalErr error) {
var (
onDone = trace.DriverOnConnNewStream(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*conn).NewStream"),
c.endpoint.Copy(), trace.Method(method),
)
useWrapping = UseWrapping(ctx)
- cc *grpc.ClientConn
- s grpc.ClientStream
)
defer func() {
- onDone(err, c.GetState())
+ onDone(finalErr, c.GetState())
}()
- cc, err = c.realConn(ctx)
+ cc, err := c.realConn(ctx)
if err != nil {
return nil, c.wrapError(err)
}
- c.touchLastUsage()
- defer c.touchLastUsage()
+ stop := c.lastUsage.Start()
+ defer stop()
ctx, traceID, err := meta.TraceID(ctx)
if err != nil {
@@ -390,8 +423,24 @@ func (c *conn) NewStream(
ctx, sentMark := markContext(meta.WithTraceID(ctx, traceID))
- s, err = cc.NewStream(ctx, desc, method, opts...)
+ ctx, cancel := xcontext.WithCancel(ctx)
+ defer func() {
+ if finalErr != nil {
+ cancel()
+ } else {
+ c.childStreams.Remember(&cancel)
+ }
+ }()
+
+ s, err := cc.NewStream(ctx, desc, method, append(opts, grpc.OnFinish(func(err error) {
+ cancel()
+ c.childStreams.Forget(&cancel)
+ }))...)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
defer func() {
c.onTransportError(ctx, err)
}()
@@ -453,9 +502,16 @@ func withOnTransportError(onTransportError func(ctx context.Context, cc Conn, ca
func newConn(e endpoint.Endpoint, config Config, opts ...option) *conn {
c := &conn{
- endpoint: e,
- config: config,
- done: make(chan struct{}),
+ endpoint: e,
+ config: config,
+ done: make(chan struct{}),
+ lastUsage: xsync.NewLastUsage(),
+ childStreams: xcontext.NewCancelsGuard(),
+ onClose: []func(*conn){
+ func(c *conn) {
+ c.childStreams.Cancel()
+ },
+ },
}
c.state.Store(uint32(Created))
for _, opt := range opts {
@@ -509,7 +565,11 @@ func getContextMark(ctx context.Context) *modificationMark {
return &modificationMark{}
}
- return v.(*modificationMark)
+ val, ok := v.(*modificationMark)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *modificationMark", val))
+ }
+ return val
}
type modificationMark struct {
diff --git a/internal/conn/grpc_client_stream.go b/internal/conn/grpc_client_stream.go
index 0ea1cae86..32377e5ab 100644
--- a/internal/conn/grpc_client_stream.go
+++ b/internal/conn/grpc_client_stream.go
@@ -25,14 +25,23 @@ type grpcClientStream struct {
}
func (s *grpcClientStream) CloseSend() (err error) {
- onDone := trace.DriverOnConnStreamCloseSend(s.c.config.Trace(), &s.ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnConnStreamCloseSend(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).CloseSend"),
+ )
defer func() {
onDone(err)
}()
+ stop := s.c.lastUsage.Start()
+ defer stop()
+
err = s.ClientStream.CloseSend()
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
if s.wrapping {
return s.wrapError(
xerrors.Transport(
@@ -50,14 +59,23 @@ func (s *grpcClientStream) CloseSend() (err error) {
}
func (s *grpcClientStream) SendMsg(m interface{}) (err error) {
- onDone := trace.DriverOnConnStreamSendMsg(s.c.config.Trace(), &s.ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnConnStreamSendMsg(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).SendMsg"),
+ )
defer func() {
onDone(err)
}()
+ stop := s.c.lastUsage.Start()
+ defer stop()
+
err = s.ClientStream.SendMsg(m)
if err != nil {
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
s.c.onTransportError(s.Context(), err)
}()
@@ -83,11 +101,16 @@ func (s *grpcClientStream) SendMsg(m interface{}) (err error) {
}
func (s *grpcClientStream) RecvMsg(m interface{}) (err error) {
- onDone := trace.DriverOnConnStreamRecvMsg(s.c.config.Trace(), &s.ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnConnStreamRecvMsg(s.c.config.Trace(), &s.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*grpcClientStream).RecvMsg"),
+ )
defer func() {
onDone(err)
}()
+ stop := s.c.lastUsage.Start()
+ defer stop()
+
defer func() {
if err != nil {
md := s.ClientStream.Trailer()
@@ -97,7 +120,11 @@ func (s *grpcClientStream) RecvMsg(m interface{}) (err error) {
err = s.ClientStream.RecvMsg(m)
- if err != nil {
+ if err != nil { //nolint:nestif
+ if xerrors.IsContextError(err) {
+ return xerrors.WithStackTrace(err)
+ }
+
defer func() {
if !xerrors.Is(err, io.EOF) {
s.c.onTransportError(s.Context(), err)
diff --git a/internal/conn/pool.go b/internal/conn/pool.go
index 02072d67c..783b7a880 100644
--- a/internal/conn/pool.go
+++ b/internal/conn/pool.go
@@ -4,6 +4,7 @@ import (
"context"
"sync"
"sync/atomic"
+ "time"
"google.golang.org/grpc"
grpcCodes "google.golang.org/grpc/codes"
@@ -11,6 +12,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/closer"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/endpoint"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
@@ -78,11 +80,24 @@ func (p *Pool) Ban(ctx context.Context, cc Conn, cause error) {
return
}
- if xerrors.IsTransportError(cause,
- grpcCodes.OK,
- grpcCodes.Canceled,
+ if !xerrors.IsTransportError(cause,
grpcCodes.ResourceExhausted,
- grpcCodes.OutOfRange,
+ grpcCodes.Unavailable,
+ // grpcCodes.OK,
+ // grpcCodes.Canceled,
+ // grpcCodes.Unknown,
+ // grpcCodes.InvalidArgument,
+ // grpcCodes.DeadlineExceeded,
+ // grpcCodes.NotFound,
+ // grpcCodes.AlreadyExists,
+ // grpcCodes.PermissionDenied,
+ // grpcCodes.FailedPrecondition,
+ // grpcCodes.Aborted,
+ // grpcCodes.OutOfRange,
+ // grpcCodes.Unimplemented,
+ // grpcCodes.Internal,
+ // grpcCodes.DataLoss,
+ // grpcCodes.Unauthenticated,
) {
return
}
@@ -99,7 +114,7 @@ func (p *Pool) Ban(ctx context.Context, cc Conn, cause error) {
trace.DriverOnConnBan(
p.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Ban"),
e, cc.GetState(), cause,
)(cc.SetState(ctx, Banned))
}
@@ -121,7 +136,7 @@ func (p *Pool) Allow(ctx context.Context, cc Conn) {
trace.DriverOnConnAllow(
p.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Allow"),
e, cc.GetState(),
)(cc.Unban(ctx))
}
@@ -133,7 +148,9 @@ func (p *Pool) Take(context.Context) error {
}
func (p *Pool) Release(ctx context.Context) (finalErr error) {
- onDone := trace.DriverOnPoolRelease(p.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnPoolRelease(p.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.(*Pool).Release"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -181,8 +198,43 @@ func (p *Pool) Release(ctx context.Context) (finalErr error) {
return nil
}
+func (p *Pool) connParker(ctx context.Context, ttl, interval time.Duration) {
+ ticker := time.NewTicker(interval)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-p.done:
+ return
+ case <-ticker.C:
+ for _, c := range p.collectConns() {
+ if time.Since(c.LastUsage()) > ttl {
+ switch c.GetState() {
+ case Online, Banned:
+ _ = c.park(ctx)
+ default:
+ // nop
+ }
+ }
+ }
+ }
+ }
+}
+
+func (p *Pool) collectConns() []*conn {
+ p.mtx.RLock()
+ defer p.mtx.RUnlock()
+ conns := make([]*conn, 0, len(p.conns))
+ for _, c := range p.conns {
+ conns = append(conns, c)
+ }
+
+ return conns
+}
+
func NewPool(ctx context.Context, config Config) *Pool {
- onDone := trace.DriverOnPoolNew(config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.DriverOnPoolNew(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/conn.NewPool"),
+ )
defer onDone()
p := &Pool{
@@ -193,5 +245,9 @@ func NewPool(ctx context.Context, config Config) *Pool {
done: make(chan struct{}),
}
+ if ttl := config.ConnectionTTL(); ttl > 0 {
+ go p.connParker(xcontext.ValueOnly(ctx), ttl, ttl/2) //nolint:gomnd
+ }
+
return p
}
diff --git a/internal/coordination/client.go b/internal/coordination/client.go
index fb9331414..e7c194049 100644
--- a/internal/coordination/client.go
+++ b/internal/coordination/client.go
@@ -3,157 +3,216 @@ package coordination
import (
"context"
"errors"
+ "sync"
+ "time"
"github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"
"google.golang.org/grpc"
"github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/coordination/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
"github.com/ydb-platform/ydb-go-sdk/v3/scheme"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
-//nolint:gofumpt
-//nolint:nolintlint
-var (
- errNilClient = xerrors.Wrap(errors.New("coordination client is not initialized"))
-)
+//go:generate mockgen -destination grpc_client_mock_test.go -package coordination -write_package_comment=false github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1 CoordinationServiceClient,CoordinationService_SessionClient
+
+var errNilClient = xerrors.Wrap(errors.New("coordination client is not initialized"))
type Client struct {
- config config.Config
- service Ydb_Coordination_V1.CoordinationServiceClient
+ config config.Config
+ client Ydb_Coordination_V1.CoordinationServiceClient
+
+ mutex sync.Mutex // guards the fields below
+ sessions map[*session]struct{}
}
func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config) *Client {
+ onDone := trace.CoordinationOnNew(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.New"),
+ )
+ defer onDone()
+
return &Client{
- config: config,
- service: Ydb_Coordination_V1.NewCoordinationServiceClient(cc),
+ config: config,
+ client: Ydb_Coordination_V1.NewCoordinationServiceClient(cc),
+ sessions: make(map[*session]struct{}),
}
}
-func (c *Client) CreateNode(ctx context.Context, path string, config coordination.NodeConfig) error {
- if c == nil {
- return xerrors.WithStackTrace(errNilClient)
- }
- call := func(ctx context.Context) error {
- return xerrors.WithStackTrace(c.createNode(ctx, path, config))
+func operationParams(
+ ctx context.Context,
+ config interface {
+ OperationTimeout() time.Duration
+ OperationCancelAfter() time.Duration
+ },
+ mode operation.Mode,
+) *Ydb_Operations.OperationParams {
+ return operation.Params(
+ ctx,
+ config.OperationTimeout(),
+ config.OperationCancelAfter(),
+ mode,
+ )
+}
+
+func createNodeRequest(
+ path string, config coordination.NodeConfig, operationParams *Ydb_Operations.OperationParams,
+) *Ydb_Coordination.CreateNodeRequest {
+ return &Ydb_Coordination.CreateNodeRequest{
+ Path: path,
+ Config: &Ydb_Coordination.Config{
+ Path: config.Path,
+ SelfCheckPeriodMillis: config.SelfCheckPeriodMillis,
+ SessionGracePeriodMillis: config.SessionGracePeriodMillis,
+ ReadConsistencyMode: config.ReadConsistencyMode.To(),
+ AttachConsistencyMode: config.AttachConsistencyMode.To(),
+ RateLimiterCountersMode: config.RatelimiterCountersMode.To(),
+ },
+ OperationParams: operationParams,
}
- if !c.config.AutoRetry() {
- return xerrors.WithStackTrace(call(ctx))
+}
+
+func createNode(
+ ctx context.Context, client Ydb_Coordination_V1.CoordinationServiceClient, request *Ydb_Coordination.CreateNodeRequest,
+) error {
+ _, err := client.CreateNode(ctx, request)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
}
- return retry.Retry(ctx,
- call, retry.WithStackTrace(),
- retry.WithIdempotent(true),
- retry.WithTrace(c.config.TraceRetry()),
- )
+ return nil
}
-func (c *Client) createNode(ctx context.Context, path string, config coordination.NodeConfig) error {
- _, err := c.service.CreateNode(
- ctx,
- &Ydb_Coordination.CreateNodeRequest{
- Path: path,
- Config: &Ydb_Coordination.Config{
- Path: config.Path,
- SelfCheckPeriodMillis: config.SelfCheckPeriodMillis,
- SessionGracePeriodMillis: config.SessionGracePeriodMillis,
- ReadConsistencyMode: config.ReadConsistencyMode.To(),
- AttachConsistencyMode: config.AttachConsistencyMode.To(),
- RateLimiterCountersMode: config.RatelimiterCountersMode.To(),
- },
- OperationParams: operation.Params(
- ctx,
- c.config.OperationTimeout(),
- c.config.OperationCancelAfter(),
- operation.ModeSync,
- ),
- },
+func (c *Client) CreateNode(ctx context.Context, path string, config coordination.NodeConfig) (finalErr error) {
+ if c == nil {
+ return xerrors.WithStackTrace(errNilClient)
+ }
+
+ onDone := trace.CoordinationOnCreateNode(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).CreateNode"),
+ path,
)
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ request := createNodeRequest(path, config, operationParams(ctx, &c.config, operation.ModeSync))
- return xerrors.WithStackTrace(err)
+ if !c.config.AutoRetry() {
+ return createNode(ctx, c.client, request)
+ }
+
+ return retry.Retry(ctx, func(ctx context.Context) error {
+ return createNode(ctx, c.client, request)
+ }, retry.WithStackTrace(), retry.WithIdempotent(true), retry.WithTrace(c.config.TraceRetry()))
}
-func (c *Client) AlterNode(ctx context.Context, path string, config coordination.NodeConfig) error {
+func (c *Client) AlterNode(ctx context.Context, path string, config coordination.NodeConfig) (finalErr error) {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
+
+ onDone := trace.CoordinationOnAlterNode(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).AlterNode"),
+ path,
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ request := alterNodeRequest(path, config, operationParams(ctx, &c.config, operation.ModeSync))
+
call := func(ctx context.Context) error {
- return xerrors.WithStackTrace(c.alterNode(ctx, path, config))
+ return alterNode(ctx, c.client, request)
}
if !c.config.AutoRetry() {
return xerrors.WithStackTrace(call(ctx))
}
- return retry.Retry(ctx,
- call,
- retry.WithStackTrace(),
- retry.WithIdempotent(true),
- retry.WithTrace(c.config.TraceRetry()),
- )
+ return retry.Retry(ctx, func(ctx context.Context) (err error) {
+ return alterNode(ctx, c.client, request)
+ }, retry.WithStackTrace(), retry.WithIdempotent(true), retry.WithTrace(c.config.TraceRetry()))
}
-func (c *Client) alterNode(ctx context.Context, path string, config coordination.NodeConfig) error {
- _, err := c.service.AlterNode(
- ctx,
- &Ydb_Coordination.AlterNodeRequest{
- Path: path,
- Config: &Ydb_Coordination.Config{
- Path: config.Path,
- SelfCheckPeriodMillis: config.SelfCheckPeriodMillis,
- SessionGracePeriodMillis: config.SessionGracePeriodMillis,
- ReadConsistencyMode: config.ReadConsistencyMode.To(),
- AttachConsistencyMode: config.AttachConsistencyMode.To(),
- RateLimiterCountersMode: config.RatelimiterCountersMode.To(),
- },
- OperationParams: operation.Params(
- ctx,
- c.config.OperationTimeout(),
- c.config.OperationCancelAfter(),
- operation.ModeSync,
- ),
+func alterNodeRequest(
+ path string, config coordination.NodeConfig, operationParams *Ydb_Operations.OperationParams,
+) *Ydb_Coordination.AlterNodeRequest {
+ return &Ydb_Coordination.AlterNodeRequest{
+ Path: path,
+ Config: &Ydb_Coordination.Config{
+ Path: config.Path,
+ SelfCheckPeriodMillis: config.SelfCheckPeriodMillis,
+ SessionGracePeriodMillis: config.SessionGracePeriodMillis,
+ ReadConsistencyMode: config.ReadConsistencyMode.To(),
+ AttachConsistencyMode: config.AttachConsistencyMode.To(),
+ RateLimiterCountersMode: config.RatelimiterCountersMode.To(),
},
- )
+ OperationParams: operationParams,
+ }
+}
- return xerrors.WithStackTrace(err)
+func alterNode(
+ ctx context.Context, client Ydb_Coordination_V1.CoordinationServiceClient, request *Ydb_Coordination.AlterNodeRequest,
+) error {
+ _, err := client.AlterNode(ctx, request)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
}
-func (c *Client) DropNode(ctx context.Context, path string) error {
+func (c *Client) DropNode(ctx context.Context, path string) (finalErr error) {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
+
+ onDone := trace.CoordinationOnDropNode(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).DropNode"),
+ path,
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ request := dropNodeRequest(path, operationParams(ctx, &c.config, operation.ModeSync))
+
call := func(ctx context.Context) error {
- return xerrors.WithStackTrace(c.dropNode(ctx, path))
+ return dropNode(ctx, c.client, request)
}
if !c.config.AutoRetry() {
return xerrors.WithStackTrace(call(ctx))
}
- return retry.Retry(ctx, call,
- retry.WithStackTrace(),
- retry.WithIdempotent(true),
- retry.WithTrace(c.config.TraceRetry()),
- )
+ return retry.Retry(ctx, func(ctx context.Context) (err error) {
+ return dropNode(ctx, c.client, request)
+ }, retry.WithStackTrace(), retry.WithIdempotent(true), retry.WithTrace(c.config.TraceRetry()))
}
-func (c *Client) dropNode(ctx context.Context, path string) error {
- _, err := c.service.DropNode(
- ctx,
- &Ydb_Coordination.DropNodeRequest{
- Path: path,
- OperationParams: operation.Params(
- ctx,
- c.config.OperationTimeout(),
- c.config.OperationCancelAfter(),
- operation.ModeSync,
- ),
- },
- )
+func dropNodeRequest(path string, operationParams *Ydb_Operations.OperationParams) *Ydb_Coordination.DropNodeRequest {
+ return &Ydb_Coordination.DropNodeRequest{
+ Path: path,
+ OperationParams: operationParams,
+ }
+}
- return xerrors.WithStackTrace(err)
+func dropNode(
+ ctx context.Context, client Ydb_Coordination_V1.CoordinationServiceClient, request *Ydb_Coordination.DropNodeRequest,
+) error {
+ _, err := client.DropNode(ctx, request)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
}
func (c *Client) DescribeNode(
@@ -162,34 +221,55 @@ func (c *Client) DescribeNode(
) (
entry *scheme.Entry,
config *coordination.NodeConfig,
- _ error,
+ finalErr error,
) {
if c == nil {
return nil, nil, xerrors.WithStackTrace(errNilClient)
}
- call := func(ctx context.Context) (err error) {
- entry, config, err = c.describeNode(ctx, path)
- return xerrors.WithStackTrace(err)
- }
+ onDone := trace.CoordinationOnDescribeNode(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).DescribeNode"),
+ path,
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ request := describeNodeRequest(path, operationParams(ctx, &c.config, operation.ModeSync))
+
if !c.config.AutoRetry() {
- err := call(ctx)
+ return describeNode(ctx, c.client, request)
+ }
+
+ err := retry.Retry(ctx, func(ctx context.Context) (err error) {
+ entry, config, err = describeNode(ctx, c.client, request)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
- return entry, config, xerrors.WithStackTrace(err)
+ return nil
+ }, retry.WithStackTrace(), retry.WithIdempotent(true), retry.WithTrace(c.config.TraceRetry()))
+ if err != nil {
+ return nil, nil, xerrors.WithStackTrace(err)
}
- err := retry.Retry(ctx, call,
- retry.WithStackTrace(),
- retry.WithIdempotent(true),
- retry.WithTrace(c.config.TraceRetry()),
- )
- return entry, config, xerrors.WithStackTrace(err)
+ return entry, config, nil
+}
+
+func describeNodeRequest(
+ path string, operationParams *Ydb_Operations.OperationParams,
+) *Ydb_Coordination.DescribeNodeRequest {
+ return &Ydb_Coordination.DescribeNodeRequest{
+ Path: path,
+ OperationParams: operationParams,
+ }
}
// DescribeNode describes a coordination node
-func (c *Client) describeNode(
+func describeNode(
ctx context.Context,
- path string,
+ client Ydb_Coordination_V1.CoordinationServiceClient,
+ request *Ydb_Coordination.DescribeNodeRequest,
) (
_ *scheme.Entry,
_ *coordination.NodeConfig,
@@ -199,21 +279,11 @@ func (c *Client) describeNode(
response *Ydb_Coordination.DescribeNodeResponse
result Ydb_Coordination.DescribeNodeResult
)
- response, err = c.service.DescribeNode(
- ctx,
- &Ydb_Coordination.DescribeNodeRequest{
- Path: path,
- OperationParams: operation.Params(
- ctx,
- c.config.OperationTimeout(),
- c.config.OperationCancelAfter(),
- operation.ModeSync,
- ),
- },
- )
+ response, err = client.DescribeNode(ctx, request)
if err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
+
err = response.GetOperation().GetResult().UnmarshalTo(&result)
if err != nil {
return nil, nil, xerrors.WithStackTrace(err)
@@ -229,15 +299,85 @@ func (c *Client) describeNode(
}, nil
}
-func (c *Client) Close(ctx context.Context) error {
+func newCreateSessionConfig(opts ...options.SessionOption) *options.CreateSessionOptions {
+ c := defaultCreateSessionConfig()
+ for _, o := range opts {
+ if o != nil {
+ o(c)
+ }
+ }
+
+ return c
+}
+
+func (c *Client) sessionCreated(s *session) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ c.sessions[s] = struct{}{}
+}
+
+func (c *Client) sessionClosed(s *session) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ delete(c.sessions, s)
+}
+
+func (c *Client) closeSessions(ctx context.Context) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ for s := range c.sessions {
+ s.Close(ctx)
+ }
+}
+
+func defaultCreateSessionConfig() *options.CreateSessionOptions {
+ return &options.CreateSessionOptions{
+ Description: "YDB Go SDK",
+ SessionTimeout: time.Second * 5, //nolint:gomnd
+ SessionStartTimeout: time.Second * 1,
+ SessionStopTimeout: time.Second * 1,
+ SessionKeepAliveTimeout: time.Second * 10, //nolint:gomnd
+ SessionReconnectDelay: time.Millisecond * 500, //nolint:gomnd
+ }
+}
+
+func (c *Client) Session(
+ ctx context.Context,
+ path string,
+ opts ...options.SessionOption,
+) (_ coordination.Session, finalErr error) {
if c == nil {
- return xerrors.WithStackTrace(errNilClient)
+ return nil, xerrors.WithStackTrace(errNilClient)
}
- return c.close(ctx)
+ onDone := trace.CoordinationOnSession(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).Session"),
+ path,
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ return createSession(ctx, c, path, newCreateSessionConfig(opts...))
}
-func (c *Client) close(context.Context) error {
+func (c *Client) Close(ctx context.Context) (finalErr error) {
+ if c == nil {
+ return xerrors.WithStackTrace(errNilClient)
+ }
+
+ onDone := trace.CoordinationOnClose(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/coordination.(*Client).Close"),
+ )
+ defer func() {
+ onDone(finalErr)
+ }()
+
+ c.closeSessions(ctx)
+
return nil
}
diff --git a/internal/coordination/client_test.go b/internal/coordination/client_test.go
new file mode 100644
index 000000000..d7778be95
--- /dev/null
+++ b/internal/coordination/client_test.go
@@ -0,0 +1,388 @@
+package coordination
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Scheme"
+ "go.uber.org/mock/gomock"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/types/known/anypb"
+ "google.golang.org/protobuf/types/known/durationpb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/config"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/operation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/scheme"
+)
+
+func TestCreateNode(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().CreateNode(gomock.Any(), gomock.Any()).Return(&Ydb_Coordination.CreateNodeResponse{
+ Operation: &Ydb_Operations.Operation{
+ Ready: true,
+ Status: Ydb.StatusIds_SUCCESS,
+ },
+ }, nil)
+ err := createNode(ctx, client, &Ydb_Coordination.CreateNodeRequest{})
+ require.NoError(t, err)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().CreateNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Transport(grpcStatus.Error(grpcCodes.ResourceExhausted, "")),
+ )
+ err := createNode(ctx, client, &Ydb_Coordination.CreateNodeRequest{})
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.ResourceExhausted))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().CreateNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ err := createNode(ctx, client, &Ydb_Coordination.CreateNodeRequest{})
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+}
+
+func TestCreateNodeRequest(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ path string
+ config coordination.NodeConfig
+ operationParams *Ydb_Operations.OperationParams
+ request *Ydb_Coordination.CreateNodeRequest
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ path: "/abc",
+ config: coordination.NodeConfig{
+ Path: "/cde",
+ },
+ operationParams: operation.Params(context.Background(), time.Second, time.Second, operation.ModeSync),
+ request: &Ydb_Coordination.CreateNodeRequest{
+ Path: "/abc",
+ Config: &Ydb_Coordination.Config{
+ Path: "/cde",
+ },
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(time.Second),
+ CancelAfter: durationpb.New(time.Second),
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ request := createNodeRequest(tt.path, tt.config, tt.operationParams)
+ require.EqualValues(t, xtest.ToJSON(tt.request), xtest.ToJSON(request))
+ })
+ }
+}
+
+func TestDescribeNodeRequest(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ path string
+ operationParams *Ydb_Operations.OperationParams
+ request *Ydb_Coordination.DescribeNodeRequest
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ path: "/a/b/c",
+ operationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ request: &Ydb_Coordination.DescribeNodeRequest{
+ Path: "/a/b/c",
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ request := describeNodeRequest(tt.path, tt.operationParams)
+ require.Equal(t, xtest.ToJSON(tt.request), xtest.ToJSON(request))
+ })
+ }
+}
+
+func TestOperationParams(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ ctx context.Context
+ config interface {
+ OperationTimeout() time.Duration
+ OperationCancelAfter() time.Duration
+ }
+ mode operation.Mode
+ operationParams *Ydb_Operations.OperationParams
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ ctx: context.Background(),
+ config: config.New(config.WithOperationCancelAfter(time.Second), config.WithOperationTimeout(time.Second)),
+ mode: operation.ModeSync,
+ operationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(time.Second),
+ CancelAfter: durationpb.New(time.Second),
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ ctx: operation.WithCancelAfter(operation.WithTimeout(context.Background(), time.Second), time.Second),
+ config: config.New(),
+ mode: operation.ModeSync,
+ operationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(time.Second),
+ CancelAfter: durationpb.New(time.Second),
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ params := operationParams(tt.ctx, tt.config, tt.mode)
+ require.Equal(t, xtest.ToJSON(tt.operationParams), xtest.ToJSON(params))
+ })
+ }
+}
+
+func TestDescribeNode(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DescribeNode(gomock.Any(), gomock.Any()).Return(&Ydb_Coordination.DescribeNodeResponse{
+ Operation: &Ydb_Operations.Operation{
+ Ready: true,
+ Status: Ydb.StatusIds_SUCCESS,
+ Result: func() *anypb.Any {
+ result, err := anypb.New(&Ydb_Coordination.DescribeNodeResult{
+ Self: &Ydb_Scheme.Entry{
+ Name: "/a/b/c",
+ Owner: "root",
+ Type: Ydb_Scheme.Entry_COORDINATION_NODE,
+ },
+ Config: &Ydb_Coordination.Config{
+ Path: "/a/b/c",
+ SelfCheckPeriodMillis: 100,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: Ydb_Coordination.ConsistencyMode_CONSISTENCY_MODE_STRICT,
+ AttachConsistencyMode: Ydb_Coordination.ConsistencyMode_CONSISTENCY_MODE_STRICT,
+ RateLimiterCountersMode: Ydb_Coordination.RateLimiterCountersMode_RATE_LIMITER_COUNTERS_MODE_AGGREGATED,
+ },
+ })
+ require.NoError(t, err)
+
+ return result
+ }(),
+ },
+ }, nil)
+ nodeScheme, nodeConfig, err := describeNode(ctx, client, &Ydb_Coordination.DescribeNodeRequest{
+ Path: "/a/b/c",
+ OperationParams: nil,
+ })
+ require.NoError(t, err)
+ require.Equal(t, xtest.ToJSON(&scheme.Entry{
+ Name: "/a/b/c",
+ Owner: "root",
+ Type: scheme.EntryCoordinationNode,
+ }), xtest.ToJSON(nodeScheme))
+ require.Equal(t, xtest.ToJSON(coordination.NodeConfig{
+ Path: "/a/b/c",
+ SelfCheckPeriodMillis: 100,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: coordination.ConsistencyModeStrict,
+ AttachConsistencyMode: coordination.ConsistencyModeStrict,
+ RatelimiterCountersMode: coordination.RatelimiterCountersModeAggregated,
+ }), xtest.ToJSON(nodeConfig))
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DescribeNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, "")),
+ )
+ nodeScheme, nodeConfig, err := describeNode(ctx, client, &Ydb_Coordination.DescribeNodeRequest{
+ Path: "/a/b/c",
+ OperationParams: nil,
+ })
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
+ require.Nil(t, nodeScheme)
+ require.Nil(t, nodeConfig)
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DescribeNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ nodeScheme, nodeConfig, err := describeNode(ctx, client, &Ydb_Coordination.DescribeNodeRequest{
+ Path: "/a/b/c",
+ OperationParams: nil,
+ })
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ require.Nil(t, nodeScheme)
+ require.Nil(t, nodeConfig)
+ })
+}
+
+func TestAlterNodeRequest(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ path string
+ config coordination.NodeConfig
+ operationParams *Ydb_Operations.OperationParams
+ request *Ydb_Coordination.AlterNodeRequest
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ path: "/a/b/c",
+ config: coordination.NodeConfig{
+ Path: "/a/b/c",
+ },
+ operationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ request: &Ydb_Coordination.AlterNodeRequest{
+ Path: "/a/b/c",
+ Config: &Ydb_Coordination.Config{
+ Path: "/a/b/c",
+ },
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ request := alterNodeRequest(tt.path, tt.config, tt.operationParams)
+ require.Equal(t, xtest.ToJSON(tt.request), xtest.ToJSON(request))
+ })
+ }
+}
+
+func TestAlterNode(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().AlterNode(gomock.Any(), gomock.Any()).Return(&Ydb_Coordination.AlterNodeResponse{
+ Operation: &Ydb_Operations.Operation{
+ Ready: true,
+ Status: Ydb.StatusIds_SUCCESS,
+ },
+ }, nil)
+ err := alterNode(ctx, client, &Ydb_Coordination.AlterNodeRequest{})
+ require.NoError(t, err)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().AlterNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Transport(grpcStatus.Error(grpcCodes.ResourceExhausted, "")),
+ )
+ err := alterNode(ctx, client, &Ydb_Coordination.AlterNodeRequest{})
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.ResourceExhausted))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().AlterNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ err := alterNode(ctx, client, &Ydb_Coordination.AlterNodeRequest{})
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+}
+
+func TestDropNodeRequest(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ path string
+ operationParams *Ydb_Operations.OperationParams
+ request *Ydb_Coordination.DropNodeRequest
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ path: "/a/b/c",
+ operationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ request: &Ydb_Coordination.DropNodeRequest{
+ Path: "/a/b/c",
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ request := dropNodeRequest(tt.path, tt.operationParams)
+ require.Equal(t, xtest.ToJSON(tt.request), xtest.ToJSON(request))
+ })
+ }
+}
+
+func TestDropNode(t *testing.T) {
+ t.Run("HappyWay", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DropNode(gomock.Any(), gomock.Any()).Return(&Ydb_Coordination.DropNodeResponse{
+ Operation: &Ydb_Operations.Operation{
+ Ready: true,
+ Status: Ydb.StatusIds_SUCCESS,
+ },
+ }, nil)
+ err := dropNode(ctx, client, &Ydb_Coordination.DropNodeRequest{})
+ require.NoError(t, err)
+ })
+ t.Run("TransportError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DropNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Transport(grpcStatus.Error(grpcCodes.ResourceExhausted, "")),
+ )
+ err := dropNode(ctx, client, &Ydb_Coordination.DropNodeRequest{})
+ require.True(t, xerrors.IsTransportError(err, grpcCodes.ResourceExhausted))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+ t.Run("OperationError", func(t *testing.T) {
+ ctx := xtest.Context(t)
+ ctrl := gomock.NewController(t)
+ client := NewMockCoordinationServiceClient(ctrl)
+ client.EXPECT().DropNode(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ err := dropNode(ctx, client, &Ydb_Coordination.DropNodeRequest{})
+ require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
+ require.True(t, xerrors.IsRetryObjectValid(err))
+ })
+}
diff --git a/internal/coordination/config/config.go b/internal/coordination/config/config.go
index ac684475f..692777a43 100644
--- a/internal/coordination/config/config.go
+++ b/internal/coordination/config/config.go
@@ -20,9 +20,9 @@ func (c Config) Trace() *trace.Coordination {
type Option func(c *Config)
// WithTrace appends coordination trace to early defined traces
-func WithTrace(trace trace.Coordination, opts ...trace.CoordinationComposeOption) Option {
+func WithTrace(trace *trace.Coordination, opts ...trace.CoordinationComposeOption) Option {
return func(c *Config) {
- c.trace = c.trace.Compose(&trace, opts...)
+ c.trace = c.trace.Compose(trace, opts...)
}
}
diff --git a/internal/coordination/conversation/conversation.go b/internal/coordination/conversation/conversation.go
new file mode 100644
index 000000000..c3c8e1863
--- /dev/null
+++ b/internal/coordination/conversation/conversation.go
@@ -0,0 +1,517 @@
+// Package conversation contains coordination session internal code that helps implement a typical conversation-like
+// session protocol based on a bidirectional gRPC stream.
+package conversation
+
+import (
+ "context"
+ "sync"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+)
+
+// Controller provides a simple mechanism to work with a session protocol using a gRPC bidirectional stream. Creating a
+// bidirectional stream client may be quite tricky because messages are usually being processed independently and in
+// parallel. Moreover, the gRPC client library puts strict limitations on an implementation of the client, e.g. multiple
+// calls of the Send or Recv methods of the stub client must not be performed from different goroutines. Also, there are
+// no guarantees that a message successfully dispatched by the Send method will actually reach the server, neither does
+// the server enjoy same guarantees when delivering messages to the client. This usually ends up having two goroutines
+// (one for sending outgoing messages and another one for receiving incoming ones) and a queue where messages are
+// published to be eventually delivered to the server. The Controller simplifies working with this model providing
+// generic implementation of the message queue and related routines, handling retries of sent and pending operations
+// when the underlying gRPC stream needs to be reconnected.
+//
+// A typical coordination session looks like this (we are going to skip for now how the gRPC stream is created, handled
+// and kept alive, you can find the details on that in the Session, and focus on the protocol):
+//
+// 1. The client opens a new gRPC bidirectional stream.
+// 2. The client sends the SessionStart request and wait until the Failure or the SessionStarted reply.
+// 3. The server sends the SessionStarted response with the SessionID. At this point the session is started. If the
+// client needs to reconnect the gRPC stream in the future, it will use that SessionID to attach to the previously
+// created session in the SessionStart request.
+// 4. The client sends the AcquireSemaphore request to acquire a permit to the semaphore in this session with count 5.
+// 5. After a moment, the client decides to acquire another semaphore, it sends one more AcquireSemaphore request with
+// count 4.
+// 6. The server replies with the AcquireSemaphoreResult response to the second AcquireSemaphore request to inform the
+// client that the semaphore was successfully acquired.
+// 7. The server replies with the AcquireSemaphorePending response in order to inform the client that the semaphore
+// from the first request has been acquired by another session.
+// 8. After a while, the server sends the AcquireSemaphoreResult response which implies that the semaphore from the
+// first request is acquired in the current session.
+// 9. Then the client sends the ReleaseSemaphore request in order to release the acquired semaphore.
+// 10. The server replies with the ReleaseSemaphoreResult.
+// 11. The client terminates the session with the SessionStop request.
+// 12. The server let the client know that the session is over sending the SessionStopped response and closing the gRPC
+// stream.
+//
+// We can notice five independent conversations here:
+//
+// 1. StartSession, SessionStarted â points 2â3;
+// 2. AcquireSemaphore, AcquireSemaphoreResult â points 4, 6;
+// 3. AcquireSemaphore, AcquireSemaphorePending, AcquireSemaphoreResult â points 5, 7 and 8;
+// 4. ReleaseSemaphore, ReleaseSemaphoreResult â points 9â10;
+// 5. SessionStop, SessionStopped â points 11â12.
+//
+// If at any time the client encounters an unrecoverable error (for example, the underlying gRPC stream becomes
+// disconnected), the client will have to replay every conversation from their very beginning. Let us see why it is
+// actually the case. But before we go into that, let us look at the grpc.ClientStream SendMsg method:
+//
+// "âĻSendMsg does not wait until the message is received by the server. An untimely stream closure may result in lost
+// messages. To ensure delivery, users should ensure the RPC completed successfully using RecvMsgâĻ"
+//
+// This is true for both, the client and the server. So when the server replies to the client it does not really know if
+// the response is received by the client. And vice versa, when the client sends a request to the server it has no way
+// to know if the request was delivered to the server unless the server sends another message to the client in reply.
+//
+// That is why conversation-like protocols typically use idempotent requests. Idempotent requests can be safely retried
+// as long as you keep the original order of the conversations. For example, if the gRPC stream is terminated before
+// the point 6, we cannot know if the server gets the requests. There may be one, two or none AcquireSemaphore requests
+// successfully delivered to and handled by the server. Moreover, the server may have already sent to the client the
+// corresponding responses. Nevertheless, if the requests are idempotent, we can safely retry them all in the newly
+// created gRPC stream and get the same results as we would have got if we had sent them without stream termination.
+// Note that if the stream is terminated before the point 8, we still need to replay the first AcquireSemaphore
+// conversation because we have no knowledge if the server replied with the AcquireSemaphoreResult in the terminated
+// stream.
+//
+// However, sometimes even idempotent requests cannot be safely retried. Consider the case wherein the point 5 from the
+// original list is:
+//
+// 5. After a moment, the client decides to modify the AcquireSemaphore request and sends another one with the same
+// semaphore but with count 4.
+//
+// If then the gRPC stream terminates, there are two likely outcomes:
+//
+// 1. The server received the first request but the second one was not delivered. The current semaphore count is 5.
+// 2. The server received and processed the both requests. The current semaphore permit count is 4.
+//
+// If we retry the both requests, the observed result will be different depending on which outcome occurs:
+//
+// 1. The first retry will be a noop, the second one will decrease the semaphore count to 4. This is expected behavior.
+// 2. The first retry will try to increase the semaphore count to 5, it causes an error. This is unexpected.
+//
+// In order to avoid that we could postpone a conversation if there is another one for the same semaphore which has been
+// sent but has not been yet delivered to the server. For more details, see the WithConflictKey option.
+type Controller struct {
+ mutex sync.Mutex // guards access to the fields below
+
+ queue []*Conversation // the message queue, the front is in the end of the slice
+ conflicts map[string]struct{}
+
+ notifyChan chan struct{}
+ closed bool
+}
+
+// ResponseFilter defines the filter function called by the controller to know if a received message relates to the
+// conversation. If a ResponseFilter returns true, the message is considered to be part of the conversation.
+type ResponseFilter func(request *Ydb_Coordination.SessionRequest, response *Ydb_Coordination.SessionResponse) bool
+
+// Conversation is a core concept of the conversation package. It is an ordered sequence of connected request/reply
+// messages. For example, the acquiring semaphore conversation may look like this:
+//
+// 1. The client sends the AcquireSemaphore request.
+// 2. The server replies with the AcquireSemaphorePending response.
+// 3. After a while, the server replies with the AcquireSemaphoreResult response. The conversation is ended.
+//
+// There may be many different conversations carried out simultaneously in one session, so the exact order of all the
+// messages in the session is unspecified. In the example above, there may be other messages (from different
+// conversations) between points 1 and 2, or 2 and 3.
+type Conversation struct {
+ message func() *Ydb_Coordination.SessionRequest
+ responseFilter ResponseFilter
+ acknowledgeFilter ResponseFilter
+ cancelMessage func(req *Ydb_Coordination.SessionRequest) *Ydb_Coordination.SessionRequest
+ cancelFilter ResponseFilter
+ conflictKey string
+ requestSent *Ydb_Coordination.SessionRequest
+ cancelRequestSent *Ydb_Coordination.SessionRequest
+ response *Ydb_Coordination.SessionResponse
+ responseErr error
+ done chan struct{}
+ idempotent bool
+ canceled bool
+}
+
+// NewController creates a new conversation controller. You usually have one controller per one session.
+func NewController() *Controller {
+ return &Controller{
+ notifyChan: make(chan struct{}, 1),
+ conflicts: make(map[string]struct{}),
+ }
+}
+
+// WithResponseFilter returns an Option that specifies the filter function that is used to detect the last response
+// message in the conversation. If such a message was found, the conversation is immediately ended and the response
+// becomes available by the Conversation.Await method.
+func WithResponseFilter(filter ResponseFilter) Option {
+ return func(c *Conversation) {
+ c.responseFilter = filter
+ }
+}
+
+// WithAcknowledgeFilter returns an Option that specifies the filter function that is used to detect an intermediate
+// response message in the conversation. If such a message was found, the conversation continues, but it lets the client
+// know that the server successfully consumed the first request of the conversation.
+func WithAcknowledgeFilter(filter ResponseFilter) Option {
+ return func(c *Conversation) {
+ c.acknowledgeFilter = filter
+ }
+}
+
+// WithCancelMessage returns an Option that specifies the message and filter functions that are used to cancel the
+// conversation which has been already sent. This message is sent in the background when the caller cancels the context
+// of the Controller.Await function. The response is never received by the caller and is only used to end the
+// conversation and remove it from the queue.
+func WithCancelMessage(
+ message func(req *Ydb_Coordination.SessionRequest) *Ydb_Coordination.SessionRequest,
+ filter ResponseFilter,
+) Option {
+ return func(c *Conversation) {
+ c.cancelMessage = message
+ c.cancelFilter = filter
+ }
+}
+
+// WithConflictKey returns an Option that specifies the key that is used to find out messages that cannot be delivered
+// to the server until the server acknowledged the request. If there is a conversation with the same conflict key in the
+// queue that has not been yet delivered to the server, the controller will temporarily suspend other conversations with
+// the same conflict key until the first one is acknowledged.
+func WithConflictKey(key string) Option {
+ return func(c *Conversation) {
+ c.conflictKey = key
+ }
+}
+
+// WithIdempotence returns an Option that enabled retries for this conversation when the underlying gRPC stream
+// reconnects. The controller will replay the whole conversation from scratch unless it is not ended.
+func WithIdempotence(idempotent bool) Option {
+ return func(c *Conversation) {
+ c.idempotent = idempotent
+ }
+}
+
+// Option configures how we create a new conversation.
+type Option func(c *Conversation)
+
+// NewConversation creates a new conversation that starts with a specified message.
+func NewConversation(request func() *Ydb_Coordination.SessionRequest, opts ...Option) *Conversation {
+ conversation := Conversation{message: request}
+ for _, o := range opts {
+ if o != nil {
+ o(&conversation)
+ }
+ }
+
+ return &conversation
+}
+
+func (c *Controller) notify() {
+ select {
+ case c.notifyChan <- struct{}{}:
+ default:
+ }
+}
+
+// PushBack puts a new conversation at the end of the queue.
+func (c *Controller) PushBack(conversation *Conversation) error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ if c.closed {
+ return coordination.ErrSessionClosed
+ }
+
+ conversation.enqueue()
+ c.queue = append([]*Conversation{conversation}, c.queue...)
+ c.notify()
+
+ return nil
+}
+
+// PushFront puts a new conversation at the beginning of the queue.
+func (c *Controller) PushFront(conversation *Conversation) error {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ if c.closed {
+ return coordination.ErrSessionClosed
+ }
+
+ conversation.enqueue()
+ c.queue = append(c.queue, conversation)
+ c.notify()
+
+ return nil
+}
+
+func (c *Controller) sendFront() *Ydb_Coordination.SessionRequest {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ // We are notified but there are no conversations in the queue. Return nil to make the loop in OnSend wait.
+ if len(c.queue) == 0 {
+ return nil
+ }
+
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+
+ if req.canceled && req.cancelRequestSent == nil {
+ req.sendCancel()
+ c.notify()
+
+ return req.cancelRequestSent
+ }
+
+ if req.requestSent != nil {
+ continue
+ }
+
+ if _, ok := c.conflicts[req.conflictKey]; ok {
+ continue
+ }
+
+ req.send()
+
+ if req.conflictKey != "" {
+ c.conflicts[req.conflictKey] = struct{}{}
+ }
+ if req.responseFilter == nil && req.acknowledgeFilter == nil {
+ c.queue = append(c.queue[:i], c.queue[i+1:]...)
+ }
+ c.notify()
+
+ return req.requestSent
+ }
+
+ return nil
+}
+
+// OnSend blocks until a new conversation request becomes available at the end of the queue. You should call this method
+// in the goroutine that handles gRPC stream Send method. ctx can be used to cancel the call.
+func (c *Controller) OnSend(ctx context.Context) (*Ydb_Coordination.SessionRequest, error) {
+ var req *Ydb_Coordination.SessionRequest
+ for {
+ select {
+ case <-ctx.Done():
+ case <-c.notifyChan:
+ req = c.sendFront()
+ }
+
+ // Process ctx.Done() first to make sure we cancel the call if conversations are too chatty.
+ if ctx.Err() != nil {
+ return nil, ctx.Err()
+ }
+
+ // We were notified but there were no messages in the queue. Just wait for more messages become available.
+ if req != nil {
+ break
+ }
+ }
+
+ return req, nil
+}
+
+// OnRecv consumes a new conversation response and process with the corresponding conversation if any exists for it. The
+// returned value indicates if any conversation considers the incoming message part of it or the controller is closed.
+// You should call this method in the goroutine that handles gRPC stream Recv method.
+func (c *Controller) OnRecv(resp *Ydb_Coordination.SessionResponse) bool {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ notify := false
+ handled := false
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+ if req.requestSent == nil {
+ continue
+ }
+
+ switch {
+ case req.responseFilter != nil && req.responseFilter(req.requestSent, resp):
+ if !req.canceled {
+ req.succeed(resp)
+
+ if req.conflictKey != "" {
+ delete(c.conflicts, req.conflictKey)
+ notify = true
+ }
+
+ c.queue = append(c.queue[:i], c.queue[i+1:]...)
+ }
+
+ handled = true
+ case req.acknowledgeFilter != nil && req.acknowledgeFilter(req.requestSent, resp):
+ if !req.canceled {
+ if req.conflictKey != "" {
+ delete(c.conflicts, req.conflictKey)
+ notify = true
+ }
+ }
+
+ handled = true
+ case req.cancelRequestSent != nil && req.cancelFilter(req.cancelRequestSent, resp):
+ if req.conflictKey != "" {
+ delete(c.conflicts, req.conflictKey)
+ notify = true
+ }
+ c.queue = append(c.queue[:i], c.queue[i+1:]...)
+ handled = true
+ }
+ }
+
+ if notify {
+ c.notify()
+ }
+
+ return c.closed || handled
+}
+
+// OnDetach fails all non-idempotent conversations if there are any in the queue. You should call this method when the
+// underlying gRPC stream of the session is closed.
+func (c *Controller) OnDetach() {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+ if !req.idempotent {
+ req.fail(coordination.ErrOperationStatusUnknown)
+
+ if req.requestSent != nil && req.conflictKey != "" {
+ delete(c.conflicts, req.conflictKey)
+ }
+
+ c.queue = append(c.queue[:i], c.queue[i+1:]...)
+ }
+ }
+}
+
+// Close fails all conversations if there are any in the queue. It also does not allow pushing more conversations to the
+// queue anymore. You may optionally specify the final conversation if needed.
+func (c *Controller) Close(byeConversation *Conversation) {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ c.closed = true
+
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+ if !req.canceled {
+ req.fail(coordination.ErrSessionClosed)
+ }
+ }
+
+ if byeConversation != nil {
+ byeConversation.enqueue()
+ c.queue = []*Conversation{byeConversation}
+ }
+
+ c.notify()
+}
+
+// OnAttach retries all idempotent conversations if there are any in the queue. You should call this method when the
+// underlying gRPC stream of the session is connected.
+func (c *Controller) OnAttach() {
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ notify := false
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+ if req.idempotent && req.requestSent != nil {
+ if req.conflictKey != "" {
+ delete(c.conflicts, req.conflictKey)
+ }
+
+ req.requestSent = nil
+ notify = true
+ }
+ }
+
+ if notify {
+ c.notify()
+ }
+}
+
+// Cancel the conversation if it has been sent and there is no response ready. This returns false if the response is
+// ready and the caller may safely return it instead of canceling the conversation.
+func (c *Controller) cancel(conversation *Conversation) bool {
+ if conversation.cancelMessage == nil {
+ return true
+ }
+
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+
+ // The context is canceled but the response is ready, return it anyway.
+ if conversation.response != nil || conversation.responseErr != nil {
+ return false
+ }
+
+ if conversation.requestSent != nil {
+ conversation.cancel()
+ c.notify()
+ } else {
+ // If the response has not been sent, just remove it from the queue.
+ for i := len(c.queue) - 1; i >= 0; i-- {
+ req := c.queue[i]
+ if req == conversation {
+ c.queue = append(c.queue[:i], c.queue[i+1:]...)
+
+ break
+ }
+ }
+ }
+
+ return true
+}
+
+// Await waits until the conversation ends. ctx can be used to cancel the call.
+func (c *Controller) Await(
+ ctx context.Context,
+ conversation *Conversation,
+) (*Ydb_Coordination.SessionResponse, error) {
+ select {
+ case <-conversation.done:
+ case <-ctx.Done():
+ }
+
+ if ctx.Err() != nil && c.cancel(conversation) {
+ return nil, ctx.Err()
+ }
+
+ if conversation.responseErr != nil {
+ return nil, conversation.responseErr
+ }
+
+ return conversation.response, nil
+}
+
+func (c *Conversation) enqueue() {
+ c.requestSent = nil
+ c.done = make(chan struct{})
+}
+
+func (c *Conversation) send() {
+ c.requestSent = c.message()
+}
+
+func (c *Conversation) sendCancel() {
+ c.cancelRequestSent = c.cancelMessage(c.requestSent)
+}
+
+func (c *Conversation) succeed(response *Ydb_Coordination.SessionResponse) {
+ c.response = response
+ close(c.done)
+}
+
+func (c *Conversation) fail(err error) {
+ c.responseErr = err
+ close(c.done)
+}
+
+func (c *Conversation) cancel() {
+ c.canceled = true
+ close(c.done)
+}
diff --git a/internal/coordination/grpc_client_mock_test.go b/internal/coordination/grpc_client_mock_test.go
new file mode 100644
index 000000000..3c2d2a711
--- /dev/null
+++ b/internal/coordination/grpc_client_mock_test.go
@@ -0,0 +1,278 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1 (interfaces: CoordinationServiceClient,CoordinationService_SessionClient)
+//
+// Generated by this command:
+//
+// mockgen -destination grpc_client_mock_test.go -package coordination -write_package_comment=false github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1 CoordinationServiceClient,CoordinationService_SessionClient
+package coordination
+
+import (
+ context "context"
+ reflect "reflect"
+
+ Ydb_Coordination_V1 "github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1"
+ Ydb_Coordination "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+ gomock "go.uber.org/mock/gomock"
+ grpc "google.golang.org/grpc"
+ metadata "google.golang.org/grpc/metadata"
+)
+
+// MockCoordinationServiceClient is a mock of CoordinationServiceClient interface.
+type MockCoordinationServiceClient struct {
+ ctrl *gomock.Controller
+ recorder *MockCoordinationServiceClientMockRecorder
+}
+
+// MockCoordinationServiceClientMockRecorder is the mock recorder for MockCoordinationServiceClient.
+type MockCoordinationServiceClientMockRecorder struct {
+ mock *MockCoordinationServiceClient
+}
+
+// NewMockCoordinationServiceClient creates a new mock instance.
+func NewMockCoordinationServiceClient(ctrl *gomock.Controller) *MockCoordinationServiceClient {
+ mock := &MockCoordinationServiceClient{ctrl: ctrl}
+ mock.recorder = &MockCoordinationServiceClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCoordinationServiceClient) EXPECT() *MockCoordinationServiceClientMockRecorder {
+ return m.recorder
+}
+
+// AlterNode mocks base method.
+func (m *MockCoordinationServiceClient) AlterNode(arg0 context.Context, arg1 *Ydb_Coordination.AlterNodeRequest, arg2 ...grpc.CallOption) (*Ydb_Coordination.AlterNodeResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "AlterNode", varargs...)
+ ret0, _ := ret[0].(*Ydb_Coordination.AlterNodeResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// AlterNode indicates an expected call of AlterNode.
+func (mr *MockCoordinationServiceClientMockRecorder) AlterNode(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AlterNode", reflect.TypeOf((*MockCoordinationServiceClient)(nil).AlterNode), varargs...)
+}
+
+// CreateNode mocks base method.
+func (m *MockCoordinationServiceClient) CreateNode(arg0 context.Context, arg1 *Ydb_Coordination.CreateNodeRequest, arg2 ...grpc.CallOption) (*Ydb_Coordination.CreateNodeResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "CreateNode", varargs...)
+ ret0, _ := ret[0].(*Ydb_Coordination.CreateNodeResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// CreateNode indicates an expected call of CreateNode.
+func (mr *MockCoordinationServiceClientMockRecorder) CreateNode(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateNode", reflect.TypeOf((*MockCoordinationServiceClient)(nil).CreateNode), varargs...)
+}
+
+// DescribeNode mocks base method.
+func (m *MockCoordinationServiceClient) DescribeNode(arg0 context.Context, arg1 *Ydb_Coordination.DescribeNodeRequest, arg2 ...grpc.CallOption) (*Ydb_Coordination.DescribeNodeResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "DescribeNode", varargs...)
+ ret0, _ := ret[0].(*Ydb_Coordination.DescribeNodeResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// DescribeNode indicates an expected call of DescribeNode.
+func (mr *MockCoordinationServiceClientMockRecorder) DescribeNode(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNode", reflect.TypeOf((*MockCoordinationServiceClient)(nil).DescribeNode), varargs...)
+}
+
+// DropNode mocks base method.
+func (m *MockCoordinationServiceClient) DropNode(arg0 context.Context, arg1 *Ydb_Coordination.DropNodeRequest, arg2 ...grpc.CallOption) (*Ydb_Coordination.DropNodeResponse, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0, arg1}
+ for _, a := range arg2 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "DropNode", varargs...)
+ ret0, _ := ret[0].(*Ydb_Coordination.DropNodeResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// DropNode indicates an expected call of DropNode.
+func (mr *MockCoordinationServiceClientMockRecorder) DropNode(arg0, arg1 any, arg2 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0, arg1}, arg2...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DropNode", reflect.TypeOf((*MockCoordinationServiceClient)(nil).DropNode), varargs...)
+}
+
+// Session mocks base method.
+func (m *MockCoordinationServiceClient) Session(arg0 context.Context, arg1 ...grpc.CallOption) (Ydb_Coordination_V1.CoordinationService_SessionClient, error) {
+ m.ctrl.T.Helper()
+ varargs := []any{arg0}
+ for _, a := range arg1 {
+ varargs = append(varargs, a)
+ }
+ ret := m.ctrl.Call(m, "Session", varargs...)
+ ret0, _ := ret[0].(Ydb_Coordination_V1.CoordinationService_SessionClient)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Session indicates an expected call of Session.
+func (mr *MockCoordinationServiceClientMockRecorder) Session(arg0 any, arg1 ...any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ varargs := append([]any{arg0}, arg1...)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Session", reflect.TypeOf((*MockCoordinationServiceClient)(nil).Session), varargs...)
+}
+
+// MockCoordinationService_SessionClient is a mock of CoordinationService_SessionClient interface.
+type MockCoordinationService_SessionClient struct {
+ ctrl *gomock.Controller
+ recorder *MockCoordinationService_SessionClientMockRecorder
+}
+
+// MockCoordinationService_SessionClientMockRecorder is the mock recorder for MockCoordinationService_SessionClient.
+type MockCoordinationService_SessionClientMockRecorder struct {
+ mock *MockCoordinationService_SessionClient
+}
+
+// NewMockCoordinationService_SessionClient creates a new mock instance.
+func NewMockCoordinationService_SessionClient(ctrl *gomock.Controller) *MockCoordinationService_SessionClient {
+ mock := &MockCoordinationService_SessionClient{ctrl: ctrl}
+ mock.recorder = &MockCoordinationService_SessionClientMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCoordinationService_SessionClient) EXPECT() *MockCoordinationService_SessionClientMockRecorder {
+ return m.recorder
+}
+
+// CloseSend mocks base method.
+func (m *MockCoordinationService_SessionClient) CloseSend() error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "CloseSend")
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// CloseSend indicates an expected call of CloseSend.
+func (mr *MockCoordinationService_SessionClientMockRecorder) CloseSend() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseSend", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).CloseSend))
+}
+
+// Context mocks base method.
+func (m *MockCoordinationService_SessionClient) Context() context.Context {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Context")
+ ret0, _ := ret[0].(context.Context)
+ return ret0
+}
+
+// Context indicates an expected call of Context.
+func (mr *MockCoordinationService_SessionClientMockRecorder) Context() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Context", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).Context))
+}
+
+// Header mocks base method.
+func (m *MockCoordinationService_SessionClient) Header() (metadata.MD, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Header")
+ ret0, _ := ret[0].(metadata.MD)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Header indicates an expected call of Header.
+func (mr *MockCoordinationService_SessionClientMockRecorder) Header() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Header", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).Header))
+}
+
+// Recv mocks base method.
+func (m *MockCoordinationService_SessionClient) Recv() (*Ydb_Coordination.SessionResponse, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Recv")
+ ret0, _ := ret[0].(*Ydb_Coordination.SessionResponse)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Recv indicates an expected call of Recv.
+func (mr *MockCoordinationService_SessionClientMockRecorder) Recv() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Recv", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).Recv))
+}
+
+// RecvMsg mocks base method.
+func (m *MockCoordinationService_SessionClient) RecvMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "RecvMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// RecvMsg indicates an expected call of RecvMsg.
+func (mr *MockCoordinationService_SessionClientMockRecorder) RecvMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecvMsg", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).RecvMsg), arg0)
+}
+
+// Send mocks base method.
+func (m *MockCoordinationService_SessionClient) Send(arg0 *Ydb_Coordination.SessionRequest) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Send", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// Send indicates an expected call of Send.
+func (mr *MockCoordinationService_SessionClientMockRecorder) Send(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Send", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).Send), arg0)
+}
+
+// SendMsg mocks base method.
+func (m *MockCoordinationService_SessionClient) SendMsg(arg0 any) error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "SendMsg", arg0)
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// SendMsg indicates an expected call of SendMsg.
+func (mr *MockCoordinationService_SessionClientMockRecorder) SendMsg(arg0 any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMsg", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).SendMsg), arg0)
+}
+
+// Trailer mocks base method.
+func (m *MockCoordinationService_SessionClient) Trailer() metadata.MD {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Trailer")
+ ret0, _ := ret[0].(metadata.MD)
+ return ret0
+}
+
+// Trailer indicates an expected call of Trailer.
+func (mr *MockCoordinationService_SessionClientMockRecorder) Trailer() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Trailer", reflect.TypeOf((*MockCoordinationService_SessionClient)(nil).Trailer))
+}
diff --git a/internal/coordination/session.go b/internal/coordination/session.go
new file mode 100644
index 000000000..9e7e2bb23
--- /dev/null
+++ b/internal/coordination/session.go
@@ -0,0 +1,891 @@
+package coordination
+
+import (
+ "context"
+ "encoding/binary"
+ "math"
+ "math/rand"
+ "sync"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-genproto/Ydb_Coordination_V1"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/coordination/conversation"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+type session struct {
+ options *options.CreateSessionOptions
+ client *Client
+
+ ctx context.Context
+ cancel context.CancelFunc
+ sessionClosedChan chan struct{}
+ controller *conversation.Controller
+ sessionID uint64
+
+ mutex sync.Mutex // guards the field below
+ lastGoodResponseTime time.Time
+ cancelStream context.CancelFunc
+}
+
+type lease struct {
+ session *session
+ name string
+ ctx context.Context
+ cancel context.CancelFunc
+}
+
+func createSession(
+ ctx context.Context,
+ client *Client,
+ path string,
+ opts *options.CreateSessionOptions,
+) (*session, error) {
+ sessionCtx, cancel := xcontext.WithCancel(xcontext.ValueOnly(ctx))
+ s := session{
+ options: opts,
+ client: client,
+ ctx: sessionCtx,
+ cancel: cancel,
+ sessionClosedChan: make(chan struct{}),
+ controller: conversation.NewController(),
+ }
+ client.sessionCreated(&s)
+
+ sessionStartedChan := make(chan struct{})
+ go s.mainLoop(path, sessionStartedChan)
+
+ select {
+ case <-ctx.Done():
+ cancel()
+
+ return nil, ctx.Err()
+ case <-sessionStartedChan:
+ }
+
+ return &s, nil
+}
+
+func newProtectionKey() []byte {
+ key := make([]byte, 8) //nolint:gomnd
+ binary.LittleEndian.PutUint64(key, rand.Uint64()) //nolint:gosec
+
+ return key
+}
+
+func newReqID() uint64 {
+ return rand.Uint64() //nolint:gosec
+}
+
+func (s *session) updateLastGoodResponseTime() {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ now := time.Now()
+
+ if now.After(s.lastGoodResponseTime) {
+ s.lastGoodResponseTime = now
+ }
+}
+
+func (s *session) getLastGoodResponseTime() time.Time {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ return s.lastGoodResponseTime
+}
+
+func (s *session) updateCancelStream(cancel context.CancelFunc) {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ s.cancelStream = cancel
+}
+
+// Create a new gRPC stream using an independent context.
+func (s *session) newStream(
+ streamCtx context.Context,
+ cancelStream context.CancelFunc,
+) (Ydb_Coordination_V1.CoordinationService_SessionClient, error) {
+ // This deadline if final. If we have not got a session before it, the session is either expired or has never been
+ // created.
+ var deadline time.Time
+ if s.sessionID != 0 {
+ deadline = s.getLastGoodResponseTime().Add(s.options.SessionTimeout)
+ } else {
+ // Large enough to make the loop infinite, small enough to allow the maximum duration value (~290 years).
+ deadline = time.Now().Add(time.Hour * 24 * 365 * 100) //nolint:gomnd
+ }
+
+ lastChance := false
+ for {
+ result := make(chan Ydb_Coordination_V1.CoordinationService_SessionClient, 1)
+ go func() {
+ var err error
+ onDone := trace.CoordinationOnStreamNew(s.client.config.Trace())
+ defer func() {
+ onDone(err)
+ }()
+
+ client, err := s.client.client.Session(streamCtx)
+ result <- client
+ }()
+
+ var client Ydb_Coordination_V1.CoordinationService_SessionClient
+ if lastChance {
+ timer := time.NewTimer(s.options.SessionKeepAliveTimeout)
+ select {
+ case <-timer.C:
+ case client = <-result:
+ }
+ timer.Stop()
+
+ if client != nil {
+ return client, nil
+ }
+
+ cancelStream()
+
+ return nil, s.ctx.Err()
+ }
+
+ // Since the deadline is probably large enough, avoid the timer leak with time.After.
+ timer := time.NewTimer(time.Until(deadline))
+ select {
+ case <-s.ctx.Done():
+ case client = <-result:
+ case <-timer.C:
+ trace.CoordinationOnSessionClientTimeout(
+ s.client.config.Trace(),
+ s.getLastGoodResponseTime(),
+ s.options.SessionTimeout,
+ )
+ cancelStream()
+
+ return nil, coordination.ErrSessionClosed
+ }
+ timer.Stop()
+
+ if client != nil {
+ return client, nil
+ }
+
+ // Waiting for some time before trying to reconnect.
+ sessionReconnectDelay := time.NewTimer(s.options.SessionReconnectDelay)
+ select {
+ case <-sessionReconnectDelay.C:
+ case <-s.ctx.Done():
+ }
+ sessionReconnectDelay.Stop()
+
+ if s.ctx.Err() != nil {
+ // Give this session the last chance to stop gracefully if the session is canceled in the reconnect cycle.
+ if s.sessionID != 0 {
+ lastChance = true
+ } else {
+ cancelStream()
+
+ return nil, s.ctx.Err()
+ }
+ }
+ }
+}
+
+func (s *session) mainLoop(path string, sessionStartedChan chan struct{}) {
+ defer s.client.sessionClosed(s)
+ defer close(s.sessionClosedChan)
+ defer s.cancel()
+
+ var seqNo uint64
+
+ protectionKey := newProtectionKey()
+ closing := false
+
+ for {
+ // Create a new grpc stream and start the receiver and sender loops.
+ //
+ // We use the stream context as a way to inform the main loop that the session must be reconnected if an
+ // unrecoverable error occurs in the receiver or sender loop. This also helps stop the other loop if an error
+ // is caught on only one of them.
+ //
+ // We intentionally place a stream context outside the scope of any existing contexts to make an attempt to
+ // close the session gracefully at the end of the main loop.
+
+ streamCtx, cancelStream := context.WithCancel(context.Background())
+ sessionClient, err := s.newStream(streamCtx, cancelStream)
+ if err != nil {
+ // Giving up, we can do nothing without a stream.
+ s.controller.Close(nil)
+
+ return
+ }
+
+ s.updateCancelStream(cancelStream)
+
+ // Start the loops.
+ wg := sync.WaitGroup{}
+ wg.Add(2) //nolint:gomnd
+ sessionStarted := make(chan *Ydb_Coordination.SessionResponse_SessionStarted, 1)
+ sessionStopped := make(chan *Ydb_Coordination.SessionResponse_SessionStopped, 1)
+ startSending := make(chan struct{})
+ s.controller.OnAttach()
+
+ go s.receiveLoop(&wg, sessionClient, cancelStream, sessionStarted, sessionStopped)
+ go s.sendLoop(
+ &wg,
+ sessionClient,
+ streamCtx,
+ cancelStream,
+ startSending,
+ path,
+ protectionKey,
+ s.sessionID,
+ seqNo,
+ )
+
+ // Wait for the session started response unless the stream context is done. We intentionally do not take into
+ // account stream context cancellation in order to proceed with the graceful shutdown if it requires reconnect.
+ sessionStartTimer := time.NewTimer(s.options.SessionStartTimeout)
+ select {
+ case start := <-sessionStarted:
+ trace.CoordinationOnSessionStarted(s.client.config.Trace(), start.GetSessionId(), s.sessionID)
+ if s.sessionID == 0 {
+ s.sessionID = start.GetSessionId()
+ close(sessionStartedChan)
+ } else if start.GetSessionId() != s.sessionID {
+ // Reconnect if the server response is invalid.
+ cancelStream()
+ }
+ close(startSending)
+ case <-sessionStartTimer.C:
+ // Reconnect if no response was received before the timeout occurred.
+ trace.CoordinationOnSessionStartTimeout(s.client.config.Trace(), s.options.SessionStartTimeout)
+ cancelStream()
+ case <-streamCtx.Done():
+ case <-s.ctx.Done():
+ }
+ sessionStartTimer.Stop()
+
+ for {
+ // Respect the failure reason priority: if the session context is done, we must stop the session, even
+ // though the stream context may also be canceled.
+ if s.ctx.Err() != nil {
+ closing = true
+
+ break
+ }
+ if streamCtx.Err() != nil {
+ // Reconnect if an error occurred during the start session conversation.
+ break
+ }
+
+ keepAliveTime := time.Until(s.getLastGoodResponseTime().Add(s.options.SessionKeepAliveTimeout))
+ keepAliveTimeTimer := time.NewTimer(keepAliveTime)
+ select {
+ case <-keepAliveTimeTimer.C:
+ last := s.getLastGoodResponseTime()
+ if time.Since(last) > s.options.SessionKeepAliveTimeout {
+ // Reconnect if the underlying stream is likely to be dead.
+ trace.CoordinationOnSessionKeepAliveTimeout(
+ s.client.config.Trace(),
+ last,
+ s.options.SessionKeepAliveTimeout,
+ )
+ cancelStream()
+ }
+ case <-streamCtx.Done():
+ case <-s.ctx.Done():
+ }
+ keepAliveTimeTimer.Stop()
+ }
+
+ if closing {
+ // No need to stop the session if it was not started.
+ if s.sessionID == 0 {
+ s.controller.Close(nil)
+ cancelStream()
+
+ return
+ }
+
+ trace.CoordinationOnSessionStop(s.client.config.Trace(), s.sessionID)
+ s.controller.Close(conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_SessionStop_{
+ SessionStop: &Ydb_Coordination.SessionRequest_SessionStop{},
+ },
+ }
+ }),
+ )
+
+ // Wait for the session stopped response unless the stream context is done.
+ sessionStopTimeout := time.NewTimer(s.options.SessionStopTimeout)
+ select {
+ case stop := <-sessionStopped:
+ sessionStopTimeout.Stop()
+ trace.CoordinationOnSessionStopped(s.client.config.Trace(), stop.GetSessionId(), s.sessionID)
+ if stop.GetSessionId() == s.sessionID {
+ cancelStream()
+
+ return
+ }
+
+ // Reconnect if the server response is invalid.
+ cancelStream()
+ case <-sessionStopTimeout.C:
+ sessionStopTimeout.Stop() // no really need, call stop for common style only
+
+ // Reconnect if no response was received before the timeout occurred.
+ trace.CoordinationOnSessionStopTimeout(s.client.config.Trace(), s.options.SessionStopTimeout)
+ cancelStream()
+ case <-s.ctx.Done():
+ sessionStopTimeout.Stop()
+ cancelStream()
+
+ return
+ case <-streamCtx.Done():
+ sessionStopTimeout.Stop()
+ }
+ }
+
+ // Make sure no one is processing the stream anymore.
+ wg.Wait()
+
+ s.controller.OnDetach()
+ seqNo++
+ }
+}
+
+func (s *session) receiveLoop(
+ wg *sync.WaitGroup,
+ sessionClient Ydb_Coordination_V1.CoordinationService_SessionClient,
+ cancelStream context.CancelFunc,
+ sessionStarted chan *Ydb_Coordination.SessionResponse_SessionStarted,
+ sessionStopped chan *Ydb_Coordination.SessionResponse_SessionStopped,
+) {
+ // If the sendLoop is done, make sure the stream is also canceled to make the receiveLoop finish its work and cause
+ // reconnect.
+ defer wg.Done()
+ defer cancelStream()
+
+ for {
+ onDone := trace.CoordinationOnSessionReceive(s.client.config.Trace())
+ message, err := sessionClient.Recv()
+ if err != nil {
+ // Any stream error is unrecoverable, try to reconnect.
+ onDone(nil, err)
+
+ return
+ }
+ onDone(message, nil)
+
+ switch message.GetResponse().(type) {
+ case *Ydb_Coordination.SessionResponse_Failure_:
+ if message.GetFailure().GetStatus() == Ydb.StatusIds_SESSION_EXPIRED ||
+ message.GetFailure().GetStatus() == Ydb.StatusIds_UNAUTHORIZED ||
+ message.GetFailure().GetStatus() == Ydb.StatusIds_NOT_FOUND {
+ // Consider the session expired if we got an unrecoverable status.
+ trace.CoordinationOnSessionServerExpire(s.client.config.Trace(), message.GetFailure())
+
+ return
+ }
+
+ trace.CoordinationOnSessionServerError(s.client.config.Trace(), message.GetFailure())
+
+ return
+ case *Ydb_Coordination.SessionResponse_SessionStarted_:
+ sessionStarted <- message.GetSessionStarted()
+ s.updateLastGoodResponseTime()
+ case *Ydb_Coordination.SessionResponse_SessionStopped_:
+ sessionStopped <- message.GetSessionStopped()
+ s.cancel()
+
+ return
+ case *Ydb_Coordination.SessionResponse_Ping:
+ opaque := message.GetPing().GetOpaque()
+ err := s.controller.PushFront(conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_Pong{
+ Pong: &Ydb_Coordination.SessionRequest_PingPong{
+ Opaque: opaque,
+ },
+ },
+ }
+ }),
+ )
+ if err != nil {
+ // The session is closed if we cannot send the pong request back, so just exit the loop.
+ return
+ }
+ s.updateLastGoodResponseTime()
+ case *Ydb_Coordination.SessionResponse_Pong:
+ // Ignore pongs since we do not ping the server.
+ default:
+ if !s.controller.OnRecv(message) {
+ // Reconnect if the message is not from any known conversation.
+ trace.CoordinationOnSessionReceiveUnexpected(s.client.config.Trace(), message)
+
+ return
+ }
+
+ s.updateLastGoodResponseTime()
+ }
+ }
+}
+
+//nolint:revive
+func (s *session) sendLoop(
+ wg *sync.WaitGroup,
+ sessionClient Ydb_Coordination_V1.CoordinationService_SessionClient,
+ streamCtx context.Context,
+ cancelStream context.CancelFunc,
+ startSending chan struct{},
+ path string,
+ protectionKey []byte,
+ sessionID uint64,
+ seqNo uint64,
+) {
+ // If the sendLoop is done, make sure the stream is also canceled to make the receiveLoop finish its work and cause
+ // reconnect.
+ defer wg.Done()
+ defer cancelStream()
+
+ // Start a new session.
+ onDone := trace.CoordinationOnSessionStart(s.client.config.Trace())
+ startSession := Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_SessionStart_{
+ SessionStart: &Ydb_Coordination.SessionRequest_SessionStart{
+ Path: path,
+ SessionId: sessionID,
+ TimeoutMillis: uint64(s.options.SessionTimeout.Milliseconds()),
+ ProtectionKey: protectionKey,
+ SeqNo: seqNo,
+ Description: s.options.Description,
+ },
+ },
+ }
+ err := sessionClient.Send(&startSession)
+ if err != nil {
+ // Reconnect if a session cannot be started in this stream.
+ onDone(err)
+
+ return
+ }
+ onDone(nil)
+
+ // Wait for a response to the session start request in order to carry over the accumulated conversations until the
+ // server confirms that the session is running. This is not absolutely necessary but helps the client to not fail
+ // non-idempotent requests in case of the session handshake errors.
+ select {
+ case <-streamCtx.Done():
+ case <-startSending:
+ }
+
+ for {
+ message, err := s.controller.OnSend(streamCtx)
+ if err != nil {
+ return
+ }
+
+ onSendDone := trace.CoordinationOnSessionSend(s.client.config.Trace(), message)
+ err = sessionClient.Send(message)
+ if err != nil {
+ // Any stream error is unrecoverable, try to reconnect.
+ onSendDone(err)
+
+ return
+ }
+ onSendDone(nil)
+ }
+}
+
+func (s *session) Context() context.Context {
+ return s.ctx
+}
+
+func (s *session) Close(ctx context.Context) error {
+ s.cancel()
+
+ select {
+ case <-s.sessionClosedChan:
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+
+ return nil
+}
+
+func (s *session) Reconnect() {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+
+ if s.cancelStream != nil {
+ s.cancelStream()
+ }
+}
+
+func (s *session) SessionID() uint64 {
+ return s.sessionID
+}
+
+func (s *session) CreateSemaphore(
+ ctx context.Context,
+ name string,
+ limit uint64,
+ opts ...options.CreateSemaphoreOption,
+) error {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ createSemaphore := Ydb_Coordination.SessionRequest_CreateSemaphore{
+ ReqId: newReqID(),
+ Name: name,
+ Limit: limit,
+ }
+ for _, o := range opts {
+ if o != nil {
+ o(&createSemaphore)
+ }
+ }
+
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_CreateSemaphore_{
+ CreateSemaphore: &createSemaphore,
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetCreateSemaphoreResult().GetReqId() == request.GetCreateSemaphore().GetReqId()
+ }),
+ )
+ if err := s.controller.PushBack(req); err != nil {
+ return err
+ }
+
+ _, err := s.controller.Await(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (s *session) UpdateSemaphore(
+ ctx context.Context,
+ name string,
+ opts ...options.UpdateSemaphoreOption,
+) error {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ updateSemaphore := Ydb_Coordination.SessionRequest_UpdateSemaphore{
+ ReqId: newReqID(),
+ Name: name,
+ }
+ for _, o := range opts {
+ if o != nil {
+ o(&updateSemaphore)
+ }
+ }
+
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_UpdateSemaphore_{
+ UpdateSemaphore: &updateSemaphore,
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetUpdateSemaphoreResult().GetReqId() == request.GetUpdateSemaphore().GetReqId()
+ }),
+ conversation.WithConflictKey(name),
+ conversation.WithIdempotence(true),
+ )
+ if err := s.controller.PushBack(req); err != nil {
+ return err
+ }
+
+ _, err := s.controller.Await(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (s *session) DeleteSemaphore(
+ ctx context.Context,
+ name string,
+ opts ...options.DeleteSemaphoreOption,
+) error {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ deleteSemaphore := Ydb_Coordination.SessionRequest_DeleteSemaphore{
+ ReqId: newReqID(),
+ Name: name,
+ }
+ for _, o := range opts {
+ if o != nil {
+ o(&deleteSemaphore)
+ }
+ }
+
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_DeleteSemaphore_{
+ DeleteSemaphore: &deleteSemaphore,
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetDeleteSemaphoreResult().GetReqId() == request.GetDeleteSemaphore().GetReqId()
+ }),
+ conversation.WithConflictKey(name),
+ )
+ if err := s.controller.PushBack(req); err != nil {
+ return err
+ }
+
+ _, err := s.controller.Await(ctx, req)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (s *session) DescribeSemaphore(
+ ctx context.Context,
+ name string,
+ opts ...options.DescribeSemaphoreOption,
+) (*coordination.SemaphoreDescription, error) {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ describeSemaphore := Ydb_Coordination.SessionRequest_DescribeSemaphore{
+ ReqId: newReqID(),
+ Name: name,
+ }
+ for _, o := range opts {
+ if o != nil {
+ o(&describeSemaphore)
+ }
+ }
+
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_DescribeSemaphore_{
+ DescribeSemaphore: &describeSemaphore,
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetDescribeSemaphoreResult().GetReqId() == request.GetDescribeSemaphore().GetReqId()
+ }),
+ conversation.WithConflictKey(name),
+ conversation.WithIdempotence(true),
+ )
+ if err := s.controller.PushBack(req); err != nil {
+ return nil, err
+ }
+
+ resp, err := s.controller.Await(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+
+ return convertSemaphoreDescription(resp.GetDescribeSemaphoreResult().GetSemaphoreDescription()), nil
+}
+
+func convertSemaphoreDescription(
+ desc *Ydb_Coordination.SemaphoreDescription,
+) *coordination.SemaphoreDescription {
+ var result coordination.SemaphoreDescription
+
+ if desc != nil {
+ result.Name = desc.GetName()
+ result.Limit = desc.GetLimit()
+ result.Ephemeral = desc.GetEphemeral()
+ result.Count = desc.GetCount()
+ result.Data = desc.GetData()
+ result.Owners = convertSemaphoreSessions(desc.GetOwners())
+ result.Waiters = convertSemaphoreSessions(desc.GetWaiters())
+ }
+
+ return &result
+}
+
+func convertSemaphoreSessions(
+ sessions []*Ydb_Coordination.SemaphoreSession,
+) []*coordination.SemaphoreSession {
+ if sessions == nil {
+ return nil
+ }
+
+ result := make([]*coordination.SemaphoreSession, len(sessions))
+ for i, s := range sessions {
+ result[i] = convertSemaphoreSession(s)
+ }
+
+ return result
+}
+
+func convertSemaphoreSession(
+ session *Ydb_Coordination.SemaphoreSession,
+) *coordination.SemaphoreSession {
+ var result coordination.SemaphoreSession
+
+ if session != nil {
+ result.SessionID = session.GetSessionId()
+ result.Count = session.GetCount()
+ result.OrderID = session.GetOrderId()
+ result.Data = session.GetData()
+ if session.GetTimeoutMillis() == math.MaxUint64 {
+ result.Timeout = time.Duration(math.MaxInt64)
+ } else {
+ // The service does not allow big timeout values, so the conversion seems to be safe.
+ result.Timeout = time.Duration(session.GetTimeoutMillis()) * time.Millisecond
+ }
+ }
+
+ return &result
+}
+
+func (s *session) AcquireSemaphore(
+ ctx context.Context,
+ name string,
+ count uint64,
+ opts ...options.AcquireSemaphoreOption,
+) (coordination.Lease, error) {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ acquireSemaphore := Ydb_Coordination.SessionRequest_AcquireSemaphore{
+ ReqId: newReqID(),
+ Name: name,
+ Count: count,
+ TimeoutMillis: math.MaxUint64,
+ }
+ for _, o := range opts {
+ if o != nil {
+ o(&acquireSemaphore)
+ }
+ }
+
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_AcquireSemaphore_{
+ AcquireSemaphore: &acquireSemaphore,
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetAcquireSemaphoreResult().GetReqId() == request.GetAcquireSemaphore().GetReqId()
+ }),
+ conversation.WithAcknowledgeFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetAcquireSemaphorePending().GetReqId() == request.GetAcquireSemaphore().GetReqId()
+ }),
+ conversation.WithCancelMessage(
+ func(request *Ydb_Coordination.SessionRequest) *Ydb_Coordination.SessionRequest {
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_ReleaseSemaphore_{
+ ReleaseSemaphore: &Ydb_Coordination.SessionRequest_ReleaseSemaphore{
+ Name: name,
+ ReqId: newReqID(),
+ },
+ },
+ }
+ },
+ func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetReleaseSemaphoreResult().GetReqId() == request.GetReleaseSemaphore().GetReqId()
+ },
+ ),
+ conversation.WithConflictKey(name),
+ conversation.WithIdempotence(true),
+ )
+ if err := s.controller.PushBack(req); err != nil {
+ return nil, err
+ }
+
+ resp, err := s.controller.Await(ctx, req)
+ if err != nil {
+ return nil, err
+ }
+
+ if !resp.GetAcquireSemaphoreResult().GetAcquired() {
+ return nil, coordination.ErrAcquireTimeout
+ }
+
+ ctx, cancel := context.WithCancel(s.ctx)
+
+ return &lease{
+ session: s,
+ name: name,
+ ctx: ctx,
+ cancel: cancel,
+ }, nil
+}
+
+func (l *lease) Context() context.Context {
+ return l.ctx
+}
+
+func (l *lease) Release() error {
+ req := conversation.NewConversation(
+ func() *Ydb_Coordination.SessionRequest {
+ return &Ydb_Coordination.SessionRequest{
+ Request: &Ydb_Coordination.SessionRequest_ReleaseSemaphore_{
+ ReleaseSemaphore: &Ydb_Coordination.SessionRequest_ReleaseSemaphore{
+ ReqId: newReqID(),
+ Name: l.name,
+ },
+ },
+ }
+ },
+ conversation.WithResponseFilter(func(
+ request *Ydb_Coordination.SessionRequest,
+ response *Ydb_Coordination.SessionResponse,
+ ) bool {
+ return response.GetReleaseSemaphoreResult().GetReqId() == request.GetReleaseSemaphore().GetReqId()
+ }),
+ conversation.WithConflictKey(l.name),
+ conversation.WithIdempotence(true),
+ )
+ if err := l.session.controller.PushBack(req); err != nil {
+ return err
+ }
+
+ _, err := l.session.controller.Await(l.session.ctx, req)
+ if err != nil {
+ return err
+ }
+
+ l.cancel()
+
+ return nil
+}
+
+func (l *lease) Session() coordination.Session {
+ return l.session
+}
diff --git a/internal/credentials/oauth2.go b/internal/credentials/oauth2.go
new file mode 100644
index 000000000..f49826127
--- /dev/null
+++ b/internal/credentials/oauth2.go
@@ -0,0 +1,846 @@
+package credentials
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/golang-jwt/jwt/v4"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/secret"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
+)
+
+const (
+ defaultRequestTimeout = time.Second * 10
+ defaultJWTTokenTTL = 3600 * time.Second
+ updateTimeDivider = 2
+)
+
+var (
+ errEmptyTokenEndpointError = errors.New("OAuth2 token exchange: empty token endpoint")
+ errCouldNotParseResponse = errors.New("OAuth2 token exchange: could not parse response")
+ errCouldNotExchangeToken = errors.New("OAuth2 token exchange: could not exchange token")
+ errUnsupportedTokenType = errors.New("OAuth2 token exchange: unsupported token type")
+ errIncorrectExpirationTime = errors.New("OAuth2 token exchange: incorrect expiration time")
+ errDifferentScope = errors.New("OAuth2 token exchange: got different scope")
+ errCouldNotMakeHTTPRequest = errors.New("OAuth2 token exchange: could not make http request")
+ errCouldNotApplyOption = errors.New("OAuth2 token exchange: could not apply option")
+ errCouldNotCreateTokenSource = errors.New("OAuth2 token exchange: could not createTokenSource")
+ errNoSigningMethodError = errors.New("JWT token source: no signing method")
+ errNoPrivateKeyError = errors.New("JWT token source: no private key")
+ errCouldNotSignJWTToken = errors.New("JWT token source: could not sign jwt token")
+ errCouldNotApplyJWTOption = errors.New("JWT token source: could not apply option")
+ errCouldNotparseRSAPrivateKey = errors.New("JWT token source: could not parse RSA private key from PEM")
+ errCouldNotParseHomeDir = errors.New("JWT token source: could not parse home dir for private key")
+ errCouldNotReadPrivateKeyFile = errors.New("JWT token source: could not read from private key file")
+)
+
+type Oauth2TokenExchangeCredentialsOption interface {
+ ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error
+}
+
+// TokenEndpoint
+type tokenEndpointOption string
+
+func (endpoint tokenEndpointOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.tokenEndpoint = string(endpoint)
+
+ return nil
+}
+
+func WithTokenEndpoint(endpoint string) tokenEndpointOption {
+ return tokenEndpointOption(endpoint)
+}
+
+// GrantType
+type grantTypeOption string
+
+func (grantType grantTypeOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.grantType = string(grantType)
+
+ return nil
+}
+
+func WithGrantType(grantType string) grantTypeOption {
+ return grantTypeOption(grantType)
+}
+
+// Resource
+type resourceOption string
+
+func (resource resourceOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.resource = string(resource)
+
+ return nil
+}
+
+func WithResource(resource string) resourceOption {
+ return resourceOption(resource)
+}
+
+// RequestedTokenType
+type requestedTokenTypeOption string
+
+func (requestedTokenType requestedTokenTypeOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.requestedTokenType = string(requestedTokenType)
+
+ return nil
+}
+
+func WithRequestedTokenType(requestedTokenType string) requestedTokenTypeOption {
+ return requestedTokenTypeOption(requestedTokenType)
+}
+
+// Audience
+type audienceOption []string
+
+func (audience audienceOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.audience = audience
+
+ return nil
+}
+
+func WithAudience(audience ...string) audienceOption {
+ return audience
+}
+
+// Scope
+type scopeOption []string
+
+func (scope scopeOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.scope = scope
+
+ return nil
+}
+
+func WithScope(scope ...string) scopeOption {
+ return scope
+}
+
+// RequestTimeout
+type requestTimeoutOption time.Duration
+
+func (timeout requestTimeoutOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ c.requestTimeout = time.Duration(timeout)
+
+ return nil
+}
+
+func WithRequestTimeout(timeout time.Duration) requestTimeoutOption {
+ return requestTimeoutOption(timeout)
+}
+
+const (
+ SubjectTokenSourceType = 1
+ ActorTokenSourceType = 2
+)
+
+// SubjectTokenSource/ActorTokenSource
+type tokenSourceOption struct {
+ source TokenSource
+ createFunc func() (TokenSource, error)
+ tokenSourceType int
+}
+
+func (tokenSource *tokenSourceOption) ApplyOauth2CredentialsOption(c *oauth2TokenExchange) error {
+ src := tokenSource.source
+ var err error
+ if src == nil {
+ src, err = tokenSource.createFunc()
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotCreateTokenSource, err))
+ }
+ }
+ switch tokenSource.tokenSourceType {
+ case SubjectTokenSourceType:
+ c.subjectTokenSource = src
+ case ActorTokenSourceType:
+ c.actorTokenSource = src
+ }
+
+ return nil
+}
+
+func WithSubjectToken(subjectToken TokenSource) *tokenSourceOption {
+ return &tokenSourceOption{
+ source: subjectToken,
+ tokenSourceType: SubjectTokenSourceType,
+ }
+}
+
+func WithFixedSubjectToken(token, tokenType string) *tokenSourceOption {
+ return &tokenSourceOption{
+ createFunc: func() (TokenSource, error) {
+ return NewFixedTokenSource(token, tokenType), nil
+ },
+ tokenSourceType: SubjectTokenSourceType,
+ }
+}
+
+func WithJWTSubjectToken(opts ...JWTTokenSourceOption) *tokenSourceOption {
+ return &tokenSourceOption{
+ createFunc: func() (TokenSource, error) {
+ return NewJWTTokenSource(opts...)
+ },
+ tokenSourceType: SubjectTokenSourceType,
+ }
+}
+
+// ActorTokenSource
+func WithActorToken(actorToken TokenSource) *tokenSourceOption {
+ return &tokenSourceOption{
+ source: actorToken,
+ tokenSourceType: ActorTokenSourceType,
+ }
+}
+
+func WithFixedActorToken(token, tokenType string) *tokenSourceOption {
+ return &tokenSourceOption{
+ createFunc: func() (TokenSource, error) {
+ return NewFixedTokenSource(token, tokenType), nil
+ },
+ tokenSourceType: ActorTokenSourceType,
+ }
+}
+
+func WithJWTActorToken(opts ...JWTTokenSourceOption) *tokenSourceOption {
+ return &tokenSourceOption{
+ createFunc: func() (TokenSource, error) {
+ return NewJWTTokenSource(opts...)
+ },
+ tokenSourceType: ActorTokenSourceType,
+ }
+}
+
+type oauth2TokenExchange struct {
+ tokenEndpoint string
+
+ // grant_type parameter
+ // urn:ietf:params:oauth:grant-type:token-exchange by default
+ grantType string
+
+ resource string
+ audience []string
+ scope []string
+
+ // requested_token_type parameter
+ // urn:ietf:params:oauth:token-type:access_token by default
+ requestedTokenType string
+
+ subjectTokenSource TokenSource
+
+ actorTokenSource TokenSource
+
+ // Http request timeout
+ // 10 by default
+ requestTimeout time.Duration
+
+ // Received data
+ receivedToken string
+ updateTokenTime time.Time
+ receivedTokenExpireTime time.Time
+
+ mutex sync.RWMutex
+ updating atomic.Bool // true if separate goroutine is run and updates token in background
+
+ sourceInfo string
+}
+
+func NewOauth2TokenExchangeCredentials(
+ opts ...Oauth2TokenExchangeCredentialsOption,
+) (*oauth2TokenExchange, error) {
+ c := &oauth2TokenExchange{
+ grantType: "urn:ietf:params:oauth:grant-type:token-exchange",
+ requestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
+ requestTimeout: defaultRequestTimeout,
+ sourceInfo: stack.Record(1),
+ }
+
+ var err error
+ for _, opt := range opts {
+ if opt != nil {
+ err = opt.ApplyOauth2CredentialsOption(c)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotApplyOption, err))
+ }
+ }
+ }
+
+ if c.tokenEndpoint == "" {
+ return nil, xerrors.WithStackTrace(errEmptyTokenEndpointError)
+ }
+
+ return c, nil
+}
+
+func (provider *oauth2TokenExchange) getScopeParam() string {
+ var scope string
+ if len(provider.scope) != 0 {
+ for _, s := range provider.scope {
+ if s != "" {
+ if scope != "" {
+ scope += " "
+ }
+ scope += s
+ }
+ }
+ }
+
+ return scope
+}
+
+func (provider *oauth2TokenExchange) addTokenSrc(params *url.Values, src TokenSource, tName, tTypeName string) error {
+ if src != nil {
+ token, err := src.Token()
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ params.Set(tName, token.Token)
+ params.Set(tTypeName, token.TokenType)
+ }
+
+ return nil
+}
+
+func (provider *oauth2TokenExchange) getRequestParams() (string, error) {
+ params := url.Values{}
+ params.Set("grant_type", provider.grantType)
+ if provider.resource != "" {
+ params.Set("resource", provider.resource)
+ }
+ for _, aud := range provider.audience {
+ if aud != "" {
+ params.Add("audience", aud)
+ }
+ }
+ scope := provider.getScopeParam()
+ if scope != "" {
+ params.Set("scope", scope)
+ }
+
+ params.Set("requested_token_type", provider.requestedTokenType)
+
+ err := provider.addTokenSrc(¶ms, provider.subjectTokenSource, "subject_token", "subject_token_type")
+ if err != nil {
+ return "", xerrors.WithStackTrace(err)
+ }
+
+ err = provider.addTokenSrc(¶ms, provider.actorTokenSource, "actor_token", "actor_token_type")
+ if err != nil {
+ return "", xerrors.WithStackTrace(err)
+ }
+
+ return params.Encode(), nil
+}
+
+func (provider *oauth2TokenExchange) processTokenExchangeResponse(result *http.Response, now time.Time) error {
+ var (
+ data []byte
+ err error
+ )
+ if result.Body != nil {
+ data, err = io.ReadAll(result.Body)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+ } else {
+ data = make([]byte, 0)
+ }
+
+ if result.StatusCode != http.StatusOK {
+ description := result.Status
+
+ //nolint:tagliatelle
+ type errorResponse struct {
+ ErrorName string `json:"error"`
+ ErrorDescription string `json:"error_description"`
+ ErrorURI string `json:"error_uri"`
+ }
+ var parsedErrorResponse errorResponse
+ if err := json.Unmarshal(data, &parsedErrorResponse); err != nil {
+ description += ", could not parse response: " + err.Error()
+
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %s", errCouldNotExchangeToken, description))
+ }
+
+ if parsedErrorResponse.ErrorName != "" {
+ description += ", error: " + parsedErrorResponse.ErrorName
+ }
+
+ if parsedErrorResponse.ErrorDescription != "" {
+ description += fmt.Sprintf(", description: %q", parsedErrorResponse.ErrorDescription)
+ }
+
+ if parsedErrorResponse.ErrorURI != "" {
+ description += ", error_uri: " + parsedErrorResponse.ErrorURI
+ }
+
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %s", errCouldNotExchangeToken, description))
+ }
+
+ //nolint:tagliatelle
+ type response struct {
+ AccessToken string `json:"access_token"`
+ TokenType string `json:"token_type"`
+ ExpiresIn int64 `json:"expires_in"`
+ Scope string `json:"scope"`
+ }
+ var parsedResponse response
+ if err := json.Unmarshal(data, &parsedResponse); err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotParseResponse, err))
+ }
+
+ if !strings.EqualFold(parsedResponse.TokenType, "bearer") {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w: %q", errUnsupportedTokenType, parsedResponse.TokenType))
+ }
+
+ if parsedResponse.ExpiresIn <= 0 {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w: %d", errIncorrectExpirationTime, parsedResponse.ExpiresIn))
+ }
+
+ if parsedResponse.Scope != "" {
+ scope := provider.getScopeParam()
+ if parsedResponse.Scope != scope {
+ return xerrors.WithStackTrace(
+ fmt.Errorf("%w. Expected %q, but got %q", errDifferentScope, scope, parsedResponse.Scope))
+ }
+ }
+
+ provider.receivedToken = "Bearer " + parsedResponse.AccessToken
+
+ // Expire time
+ expireDelta := time.Duration(parsedResponse.ExpiresIn)
+ expireDelta *= time.Second
+ provider.receivedTokenExpireTime = now.Add(expireDelta)
+
+ updateDelta := time.Duration(parsedResponse.ExpiresIn / updateTimeDivider)
+ updateDelta *= time.Second
+ provider.updateTokenTime = now.Add(updateDelta)
+
+ return nil
+}
+
+func (provider *oauth2TokenExchange) exchangeToken(ctx context.Context, now time.Time) error {
+ body, err := provider.getRequestParams()
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotMakeHTTPRequest, err))
+ }
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, provider.tokenEndpoint, strings.NewReader(body))
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotMakeHTTPRequest, err))
+ }
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Add("Content-Length", strconv.Itoa(len(body)))
+ req.Close = true
+
+ client := http.Client{
+ Transport: http.DefaultTransport,
+ Timeout: provider.requestTimeout,
+ }
+
+ result, err := client.Do(req)
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotExchangeToken, err))
+ }
+
+ defer result.Body.Close()
+
+ return provider.processTokenExchangeResponse(result, now)
+}
+
+func (provider *oauth2TokenExchange) exchangeTokenInBackground() {
+ provider.mutex.Lock()
+ defer provider.mutex.Unlock()
+
+ now := time.Now()
+ if !provider.needUpdate(now) {
+ return
+ }
+
+ ctx := context.Background()
+ _ = provider.exchangeToken(ctx, now)
+
+ provider.updating.Store(false)
+}
+
+func (provider *oauth2TokenExchange) checkBackgroundUpdate(now time.Time) {
+ if provider.needUpdate(now) && !provider.updating.Load() {
+ if provider.updating.CompareAndSwap(false, true) {
+ go provider.exchangeTokenInBackground()
+ }
+ }
+}
+
+func (provider *oauth2TokenExchange) expired(now time.Time) bool {
+ return now.Compare(provider.receivedTokenExpireTime) > 0
+}
+
+func (provider *oauth2TokenExchange) needUpdate(now time.Time) bool {
+ return now.Compare(provider.updateTokenTime) > 0
+}
+
+func (provider *oauth2TokenExchange) fastCheck(now time.Time) string {
+ provider.mutex.RLock()
+ defer provider.mutex.RUnlock()
+
+ if !provider.expired(now) {
+ provider.checkBackgroundUpdate(now)
+
+ return provider.receivedToken
+ }
+
+ return ""
+}
+
+func (provider *oauth2TokenExchange) Token(ctx context.Context) (string, error) {
+ now := time.Now()
+
+ token := provider.fastCheck(now)
+ if token != "" {
+ return token, nil
+ }
+
+ provider.mutex.Lock()
+ defer provider.mutex.Unlock()
+
+ if !provider.expired(now) {
+ return provider.receivedToken, nil
+ }
+
+ if err := provider.exchangeToken(ctx, now); err != nil {
+ return "", err
+ }
+
+ return provider.receivedToken, nil
+}
+
+func (provider *oauth2TokenExchange) String() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ fmt.Fprintf(
+ buffer,
+ "OAuth2TokenExchange{Endpoint:%q,GrantType:%s,Resource:%s,Audience:%v,Scope:%v,RequestedTokenType:%s",
+ provider.tokenEndpoint,
+ provider.grantType,
+ provider.resource,
+ provider.audience,
+ provider.scope,
+ provider.requestedTokenType,
+ )
+ if provider.subjectTokenSource != nil {
+ fmt.Fprintf(buffer, ",SubjectToken:%s", provider.subjectTokenSource)
+ }
+ if provider.actorTokenSource != nil {
+ fmt.Fprintf(buffer, ",ActorToken:%s", provider.actorTokenSource)
+ }
+ if provider.sourceInfo != "" {
+ fmt.Fprintf(buffer, ",From:%q", provider.sourceInfo)
+ }
+ buffer.WriteByte('}')
+
+ return buffer.String()
+}
+
+type Token struct {
+ Token string
+
+ // token type according to OAuth 2.0 token exchange protocol
+ // https://www.rfc-editor.org/rfc/rfc8693#TokenTypeIdentifiers
+ // for example urn:ietf:params:oauth:token-type:jwt
+ TokenType string
+}
+
+type TokenSource interface {
+ Token() (Token, error)
+}
+
+type fixedTokenSource struct {
+ fixedToken Token
+}
+
+func (s *fixedTokenSource) Token() (Token, error) {
+ return s.fixedToken, nil
+}
+
+func (s *fixedTokenSource) String() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ fmt.Fprintf(
+ buffer,
+ "FixedTokenSource{Token:%q,Type:%s}",
+ secret.Token(s.fixedToken.Token),
+ s.fixedToken.TokenType,
+ )
+
+ return buffer.String()
+}
+
+func NewFixedTokenSource(token, tokenType string) *fixedTokenSource {
+ return &fixedTokenSource{
+ fixedToken: Token{
+ Token: token,
+ TokenType: tokenType,
+ },
+ }
+}
+
+type JWTTokenSourceOption interface {
+ ApplyJWTTokenSourceOption(s *jwtTokenSource) error
+}
+
+// Issuer
+type issuerOption string
+
+func (issuer issuerOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.issuer = string(issuer)
+
+ return nil
+}
+
+func WithIssuer(issuer string) issuerOption {
+ return issuerOption(issuer)
+}
+
+// Subject
+type subjectOption string
+
+func (subject subjectOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.subject = string(subject)
+
+ return nil
+}
+
+func WithSubject(subject string) subjectOption {
+ return subjectOption(subject)
+}
+
+// Audience
+func (audience audienceOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.audience = audience
+
+ return nil
+}
+
+// ID
+type idOption string
+
+func (id idOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.id = string(id)
+
+ return nil
+}
+
+func WithID(id string) idOption {
+ return idOption(id)
+}
+
+// TokenTTL
+type tokenTTLOption time.Duration
+
+func (ttl tokenTTLOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.tokenTTL = time.Duration(ttl)
+
+ return nil
+}
+
+func WithTokenTTL(ttl time.Duration) tokenTTLOption {
+ return tokenTTLOption(ttl)
+}
+
+// SigningMethod
+type signingMethodOption struct {
+ method jwt.SigningMethod
+}
+
+func (method *signingMethodOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.signingMethod = method.method
+
+ return nil
+}
+
+func WithSigningMethod(method jwt.SigningMethod) *signingMethodOption {
+ return &signingMethodOption{method}
+}
+
+// KeyID
+type keyIDOption string
+
+func (id keyIDOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.keyID = string(id)
+
+ return nil
+}
+
+func WithKeyID(id string) keyIDOption {
+ return keyIDOption(id)
+}
+
+// PrivateKey
+type privateKeyOption struct {
+ key interface{}
+}
+
+func (key *privateKeyOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ s.privateKey = key.key
+
+ return nil
+}
+
+func WithPrivateKey(key interface{}) *privateKeyOption {
+ return &privateKeyOption{key}
+}
+
+// PrivateKey
+type rsaPrivateKeyPemContentOption struct {
+ keyContent []byte
+}
+
+func (key *rsaPrivateKeyPemContentOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(key.keyContent)
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotparseRSAPrivateKey, err))
+ }
+ s.privateKey = privateKey
+
+ return nil
+}
+
+func WithRSAPrivateKeyPEMContent(key []byte) *rsaPrivateKeyPemContentOption {
+ return &rsaPrivateKeyPemContentOption{key}
+}
+
+// PrivateKey
+type rsaPrivateKeyPemFileOption struct {
+ path string
+}
+
+func (key *rsaPrivateKeyPemFileOption) ApplyJWTTokenSourceOption(s *jwtTokenSource) error {
+ if len(key.path) > 0 && key.path[0] == '~' {
+ usr, err := user.Current()
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotParseHomeDir, err))
+ }
+ key.path = filepath.Join(usr.HomeDir, key.path[1:])
+ }
+ bytes, err := os.ReadFile(key.path)
+ if err != nil {
+ return xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotReadPrivateKeyFile, err))
+ }
+
+ o := rsaPrivateKeyPemContentOption{bytes}
+
+ return o.ApplyJWTTokenSourceOption(s)
+}
+
+func WithRSAPrivateKeyPEMFile(path string) *rsaPrivateKeyPemFileOption {
+ return &rsaPrivateKeyPemFileOption{path}
+}
+
+func NewJWTTokenSource(opts ...JWTTokenSourceOption) (*jwtTokenSource, error) {
+ s := &jwtTokenSource{
+ tokenTTL: defaultJWTTokenTTL,
+ }
+
+ var err error
+ for _, opt := range opts {
+ if opt != nil {
+ err = opt.ApplyJWTTokenSourceOption(s)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotApplyJWTOption, err))
+ }
+ }
+ }
+
+ if s.signingMethod == nil {
+ return nil, xerrors.WithStackTrace(errNoSigningMethodError)
+ }
+
+ if s.privateKey == nil {
+ return nil, xerrors.WithStackTrace(errNoPrivateKeyError)
+ }
+
+ return s, nil
+}
+
+type jwtTokenSource struct {
+ signingMethod jwt.SigningMethod
+ keyID string
+ privateKey interface{} // symmetric key in case of symmetric algorithm
+
+ // JWT claims
+ issuer string
+ subject string
+ audience []string
+ id string
+ tokenTTL time.Duration
+}
+
+func (s *jwtTokenSource) Token() (Token, error) {
+ var (
+ now = time.Now()
+ issued = jwt.NewNumericDate(now.UTC())
+ expire = jwt.NewNumericDate(now.Add(s.tokenTTL).UTC())
+ err error
+ )
+ t := jwt.Token{
+ Header: map[string]interface{}{
+ "typ": "JWT",
+ "alg": s.signingMethod.Alg(),
+ "kid": s.keyID,
+ },
+ Claims: jwt.RegisteredClaims{
+ Issuer: s.issuer,
+ Subject: s.subject,
+ IssuedAt: issued,
+ Audience: s.audience,
+ ExpiresAt: expire,
+ ID: s.id,
+ },
+ Method: s.signingMethod,
+ }
+
+ var token Token
+ token.Token, err = t.SignedString(s.privateKey)
+ if err != nil {
+ return token, xerrors.WithStackTrace(fmt.Errorf("%w: %w", errCouldNotSignJWTToken, err))
+ }
+ token.TokenType = "urn:ietf:params:oauth:token-type:jwt"
+
+ return token, nil
+}
+
+func (s *jwtTokenSource) String() string {
+ buffer := xstring.Buffer()
+ defer buffer.Free()
+ fmt.Fprintf(
+ buffer,
+ "JWTTokenSource{Method:%s,KeyID:%s,Issuer:%q,Subject:%q,Audience:%v,ID:%s,TokenTTL:%s}",
+ s.signingMethod.Alg(),
+ s.keyID,
+ s.issuer,
+ s.subject,
+ s.audience,
+ s.id,
+ s.tokenTTL,
+ )
+
+ return buffer.String()
+}
diff --git a/internal/credentials/oauth2_test.go b/internal/credentials/oauth2_test.go
new file mode 100644
index 000000000..3ce391961
--- /dev/null
+++ b/internal/credentials/oauth2_test.go
@@ -0,0 +1,470 @@
+package credentials
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "os/user"
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/golang-jwt/jwt/v4"
+ "github.com/stretchr/testify/require"
+)
+
+var (
+ testPrivateKeyContent = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC75/JS3rMcLJxv\nFgpOzF5+2gH+Yig3RE2MTl9uwC0BZKAv6foYr7xywQyWIK+W1cBhz8R4LfFmZo2j\nM0aCvdRmNBdW0EDSTnHLxCsFhoQWLVq+bI5f5jzkcoiioUtaEpADPqwgVULVtN/n\nnPJiZ6/dU30C3jmR6+LUgEntUtWt3eq3xQIn5lG3zC1klBY/HxtfH5Hu8xBvwRQT\nJnh3UpPLj8XwSmriDgdrhR7o6umWyVuGrMKlLHmeivlfzjYtfzO1MOIMG8t2/zxG\nR+xb4Vwks73sH1KruH/0/JMXU97npwpe+Um+uXhpldPygGErEia7abyZB2gMpXqr\nWYKMo02NAgMBAAECggEAO0BpC5OYw/4XN/optu4/r91bupTGHKNHlsIR2rDzoBhU\nYLd1evpTQJY6O07EP5pYZx9mUwUdtU4KRJeDGO/1/WJYp7HUdtxwirHpZP0lQn77\nuccuX/QQaHLrPekBgz4ONk+5ZBqukAfQgM7fKYOLk41jgpeDbM2Ggb6QUSsJISEp\nzrwpI/nNT/wn+Hvx4DxrzWU6wF+P8kl77UwPYlTA7GsT+T7eKGVH8xsxmK8pt6lg\nsvlBA5XosWBWUCGLgcBkAY5e4ZWbkdd183o+oMo78id6C+PQPE66PLDtHWfpRRmN\nm6XC03x6NVhnfvfozoWnmS4+e4qj4F/emCHvn0GMywKBgQDLXlj7YPFVXxZpUvg/\nrheVcCTGbNmQJ+4cZXx87huqwqKgkmtOyeWsRc7zYInYgraDrtCuDBCfP//ZzOh0\nLxepYLTPk5eNn/GT+VVrqsy35Ccr60g7Lp/bzb1WxyhcLbo0KX7/6jl0lP+VKtdv\nmto+4mbSBXSM1Y5BVVoVgJ3T/wKBgQDsiSvPRzVi5TTj13x67PFymTMx3HCe2WzH\nJUyepCmVhTm482zW95pv6raDr5CTO6OYpHtc5sTTRhVYEZoEYFTM9Vw8faBtluWG\nBjkRh4cIpoIARMn74YZKj0C/0vdX7SHdyBOU3bgRPHg08Hwu3xReqT1kEPSI/B2V\n4pe5fVrucwKBgQCNFgUxUA3dJjyMES18MDDYUZaRug4tfiYouRdmLGIxUxozv6CG\nZnbZzwxFt+GpvPUV4f+P33rgoCvFU+yoPctyjE6j+0aW0DFucPmb2kBwCu5J/856\nkFwCx3blbwFHAco+SdN7g2kcwgmV2MTg/lMOcU7XwUUcN0Obe7UlWbckzQKBgQDQ\nnXaXHL24GGFaZe4y2JFmujmNy1dEsoye44W9ERpf9h1fwsoGmmCKPp90az5+rIXw\nFXl8CUgk8lXW08db/r4r+ma8Lyx0GzcZyplAnaB5/6j+pazjSxfO4KOBy4Y89Tb+\nTP0AOcCi6ws13bgY+sUTa/5qKA4UVw+c5zlb7nRpgwKBgGXAXhenFw1666482iiN\ncHSgwc4ZHa1oL6aNJR1XWH+aboBSwR+feKHUPeT4jHgzRGo/aCNHD2FE5I8eBv33\nof1kWYjAO0YdzeKrW0rTwfvt9gGg+CS397aWu4cy+mTI+MNfBgeDAIVBeJOJXLlX\nhL8bFAuNNVrCOp79TNnNIsh7\n-----END PRIVATE KEY-----\n" //nolint:lll
+ testPublicKeyContent = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu+fyUt6zHCycbxYKTsxe\nftoB/mIoN0RNjE5fbsAtAWSgL+n6GK+8csEMliCvltXAYc/EeC3xZmaNozNGgr3U\nZjQXVtBA0k5xy8QrBYaEFi1avmyOX+Y85HKIoqFLWhKQAz6sIFVC1bTf55zyYmev\n3VN9At45kevi1IBJ7VLVrd3qt8UCJ+ZRt8wtZJQWPx8bXx+R7vMQb8EUEyZ4d1KT\ny4/F8Epq4g4Ha4Ue6OrplslbhqzCpSx5nor5X842LX8ztTDiDBvLdv88RkfsW+Fc\nJLO97B9Sq7h/9PyTF1Pe56cKXvlJvrl4aZXT8oBhKxImu2m8mQdoDKV6q1mCjKNN\njQIDAQAB\n-----END PUBLIC KEY-----\n" //nolint:lll
+)
+
+type httpServerKey int
+
+const (
+ keyServerAddr httpServerKey = 42
+)
+
+func WriteErr(w http.ResponseWriter, err error) {
+ WriteResponse(w, http.StatusInternalServerError, err.Error(), "text/html")
+}
+
+func WriteResponse(w http.ResponseWriter, code int, body string, bodyType string) {
+ w.Header().Add("Content-Type", bodyType)
+ w.Header().Add("Content-Length", strconv.Itoa(len(body)))
+ w.WriteHeader(code)
+ _, _ = w.Write([]byte(body))
+}
+
+func runTokenExchangeServer(
+ ctx context.Context,
+ cancel context.CancelFunc,
+ port int,
+ currentTestParams *Oauth2TokenExchangeTestParams,
+) {
+ defer cancel()
+ mux := http.NewServeMux()
+ mux.HandleFunc("/exchange", func(w http.ResponseWriter, r *http.Request) {
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ WriteErr(w, err)
+ }
+
+ fmt.Printf("got token exchange request: %s\n", body)
+
+ params, err := url.ParseQuery(string(body))
+ if err != nil {
+ WriteErr(w, err)
+ }
+ expectedParams := url.Values{}
+ expectedParams.Set("scope", "test_scope1 test_scope2")
+ expectedParams.Set("audience", "test_audience")
+ expectedParams.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")
+ expectedParams.Set("requested_token_type", "urn:ietf:params:oauth:token-type:access_token")
+ expectedParams.Set("subject_token", "test_source_token")
+ expectedParams.Set("subject_token_type", "urn:ietf:params:oauth:token-type:test_jwt")
+
+ if !reflect.DeepEqual(expectedParams, params) {
+ WriteResponse(w, 555, fmt.Sprintf("Params are not as expected: \"%s\" != \"%s\"",
+ expectedParams.Encode(), body), "text/html") // error will be checked in test thread
+ } else {
+ WriteResponse(w, currentTestParams.Status, currentTestParams.Response, "application/json")
+ }
+ })
+ server := http.Server{
+ Addr: fmt.Sprintf(":%d", port),
+ Handler: mux,
+ BaseContext: func(l net.Listener) context.Context {
+ ctx = context.WithValue(ctx, keyServerAddr, l.Addr().String())
+
+ return ctx
+ },
+ ReadHeaderTimeout: 10 * time.Second,
+ }
+ err := server.ListenAndServe()
+ if err != nil {
+ fmt.Printf("Failed to run http server: %s", err.Error())
+ }
+}
+
+type Oauth2TokenExchangeTestParams struct {
+ Response string
+ Status int
+ ExpectedToken string
+ ExpectedError error
+ ExpectedErrorPart string
+}
+
+func TestOauth2TokenExchange(t *testing.T) {
+ var currentTestParams Oauth2TokenExchangeTestParams
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ runCtx, runCancel := context.WithCancel(ctx)
+ go runTokenExchangeServer(runCtx, runCancel, 14321, ¤tTestParams)
+
+ testsParams := []Oauth2TokenExchangeTestParams{
+ {
+ Response: `{"access_token":"test_token","token_type":"BEARER","expires_in":42,"some_other_field":"x"}`,
+ Status: http.StatusOK,
+ ExpectedToken: "Bearer test_token",
+ },
+ {
+ Response: `aaa`,
+ Status: http.StatusOK,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotParseResponse,
+ },
+ {
+ Response: `{}`,
+ Status: http.StatusBadRequest,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotExchangeToken,
+ },
+ {
+ Response: `not json`,
+ Status: http.StatusNotFound,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotExchangeToken,
+ },
+ {
+ Response: `{"error": "invalid_request"}`,
+ Status: http.StatusBadRequest,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotExchangeToken,
+ ExpectedErrorPart: "400 Bad Request, error: invalid_request",
+ },
+ {
+ Response: `{"error":"unauthorized_client","error_description":"something went bad"}`,
+ Status: http.StatusInternalServerError,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotExchangeToken,
+ ExpectedErrorPart: "500 Internal Server Error, error: unauthorized_client, description: \"something went bad\"", //nolint:lll
+ },
+ {
+ Response: `{"error_description":"something went bad","error_uri":"my_error_uri"}`,
+ Status: http.StatusForbidden,
+ ExpectedToken: "",
+ ExpectedError: errCouldNotExchangeToken,
+ ExpectedErrorPart: "403 Forbidden, description: \"something went bad\", error_uri: my_error_uri",
+ },
+ {
+ Response: `{"access_token":"test_token","token_type":"","expires_in":42,"some_other_field":"x"}`,
+ Status: http.StatusOK,
+ ExpectedToken: "",
+ ExpectedError: errUnsupportedTokenType,
+ },
+ {
+ Response: `{"access_token":"test_token","token_type":"basic","expires_in":42,"some_other_field":"x"}`,
+ Status: http.StatusOK,
+ ExpectedToken: "",
+ ExpectedError: errUnsupportedTokenType,
+ },
+ {
+ Response: `{"access_token":"test_token","token_type":"Bearer","expires_in":-42,"some_other_field":"x"}`,
+ Status: http.StatusOK,
+ ExpectedToken: "",
+ ExpectedError: errIncorrectExpirationTime,
+ },
+ {
+ Response: `{"access_token":"test_token","token_type":"Bearer","expires_in":42,"scope":"s"}`,
+ Status: http.StatusOK,
+ ExpectedToken: "",
+ ExpectedError: errDifferentScope,
+ ExpectedErrorPart: "Expected \"test_scope1 test_scope2\", but got \"s\"",
+ },
+ }
+
+ for _, params := range testsParams {
+ currentTestParams = params
+
+ client, err := NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http://localhost:14321/exchange"),
+ WithAudience("test_audience"),
+ WithScope("test_scope1", "test_scope2"),
+ WithSubjectToken(NewFixedTokenSource("test_source_token", "urn:ietf:params:oauth:token-type:test_jwt")),
+ )
+ require.NoError(t, err)
+
+ token, err := client.Token(ctx)
+ if params.ExpectedErrorPart == "" && params.ExpectedError == nil {
+ require.NoError(t, err)
+ } else {
+ if params.ExpectedErrorPart != "" {
+ require.ErrorContains(t, err, params.ExpectedErrorPart)
+ }
+ if params.ExpectedError != nil {
+ require.ErrorIs(t, err, params.ExpectedError)
+ }
+ }
+ require.Equal(t, params.ExpectedToken, token)
+ }
+}
+
+func TestOauth2TokenUpdate(t *testing.T) {
+ var currentTestParams Oauth2TokenExchangeTestParams
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ runCtx, runCancel := context.WithCancel(ctx)
+ go runTokenExchangeServer(runCtx, runCancel, 14322, ¤tTestParams)
+
+ // First exchange
+ currentTestParams = Oauth2TokenExchangeTestParams{
+ Response: `{"access_token":"test_token_1", "token_type":"Bearer","expires_in":2}`,
+ Status: http.StatusOK,
+ }
+
+ client, err := NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http://localhost:14322/exchange"),
+ WithAudience("test_audience"),
+ WithScope("test_scope1", "test_scope2"),
+ WithFixedSubjectToken("test_source_token", "urn:ietf:params:oauth:token-type:test_jwt"),
+ )
+ require.NoError(t, err)
+
+ token, err := client.Token(ctx)
+ t1 := time.Now()
+ require.NoError(t, err)
+ require.Equal(t, "Bearer test_token_1", token)
+
+ // Second exchange
+ currentTestParams = Oauth2TokenExchangeTestParams{
+ Response: `{"access_token":"test_token_2", "token_type":"Bearer","expires_in":10000}`,
+ Status: http.StatusOK,
+ }
+
+ token, err = client.Token(ctx)
+ t2 := time.Now()
+ require.NoError(t, err)
+ if t2.Sub(t1) <= time.Second { // half expire period => no attempts to update
+ require.Equal(t, "Bearer test_token_1", token)
+ }
+
+ time.Sleep(time.Second) // wait half expire period
+ for i := 1; i <= 100; i++ {
+ t3 := time.Now()
+ token, err = client.Token(ctx)
+ require.NoError(t, err)
+ if t3.Sub(t1) >= 2*time.Second {
+ require.Equal(t, "Bearer test_token_2", token) // Must update at least sync
+ }
+ if token == "Bearer test_token_2" { // already updated
+ break
+ }
+ require.Equal(t, "Bearer test_token_1", token)
+
+ time.Sleep(10 * time.Millisecond)
+ }
+
+ // Third exchange (never got, because token will be expired later)
+ currentTestParams = Oauth2TokenExchangeTestParams{
+ Response: `{}`,
+ Status: http.StatusInternalServerError,
+ }
+
+ for i := 1; i <= 5; i++ {
+ token, err = client.Token(ctx)
+ require.NoError(t, err)
+ require.Equal(t, "Bearer test_token_2", token)
+ }
+}
+
+func TestWrongParameters(t *testing.T) {
+ _, err := NewOauth2TokenExchangeCredentials(
+ // No endpoint
+ WithFixedActorToken("test_source_token", "urn:ietf:params:oauth:token-type:test_jwt"),
+ WithRequestedTokenType("access_token"),
+ )
+ require.ErrorIs(t, err, errEmptyTokenEndpointError)
+}
+
+type errorTokenSource struct{}
+
+var errTokenSource = errors.New("test error")
+
+func (s *errorTokenSource) Token() (Token, error) {
+ return Token{"", ""}, errTokenSource
+}
+
+func TestErrorInSourceToken(t *testing.T) {
+ // Create
+ _, err := NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http:trololo"),
+ WithJWTSubjectToken(
+ WithRSAPrivateKeyPEMContent([]byte("invalid")),
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ WithAudience("test_audience"),
+ ),
+ )
+ require.ErrorIs(t, err, errCouldNotCreateTokenSource)
+
+ // Use
+ client, err := NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http:trololo"),
+ WithGrantType("grant_type"),
+ WithRequestTimeout(time.Second),
+ WithResource("res"),
+ WithFixedSubjectToken("t", "tt"),
+ WithActorToken(&errorTokenSource{}),
+ WithSourceInfo("TestErrorInSourceToken"),
+ )
+ require.NoError(t, err)
+
+ // Check that token prints well
+ formatted := fmt.Sprint(client)
+ require.Equal(t, `OAuth2TokenExchange{Endpoint:"http:trololo",GrantType:grant_type,Resource:res,Audience:[],Scope:[],RequestedTokenType:urn:ietf:params:oauth:token-type:access_token,SubjectToken:FixedTokenSource{Token:"****(CRC-32c: 856A5AA8)",Type:tt},ActorToken:&{},From:"TestErrorInSourceToken"}`, formatted) //nolint:lll
+
+ token, err := client.Token(context.Background())
+ require.ErrorIs(t, err, errTokenSource)
+ require.Equal(t, "", token)
+
+ client, err = NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http:trololo"),
+ WithGrantType("grant_type"),
+ WithRequestTimeout(time.Second),
+ WithResource("res"),
+ WithSubjectToken(&errorTokenSource{}),
+ )
+ require.NoError(t, err)
+
+ token, err = client.Token(context.Background())
+ require.ErrorIs(t, err, errTokenSource)
+ require.Equal(t, "", token)
+}
+
+func TestErrorInHTTPRequest(t *testing.T) {
+ client, err := NewOauth2TokenExchangeCredentials(
+ WithTokenEndpoint("http://invalid_host:42/exchange"),
+ WithJWTSubjectToken(
+ WithRSAPrivateKeyPEMContent([]byte(testPrivateKeyContent)),
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ WithAudience("test_audience"),
+ ),
+ WithJWTActorToken(
+ WithRSAPrivateKeyPEMContent([]byte(testPrivateKeyContent)),
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ ),
+ WithScope("1", "2", "3"),
+ WithSourceInfo("TestErrorInHTTPRequest"),
+ )
+ require.NoError(t, err)
+
+ token, err := client.Token(context.Background())
+ require.ErrorIs(t, err, errCouldNotExchangeToken)
+ require.Equal(t, "", token)
+
+ // check format:
+ formatted := fmt.Sprint(client)
+ require.Equal(t, `OAuth2TokenExchange{Endpoint:"http://invalid_host:42/exchange",GrantType:urn:ietf:params:oauth:grant-type:token-exchange,Resource:,Audience:[],Scope:[1 2 3],RequestedTokenType:urn:ietf:params:oauth:token-type:access_token,SubjectToken:JWTTokenSource{Method:RS256,KeyID:key_id,Issuer:"test_issuer",Subject:"",Audience:[test_audience],ID:,TokenTTL:1h0m0s},ActorToken:JWTTokenSource{Method:RS256,KeyID:key_id,Issuer:"test_issuer",Subject:"",Audience:[],ID:,TokenTTL:1h0m0s},From:"TestErrorInHTTPRequest"}`, formatted) //nolint:lll
+}
+
+func TestJWTTokenSource(t *testing.T) {
+ publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(testPublicKeyContent))
+ require.NoError(t, err)
+ getPublicKey := func(*jwt.Token) (interface{}, error) {
+ return publicKey, nil
+ }
+
+ var src TokenSource
+ src, err = NewJWTTokenSource(
+ WithRSAPrivateKeyPEMContent([]byte(testPrivateKeyContent)),
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ WithAudience("test_audience"),
+ )
+ require.NoError(t, err)
+
+ token, err := src.Token()
+ require.NoError(t, err)
+ require.Equal(t, "urn:ietf:params:oauth:token-type:jwt", token.TokenType)
+
+ claims := jwt.RegisteredClaims{}
+ parsedToken, err := jwt.ParseWithClaims(token.Token, &claims, getPublicKey)
+ require.NoError(t, err)
+
+ require.True(t, parsedToken.Valid)
+ require.NoError(t, parsedToken.Claims.Valid())
+ require.Equal(t, "test_issuer", claims.Issuer)
+ require.Equal(t, "test_audience", claims.Audience[0])
+ require.Equal(t, "key_id", parsedToken.Header["kid"].(string))
+ require.Equal(t, "RS256", parsedToken.Header["alg"].(string))
+}
+
+func TestJWTTokenBadParams(t *testing.T) {
+ privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(testPrivateKeyContent))
+ require.NoError(t, err)
+
+ _, err = NewJWTTokenSource(
+ // no private key
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ WithAudience("test_audience"),
+ WithID("id"),
+ )
+ require.ErrorIs(t, err, errNoPrivateKeyError)
+
+ _, err = NewJWTTokenSource(
+ WithPrivateKey(privateKey),
+ WithKeyID("key_id"),
+ // no signing method
+ WithSubject("s"),
+ WithTokenTTL(time.Minute),
+ WithAudience("test_audience"),
+ )
+ require.ErrorIs(t, err, errNoSigningMethodError)
+}
+
+func TestJWTTokenSourceReadPrivateKeyFromFile(t *testing.T) {
+ const perm = 0o600
+ usr, err := user.Current()
+ require.NoError(t, err)
+ fileName := strconv.Itoa(time.Now().Second())
+ filePath := filepath.Join(usr.HomeDir, fileName)
+ beautifulFilePath := filepath.Join("~", fileName)
+ err = os.WriteFile(
+ filePath,
+ []byte(testPrivateKeyContent),
+ perm,
+ )
+ require.NoError(t, err)
+ defer os.Remove(filePath)
+
+ var src TokenSource
+ src, err = NewJWTTokenSource(
+ WithRSAPrivateKeyPEMFile(beautifulFilePath),
+ WithKeyID("key_id"),
+ WithSigningMethod(jwt.SigningMethodRS256),
+ WithIssuer("test_issuer"),
+ WithAudience("test_audience"),
+ )
+ require.NoError(t, err)
+
+ token, err := src.Token()
+ require.NoError(t, err)
+
+ // parse token
+ publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(testPublicKeyContent))
+ require.NoError(t, err)
+ getPublicKey := func(*jwt.Token) (interface{}, error) {
+ return publicKey, nil
+ }
+
+ claims := jwt.RegisteredClaims{}
+ _, err = jwt.ParseWithClaims(token.Token, &claims, getPublicKey)
+ require.NoError(t, err)
+}
diff --git a/internal/credentials/source_info.go b/internal/credentials/source_info.go
index 017a49a2e..53f7c5065 100644
--- a/internal/credentials/source_info.go
+++ b/internal/credentials/source_info.go
@@ -14,6 +14,12 @@ func (sourceInfo SourceInfoOption) ApplyAccessTokenCredentialsOption(h *AccessTo
h.sourceInfo = string(sourceInfo)
}
+func (sourceInfo SourceInfoOption) ApplyOauth2CredentialsOption(h *oauth2TokenExchange) error {
+ h.sourceInfo = string(sourceInfo)
+
+ return nil
+}
+
// WithSourceInfo option append to credentials object the source info for reporting source info details on error case
func WithSourceInfo(sourceInfo string) SourceInfoOption {
return SourceInfoOption(sourceInfo)
diff --git a/internal/credentials/static.go b/internal/credentials/static.go
index 298785bf1..7d9437dfb 100644
--- a/internal/credentials/static.go
+++ b/internal/credentials/static.go
@@ -19,6 +19,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
+const TokenRefreshDivisor = 10
+
var (
_ Credentials = (*Static)(nil)
_ fmt.Stringer = (*Static)(nil)
@@ -133,7 +135,7 @@ func (c *Static) Token(ctx context.Context) (token string, err error) {
return "", xerrors.WithStackTrace(err)
}
- c.requestAt = time.Now().Add(time.Until(expiresAt) / 10)
+ c.requestAt = time.Now().Add(time.Until(expiresAt) / TokenRefreshDivisor)
c.token = result.GetToken()
return c.token, nil
diff --git a/internal/decimal/decimal.go b/internal/decimal/decimal.go
index a4753992a..4fdbd32e6 100644
--- a/internal/decimal/decimal.go
+++ b/internal/decimal/decimal.go
@@ -7,15 +7,19 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
-const wordSize = bits.UintSize / 8
+const (
+ wordSize = bits.UintSize / 8
+ bufferSize = 40
+ negMask = 0x80
+)
var (
- ten = big.NewInt(10)
+ ten = big.NewInt(10) //nolint:gomnd
zero = big.NewInt(0)
one = big.NewInt(1)
inf = big.NewInt(0).Mul(
- big.NewInt(100000000000000000),
- big.NewInt(1000000000000000000),
+ big.NewInt(100000000000000000), //nolint:gomnd
+ big.NewInt(1000000000000000000), //nolint:gomnd
)
nan = big.NewInt(0).Add(inf, one)
err = big.NewInt(0).Add(nan, one)
@@ -58,7 +62,7 @@ func FromBytes(bts []byte, precision, scale uint32) *big.Int {
v.SetBytes(bts)
- neg := bts[0]&0x80 != 0
+ neg := bts[0]&negMask != 0
if neg {
// Given bytes contains negative value.
// Interpret is as two's complement.
@@ -216,7 +220,7 @@ func Format(x *big.Int, precision, scale uint32) string {
// log_{10}(2^120) ~= 36.12, 37 decimal places
// plus dot, zero before dot, sign.
- bts := make([]byte, 40)
+ bts := make([]byte, bufferSize)
pos := len(bts)
var digit big.Int
diff --git a/internal/discovery/discovery.go b/internal/discovery/discovery.go
index 65237078a..dfda2660c 100644
--- a/internal/discovery/discovery.go
+++ b/internal/discovery/discovery.go
@@ -40,7 +40,7 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
var (
onDone = trace.DiscoveryOnDiscover(
c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/discovery.(*Client).Discover"),
c.config.Endpoint(), c.config.Database(),
)
request = Ydb_Discovery.ListEndpointsRequest{
@@ -99,7 +99,9 @@ func (c *Client) Discover(ctx context.Context) (endpoints []endpoint.Endpoint, e
func (c *Client) WhoAmI(ctx context.Context) (whoAmI *discovery.WhoAmI, err error) {
var (
- onDone = trace.DiscoveryOnWhoAmI(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone = trace.DiscoveryOnWhoAmI(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/discovery.(*Client).WhoAmI"),
+ )
request = Ydb_Discovery.WhoAmIRequest{}
response *Ydb_Discovery.WhoAmIResponse
whoAmIResultResult Ydb_Discovery.WhoAmIResult
diff --git a/internal/endpoint/endpoint.go b/internal/endpoint/endpoint.go
index 823d721d0..37a889b81 100644
--- a/internal/endpoint/endpoint.go
+++ b/internal/endpoint/endpoint.go
@@ -9,10 +9,15 @@ import (
type Info interface {
NodeID() uint32
Address() string
- LocalDC() bool
Location() string
LastUpdated() time.Time
LoadFactor() float32
+
+ // Deprecated: LocalDC check "local" by compare endpoint location with discovery "selflocation" field.
+ // It work good only if connection url always point to local dc.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+ LocalDC() bool
}
type Endpoint interface {
@@ -23,17 +28,17 @@ type Endpoint interface {
Touch(opts ...Option)
}
-type endpoint struct {
+type endpoint struct { //nolint:maligned
mu sync.RWMutex
id uint32
address string
location string
services []string
- loadFactor float32
- local bool
-
+ loadFactor float32
lastUpdated time.Time
+
+ local bool
}
func (e *endpoint) Copy() Endpoint {
@@ -86,6 +91,10 @@ func (e *endpoint) Location() string {
return e.location
}
+// Deprecated: LocalDC check "local" by compare endpoint location with discovery "selflocation" field.
+// It work good only if connection url always point to local dc.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (e *endpoint) LocalDC() bool {
e.mu.RLock()
defer e.mu.RUnlock()
diff --git a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
index e2689df5a..8ff0b9727 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter.go
@@ -177,6 +177,7 @@ func sendWriteRequest(send sendFunc, req *Ydb_Topic.StreamWriteMessage_FromClien
return sendErr
}
+ //nolint:gomnd
splitIndex := len(grpcMessages) / 2
firstMessages, lastMessages := grpcMessages[:splitIndex], grpcMessages[splitIndex:]
defer func() {
diff --git a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
index f076adab9..b268ef0d7 100644
--- a/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
+++ b/internal/grpcwrapper/rawtopic/rawtopicwriter/streamwriter_test.go
@@ -1,6 +1,7 @@
package rawtopicwriter
import (
+ "fmt"
"testing"
"github.com/stretchr/testify/require"
@@ -72,7 +73,11 @@ func TestSendWriteRequest(t *testing.T) {
}
getWriteRequest := func(req *Ydb_Topic.StreamWriteMessage_FromClient) *Ydb_Topic.StreamWriteMessage_WriteRequest {
- return req.GetClientMessage().(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest).WriteRequest
+ res, ok := req.ClientMessage.(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest", res))
+ }
+ return res.WriteRequest
}
sendCounter := 0
diff --git a/internal/meta/context.go b/internal/meta/context.go
index b3a410dcc..049d0a6da 100644
--- a/internal/meta/context.go
+++ b/internal/meta/context.go
@@ -41,7 +41,7 @@ func WithRequestType(ctx context.Context, requestType string) context.Context {
// WithAllowFeatures returns a copy of parent context with allowed client feature
func WithAllowFeatures(ctx context.Context, features ...string) context.Context {
- kv := make([]string, 0, len(features)*2)
+ kv := make([]string, 0, len(features)*2) //nolint:gomnd
for _, feature := range features {
kv = append(kv, HeaderClientCapabilities, feature)
}
diff --git a/internal/meta/meta.go b/internal/meta/meta.go
index 7311f0f38..8f856379d 100644
--- a/internal/meta/meta.go
+++ b/internal/meta/meta.go
@@ -15,6 +15,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
+var pid = os.Getpid()
+
func New(
database string,
credentials credentials.Credentials,
@@ -22,7 +24,7 @@ func New(
opts ...Option,
) *Meta {
m := &Meta{
- pid: strconv.Itoa(os.Getpid()),
+ pid: strconv.Itoa(pid),
trace: trace,
credentials: credentials,
database: database,
@@ -115,7 +117,9 @@ func (m *Meta) meta(ctx context.Context) (_ metadata.MD, err error) {
var token string
- done := trace.DriverOnGetCredentials(m.trace, &ctx, stack.FunctionID(""))
+ done := trace.DriverOnGetCredentials(m.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/meta.(*Meta).meta"),
+ )
defer func() {
done(token, err)
}()
diff --git a/internal/mock/conn.go b/internal/mock/conn.go
index ac57f6c41..b4ceb9f69 100644
--- a/internal/mock/conn.go
+++ b/internal/mock/conn.go
@@ -95,6 +95,10 @@ func (e *Endpoint) Address() string {
return e.AddrField
}
+// Deprecated: LocalDC check "local" by compare endpoint location with discovery "selflocation" field.
+// It work good only if connection url always point to local dc.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (e *Endpoint) LocalDC() bool {
return e.LocalDCField
}
diff --git a/internal/operation/context.go b/internal/operation/context.go
index 3ce2e1ee5..2f76340a5 100644
--- a/internal/operation/context.go
+++ b/internal/operation/context.go
@@ -13,7 +13,7 @@ type (
// WithTimeout returns a copy of parent context in which YDB operation timeout
// parameter is set to d. If parent context timeout is smaller than d, parent context is returned.
func WithTimeout(ctx context.Context, operationTimeout time.Duration) context.Context {
- if d, ok := Timeout(ctx); ok && operationTimeout >= d {
+ if d, ok := ctxTimeout(ctx); ok && operationTimeout >= d {
// The current cancelation timeout is already smaller than the new one.
return ctx
}
@@ -25,7 +25,7 @@ func WithTimeout(ctx context.Context, operationTimeout time.Duration) context.Co
// cancel after parameter is set to d. If parent context cancellation timeout is smaller
// than d, parent context is returned.
func WithCancelAfter(ctx context.Context, operationCancelAfter time.Duration) context.Context {
- if d, ok := CancelAfter(ctx); ok && operationCancelAfter >= d {
+ if d, ok := ctxCancelAfter(ctx); ok && operationCancelAfter >= d {
// The current cancelation timeout is already smaller than the new one.
return ctx
}
@@ -33,23 +33,23 @@ func WithCancelAfter(ctx context.Context, operationCancelAfter time.Duration) co
return context.WithValue(ctx, ctxOperationCancelAfterKey{}, operationCancelAfter)
}
-// Timeout returns the timeout within given context after which
+// ctxTimeout returns the timeout within given context after which
// YDB should try to cancel operation and return result regardless of the cancelation.
-func Timeout(ctx context.Context) (d time.Duration, ok bool) {
+func ctxTimeout(ctx context.Context) (d time.Duration, ok bool) {
d, ok = ctx.Value(ctxOperationTimeoutKey{}).(time.Duration)
return
}
-// CancelAfter returns the timeout within given context after which
+// ctxCancelAfter returns the timeout within given context after which
// YDB should try to cancel operation and return result regardless of the cancellation.
-func CancelAfter(ctx context.Context) (d time.Duration, ok bool) {
+func ctxCancelAfter(ctx context.Context) (d time.Duration, ok bool) {
d, ok = ctx.Value(ctxOperationCancelAfterKey{}).(time.Duration)
return
}
-func untilDeadline(ctx context.Context) (time.Duration, bool) {
+func ctxUntilDeadline(ctx context.Context) (time.Duration, bool) {
deadline, ok := ctx.Deadline()
if ok {
return time.Until(deadline), true
diff --git a/internal/operation/params.go b/internal/operation/params.go
index f45e941f8..03d342e9a 100644
--- a/internal/operation/params.go
+++ b/internal/operation/params.go
@@ -13,13 +13,13 @@ func Params(
cancelAfter time.Duration,
mode Mode,
) *Ydb_Operations.OperationParams {
- if d, ok := Timeout(ctx); ok {
+ if d, ok := ctxTimeout(ctx); ok {
timeout = d
}
- if d, ok := CancelAfter(ctx); ok {
+ if d, ok := ctxCancelAfter(ctx); ok {
cancelAfter = d
}
- if d, ok := untilDeadline(ctx); mode == ModeSync && ok && d < timeout {
+ if d, ok := ctxUntilDeadline(ctx); mode == ModeSync && ok && d < timeout {
timeout = d
}
if timeout == 0 && cancelAfter == 0 && mode == 0 {
diff --git a/internal/params/builder_test.go b/internal/params/builder_test.go
index b1d004cbf..da1a7dda7 100644
--- a/internal/params/builder_test.go
+++ b/internal/params/builder_test.go
@@ -1,7 +1,6 @@
package params
import (
- "encoding/json"
"testing"
"time"
@@ -12,12 +11,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
)
-func paramsToJSON(params map[string]*Ydb.TypedValue) string {
- b, _ := json.MarshalIndent(params, "", "\t") //nolint:errchkjson
-
- return string(b)
-}
-
func TestBuilder(t *testing.T) {
type expected struct {
Type *Ydb.Type
@@ -427,14 +420,14 @@ func TestBuilder(t *testing.T) {
params := result.Build().ToYDB(a)
require.Equal(t,
- paramsToJSON(
+ xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: tc.expected.Type,
Value: tc.expected.Value,
},
}),
- paramsToJSON(params),
+ xtest.ToJSON(params),
)
})
}
diff --git a/internal/params/dict_test.go b/internal/params/dict_test.go
index 2fed82d33..0dc6b246c 100644
--- a/internal/params/dict_test.go
+++ b/internal/params/dict_test.go
@@ -424,7 +424,7 @@ func TestDict(t *testing.T) {
require.True(t, ok)
params := d.EndDict().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -444,7 +444,7 @@ func TestDict(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
})
}
}
@@ -467,7 +467,7 @@ func TestDict_AddPairs(t *testing.T) {
params := Builder{}.Param("$x").BeginDict().AddPairs(pairs...).EndDict().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -515,5 +515,5 @@ func TestDict_AddPairs(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
}
diff --git a/internal/params/list_test.go b/internal/params/list_test.go
index 153212f89..288e0a5f7 100644
--- a/internal/params/list_test.go
+++ b/internal/params/list_test.go
@@ -419,7 +419,7 @@ func TestList(t *testing.T) {
require.True(t, ok)
params := result.EndList().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -435,7 +435,7 @@ func TestList(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
})
}
}
@@ -446,7 +446,7 @@ func TestList_AddItems(t *testing.T) {
params := Builder{}.Param("$x").BeginList().
AddItems(value.Uint64Value(123), value.Uint64Value(321)).
EndList().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -471,5 +471,5 @@ func TestList_AddItems(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
}
diff --git a/internal/params/optional_test.go b/internal/params/optional_test.go
index 37246e364..0c21718a1 100644
--- a/internal/params/optional_test.go
+++ b/internal/params/optional_test.go
@@ -418,7 +418,7 @@ func TestOptional(t *testing.T) {
require.True(t, ok)
params := result.EndOptional().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -430,7 +430,7 @@ func TestOptional(t *testing.T) {
},
Value: tc.expected.Value,
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
})
}
}
diff --git a/internal/params/parameters.go b/internal/params/parameters.go
index 18210cc16..aae4e38d0 100644
--- a/internal/params/parameters.go
+++ b/internal/params/parameters.go
@@ -134,6 +134,20 @@ func (p *Parameter) BeginTuple() *tuple {
}
}
+func (p *Parameter) BeginStruct() *structure {
+ return &structure{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
+func (p *Parameter) BeginVariant() *variant {
+ return &variant{
+ parent: p.parent,
+ name: p.name,
+ }
+}
+
func (p *Parameter) Text(v string) Builder {
p.value = value.TextValue(v)
p.parent.params = append(p.parent.params, p)
diff --git a/internal/params/pg_test.go b/internal/params/pg_test.go
index 4fc6f15f1..ce470864c 100644
--- a/internal/params/pg_test.go
+++ b/internal/params/pg_test.go
@@ -88,13 +88,13 @@ func TestPg(t *testing.T) {
params := result.Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: tc.expected.Type,
Value: tc.expected.Value,
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
})
}
}
diff --git a/internal/params/set_test.go b/internal/params/set_test.go
index 0a97b866b..6ff75d464 100644
--- a/internal/params/set_test.go
+++ b/internal/params/set_test.go
@@ -419,7 +419,7 @@ func TestSet(t *testing.T) {
require.True(t, ok)
params := result.EndSet().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -443,7 +443,7 @@ func TestSet(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
})
}
}
@@ -454,7 +454,7 @@ func TestSet_AddItems(t *testing.T) {
params := Builder{}.Param("$x").BeginSet().
AddItems(value.Uint64Value(123), value.Uint64Value(321)).
EndSet().Build().ToYDB(a)
- require.Equal(t, paramsToJSON(
+ require.Equal(t, xtest.ToJSON(
map[string]*Ydb.TypedValue{
"$x": {
Type: &Ydb.Type{
@@ -496,5 +496,5 @@ func TestSet_AddItems(t *testing.T) {
},
},
},
- }), paramsToJSON(params))
+ }), xtest.ToJSON(params))
}
diff --git a/internal/params/struct.go b/internal/params/struct.go
new file mode 100644
index 000000000..0a8af589b
--- /dev/null
+++ b/internal/params/struct.go
@@ -0,0 +1,268 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ structure struct {
+ parent Builder
+ name string
+ values []value.StructValueField
+ }
+
+ structValue struct {
+ parent *structure
+ name string
+ }
+)
+
+func (s *structure) AddItems(items ...value.StructValueField) *structure {
+ s.values = append(s.values, items...)
+
+ return s
+}
+
+func (s *structure) Field(v string) *structValue {
+ return &structValue{
+ parent: s,
+ name: v,
+ }
+}
+
+func (s *structure) EndStruct() Builder {
+ s.parent.params = append(s.parent.params, &Parameter{
+ parent: s.parent,
+ name: s.name,
+ value: value.StructValue(s.values...),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Text(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TextValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Bytes(v []byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.BytesValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Bool(v bool) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.BoolValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint64(v uint64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint64Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int64(v int64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int64Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint32(v uint32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint32Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int32(v int32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int32Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint16(v uint16) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint16Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int16(v int16) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int16Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Uint8(v uint8) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Uint8Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Int8(v int8) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.Int8Value(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Float(v float32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.FloatValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Double(v float64) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DoubleValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Decimal(v [16]byte, precision, scale uint32) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DecimalValue(v, precision, scale),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Timestamp(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TimestampValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Date(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DateValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Datetime(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.DatetimeValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) Interval(v time.Duration) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.IntervalValueFromDuration(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) JSON(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.JSONValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) JSONDocument(v string) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.JSONDocumentValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) YSON(v []byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.YSONValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) UUID(v [16]byte) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.UUIDValue(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzDatetime(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzDatetimeValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzTimestamp(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzTimestampValueFromTime(v),
+ })
+
+ return s.parent
+}
+
+func (s *structValue) TzDate(v time.Time) *structure {
+ s.parent.values = append(s.parent.values, value.StructValueField{
+ Name: s.name,
+ V: value.TzDateValueFromTime(v),
+ })
+
+ return s.parent
+}
diff --git a/internal/params/struct_test.go b/internal/params/struct_test.go
new file mode 100644
index 000000000..cad24fcaf
--- /dev/null
+++ b/internal/params/struct_test.go
@@ -0,0 +1,922 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestStruct(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ builder Builder
+ params map[string]*Ydb.TypedValue
+ }{
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint64(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int64(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint32(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int32(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT32,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint16(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int16(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT16,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Uint8(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Int8(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Bool(true).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Text("test").EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Bytes([]byte("test")).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_STRING,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Float(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_FLOAT,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Double(123).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DOUBLE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: 123,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Interval(time.Second).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INTERVAL,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Datetime(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATETIME,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Date(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_DATE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Timestamp(time.Unix(123456789, 456)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TIMESTAMP,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").Decimal([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9).EndStruct(), //nolint:lll
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").JSON(`{"a": 1,"b": "B"}`).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").JSONDocument(`{"a": 1,"b": "B"}`).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_JSON_DOCUMENT,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").YSON([]byte(`[ 1; 2; 3; 4; 5 ]`)).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_YSON,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`[ 1; 2; 3; 4; 5 ]`),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").
+ UUID([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UUID,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().
+ Field("col1").Text("text").
+ Field("col2").Uint32(123).
+ Field("col3").Int64(456).
+ EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ {
+ Name: "col2",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT32,
+ },
+ },
+ },
+ {
+ Name: "col3",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "text",
+ },
+ },
+ {
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ },
+ {
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 456,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzDatetime(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_DATETIME,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzDate(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_DATE,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ {
+ name: xtest.CurrentFileLine(),
+ builder: Builder{}.Param("$x").BeginStruct().Field("col1").TzTimestamp(time.Unix(123456789, 456).UTC()).EndStruct(),
+ params: map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_StructType{
+ StructType: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "col1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_TZ_TIMESTAMP,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := tt.builder.Build().ToYDB(a)
+ require.Equal(t, xtest.ToJSON(tt.params), xtest.ToJSON(params))
+ })
+ }
+}
diff --git a/internal/params/tuple.go b/internal/params/tuple.go
index 0762cdb05..7718a5026 100644
--- a/internal/params/tuple.go
+++ b/internal/params/tuple.go
@@ -170,3 +170,21 @@ func (t *tupleItem) UUID(v [16]byte) *tuple {
return t.parent
}
+
+func (t *tupleItem) TzDate(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.TzDateValueFromTime(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) TzTimestamp(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.TzTimestampValueFromTime(v))
+
+ return t.parent
+}
+
+func (t *tupleItem) TzDatetime(v time.Time) *tuple {
+ t.parent.values = append(t.parent.values, value.TzDatetimeValueFromTime(v))
+
+ return t.parent
+}
diff --git a/internal/params/tuple_test.go b/internal/params/tuple_test.go
index 9938fae0c..1c6510603 100644
--- a/internal/params/tuple_test.go
+++ b/internal/params/tuple_test.go
@@ -13,723 +13,476 @@ import (
)
func TestTuple(t *testing.T) {
- for _, tt := range []struct {
- name string
- builder Builder
- params map[string]*Ydb.TypedValue
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+ args []any
+
+ expected expected
}{
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Uint64(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT64,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint64Value{
- Uint64Value: 123,
- },
- },
- },
+ method: "Uint64",
+ args: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Int64(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_INT64,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Int64Value{
- Int64Value: 123,
- },
- },
- },
+ method: "Int64",
+ args: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Uint32(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT32,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint32Value{
- Uint32Value: 123,
- },
- },
- },
+ method: "Uint32",
+ args: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Int32(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_INT32,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Int32Value{
- Int32Value: 123,
- },
- },
- },
+ method: "Int32",
+ args: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Uint16(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT16,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint32Value{
- Uint32Value: 123,
- },
- },
- },
+ method: "Uint16",
+ args: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Int16(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_INT16,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Int32Value{
- Int32Value: 123,
- },
- },
- },
+ method: "Int16",
+ args: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Uint8(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT8,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint32Value{
- Uint32Value: 123,
- },
- },
- },
+ method: "Uint8",
+ args: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Int8(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_INT8,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Int32Value{
- Int32Value: 123,
- },
- },
- },
+ method: "Int8",
+ args: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Bool(true).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_BOOL,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_BoolValue{
- BoolValue: true,
- },
- },
- },
+ method: "Bool",
+ args: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Text("test").EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UTF8,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_TextValue{
- TextValue: "test",
- },
- },
- },
+ method: "Text",
+ args: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Bytes([]byte("test")).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_STRING,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_BytesValue{
- BytesValue: []byte("test"),
- },
- },
- },
+ method: "Bytes",
+ args: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Float(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_FLOAT,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_FloatValue{
- FloatValue: 123,
- },
- },
- },
+ method: "Float",
+ args: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Double(123).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_DOUBLE,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_DoubleValue{
- DoubleValue: 123,
- },
- },
- },
+ method: "Double",
+ args: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Interval(time.Second).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_INTERVAL,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Int64Value{
- Int64Value: 1000000,
- },
- },
- },
+ method: "Interval",
+ args: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Datetime(time.Unix(123456789, 456)).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_DATETIME,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint32Value{
- Uint32Value: 123456789,
- },
- },
- },
+ method: "Datetime",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Date(time.Unix(123456789, 456)).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_DATE,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint32Value{
- Uint32Value: 1428,
- },
- },
- },
+ method: "Date",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Timestamp(time.Unix(123456789, 456)).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_TIMESTAMP,
- },
- },
- },
- },
- },
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint64Value{
- Uint64Value: 123456789000000,
- },
- },
- },
+ method: "Timestamp",
+ args: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().Decimal([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9).EndTuple(), //nolint:lll
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_DecimalType{
- DecimalType: &Ydb.DecimalType{
- Precision: 22,
- Scale: 9,
- },
- },
- },
- },
- },
+ method: "Decimal",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
},
},
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- High_128: 72623859790382856,
- Value: &Ydb.Value_Low_128{
- Low_128: 648519454493508870,
- },
- },
- },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().JSON(`{"a": 1,"b": "B"}`).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_JSON,
- },
- },
- },
- },
- },
+ method: "JSON",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
},
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_TextValue{
- TextValue: `{"a": 1,"b": "B"}`,
- },
- },
- },
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ args: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().JSONDocument(`{"a": 1,"b": "B"}`).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_JSON_DOCUMENT,
- },
- },
- },
- },
- },
+ method: "YSON",
+ args: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
},
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_TextValue{
- TextValue: `{"a": 1,"b": "B"}`,
- },
- },
- },
+ },
+ },
+ },
+ {
+ method: "UUID",
+ args: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
},
+ High_128: 72623859790382856,
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().YSON([]byte(`[ 1; 2; 3; 4; 5 ]`)).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_YSON,
- },
- },
- },
- },
- },
+ method: "TzDatetime",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
},
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_BytesValue{
- BytesValue: []byte(`[ 1; 2; 3; 4; 5 ]`),
- },
- },
- },
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
},
},
},
},
{
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().Add().
- UUID([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UUID,
- },
+ method: "TzTimestamp",
+ args: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginTuple().Add()
+
+ result, ok := xtest.CallMethod(item, tc.method, tc.args...)[0].(*tuple)
+ require.True(t, ok)
+
+ params := result.EndTuple().Build().ToYDB(a)
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ tc.expected.Type,
},
},
},
},
- },
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Low_128{
- Low_128: 651345242494996240,
- },
- High_128: 72623859790382856,
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ tc.expected.Value,
},
},
},
- },
- },
- },
- {
- name: xtest.CurrentFileLine(),
- builder: Builder{}.Param("$x").BeginTuple().AddItems(value.Uint64Value(123), value.Uint64Value(321)).EndTuple(),
- params: map[string]*Ydb.TypedValue{
- "$x": {
- Type: &Ydb.Type{
- Type: &Ydb.Type_TupleType{
- TupleType: &Ydb.TupleType{
- Elements: []*Ydb.Type{
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT64,
- },
+ }), xtest.ToJSON(params))
+ })
+ }
+}
+
+func TestTuple_AddItems(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+ params := Builder{}.Param("$x").BeginTuple().
+ AddItems(value.Uint64Value(123), value.Uint64Value(321)).
+ EndTuple().Build().ToYDB(a)
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TupleType{
+ TupleType: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
},
- {
- Type: &Ydb.Type_TypeId{
- TypeId: Ydb.Type_UINT64,
- },
+ },
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
},
},
},
},
},
- Value: &Ydb.Value{
- Items: []*Ydb.Value{
- {
- Value: &Ydb.Value_Uint64Value{
- Uint64Value: 123,
- },
+ },
+ Value: &Ydb.Value{
+ Items: []*Ydb.Value{
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
},
- {
- Value: &Ydb.Value_Uint64Value{
- Uint64Value: 321,
- },
+ },
+ {
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 321,
},
},
},
},
},
- },
- } {
- t.Run(tt.name, func(t *testing.T) {
- a := allocator.New()
- defer a.Free()
- params := tt.builder.Build().ToYDB(a)
- require.Equal(t, paramsToJSON(tt.params), paramsToJSON(params))
- })
- }
+ }), xtest.ToJSON(params))
}
diff --git a/internal/params/variant.go b/internal/params/variant.go
new file mode 100644
index 000000000..16815e38e
--- /dev/null
+++ b/internal/params/variant.go
@@ -0,0 +1,37 @@
+package params
+
+import "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+
+type (
+ variant struct {
+ parent Builder
+ name string
+ value value.Value
+ }
+
+ variantBuilder struct {
+ variant *variant
+ }
+)
+
+func (vb *variantBuilder) EndVariant() Builder {
+ vb.variant.parent.params = append(vb.variant.parent.params, &Parameter{
+ parent: vb.variant.parent,
+ name: vb.variant.name,
+ value: vb.variant.value,
+ })
+
+ return vb.variant.parent
+}
+
+func (v *variant) BeginTuple() *variantTuple {
+ return &variantTuple{
+ parent: v,
+ }
+}
+
+func (v *variant) BeginStruct() *variantStruct {
+ return &variantStruct{
+ parent: v,
+ }
+}
diff --git a/internal/params/variant_struct.go b/internal/params/variant_struct.go
new file mode 100644
index 000000000..190e7d85f
--- /dev/null
+++ b/internal/params/variant_struct.go
@@ -0,0 +1,489 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ variantStruct struct {
+ parent *variant
+
+ fields []types.StructField
+ name string
+ value value.Value
+ }
+
+ variantStructField struct {
+ name string
+ parent *variantStruct
+ }
+
+ variantStructItem struct {
+ parent *variantStruct
+ }
+
+ variantStructBuilder struct {
+ parent *variantStruct
+ }
+)
+
+func (vs *variantStruct) Field(name string) *variantStructField {
+ return &variantStructField{
+ name: name,
+ parent: vs,
+ }
+}
+
+func (vs *variantStruct) AddFields(args ...types.StructField) *variantStruct {
+ vs.fields = append(vs.fields, args...)
+
+ return vs
+}
+
+func (vsf *variantStructField) Text() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Text,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Bytes() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Bytes,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Bool() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Bool,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Uint64() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Uint64,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Int64() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Int64,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Uint32() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Uint32,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Int32() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Int32,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Uint16() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Uint16,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Int16() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Int16,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Uint8() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Uint8,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Int8() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Int8,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Float() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Float,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Double() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Double,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Decimal(precision, scale uint32) *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.NewDecimal(precision, scale),
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Timestamp() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Timestamp,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Date() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Date,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Datetime() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Datetime,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) Interval() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.Interval,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) JSON() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.JSON,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) JSONDocument() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.JSONDocument,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) YSON() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.YSON,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) UUID() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.UUID,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) TzDate() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.TzDate,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) TzTimestamp() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.TzTimestamp,
+ })
+
+ return vsf.parent
+}
+
+func (vsf *variantStructField) TzDatetime() *variantStruct {
+ vsf.parent.fields = append(vsf.parent.fields, types.StructField{
+ Name: vsf.name,
+ T: types.TzDatetime,
+ })
+
+ return vsf.parent
+}
+
+func (vs *variantStruct) Name(name string) *variantStructItem {
+ vs.name = name
+
+ return &variantStructItem{
+ parent: vs,
+ }
+}
+
+func (vsi *variantStructItem) Text(v string) *variantStructBuilder {
+ vsi.parent.value = value.TextValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Bytes(v []byte) *variantStructBuilder {
+ vsi.parent.value = value.BytesValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Bool(v bool) *variantStructBuilder {
+ vsi.parent.value = value.BoolValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Uint64(v uint64) *variantStructBuilder {
+ vsi.parent.value = value.Uint64Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Int64(v int64) *variantStructBuilder {
+ vsi.parent.value = value.Int64Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Uint32(v uint32) *variantStructBuilder {
+ vsi.parent.value = value.Uint32Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Int32(v int32) *variantStructBuilder {
+ vsi.parent.value = value.Int32Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Uint16(v uint16) *variantStructBuilder {
+ vsi.parent.value = value.Uint16Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Int16(v int16) *variantStructBuilder {
+ vsi.parent.value = value.Int16Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Uint8(v uint8) *variantStructBuilder {
+ vsi.parent.value = value.Uint8Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Int8(v int8) *variantStructBuilder {
+ vsi.parent.value = value.Int8Value(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Float(v float32) *variantStructBuilder {
+ vsi.parent.value = value.FloatValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Double(v float64) *variantStructBuilder {
+ vsi.parent.value = value.DoubleValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Decimal(v [16]byte, precision, scale uint32) *variantStructBuilder {
+ vsi.parent.value = value.DecimalValue(v, precision, scale)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Timestamp(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.TimestampValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Date(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.DateValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Datetime(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.DatetimeValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) Interval(v time.Duration) *variantStructBuilder {
+ vsi.parent.value = value.IntervalValueFromDuration(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) JSON(v string) *variantStructBuilder {
+ vsi.parent.value = value.JSONValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) JSONDocument(v string) *variantStructBuilder {
+ vsi.parent.value = value.JSONDocumentValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) YSON(v []byte) *variantStructBuilder {
+ vsi.parent.value = value.YSONValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) UUID(v [16]byte) *variantStructBuilder {
+ vsi.parent.value = value.UUIDValue(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) TzDate(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.TzDateValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) TzTimestamp(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.TzTimestampValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsi *variantStructItem) TzDatetime(v time.Time) *variantStructBuilder {
+ vsi.parent.value = value.TzDatetimeValueFromTime(v)
+
+ return &variantStructBuilder{
+ parent: vsi.parent,
+ }
+}
+
+func (vsb *variantStructBuilder) EndStruct() *variantBuilder {
+ vsb.parent.parent.value = value.VariantValueStruct(
+ vsb.parent.value,
+ vsb.parent.name,
+ types.NewVariantStruct(vsb.parent.fields...),
+ )
+
+ return &variantBuilder{
+ variant: vsb.parent.parent,
+ }
+}
diff --git a/internal/params/variant_struct_test.go b/internal/params/variant_struct_test.go
new file mode 100644
index 000000000..cf8330da0
--- /dev/null
+++ b/internal/params/variant_struct_test.go
@@ -0,0 +1,557 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestVariantStruct(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+
+ typeArgs []any
+ itemArgs []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ itemArgs: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int64",
+ itemArgs: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ itemArgs: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int32",
+ itemArgs: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ itemArgs: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int16",
+ itemArgs: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ itemArgs: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int8",
+ itemArgs: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Bool",
+ itemArgs: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Text",
+ itemArgs: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ itemArgs: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Float",
+ itemArgs: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Double",
+ itemArgs: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Interval",
+ itemArgs: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Date",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ typeArgs: []any{uint32(22), uint32(9)},
+ itemArgs: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "JSON",
+ itemArgs: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ itemArgs: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "YSON",
+ itemArgs: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "UUID",
+ itemArgs: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginVariant().BeginStruct().Field("key")
+
+ vs, ok := xtest.CallMethod(item, tc.method, tc.typeArgs...)[0].(*variantStruct)
+ require.True(t, ok)
+
+ builder, ok := xtest.CallMethod(vs.Name("key"), tc.method, tc.itemArgs...)[0].(*variantStructBuilder)
+ require.True(t, ok)
+
+ params := builder.EndStruct().EndVariant().Build().ToYDB(a)
+
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_VariantType{
+ VariantType: &Ydb.VariantType{
+ Type: &Ydb.VariantType_StructItems{
+ StructItems: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "key",
+ Type: tc.expected.Type,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_NestedValue{
+ NestedValue: tc.expected.Value,
+ },
+ VariantIndex: 0,
+ },
+ },
+ }), xtest.ToJSON(params))
+ })
+ }
+}
+
+func TestVariantStruct_AddFields(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ params := Builder{}.Param("$x").BeginVariant().BeginStruct().
+ AddFields([]types.StructField{
+ {
+ Name: "key1",
+ T: types.Bool,
+ },
+ {
+ Name: "key2",
+ T: types.Uint64,
+ },
+ {
+ Name: "key3",
+ T: types.Text,
+ },
+ }...).Name("key3").Text("Hello, World!").EndStruct().
+ EndVariant().Build().ToYDB(a)
+
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_VariantType{
+ VariantType: &Ydb.VariantType{
+ Type: &Ydb.VariantType_StructItems{
+ StructItems: &Ydb.StructType{
+ Members: []*Ydb.StructMember{
+ {
+ Name: "key1",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ {
+ Name: "key2",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "key3",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_NestedValue{
+ NestedValue: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "Hello, World!",
+ },
+ },
+ },
+ VariantIndex: 2,
+ },
+ },
+ }), xtest.ToJSON(params))
+}
diff --git a/internal/params/variant_tuple.go b/internal/params/variant_tuple.go
new file mode 100644
index 000000000..9fea4fdaa
--- /dev/null
+++ b/internal/params/variant_tuple.go
@@ -0,0 +1,412 @@
+package params
+
+import (
+ "time"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/value"
+)
+
+type (
+ variantTuple struct {
+ parent *variant
+
+ types []types.Type
+ index uint32
+ value value.Value
+ }
+
+ variantTupleTypes struct {
+ tuple *variantTuple
+ }
+
+ variantTupleItem struct {
+ tuple *variantTuple
+ }
+
+ variantTupleBuilder struct {
+ tuple *variantTuple
+ }
+)
+
+func (vt *variantTuple) Types() *variantTupleTypes {
+ return &variantTupleTypes{
+ tuple: vt,
+ }
+}
+
+func (vtt *variantTupleTypes) AddTypes(args ...types.Type) *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, args...)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Text() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Text)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Bytes() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Bytes)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Bool() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Bool)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Uint64() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Uint64)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Int64() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Int64)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Uint32() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Uint32)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Int32() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Int32)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Uint16() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Uint16)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Int16() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Int16)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Uint8() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Uint8)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Int8() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Int8)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Float() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Float)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Double() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Double)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Decimal(precision, scale uint32) *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.NewDecimal(precision, scale))
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Timestamp() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Timestamp)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Date() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Date)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Datetime() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Datetime)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Interval() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.Interval)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) JSON() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.JSON)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) JSONDocument() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.JSONDocument)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) YSON() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.YSON)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) UUID() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.UUID)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) TzDate() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.TzDate)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) TzTimestamp() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.TzTimestamp)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) TzDatetime() *variantTupleTypes {
+ vtt.tuple.types = append(vtt.tuple.types, types.TzDatetime)
+
+ return vtt
+}
+
+func (vtt *variantTupleTypes) Index(i uint32) *variantTupleItem {
+ vtt.tuple.index = i
+
+ return &variantTupleItem{
+ tuple: vtt.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Text(v string) *variantTupleBuilder {
+ vti.tuple.value = value.TextValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Bytes(v []byte) *variantTupleBuilder {
+ vti.tuple.value = value.BytesValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Bool(v bool) *variantTupleBuilder {
+ vti.tuple.value = value.BoolValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Uint64(v uint64) *variantTupleBuilder {
+ vti.tuple.value = value.Uint64Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Int64(v int64) *variantTupleBuilder {
+ vti.tuple.value = value.Int64Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Uint32(v uint32) *variantTupleBuilder {
+ vti.tuple.value = value.Uint32Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Int32(v int32) *variantTupleBuilder {
+ vti.tuple.value = value.Int32Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Uint16(v uint16) *variantTupleBuilder {
+ vti.tuple.value = value.Uint16Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Int16(v int16) *variantTupleBuilder {
+ vti.tuple.value = value.Int16Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Uint8(v uint8) *variantTupleBuilder {
+ vti.tuple.value = value.Uint8Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Int8(v int8) *variantTupleBuilder {
+ vti.tuple.value = value.Int8Value(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Float(v float32) *variantTupleBuilder {
+ vti.tuple.value = value.FloatValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Double(v float64) *variantTupleBuilder {
+ vti.tuple.value = value.DoubleValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Decimal(v [16]byte, precision, scale uint32) *variantTupleBuilder {
+ vti.tuple.value = value.DecimalValue(v, precision, scale)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Timestamp(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.TimestampValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Date(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.DateValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Datetime(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.DatetimeValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) Interval(v time.Duration) *variantTupleBuilder {
+ vti.tuple.value = value.IntervalValueFromDuration(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) JSON(v string) *variantTupleBuilder {
+ vti.tuple.value = value.JSONValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) JSONDocument(v string) *variantTupleBuilder {
+ vti.tuple.value = value.JSONDocumentValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) YSON(v []byte) *variantTupleBuilder {
+ vti.tuple.value = value.YSONValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) UUID(v [16]byte) *variantTupleBuilder {
+ vti.tuple.value = value.UUIDValue(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) TzDate(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.TzDateValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) TzTimestamp(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.TzTimestampValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vti *variantTupleItem) TzDatetime(v time.Time) *variantTupleBuilder {
+ vti.tuple.value = value.TzDatetimeValueFromTime(v)
+
+ return &variantTupleBuilder{
+ tuple: vti.tuple,
+ }
+}
+
+func (vtb *variantTupleBuilder) EndTuple() *variantBuilder {
+ vtb.tuple.parent.value = value.VariantValueTuple(
+ vtb.tuple.value,
+ vtb.tuple.index,
+ types.NewVariantTuple(vtb.tuple.types...),
+ )
+
+ return &variantBuilder{
+ variant: vtb.tuple.parent,
+ }
+}
diff --git a/internal/params/variant_tuple_test.go b/internal/params/variant_tuple_test.go
new file mode 100644
index 000000000..b24480d38
--- /dev/null
+++ b/internal/params/variant_tuple_test.go
@@ -0,0 +1,528 @@
+package params
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+)
+
+func TestVariantTuple(t *testing.T) {
+ type expected struct {
+ Type *Ydb.Type
+ Value *Ydb.Value
+ }
+
+ tests := []struct {
+ method string
+
+ typeArgs []any
+ itemArgs []any
+
+ expected expected
+ }{
+ {
+ method: "Uint64",
+ itemArgs: []any{uint64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int64",
+ itemArgs: []any{int64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT64},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint32",
+ itemArgs: []any{uint32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int32",
+ itemArgs: []any{int32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT32},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint16",
+ itemArgs: []any{uint16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int16",
+ itemArgs: []any{int16(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT16},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Uint8",
+ itemArgs: []any{uint8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UINT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Int8",
+ itemArgs: []any{int8(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INT8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int32Value{
+ Int32Value: 123,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Bool",
+ itemArgs: []any{true},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_BOOL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Text",
+ itemArgs: []any{"test"},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UTF8},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "test",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Bytes",
+ itemArgs: []any{[]byte("test")},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_STRING},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte("test"),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Float",
+ itemArgs: []any{float32(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_FLOAT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_FloatValue{
+ FloatValue: float32(123),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Double",
+ itemArgs: []any{float64(123)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DOUBLE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_DoubleValue{
+ DoubleValue: float64(123),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Interval",
+ itemArgs: []any{time.Second},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_INTERVAL},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Int64Value{
+ Int64Value: 1000000,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Datetime",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 123456789,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Date",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint32Value{
+ Uint32Value: 1428,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Timestamp",
+ itemArgs: []any{time.Unix(123456789, 456)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 123456789000000,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "Decimal",
+ typeArgs: []any{uint32(22), uint32(9)},
+ itemArgs: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, uint32(22), uint32(9)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_DecimalType{
+ DecimalType: &Ydb.DecimalType{
+ Precision: 22,
+ Scale: 9,
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ High_128: 72623859790382856,
+ Value: &Ydb.Value_Low_128{
+ Low_128: 648519454493508870,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "JSON",
+ itemArgs: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "JSONDocument",
+ itemArgs: []any{`{"a": 1,"b": "B"}`},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_JSON_DOCUMENT},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: `{"a": 1,"b": "B"}`,
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "YSON",
+ itemArgs: []any{[]byte(`{"a": 1,"b": "B"}`)},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_YSON},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_BytesValue{
+ BytesValue: []byte(`{"a": 1,"b": "B"}`),
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "UUID",
+ itemArgs: []any{[...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_UUID},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_Low_128{
+ Low_128: 651345242494996240,
+ },
+ High_128: 72623859790382856,
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzDatetime",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATETIME},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09Z",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzDate",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_DATE},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ {
+ method: "TzTimestamp",
+ itemArgs: []any{time.Unix(123456789, 456).UTC()},
+
+ expected: expected{
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{TypeId: Ydb.Type_TZ_TIMESTAMP},
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1973-11-29T21:33:09.000000Z",
+ },
+ VariantIndex: 0,
+ },
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.method, func(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ item := Builder{}.Param("$x").BeginVariant().BeginTuple().Types()
+
+ types, ok := xtest.CallMethod(item, tc.method, tc.typeArgs...)[0].(*variantTupleTypes)
+ require.True(t, ok)
+
+ builder, ok := xtest.CallMethod(types.Index(0), tc.method, tc.itemArgs...)[0].(*variantTupleBuilder)
+ require.True(t, ok)
+
+ params := builder.EndTuple().EndVariant().Build().ToYDB(a)
+
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_VariantType{
+ VariantType: &Ydb.VariantType{
+ Type: &Ydb.VariantType_TupleItems{
+ TupleItems: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ tc.expected.Type,
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_NestedValue{
+ NestedValue: tc.expected.Value,
+ },
+ },
+ },
+ }), xtest.ToJSON(params))
+ })
+ }
+}
+
+func TestVariantTuple_AddTypes(t *testing.T) {
+ a := allocator.New()
+ defer a.Free()
+
+ params := Builder{}.Param("$x").BeginVariant().BeginTuple().
+ Types().AddTypes(types.Int64, types.Bool).
+ Index(1).
+ Bool(true).
+ EndTuple().EndVariant().Build().ToYDB(a)
+
+ require.Equal(t, xtest.ToJSON(
+ map[string]*Ydb.TypedValue{
+ "$x": {
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_VariantType{
+ VariantType: &Ydb.VariantType{
+ Type: &Ydb.VariantType_TupleItems{
+ TupleItems: &Ydb.TupleType{
+ Elements: []*Ydb.Type{
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_INT64,
+ },
+ },
+ {
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_BOOL,
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ Value: &Ydb.Value{
+ Value: &Ydb.Value_NestedValue{
+ NestedValue: &Ydb.Value{
+ Value: &Ydb.Value_BoolValue{
+ BoolValue: true,
+ },
+ },
+ },
+ VariantIndex: 1,
+ },
+ },
+ }), xtest.ToJSON(params))
+}
diff --git a/internal/pool/errors.go b/internal/pool/errors.go
index 8e2eb6f21..36b6526c7 100644
--- a/internal/pool/errors.go
+++ b/internal/pool/errors.go
@@ -2,12 +2,9 @@ package pool
import (
"errors"
-
- "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
)
var (
errClosedPool = errors.New("closed pool")
- errPoolOverflow = xerrors.Retryable(errors.New("pool overflow"))
errItemIsNotAlive = errors.New("item is not alive")
)
diff --git a/internal/pool/pool.go b/internal/pool/pool.go
index 82b2905ef..3368aadc8 100644
--- a/internal/pool/pool.go
+++ b/internal/pool/pool.go
@@ -2,10 +2,13 @@ package pool
import (
"context"
- "sync/atomic"
+ "time"
+
+ "golang.org/x/sync/errgroup"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/pool/stats"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsync"
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
@@ -18,38 +21,112 @@ type (
IsAlive() bool
Close(ctx context.Context) error
}
- Stats struct {
- locked *xsync.Locked[stats.Stats]
+ safeStats struct {
+ mu xsync.RWMutex
+ v stats.Stats
onChange func(stats.Stats)
}
+ statsItemAddr struct {
+ v *int
+ onChange func(func())
+ }
Pool[PT Item[T], T any] struct {
trace *Trace
limit int
- create func(ctx context.Context) (PT, error)
+ createItem func(ctx context.Context) (PT, error)
+ createTimeout time.Duration
+ closeTimeout time.Duration
mu xsync.Mutex
idle []PT
index map[PT]struct{}
+ done chan struct{}
- done atomic.Bool
-
- stats *Stats
+ stats *safeStats
}
option[PT Item[T], T any] func(p *Pool[PT, T])
)
-func (stats *Stats) Change(f func(s stats.Stats) stats.Stats) {
- stats.onChange(stats.locked.Change(f))
+func (field statsItemAddr) Inc() {
+ field.onChange(func() {
+ *field.v++
+ })
+}
+
+func (field statsItemAddr) Dec() {
+ field.onChange(func() {
+ *field.v--
+ })
+}
+
+func (s *safeStats) Get() stats.Stats {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return s.v
+}
+
+func (s *safeStats) Index() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.Index,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
+}
+
+func (s *safeStats) Idle() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.Idle,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
}
-func (stats *Stats) Get() stats.Stats {
- return stats.locked.Get()
+func (s *safeStats) InUse() statsItemAddr {
+ s.mu.RLock()
+ defer s.mu.RUnlock()
+
+ return statsItemAddr{
+ v: &s.v.InUse,
+ onChange: func(f func()) {
+ s.mu.WithLock(f)
+ if s.onChange != nil {
+ s.onChange(s.Get())
+ }
+ },
+ }
}
func WithCreateFunc[PT Item[T], T any](f func(ctx context.Context) (PT, error)) option[PT, T] {
return func(p *Pool[PT, T]) {
- p.create = f
+ p.createItem = f
+ }
+}
+
+func WithCreateItemTimeout[PT Item[T], T any](t time.Duration) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.createTimeout = t
+ }
+}
+
+func WithCloseItemTimeout[PT Item[T], T any](t time.Duration) option[PT, T] {
+ return func(p *Pool[PT, T]) {
+ p.closeTimeout = t
}
}
@@ -72,11 +149,12 @@ func New[PT Item[T], T any](
p := &Pool[PT, T]{
trace: defaultTrace,
limit: DefaultLimit,
- create: func(ctx context.Context) (PT, error) {
+ createItem: func(ctx context.Context) (PT, error) {
var item T
return &item, nil
},
+ done: make(chan struct{}),
}
for _, opt := range opts {
@@ -87,7 +165,7 @@ func New[PT Item[T], T any](
onDone := p.trace.OnNew(&NewStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.New"),
})
defer func() {
@@ -96,12 +174,85 @@ func New[PT Item[T], T any](
})
}()
+ createItem := p.createItem
+
+ p.createItem = func(ctx context.Context) (PT, error) {
+ var (
+ ch = make(chan PT)
+ createErr error
+ )
+ go func() {
+ defer close(ch)
+ createErr = func() error {
+ var (
+ createCtx = xcontext.ValueOnly(ctx)
+ cancelCreate context.CancelFunc
+ )
+ if d := p.createTimeout; d > 0 {
+ createCtx, cancelCreate = xcontext.WithTimeout(createCtx, d)
+ } else {
+ createCtx, cancelCreate = xcontext.WithCancel(createCtx)
+ }
+ defer cancelCreate()
+
+ newItem, err := createItem(createCtx)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ needCloseItem := true
+ defer func() {
+ if needCloseItem {
+ _ = p.closeItem(ctx, newItem)
+ }
+ }()
+
+ select {
+ case <-p.done:
+ return xerrors.WithStackTrace(errClosedPool)
+
+ case <-ctx.Done():
+ p.mu.Lock()
+ defer p.mu.Unlock()
+
+ if len(p.index) < p.limit {
+ p.idle = append(p.idle, newItem)
+ p.index[newItem] = struct{}{}
+ p.stats.Index().Inc()
+ needCloseItem = false
+ }
+
+ return xerrors.WithStackTrace(ctx.Err())
+
+ case ch <- newItem:
+ needCloseItem = false
+
+ return nil
+ }
+ }()
+ }()
+
+ select {
+ case <-p.done:
+ return nil, xerrors.WithStackTrace(errClosedPool)
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ case item, has := <-ch:
+ if !has {
+ if ctxErr := ctx.Err(); ctxErr == nil && xerrors.IsContextError(createErr) {
+ return nil, xerrors.WithStackTrace(xerrors.Retryable(createErr))
+ }
+
+ return nil, xerrors.WithStackTrace(createErr)
+ }
+
+ return item, nil
+ }
+ }
p.idle = make([]PT, 0, p.limit)
p.index = make(map[PT]struct{}, p.limit)
- p.stats = &Stats{
- locked: xsync.NewLocked[stats.Stats](stats.Stats{
- Limit: p.limit,
- }),
+ p.stats = &safeStats{
+ v: stats.Stats{Limit: p.limit},
onChange: p.trace.OnChange,
}
@@ -112,10 +263,10 @@ func (p *Pool[PT, T]) Stats() stats.Stats {
return p.stats.Get()
}
-func (p *Pool[PT, T]) get(ctx context.Context) (_ PT, finalErr error) {
+func (p *Pool[PT, T]) getItem(ctx context.Context) (_ PT, finalErr error) {
onDone := p.trace.OnGet(&GetStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).getItem"),
})
defer func() {
onDone(&GetDoneInfo{
@@ -127,63 +278,55 @@ func (p *Pool[PT, T]) get(ctx context.Context) (_ PT, finalErr error) {
return nil, xerrors.WithStackTrace(err)
}
- if p.done.Load() {
+ select {
+ case <-p.done:
return nil, xerrors.WithStackTrace(errClosedPool)
- }
-
- var item PT
- p.mu.WithLock(func() {
- if len(p.idle) > 0 {
- item, p.idle = p.idle[0], p.idle[1:]
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.Idle--
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ default:
+ var item PT
+ p.mu.WithLock(func() {
+ if len(p.idle) > 0 {
+ item, p.idle = p.idle[0], p.idle[1:]
+ p.stats.Idle().Dec()
+ }
+ })
- return v
+ if item != nil {
+ if item.IsAlive() {
+ return item, nil
+ }
+ _ = p.closeItem(ctx, item)
+ p.mu.WithLock(func() {
+ delete(p.index, item)
})
+ p.stats.Index().Dec()
}
- })
- if item != nil {
- if item.IsAlive() {
- return item, nil
+ item, err := p.createItem(ctx)
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
}
- _ = item.Close(ctx)
- p.mu.WithLock(func() {
- delete(p.index, item)
- })
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.Index--
- return v
+ addedToIndex := false
+ p.mu.WithLock(func() {
+ if len(p.index) < p.limit {
+ p.index[item] = struct{}{}
+ addedToIndex = true
+ }
})
- }
-
- p.mu.Lock()
- defer p.mu.Unlock()
+ if addedToIndex {
+ p.stats.Index().Inc()
+ }
- if len(p.index) == p.limit {
- return nil, xerrors.WithStackTrace(errPoolOverflow)
+ return item, nil
}
-
- item, err := p.create(ctx)
- if err != nil {
- return nil, xerrors.WithStackTrace(err)
- }
-
- p.index[item] = struct{}{}
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.Index++
-
- return v
- })
-
- return item, nil
}
-func (p *Pool[PT, T]) put(ctx context.Context, item PT) (finalErr error) {
+func (p *Pool[PT, T]) putItem(ctx context.Context, item PT) (finalErr error) {
onDone := p.trace.OnPut(&PutStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).putItem"),
})
defer func() {
onDone(&PutDoneInfo{
@@ -195,41 +338,48 @@ func (p *Pool[PT, T]) put(ctx context.Context, item PT) (finalErr error) {
return xerrors.WithStackTrace(err)
}
- if p.done.Load() {
+ select {
+ case <-p.done:
return xerrors.WithStackTrace(errClosedPool)
- }
+ default:
+ if !item.IsAlive() {
+ _ = p.closeItem(ctx, item)
- if !item.IsAlive() {
- _ = item.Close(ctx)
+ p.mu.WithLock(func() {
+ delete(p.index, item)
+ })
+ p.stats.Index().Dec()
- p.mu.WithLock(func() {
- delete(p.index, item)
- })
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.Index--
+ return xerrors.WithStackTrace(errItemIsNotAlive)
+ }
- return v
+ p.mu.WithLock(func() {
+ p.idle = append(p.idle, item)
})
+ p.stats.Idle().Inc()
- return xerrors.WithStackTrace(errItemIsNotAlive)
+ return nil
}
+}
- p.mu.WithLock(func() {
- p.idle = append(p.idle, item)
- })
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.Idle++
+func (p *Pool[PT, T]) closeItem(ctx context.Context, item PT) error {
+ ctx = xcontext.ValueOnly(ctx)
- return v
- })
+ var cancel context.CancelFunc
+ if d := p.closeTimeout; d > 0 {
+ ctx, cancel = xcontext.WithTimeout(ctx, d)
+ } else {
+ ctx, cancel = xcontext.WithCancel(ctx)
+ }
+ defer cancel()
- return nil
+ return item.Close(ctx)
}
func (p *Pool[PT, T]) try(ctx context.Context, f func(ctx context.Context, item PT) error) (finalErr error) {
onDone := p.trace.OnTry(&TryStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).try"),
})
defer func() {
onDone(&TryDoneInfo{
@@ -237,27 +387,21 @@ func (p *Pool[PT, T]) try(ctx context.Context, f func(ctx context.Context, item
})
}()
- item, err := p.get(ctx)
+ item, err := p.getItem(ctx)
if err != nil {
+ if xerrors.IsYdb(err) {
+ return xerrors.WithStackTrace(xerrors.Retryable(err))
+ }
+
return xerrors.WithStackTrace(err)
}
defer func() {
- _ = p.put(ctx, item)
+ _ = p.putItem(ctx, item)
}()
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.InUse++
-
- return v
- })
- defer func() {
- p.stats.Change(func(v stats.Stats) stats.Stats {
- v.InUse--
-
- return v
- })
- }()
+ p.stats.InUse().Inc()
+ defer p.stats.InUse().Dec()
err = f(ctx, item)
if err != nil {
@@ -275,7 +419,7 @@ func (p *Pool[PT, T]) With(
var (
onDone = p.trace.OnWith(&WithStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).With"),
})
attempts int
)
@@ -294,11 +438,9 @@ func (p *Pool[PT, T]) With(
return nil
}, append(opts, retry.WithTrace(&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
}))...)
@@ -312,7 +454,7 @@ func (p *Pool[PT, T]) With(
func (p *Pool[PT, T]) Close(ctx context.Context) (finalErr error) {
onDone := p.trace.OnClose(&CloseStartInfo{
Context: &ctx,
- Call: stack.FunctionID(""),
+ Call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/pool.(*Pool).Close"),
})
defer func() {
onDone(&CloseDoneInfo{
@@ -320,25 +462,21 @@ func (p *Pool[PT, T]) Close(ctx context.Context) (finalErr error) {
})
}()
- p.done.Store(true)
+ close(p.done)
p.mu.Lock()
defer p.mu.Unlock()
- errs := make([]error, 0, len(p.index))
-
+ var g errgroup.Group
for item := range p.index {
- if err := item.Close(ctx); err != nil {
- errs = append(errs, err)
- }
+ item := item
+ g.Go(func() error {
+ return item.Close(ctx)
+ })
}
-
- switch len(errs) {
- case 0:
- return nil
- case 1:
- return errs[0]
- default:
- return xerrors.Join(errs...)
+ if err := g.Wait(); err != nil {
+ return xerrors.WithStackTrace(err)
}
+
+ return nil
}
diff --git a/internal/pool/pool_test.go b/internal/pool/pool_test.go
index f1f220804..63f8a1c11 100644
--- a/internal/pool/pool_test.go
+++ b/internal/pool/pool_test.go
@@ -3,12 +3,16 @@ package pool
import (
"context"
"errors"
+ "math/rand"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/require"
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
+ grpcCodes "google.golang.org/grpc/codes"
+ grpcStatus "google.golang.org/grpc/status"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
@@ -73,7 +77,97 @@ func TestPool(t *testing.T) {
require.EqualValues(t, p.limit, atomic.LoadInt64(&newCounter))
})
})
- t.Run("Change", func(t *testing.T) {
+ t.Run("Retry", func(t *testing.T) {
+ t.Run("CreateItem", func(t *testing.T) {
+ t.Run("context", func(t *testing.T) {
+ t.Run("Cancelled", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, context.Canceled
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ t.Run("DeadlineExceeded", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, context.DeadlineExceeded
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ })
+ t.Run("OnTransportError", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, ""))
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ t.Run("OnOperationError", func(t *testing.T) {
+ var counter int64
+ p := New(rootCtx,
+ WithCreateFunc(func(context.Context) (*testItem, error) {
+ atomic.AddInt64(&counter, 1)
+
+ if atomic.LoadInt64(&counter) < 10 {
+ return nil, xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE))
+ }
+
+ var v testItem
+
+ return &v, nil
+ }),
+ )
+ err := p.With(rootCtx, func(ctx context.Context, item *testItem) error {
+ return nil
+ })
+ require.NoError(t, err)
+ require.GreaterOrEqual(t, atomic.LoadInt64(&counter), int64(10))
+ })
+ })
+ })
+ t.Run("On", func(t *testing.T) {
t.Run("Context", func(t *testing.T) {
t.Run("Canceled", func(t *testing.T) {
ctx, cancel := context.WithCancel(rootCtx)
@@ -133,7 +227,7 @@ func TestPool(t *testing.T) {
var (
newItems int64
deleteItems int64
- expErr = xerrors.Retryable(errors.New("expected error"), xerrors.WithDeleteSession())
+ expErr = xerrors.Retryable(errors.New("expected error"), xerrors.InvalidObject())
)
p := New(rootCtx,
WithLimit[*testItem, testItem](1),
@@ -196,3 +290,31 @@ func TestPool(t *testing.T) {
}, xtest.StopAfter(42*time.Second))
})
}
+
+func TestSafeStatsRace(t *testing.T) {
+ xtest.TestManyTimes(t, func(t testing.TB) {
+ var (
+ wg sync.WaitGroup
+ s = &safeStats{}
+ )
+ wg.Add(10000)
+ for range make([]struct{}, 10000) {
+ go func() {
+ defer wg.Done()
+ require.NotPanics(t, func() {
+ switch rand.Int31n(4) { //nolint:gosec
+ case 0:
+ s.Index().Inc()
+ case 1:
+ s.InUse().Inc()
+ case 2:
+ s.Idle().Inc()
+ default:
+ s.Get()
+ }
+ })
+ }()
+ }
+ wg.Wait()
+ }, xtest.StopAfter(5*time.Second))
+}
diff --git a/internal/query/client.go b/internal/query/client.go
index a8bfa8ad5..3019e83cd 100644
--- a/internal/query/client.go
+++ b/internal/query/client.go
@@ -70,7 +70,7 @@ func do(
err := op(ctx, s)
if err != nil {
- if xerrors.MustDeleteSession(err) {
+ if !xerrors.IsRetryObjectValid(err) {
s.setStatus(statusError)
}
@@ -81,17 +81,9 @@ func do(
return nil
}, append(doOpts.RetryOpts(), retry.WithTrace(&trace.Retry{
- OnRetry: func(
- info trace.RetryLoopStartInfo,
- ) func(
- trace.RetryLoopIntermediateInfo,
- ) func(
- trace.RetryLoopDoneInfo,
- ) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
}))...)
@@ -107,7 +99,9 @@ func (c *Client) Do(ctx context.Context, op query.Operation, opts ...options.DoO
case <-c.done:
return xerrors.WithStackTrace(errClosedClient)
default:
- onDone := trace.QueryOnDo(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnDo(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Client).Do"),
+ )
attempts, err := do(ctx, c.pool, op, c.config.Trace(), opts...)
onDone(attempts, err)
@@ -157,12 +151,14 @@ func doTx(
return attempts, nil
}
-func (c *Client) DoTx(ctx context.Context, op query.TxOperation, opts ...options.DoTxOption) error {
+func (c *Client) DoTx(ctx context.Context, op query.TxOperation, opts ...options.DoTxOption) (err error) {
select {
case <-c.done:
return xerrors.WithStackTrace(errClosedClient)
default:
- onDone := trace.QueryOnDoTx(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnDoTx(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Client).DoTx"),
+ )
attempts, err := doTx(ctx, c.pool, op, c.config.Trace(), opts...)
onDone(attempts, err)
@@ -171,7 +167,9 @@ func (c *Client) DoTx(ctx context.Context, op query.TxOperation, opts ...options
}
func New(ctx context.Context, balancer balancer, cfg *config.Config) *Client {
- onDone := trace.QueryOnNew(cfg.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnNew(cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.New"),
+ )
defer onDone()
client := &Client{
@@ -183,18 +181,21 @@ func New(ctx context.Context, balancer balancer, cfg *config.Config) *Client {
client.pool = pool.New(ctx,
pool.WithLimit[*Session, Session](cfg.PoolLimit()),
pool.WithTrace[*Session, Session](poolTrace(cfg.Trace())),
+ pool.WithCreateItemTimeout[*Session, Session](cfg.SessionCreateTimeout()),
+ pool.WithCloseItemTimeout[*Session, Session](cfg.SessionDeleteTimeout()),
pool.WithCreateFunc(func(ctx context.Context) (_ *Session, err error) {
- var cancel context.CancelFunc
+ var (
+ createCtx context.Context
+ cancelCreate context.CancelFunc
+ )
if d := cfg.SessionCreateTimeout(); d > 0 {
- ctx, cancel = xcontext.WithTimeout(ctx, d)
+ createCtx, cancelCreate = xcontext.WithTimeout(ctx, d)
} else {
- ctx, cancel = xcontext.WithCancel(ctx)
+ createCtx, cancelCreate = xcontext.WithCancel(ctx)
}
- defer cancel()
+ defer cancelCreate()
- s, err := createSession(ctx,
- client.grpcClient,
- withSessionTrace(cfg.Trace()),
+ s, err := createSession(createCtx, client.grpcClient, cfg,
withSessionCheck(func(s *Session) bool {
return balancer.HasNode(uint32(s.nodeID))
}),
diff --git a/internal/query/client_test.go b/internal/query/client_test.go
index 7c49b22e7..1b7260750 100644
--- a/internal/query/client_test.go
+++ b/internal/query/client_test.go
@@ -15,6 +15,7 @@ import (
grpcStatus "google.golang.org/grpc/status"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/pool"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
"github.com/ydb-platform/ydb-go-sdk/v3/query"
@@ -39,9 +40,8 @@ func TestCreateSession(t *testing.T) {
service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
Status: Ydb.StatusIds_SUCCESS,
}, nil)
- t.Log("createSession")
attached := 0
- s, err := createSession(ctx, service, withSessionTrace(
+ s, err := createSession(ctx, service, config.New(config.WithTrace(
&trace.Query{
OnSessionAttach: func(info trace.QuerySessionAttachStartInfo) func(info trace.QuerySessionAttachDoneInfo) {
return func(info trace.QuerySessionAttachDoneInfo) {
@@ -56,7 +56,7 @@ func TestCreateSession(t *testing.T) {
return nil
},
},
- ))
+ )))
require.NoError(t, err)
require.EqualValues(t, "test", s.id)
require.EqualValues(t, 1, attached)
@@ -72,8 +72,7 @@ func TestCreateSession(t *testing.T) {
ctrl := gomock.NewController(t)
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
- t.Log("execute")
- _, err := createSession(ctx, service)
+ _, err := createSession(ctx, service, config.New())
require.Error(t, err)
require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
}, xtest.StopAfter(time.Second))
@@ -89,8 +88,7 @@ func TestCreateSession(t *testing.T) {
}, nil)
service.EXPECT().AttachSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
- t.Log("execute")
- _, err := createSession(ctx, service)
+ _, err := createSession(ctx, service, config.New())
require.Error(t, err)
require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
}, xtest.StopAfter(time.Second))
@@ -110,8 +108,7 @@ func TestCreateSession(t *testing.T) {
service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
Status: Ydb.StatusIds_SUCCESS,
}, nil)
- t.Log("execute")
- _, err := createSession(ctx, service)
+ _, err := createSession(ctx, service, config.New())
require.Error(t, err)
require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
}, xtest.StopAfter(time.Second))
@@ -123,11 +120,10 @@ func TestCreateSession(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
service := NewMockQueryServiceClient(ctrl)
- service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
- Status: Ydb.StatusIds_UNAVAILABLE,
- }, nil)
- t.Log("execute")
- _, err := createSession(ctx, service)
+ service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
+ _, err := createSession(ctx, service, config.New())
require.Error(t, err)
require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
}, xtest.StopAfter(time.Second))
@@ -137,9 +133,9 @@ func TestCreateSession(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
attachStream := NewMockQueryService_AttachSessionClient(ctrl)
- attachStream.EXPECT().Recv().Return(&Ydb_Query.SessionState{
- Status: Ydb.StatusIds_UNAVAILABLE,
- }, nil).AnyTimes()
+ attachStream.EXPECT().Recv().Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.CreateSessionResponse{
Status: Ydb.StatusIds_SUCCESS,
@@ -149,8 +145,7 @@ func TestCreateSession(t *testing.T) {
service.EXPECT().DeleteSession(gomock.Any(), gomock.Any()).Return(&Ydb_Query.DeleteSessionResponse{
Status: Ydb.StatusIds_SUCCESS,
}, nil)
- t.Log("execute")
- _, err := createSession(ctx, service)
+ _, err := createSession(ctx, service, config.New())
require.Error(t, err)
require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
}, xtest.StopAfter(time.Second))
@@ -158,19 +153,21 @@ func TestCreateSession(t *testing.T) {
})
}
-func newTestSession() (*Session, error) {
+func newTestSession(id string) *Session {
return &Session{
+ id: id,
statusCode: statusIdle,
- trace: &trace.Query{},
- }, nil
+ cfg: config.New(),
+ }
}
-func newTestSessionWithClient(client Ydb_Query_V1.QueryServiceClient) (*Session, error) {
+func newTestSessionWithClient(id string, client Ydb_Query_V1.QueryServiceClient) *Session {
return &Session{
+ id: id,
grpcClient: client,
statusCode: statusIdle,
- trace: &trace.Query{},
- }, nil
+ cfg: config.New(),
+ }
}
func testPool(
@@ -187,7 +184,7 @@ func TestDo(t *testing.T) {
ctx := xtest.Context(t)
t.Run("HappyWay", func(t *testing.T) {
attempts, err := do(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
- return newTestSession()
+ return newTestSession("123"), nil
}), func(ctx context.Context, s query.Session) error {
return nil
}, &trace.Query{})
@@ -197,7 +194,7 @@ func TestDo(t *testing.T) {
t.Run("RetryableError", func(t *testing.T) {
counter := 0
attempts, err := do(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
- return newTestSession()
+ return newTestSession("123"), nil
}), func(ctx context.Context, s query.Session) error {
counter++
if counter < 10 {
@@ -224,7 +221,7 @@ func TestDoTx(t *testing.T) {
Status: Ydb.StatusIds_SUCCESS,
}, nil)
attempts, err := doTx(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
- return newTestSessionWithClient(client)
+ return newTestSessionWithClient("123", client), nil
}), func(ctx context.Context, tx query.TxActor) error {
return nil
}, &trace.Query{})
@@ -245,7 +242,7 @@ func TestDoTx(t *testing.T) {
Status: Ydb.StatusIds_SUCCESS,
}, nil).AnyTimes()
attempts, err := doTx(ctx, testPool(ctx, func(ctx context.Context) (*Session, error) {
- return newTestSessionWithClient(client)
+ return newTestSessionWithClient("123", client), nil
}), func(ctx context.Context, tx query.TxActor) error {
counter++
if counter < 10 {
diff --git a/internal/query/config/config.go b/internal/query/config/config.go
index 392f2ec4d..7adb08242 100644
--- a/internal/query/config/config.go
+++ b/internal/query/config/config.go
@@ -10,7 +10,7 @@ import (
const (
DefaultSessionDeleteTimeout = 500 * time.Millisecond
- DefaultSessionCreateTimeout = 5 * time.Second
+ DefaultSessionCreateTimeout = 500 * time.Millisecond
DefaultPoolMaxSize = pool.DefaultLimit
)
@@ -62,9 +62,9 @@ func (c *Config) SessionCreateTimeout() time.Duration {
return c.sessionCreateTimeout
}
-// DeleteTimeout limits maximum time spent on Delete request
+// SessionDeleteTimeout limits maximum time spent on Delete request
//
-// If DeleteTimeout is less than or equal to zero then the DefaultSessionDeleteTimeout is used.
-func (c *Config) DeleteTimeout() time.Duration {
+// If SessionDeleteTimeout is less than or equal to zero then the DefaultSessionDeleteTimeout is used.
+func (c *Config) SessionDeleteTimeout() time.Duration {
return c.sessionDeleteTimeout
}
diff --git a/internal/query/execute_query.go b/internal/query/execute_query.go
index 182e75c0b..bf2fef314 100644
--- a/internal/query/execute_query.go
+++ b/internal/query/execute_query.go
@@ -60,14 +60,14 @@ func execute(ctx context.Context, s *Session, c Ydb_Query_V1.QueryServiceClient,
request, callOptions := executeQueryRequest(a, s.id, q, cfg)
- executeCtx, cancelExecute := xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ executeCtx, cancelExecute := xcontext.WithCancel(xcontext.ValueOnly(ctx))
stream, err := c.ExecuteQuery(executeCtx, request, callOptions...)
if err != nil {
return nil, nil, xerrors.WithStackTrace(err)
}
- r, txID, err := newResult(ctx, stream, s.trace, cancelExecute)
+ r, txID, err := newResult(ctx, stream, s.cfg.Trace(), cancelExecute)
if err != nil {
cancelExecute()
@@ -78,5 +78,5 @@ func execute(ctx context.Context, s *Session, c Ydb_Query_V1.QueryServiceClient,
return nil, r, nil
}
- return newTransaction(txID, s, s.trace), r, nil
+ return newTransaction(txID, s), r, nil
}
diff --git a/internal/query/execute_query_test.go b/internal/query/execute_query_test.go
index 9e6a2c2a0..c3c14d754 100644
--- a/internal/query/execute_query_test.go
+++ b/internal/query/execute_query_test.go
@@ -19,6 +19,7 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
+ "github.com/ydb-platform/ydb-go-sdk/v3/query"
)
func TestExecute(t *testing.T) {
@@ -355,8 +356,7 @@ func TestExecute(t *testing.T) {
stream.EXPECT().Recv().Return(nil, io.EOF)
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
- t.Log("execute")
- tx, r, err := execute(ctx, &Session{id: "123"}, service, "", options.ExecuteSettings())
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
require.NoError(t, err)
defer r.Close(ctx)
require.EqualValues(t, "456", tx.id)
@@ -469,7 +469,7 @@ func TestExecute(t *testing.T) {
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(nil, grpcStatus.Error(grpcCodes.Unavailable, ""))
t.Log("execute")
- _, _, err := execute(ctx, &Session{id: "123"}, service, "", options.ExecuteSettings())
+ _, _, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
require.Error(t, err)
require.True(t, xerrors.IsTransportError(err, grpcCodes.Unavailable))
})
@@ -573,7 +573,7 @@ func TestExecute(t *testing.T) {
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
t.Log("execute")
- tx, r, err := execute(ctx, &Session{id: "123"}, service, "", options.ExecuteSettings())
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
require.NoError(t, err)
defer r.Close(ctx)
require.EqualValues(t, "456", tx.id)
@@ -637,7 +637,7 @@ func TestExecute(t *testing.T) {
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
t.Log("execute")
- _, _, err := execute(ctx, &Session{id: "123"}, service, "", options.ExecuteSettings())
+ _, _, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
require.Error(t, err)
require.True(t, xerrors.IsOperationError(err, Ydb.StatusIds_UNAVAILABLE))
})
@@ -713,7 +713,7 @@ func TestExecute(t *testing.T) {
service := NewMockQueryServiceClient(ctrl)
service.EXPECT().ExecuteQuery(gomock.Any(), gomock.Any()).Return(stream, nil)
t.Log("execute")
- tx, r, err := execute(ctx, &Session{id: "123"}, service, "", options.ExecuteSettings())
+ tx, r, err := execute(ctx, newTestSession("123"), service, "", options.ExecuteSettings())
require.NoError(t, err)
defer r.Close(ctx)
require.EqualValues(t, "456", tx.id)
@@ -769,6 +769,24 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithoutOptions",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
+ Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
+ QueryContent: &Ydb_Query.QueryContent{
+ Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
+ Text: "WithoutOptions",
+ },
+ },
+ StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
+ ConcurrentResultSets: false,
+ },
+ },
+ {
+ name: "WithTxControl",
+ opts: []options.ExecuteOption{
+ options.WithTxControl(query.SerializableReadWriteTxControl(query.CommitTx())),
+ },
+ request: &Ydb_Query.ExecuteQueryRequest{
+ SessionId: "WithTxControl",
+ ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
TxControl: &Ydb_Query.TransactionControl{
TxSelector: &Ydb_Query.TransactionControl_BeginTx{
BeginTx: &Ydb_Query.TransactionSettings{
@@ -782,7 +800,7 @@ func TestExecuteQueryRequest(t *testing.T) {
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
- Text: "WithoutOptions",
+ Text: "WithTxControl",
},
},
StatsMode: Ydb_Query.StatsMode_STATS_MODE_NONE,
@@ -803,16 +821,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithParams",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -869,16 +877,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithExplain",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXPLAIN,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -897,16 +895,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithValidate",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_VALIDATE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -925,16 +913,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithValidate",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_PARSE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -953,16 +931,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithStatsFull",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -981,16 +949,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithStatsBasic",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -1009,16 +967,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithStatsProfile",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
@@ -1039,16 +987,6 @@ func TestExecuteQueryRequest(t *testing.T) {
request: &Ydb_Query.ExecuteQueryRequest{
SessionId: "WithGrpcCallOptions",
ExecMode: Ydb_Query.ExecMode_EXEC_MODE_EXECUTE,
- TxControl: &Ydb_Query.TransactionControl{
- TxSelector: &Ydb_Query.TransactionControl_BeginTx{
- BeginTx: &Ydb_Query.TransactionSettings{
- TxMode: &Ydb_Query.TransactionSettings_SerializableReadWrite{
- SerializableReadWrite: &Ydb_Query.SerializableModeSettings{},
- },
- },
- },
- CommitTx: true,
- },
Query: &Ydb_Query.ExecuteQueryRequest_QueryContent{
QueryContent: &Ydb_Query.QueryContent{
Syntax: Ydb_Query.Syntax_SYNTAX_YQL_V1,
diff --git a/internal/query/result.go b/internal/query/result.go
index 9a25da8e7..78478610d 100644
--- a/internal/query/result.go
+++ b/internal/query/result.go
@@ -40,7 +40,9 @@ func newResult(
closeResult = func() {}
}
- onDone := trace.QueryOnResultNew(t, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnResultNew(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.newResult"),
+ )
defer func() {
onDone(err)
}()
@@ -86,7 +88,9 @@ func nextPart(
t = &trace.Query{}
}
- onDone := trace.QueryOnResultNextPart(t, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnResultNextPart(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.nextPart"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -100,7 +104,9 @@ func nextPart(
}
func (r *result) Close(ctx context.Context) (err error) {
- onDone := trace.QueryOnResultClose(r.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnResultClose(r.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*result).Close"),
+ )
defer func() {
onDone(err)
}()
@@ -176,7 +182,9 @@ func (r *result) nextResultSet(ctx context.Context) (_ *resultSet, err error) {
}
func (r *result) NextResultSet(ctx context.Context) (_ query.ResultSet, err error) {
- onDone := trace.QueryOnResultNextResultSet(r.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnResultNextResultSet(r.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*result).NextResultSet"),
+ )
defer func() {
onDone(err)
}()
diff --git a/internal/query/result_set.go b/internal/query/result_set.go
index 445cc7050..8d2ae8b71 100644
--- a/internal/query/result_set.go
+++ b/internal/query/result_set.go
@@ -48,44 +48,50 @@ func newResultSet(
func (rs *resultSet) nextRow(ctx context.Context) (*row, error) {
rs.rowIndex++
- select {
- case <-rs.done:
- return nil, io.EOF
- case <-ctx.Done():
- return nil, xerrors.WithStackTrace(ctx.Err())
- default:
- if rs.rowIndex == len(rs.currentPart.GetResultSet().GetRows()) {
- part, err := rs.recv()
- if err != nil {
- if xerrors.Is(err, io.EOF) {
- close(rs.done)
+ for {
+ select {
+ case <-rs.done:
+ return nil, io.EOF
+ case <-ctx.Done():
+ return nil, xerrors.WithStackTrace(ctx.Err())
+ default:
+ if rs.rowIndex == len(rs.currentPart.GetResultSet().GetRows()) {
+ part, err := rs.recv()
+ if err != nil {
+ if xerrors.Is(err, io.EOF) {
+ close(rs.done)
+ }
+
+ return nil, xerrors.WithStackTrace(err)
}
+ rs.rowIndex = 0
+ rs.currentPart = part
+ if part == nil {
+ close(rs.done)
- return nil, xerrors.WithStackTrace(err)
+ return nil, xerrors.WithStackTrace(io.EOF)
+ }
}
- rs.rowIndex = 0
- rs.currentPart = part
- if part == nil {
+ if rs.index != rs.currentPart.GetResultSetIndex() {
close(rs.done)
- return nil, xerrors.WithStackTrace(io.EOF)
+ return nil, xerrors.WithStackTrace(fmt.Errorf(
+ "received part with result set index = %d, current result set index = %d: %w",
+ rs.index, rs.currentPart.GetResultSetIndex(), errWrongResultSetIndex,
+ ))
}
- }
- if rs.index != rs.currentPart.GetResultSetIndex() {
- close(rs.done)
- return nil, xerrors.WithStackTrace(fmt.Errorf(
- "received part with result set index = %d, current result set index = %d: %w",
- rs.index, rs.currentPart.GetResultSetIndex(), errWrongResultSetIndex,
- ))
+ if rs.rowIndex < len(rs.currentPart.GetResultSet().GetRows()) {
+ return newRow(ctx, rs.columns, rs.currentPart.GetResultSet().GetRows()[rs.rowIndex], rs.trace)
+ }
}
-
- return newRow(ctx, rs.columns, rs.currentPart.GetResultSet().GetRows()[rs.rowIndex], rs.trace)
}
}
func (rs *resultSet) NextRow(ctx context.Context) (_ query.Row, err error) {
- onDone := trace.QueryOnResultSetNextRow(rs.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnResultSetNextRow(rs.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*resultSet).NextRow"),
+ )
defer func() {
onDone(err)
}()
diff --git a/internal/query/result_set_test.go b/internal/query/result_set_test.go
index a011d2781..93f0491bf 100644
--- a/internal/query/result_set_test.go
+++ b/internal/query/result_set_test.go
@@ -20,6 +20,324 @@ import (
func TestResultSetNext(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
+ t.Run("EmptyResultSet", func(t *testing.T) {
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{},
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ })
+ t.Run("SecondResultSetEmpty", func(t *testing.T) {
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{},
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ })
+ t.Run("IntermediateResultSetEmpty", func(t *testing.T) {
+ stream := NewMockQueryService_ExecuteQueryClient(ctrl)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Rows: []*Ydb.Value{},
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
+ Status: Ydb.StatusIds_SUCCESS,
+ ResultSetIndex: 0,
+ ResultSet: &Ydb.ResultSet{
+ Columns: []*Ydb.Column{
+ {
+ Name: "a",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UINT64,
+ },
+ },
+ },
+ {
+ Name: "b",
+ Type: &Ydb.Type{
+ Type: &Ydb.Type_TypeId{
+ TypeId: Ydb.Type_UTF8,
+ },
+ },
+ },
+ },
+ Rows: []*Ydb.Value{
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 1,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "1",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 2,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "2",
+ },
+ }},
+ },
+ {
+ Items: []*Ydb.Value{{
+ Value: &Ydb.Value_Uint64Value{
+ Uint64Value: 3,
+ },
+ }, {
+ Value: &Ydb.Value_TextValue{
+ TextValue: "3",
+ },
+ }},
+ },
+ },
+ },
+ }, nil)
+ stream.EXPECT().Recv().Return(nil, io.EOF)
+ recv, err := stream.Recv()
+ require.NoError(t, err)
+ rs := newResultSet(func() (*Ydb_Query.ExecuteQueryResponsePart, error) {
+ part, err := stream.Recv()
+ if err != nil {
+ return nil, xerrors.WithStackTrace(err)
+ }
+
+ return part, nil
+ }, recv, nil)
+ require.EqualValues(t, 0, rs.index)
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 0, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 1, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.NoError(t, err)
+ require.EqualValues(t, 2, rs.rowIndex)
+ }
+ {
+ _, err := rs.nextRow(ctx)
+ require.ErrorIs(t, err, io.EOF)
+ }
+ })
t.Run("OverTwoParts", func(t *testing.T) {
stream := NewMockQueryService_ExecuteQueryClient(ctrl)
stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{
diff --git a/internal/query/row.go b/internal/query/row.go
index 27c5cb168..476b6aa14 100644
--- a/internal/query/row.go
+++ b/internal/query/row.go
@@ -35,7 +35,9 @@ func newRow(ctx context.Context, columns []*Ydb.Column, v *Ydb.Value, t *trace.Q
}
func (r row) Scan(dst ...interface{}) (err error) {
- onDone := trace.QueryOnRowScan(r.trace, &r.ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnRowScan(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.Scan"),
+ )
defer func() {
onDone(err)
}()
@@ -44,7 +46,9 @@ func (r row) Scan(dst ...interface{}) (err error) {
}
func (r row) ScanNamed(dst ...scanner.NamedDestination) (err error) {
- onDone := trace.QueryOnRowScanNamed(r.trace, &r.ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnRowScanNamed(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.ScanNamed"),
+ )
defer func() {
onDone(err)
}()
@@ -53,7 +57,9 @@ func (r row) ScanNamed(dst ...scanner.NamedDestination) (err error) {
}
func (r row) ScanStruct(dst interface{}, opts ...scanner.ScanStructOption) (err error) {
- onDone := trace.QueryOnRowScanStruct(r.trace, &r.ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnRowScanStruct(r.trace, &r.ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.row.ScanStruct"),
+ )
defer func() {
onDone(err)
}()
diff --git a/internal/query/session.go b/internal/query/session.go
index 42a482339..708b36df6 100644
--- a/internal/query/session.go
+++ b/internal/query/session.go
@@ -6,10 +6,10 @@ import (
"sync/atomic"
"github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
- "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/config"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
@@ -23,11 +23,11 @@ var _ query.Session = (*Session)(nil)
type (
Session struct {
+ cfg *config.Config
id string
nodeID int64
grpcClient Ydb_Query_V1.QueryServiceClient
statusCode statusCode
- trace *trace.Query
closeOnce func(ctx context.Context) error
checks []func(s *Session) bool
}
@@ -40,19 +40,13 @@ func withSessionCheck(f func(*Session) bool) sessionOption {
}
}
-func withSessionTrace(t *trace.Query) sessionOption {
- return func(s *Session) {
- s.trace = s.trace.Compose(t)
- }
-}
-
func createSession(
- ctx context.Context, client Ydb_Query_V1.QueryServiceClient, opts ...sessionOption,
+ ctx context.Context, client Ydb_Query_V1.QueryServiceClient, cfg *config.Config, opts ...sessionOption,
) (s *Session, finalErr error) {
s = &Session{
+ cfg: cfg,
grpcClient: client,
statusCode: statusUnknown,
- trace: &trace.Query{},
checks: []func(*Session) bool{
func(s *Session) bool {
switch s.status() {
@@ -74,22 +68,16 @@ func createSession(
opt(s)
}
- onDone := trace.QueryOnSessionCreate(s.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.QueryOnSessionCreate(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.createSession"),
+ )
defer func() {
onDone(s, finalErr)
}()
response, err := client.CreateSession(ctx, &Ydb_Query.CreateSessionRequest{})
if err != nil {
- return nil, xerrors.WithStackTrace(
- xerrors.Transport(err),
- )
- }
-
- if response.GetStatus() != Ydb.StatusIds_SUCCESS {
- return nil, xerrors.WithStackTrace(
- xerrors.FromOperation(response),
- )
+ return nil, xerrors.WithStackTrace(err)
}
defer func() {
@@ -103,9 +91,7 @@ func createSession(
err = s.attach(ctx)
if err != nil {
- return nil, xerrors.WithStackTrace(
- xerrors.Transport(err),
- )
+ return nil, xerrors.WithStackTrace(err)
}
s.setStatus(statusIdle)
@@ -114,41 +100,42 @@ func createSession(
}
func (s *Session) attach(ctx context.Context) (finalErr error) {
- onDone := trace.QueryOnSessionAttach(s.trace, &ctx, stack.FunctionID(""), s)
+ onDone := trace.QueryOnSessionAttach(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).attach"), s)
defer func() {
onDone(finalErr)
}()
- attachCtx, cancelAttach := xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ attachCtx, cancelAttach := xcontext.WithCancel(xcontext.ValueOnly(ctx))
attach, err := s.grpcClient.AttachSession(attachCtx, &Ydb_Query.AttachSessionRequest{
SessionId: s.id,
})
if err != nil {
- return xerrors.WithStackTrace(
- xerrors.Transport(err),
- )
+ return xerrors.WithStackTrace(err)
}
- state, err := attach.Recv()
+ _, err = attach.Recv()
if err != nil {
cancelAttach()
- return xerrors.WithStackTrace(xerrors.Transport(err))
- }
-
- if state.GetStatus() != Ydb.StatusIds_SUCCESS {
- cancelAttach()
-
- return xerrors.WithStackTrace(xerrors.FromOperation(state))
+ return xerrors.WithStackTrace(err)
}
s.closeOnce = xsync.OnceFunc(func(ctx context.Context) (err error) {
- cancelAttach()
+ defer cancelAttach()
s.setStatus(statusClosing)
defer s.setStatus(statusClosed)
+ var cancel context.CancelFunc
+ if d := s.cfg.SessionDeleteTimeout(); d > 0 {
+ ctx, cancel = xcontext.WithTimeout(ctx, d)
+ } else {
+ ctx, cancel = xcontext.WithCancel(ctx)
+ }
+ defer cancel()
+
if err = deleteSession(ctx, s.grpcClient, s.id); err != nil {
return xerrors.WithStackTrace(err)
}
@@ -158,14 +145,14 @@ func (s *Session) attach(ctx context.Context) (finalErr error) {
go func() {
defer func() {
- _ = s.closeOnce(ctx)
+ _ = s.closeOnce(xcontext.ValueOnly(ctx))
}()
for {
if !s.IsAlive() {
return
}
- recv, recvErr := attach.Recv()
+ _, recvErr := attach.Recv()
if recvErr != nil {
if xerrors.Is(recvErr, io.EOF) {
s.setStatus(statusClosed)
@@ -173,11 +160,6 @@ func (s *Session) attach(ctx context.Context) (finalErr error) {
s.setStatus(statusError)
}
- return
- }
- if recv.GetStatus() != Ydb.StatusIds_SUCCESS {
- s.setStatus(statusError)
-
return
}
}
@@ -187,16 +169,13 @@ func (s *Session) attach(ctx context.Context) (finalErr error) {
}
func deleteSession(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID string) error {
- response, err := client.DeleteSession(ctx,
+ _, err := client.DeleteSession(ctx,
&Ydb_Query.DeleteSessionRequest{
SessionId: sessionID,
},
)
if err != nil {
- return xerrors.WithStackTrace(xerrors.Transport(err))
- }
- if response.GetStatus() != Ydb.StatusIds_SUCCESS {
- return xerrors.WithStackTrace(xerrors.FromOperation(response))
+ return xerrors.WithStackTrace(err)
}
return nil
@@ -213,7 +192,8 @@ func (s *Session) IsAlive() bool {
}
func (s *Session) Close(ctx context.Context) (err error) {
- onDone := trace.QueryOnSessionDelete(s.trace, &ctx, stack.FunctionID(""), s)
+ onDone := trace.QueryOnSessionDelete(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Close"), s)
defer func() {
onDone(err)
}()
@@ -240,13 +220,10 @@ func begin(
},
)
if err != nil {
- return nil, xerrors.WithStackTrace(xerrors.Transport(err))
- }
- if response.GetStatus() != Ydb.StatusIds_SUCCESS {
- return nil, xerrors.WithStackTrace(xerrors.FromOperation(response))
+ return nil, xerrors.WithStackTrace(err)
}
- return newTransaction(response.GetTxMeta().GetId(), s, s.trace), nil
+ return newTransaction(response.GetTxMeta().GetId(), s), nil
}
func (s *Session) Begin(
@@ -257,7 +234,8 @@ func (s *Session) Begin(
) {
var tx *transaction
- onDone := trace.QueryOnSessionBegin(s.trace, &ctx, stack.FunctionID(""), s)
+ onDone := trace.QueryOnSessionBegin(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Begin"), s)
defer func() {
onDone(err, tx)
}()
@@ -294,7 +272,8 @@ func (s *Session) Status() string {
func (s *Session) Execute(
ctx context.Context, q string, opts ...options.ExecuteOption,
) (_ query.Transaction, _ query.Result, err error) {
- onDone := trace.QueryOnSessionExecute(s.trace, &ctx, stack.FunctionID(""), s, q)
+ onDone := trace.QueryOnSessionExecute(s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.(*Session).Execute"), s, q)
defer func() {
onDone(err)
}()
diff --git a/internal/query/session_test.go b/internal/query/session_test.go
index c96989855..b75faf5d7 100644
--- a/internal/query/session_test.go
+++ b/internal/query/session_test.go
@@ -45,9 +45,9 @@ func TestBegin(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
service := NewMockQueryServiceClient(ctrl)
- service.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(&Ydb_Query.BeginTransactionResponse{
- Status: Ydb.StatusIds_UNAVAILABLE,
- }, nil)
+ service.EXPECT().BeginTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
+ )
t.Log("begin")
_, err := begin(ctx, service, &Session{id: "123"}, query.TxSettings())
require.Error(t, err)
diff --git a/internal/query/transaction.go b/internal/query/transaction.go
index e62778890..fbfcd9151 100644
--- a/internal/query/transaction.go
+++ b/internal/query/transaction.go
@@ -4,7 +4,6 @@ import (
"context"
"github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
- "github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
@@ -17,20 +16,14 @@ import (
var _ query.Transaction = (*transaction)(nil)
type transaction struct {
- id string
- s *Session
- trace *trace.Query
+ id string
+ s *Session
}
-func newTransaction(id string, s *Session, t *trace.Query) *transaction {
- if t == nil {
- t = &trace.Query{}
- }
-
+func newTransaction(id string, s *Session) *transaction {
return &transaction{
- id: id,
- s: s,
- trace: t,
+ id: id,
+ s: s,
}
}
@@ -41,7 +34,8 @@ func (tx transaction) ID() string {
func (tx transaction) Execute(ctx context.Context, q string, opts ...options.TxExecuteOption) (
r query.Result, finalErr error,
) {
- onDone := trace.QueryOnTxExecute(tx.trace, &ctx, stack.FunctionID(""), tx.s, tx, q)
+ onDone := trace.QueryOnTxExecute(tx.s.cfg.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/query.transaction.Execute"), tx.s, tx, q)
defer func() {
onDone(finalErr)
}()
@@ -55,15 +49,12 @@ func (tx transaction) Execute(ctx context.Context, q string, opts ...options.TxE
}
func commitTx(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID, txID string) error {
- response, err := client.CommitTransaction(ctx, &Ydb_Query.CommitTransactionRequest{
+ _, err := client.CommitTransaction(ctx, &Ydb_Query.CommitTransactionRequest{
SessionId: sessionID,
TxId: txID,
})
if err != nil {
- return xerrors.WithStackTrace(xerrors.Transport(err))
- }
- if response.GetStatus() != Ydb.StatusIds_SUCCESS {
- return xerrors.WithStackTrace(xerrors.FromOperation(response))
+ return xerrors.WithStackTrace(err)
}
return nil
@@ -74,15 +65,12 @@ func (tx transaction) CommitTx(ctx context.Context) (err error) {
}
func rollback(ctx context.Context, client Ydb_Query_V1.QueryServiceClient, sessionID, txID string) error {
- response, err := client.RollbackTransaction(ctx, &Ydb_Query.RollbackTransactionRequest{
+ _, err := client.RollbackTransaction(ctx, &Ydb_Query.RollbackTransactionRequest{
SessionId: sessionID,
TxId: txID,
})
if err != nil {
- return xerrors.WithStackTrace(xerrors.Transport(err))
- }
- if response.GetStatus() != Ydb.StatusIds_SUCCESS {
- return xerrors.WithStackTrace(xerrors.FromOperation(response))
+ return xerrors.WithStackTrace(err)
}
return nil
diff --git a/internal/query/transaction_test.go b/internal/query/transaction_test.go
index 90b305f85..83ecdfc6c 100644
--- a/internal/query/transaction_test.go
+++ b/internal/query/transaction_test.go
@@ -49,10 +49,8 @@ func TestCommitTx(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
service := NewMockQueryServiceClient(ctrl)
- service.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(
- &Ydb_Query.CommitTransactionResponse{
- Status: Ydb.StatusIds_UNAVAILABLE,
- }, nil,
+ service.EXPECT().CommitTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
)
t.Log("commit")
err := commitTx(ctx, service, "123", "456")
@@ -91,10 +89,8 @@ func TestRollback(t *testing.T) {
ctx := xtest.Context(t)
ctrl := gomock.NewController(t)
service := NewMockQueryServiceClient(ctrl)
- service.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(
- &Ydb_Query.RollbackTransactionResponse{
- Status: Ydb.StatusIds_UNAVAILABLE,
- }, nil,
+ service.EXPECT().RollbackTransaction(gomock.Any(), gomock.Any()).Return(nil,
+ xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_UNAVAILABLE)),
)
t.Log("rollback")
err := rollback(ctx, service, "123", "456")
diff --git a/internal/query/tx/control.go b/internal/query/tx/control.go
index f6e6f15d5..a5be2fb21 100644
--- a/internal/query/tx/control.go
+++ b/internal/query/tx/control.go
@@ -125,10 +125,7 @@ func NoTx() *Control {
// DefaultTxControl returns default transaction control with serializable read-write isolation mode and auto-commit
func DefaultTxControl() *Control {
- return NewControl(
- BeginTx(WithSerializableReadWrite()),
- CommitTx(),
- )
+ return NoTx()
}
// SerializableReadWriteTxControl returns transaction control with serializable read-write isolation mode
diff --git a/internal/repeater/repeater.go b/internal/repeater/repeater.go
index 033b44a14..ec75be3c1 100644
--- a/internal/repeater/repeater.go
+++ b/internal/repeater/repeater.go
@@ -147,7 +147,7 @@ func (r *repeater) wakeUp(ctx context.Context, e Event) (err error) {
ctx = WithEvent(ctx, e)
onDone := trace.DriverOnRepeaterWakeUp(r.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/repeater.(*repeater).wakeUp"),
r.name, e,
)
defer func() {
@@ -172,8 +172,8 @@ func (r *repeater) worker(ctx context.Context, tick clockwork.Ticker) {
// force returns backoff with delays [500ms...32s]
force := backoff.New(
- backoff.WithSlotDuration(500*time.Millisecond),
- backoff.WithCeiling(6),
+ backoff.WithSlotDuration(500*time.Millisecond), //nolint:gomnd
+ backoff.WithCeiling(6), //nolint:gomnd
backoff.WithJitterLimit(1),
)
diff --git a/internal/scheme/client.go b/internal/scheme/client.go
index 9d0cf10e0..6f46ed736 100644
--- a/internal/scheme/client.go
+++ b/internal/scheme/client.go
@@ -47,7 +47,7 @@ func New(ctx context.Context, cc grpc.ClientConnInterface, config config.Config)
func (c *Client) MakeDirectory(ctx context.Context, path string) (finalErr error) {
onDone := trace.SchemeOnMakeDirectory(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).MakeDirectory"),
path,
)
defer func() {
@@ -86,7 +86,7 @@ func (c *Client) makeDirectory(ctx context.Context, path string) (err error) {
func (c *Client) RemoveDirectory(ctx context.Context, path string) (finalErr error) {
onDone := trace.SchemeOnRemoveDirectory(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).RemoveDirectory"),
path,
)
defer func() {
@@ -124,7 +124,9 @@ func (c *Client) removeDirectory(ctx context.Context, path string) (err error) {
}
func (c *Client) ListDirectory(ctx context.Context, path string) (d scheme.Directory, finalErr error) {
- onDone := trace.SchemeOnListDirectory(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.SchemeOnListDirectory(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).ListDirectory"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -182,7 +184,7 @@ func (c *Client) listDirectory(ctx context.Context, path string) (scheme.Directo
func (c *Client) DescribePath(ctx context.Context, path string) (e scheme.Entry, finalErr error) {
onDone := trace.SchemeOnDescribePath(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).DescribePath"),
path,
)
defer func() {
@@ -243,7 +245,7 @@ func (c *Client) ModifyPermissions(
ctx context.Context, path string, opts ...scheme.PermissionsOption,
) (finalErr error) {
onDone := trace.SchemeOnModifyPermissions(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scheme.(*Client).ModifyPermissions"),
path,
)
defer func() {
diff --git a/internal/scripting/client.go b/internal/scripting/client.go
index 60b85a248..a8ecc18bb 100644
--- a/internal/scripting/client.go
+++ b/internal/scripting/client.go
@@ -72,7 +72,7 @@ func (c *Client) execute(
) (r result.Result, err error) {
var (
onDone = trace.ScriptingOnExecute(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).execute"),
query, parameters,
)
a = allocator.New()
@@ -151,7 +151,7 @@ func (c *Client) explain(
) (e table.ScriptingYQLExplanation, err error) {
var (
onDone = trace.ScriptingOnExplain(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).explain"),
query,
)
request = &Ydb_Scripting.ExplainYqlRequest{
@@ -225,7 +225,7 @@ func (c *Client) streamExecute(
) (r result.StreamResult, err error) {
var (
onIntermediate = trace.ScriptingOnStreamExecute(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).streamExecute"),
query, parameters,
)
a = allocator.New()
@@ -292,7 +292,9 @@ func (c *Client) Close(ctx context.Context) (err error) {
if c == nil {
return xerrors.WithStackTrace(errNilClient)
}
- onDone := trace.ScriptingOnClose(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.ScriptingOnClose(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/scripting.(*Client).Close"),
+ )
defer func() {
onDone(err)
}()
diff --git a/internal/secret/token.go b/internal/secret/token.go
index dc90e0c59..5383a8e0f 100644
--- a/internal/secret/token.go
+++ b/internal/secret/token.go
@@ -6,9 +6,11 @@ import (
"hash/crc32"
)
+const minTokenLength = 16
+
func Token(token string) string {
var mask bytes.Buffer
- if len(token) > 16 {
+ if len(token) > minTokenLength {
mask.WriteString(token[:4])
mask.WriteString("****")
mask.WriteString(token[len(token)-4:])
diff --git a/internal/stack/function_id_test.go b/internal/stack/function_id_test.go
index c913a6d00..b7adabee5 100644
--- a/internal/stack/function_id_test.go
+++ b/internal/stack/function_id_test.go
@@ -1,13 +1,17 @@
package stack
import (
+ "sync"
"testing"
+ "time"
"github.com/stretchr/testify/require"
)
type genericType[T any] struct{}
+type starType struct{}
+
func (t genericType[T]) Call() string {
return FunctionID("").FunctionID()
}
@@ -16,6 +20,26 @@ func staticCall() string {
return FunctionID("").FunctionID()
}
+func (e *starType) starredCall() string {
+ return FunctionID("").FunctionID()
+}
+
+func anonymousFunctionCall() string {
+ var result string
+ var mu sync.Mutex
+ go func() {
+ mu.Lock()
+ defer mu.Unlock()
+ result = FunctionID("").FunctionID()
+ }()
+ time.Sleep(time.Second)
+
+ mu.Lock()
+ defer mu.Unlock()
+
+ return result
+}
+
func TestFunctionIDForGenericType(t *testing.T) {
t.Run("StaticFunc", func(t *testing.T) {
require.Equal(t,
@@ -29,4 +53,17 @@ func TestFunctionIDForGenericType(t *testing.T) {
genericType[uint64]{}.Call(),
)
})
+ t.Run("StarTypeCall", func(t *testing.T) {
+ x := starType{}
+ require.Equal(t,
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.(*starType).starredCall",
+ x.starredCall(),
+ )
+ })
+ t.Run("AnonymousFunctionCall", func(t *testing.T) {
+ require.Equal(t,
+ "github.com/ydb-platform/ydb-go-sdk/v3/internal/stack.anonymousFunctionCall",
+ anonymousFunctionCall(),
+ )
+ })
}
diff --git a/internal/stack/record.go b/internal/stack/record.go
index efe5e9db6..2098c1ec8 100644
--- a/internal/stack/record.go
+++ b/internal/stack/record.go
@@ -122,7 +122,7 @@ func (c call) Record(opts ...recordOption) string {
if len(split) > 1 {
funcName = split[len(split)-1]
}
- if len(split) > 2 {
+ if len(split) > 2 { //nolint:gomnd
structName = split[1]
}
diff --git a/internal/table/client.go b/internal/table/client.go
index da0f84534..9a7794625 100644
--- a/internal/table/client.go
+++ b/internal/table/client.go
@@ -35,7 +35,9 @@ type balancer interface {
}
func New(ctx context.Context, balancer balancer, config *config.Config) *Client {
- onDone := trace.TableOnInit(config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnInit(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.New"),
+ )
defer func() {
onDone(config.SizeLimit())
}()
@@ -166,7 +168,7 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
err error
)
- createSessionCtx := xcontext.WithoutDeadline(ctx)
+ createSessionCtx := xcontext.ValueOnly(ctx)
if timeout := c.config.CreateSessionTimeout(); timeout > 0 {
var cancel context.CancelFunc
@@ -179,7 +181,7 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
return
}
- closeSessionCtx := xcontext.WithoutDeadline(ctx)
+ closeSessionCtx := xcontext.ValueOnly(ctx)
if timeout := c.config.DeleteTimeout(); timeout > 0 {
var cancel context.CancelFunc
@@ -261,15 +263,13 @@ func (c *Client) CreateSession(ctx context.Context, opts ...table.Option) (_ tab
[]retry.Option{
retry.WithIdempotent(true),
retry.WithTrace(&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- onIntermediate := trace.TableOnCreateSession(c.config.Trace(), info.Context, stack.FunctionID(""))
-
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- onDone := onIntermediate(info.Error)
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ onDone := trace.TableOnCreateSession(c.config.Trace(), info.Context,
+ stack.FunctionID(
+ "github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).CreateSession"))
- return func(info trace.RetryLoopDoneInfo) {
- onDone(s, info.Attempts, info.Error)
- }
+ return func(info trace.RetryLoopDoneInfo) {
+ onDone(s, info.Attempts, info.Error)
}
},
}),
@@ -381,7 +381,9 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
}
}
- onDone := trace.TableOnPoolGet(o.t, &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnPoolGet(o.t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).internalPoolGet"),
+ )
defer func() {
onDone(s, i, err)
}()
@@ -477,7 +479,9 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
el = c.waitQ.PushBack(ch)
})
- waitDone := trace.TableOnPoolWait(t, &ctx, stack.FunctionID(""))
+ waitDone := trace.TableOnPoolWait(t, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).internalPoolWaitFromCh"),
+ )
defer func() {
waitDone(s, err)
@@ -485,7 +489,10 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
var createSessionTimeoutCh <-chan time.Time
if timeout := c.config.CreateSessionTimeout(); timeout > 0 {
- createSessionTimeoutCh = c.clock.After(timeout)
+ createSessionTimeoutChTimer := c.clock.NewTimer(timeout)
+ defer createSessionTimeoutChTimer.Stop()
+
+ createSessionTimeoutCh = createSessionTimeoutChTimer.Chan()
}
select {
@@ -539,7 +546,7 @@ func (c *Client) internalPoolWaitFromCh(ctx context.Context, t *trace.Table) (s
// panic.
func (c *Client) Put(ctx context.Context, s *session) (err error) {
onDone := trace.TableOnPoolPut(c.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Put"),
s,
)
defer func() {
@@ -598,7 +605,9 @@ func (c *Client) Close(ctx context.Context) (err error) {
default:
close(c.done)
- onDone := trace.TableOnClose(c.config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnClose(c.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Close"),
+ )
defer func() {
onDone(err)
}()
@@ -606,12 +615,18 @@ func (c *Client) Close(ctx context.Context) (err error) {
c.limit = 0
for el := c.waitQ.Front(); el != nil; el = el.Next() {
- ch := el.Value.(*chan *session)
+ ch, ok := el.Value.(*chan *session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *chan *session", ch))
+ }
close(*ch)
}
for e := c.idle.Front(); e != nil; e = e.Next() {
- s := e.Value.(*session)
+ s, ok := e.Value.(*session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *chan *session", s))
+ }
s.SetStatus(table.SessionClosing)
c.wg.Add(1)
go func() {
@@ -643,17 +658,16 @@ func (c *Client) Do(ctx context.Context, op table.Operation, opts ...table.Optio
config := c.retryOptions(opts...)
- attempts, onIntermediate := 0, trace.TableOnDo(config.Trace, &ctx,
- stack.FunctionID(""),
+ attempts, onDone := 0, trace.TableOnDo(config.Trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).Do"),
config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
err := do(ctx, c, c.config, op, func(err error) {
attempts++
- onIntermediate(err)
}, config.RetryOptions...)
if err != nil {
return xerrors.WithStackTrace(err)
@@ -673,22 +687,18 @@ func (c *Client) DoTx(ctx context.Context, op table.TxOperation, opts ...table.O
config := c.retryOptions(opts...)
- attempts, onIntermediate := 0, trace.TableOnDoTx(config.Trace, &ctx,
- stack.FunctionID(""),
+ attempts, onDone := 0, trace.TableOnDoTx(config.Trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*Client).DoTx"),
config.Label, config.Idempotent, xcontext.IsNestedCall(ctx),
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
return retryBackoff(ctx, c,
func(ctx context.Context, s table.Session) (err error) {
attempts++
- defer func() {
- onIntermediate(err)
- }()
-
tx, err := s.BeginTransaction(ctx, config.TxSettings)
if err != nil {
return xerrors.WithStackTrace(err)
@@ -741,7 +751,10 @@ func (c *Client) internalPoolGCTick(ctx context.Context, idleThreshold time.Dura
return
}
for e := c.idle.Front(); e != nil; e = e.Next() {
- s := e.Value.(*session)
+ s, ok := e.Value.(*session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *session", s))
+ }
info, has := c.index[s]
if !has {
panic("session not found in pool")
@@ -777,7 +790,7 @@ func (c *Client) internalPoolGC(ctx context.Context, idleThreshold time.Duration
case <-timer.Chan():
c.internalPoolGCTick(ctx, idleThreshold)
- timer.Reset(idleThreshold / 2)
+ timer.Reset(idleThreshold / 2) //nolint:gomnd
}
}
}
@@ -814,7 +827,10 @@ func (c *Client) internalPoolPeekFirstIdle() (s *session, touched time.Time) {
if el == nil {
return
}
- s = el.Value.(*session)
+ s, ok := el.Value.(*session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *session", s))
+ }
info, has := c.index[s]
if !has || el != info.idle {
panic("inconsistent session client index")
@@ -853,7 +869,10 @@ func (c *Client) internalPoolNotify(s *session) (notified bool) {
// missed something and may want to retry (especially for case (3)).
//
// After that we taking a next waiter and repeat the same.
- ch := c.waitQ.Remove(el).(*chan *session)
+ ch, ok := c.waitQ.Remove(el).(*chan *session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *chan *session", ch))
+ }
select {
case *ch <- s:
// Case (1).
diff --git a/internal/table/client_test.go b/internal/table/client_test.go
index 82b7eb6af..6f1331b6e 100644
--- a/internal/table/client_test.go
+++ b/internal/table/client_test.go
@@ -912,7 +912,10 @@ func (s *StubBuilder) createSession(ctx context.Context) (session *session, err
func (c *Client) debug() {
fmt.Print("head ")
for el := c.idle.Front(); el != nil; el = el.Next() {
- s := el.Value.(*session)
+ s, ok := el.Value.(*session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *session", s))
+ }
x := c.index[s]
fmt.Printf("<-> %s(%d) ", s.ID(), x.touched.Unix())
}
diff --git a/internal/table/config/config.go b/internal/table/config/config.go
index de94fb3e6..7c03b33e8 100644
--- a/internal/table/config/config.go
+++ b/internal/table/config/config.go
@@ -15,13 +15,19 @@ const (
DefaultSessionPoolSizeLimit = 50
DefaultSessionPoolIdleThreshold = 5 * time.Minute
- // Deprecated: table client do not supports background session keep-aliving now
+ // Deprecated: table client do not supports background session keep-aliving now.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
DefaultKeepAliveMinSize = 10
- // Deprecated: table client do not supports background session keep-aliving now
+ // Deprecated: table client do not supports background session keep-aliving now.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
DefaultIdleKeepAliveThreshold = 2
- // Deprecated: table client do not supports background session keep-aliving now
+ // Deprecated: table client do not supports background session keep-aliving now.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
DefaultSessionPoolKeepAliveTimeout = 500 * time.Millisecond
)
@@ -61,7 +67,9 @@ func WithSizeLimit(sizeLimit int) Option {
// If keepAliveMinSize is less than zero, then no sessions will be preserved
// If keepAliveMinSize is zero, the DefaultKeepAliveMinSize is used
//
-// Deprecated: table client do not supports background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithKeepAliveMinSize(keepAliveMinSize int) Option {
return func(c *Config) {}
}
@@ -73,7 +81,9 @@ func WithKeepAliveMinSize(keepAliveMinSize int) Option {
// be removed ever.
// If IdleKeepAliveThreshold is equal to zero, it will be set to DefaultIdleKeepAliveThreshold
//
-// Deprecated: table client do not support background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithIdleKeepAliveThreshold(idleKeepAliveThreshold int) Option {
return func(c *Config) {}
}
@@ -95,7 +105,9 @@ func WithIdleThreshold(idleThreshold time.Duration) Option {
// WithKeepAliveTimeout limits maximum time spent on KeepAlive request
// If keepAliveTimeout is less than or equal to zero then the DefaultSessionPoolKeepAliveTimeout is used.
//
-// Deprecated: table client do not support background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithKeepAliveTimeout(keepAliveTimeout time.Duration) Option {
return func(c *Config) {}
}
@@ -182,7 +194,9 @@ func (c *Config) SizeLimit() int {
// If KeepAliveMinSize is less than zero, then no sessions will be preserved
// If KeepAliveMinSize is zero, the DefaultKeepAliveMinSize is used
//
-// Deprecated: table client do not support background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (c *Config) KeepAliveMinSize() int {
return DefaultKeepAliveMinSize
}
@@ -199,7 +213,9 @@ func (c *Config) IgnoreTruncated() bool {
// be removed ever.
// If IdleKeepAliveThreshold is equal to zero, it will be set to DefaultIdleKeepAliveThreshold
//
-// Deprecated: table client do not support background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (c *Config) IdleKeepAliveThreshold() int {
return DefaultIdleKeepAliveThreshold
}
@@ -216,7 +232,9 @@ func (c *Config) IdleThreshold() time.Duration {
// KeepAliveTimeout limits maximum time spent on KeepAlive request
// If KeepAliveTimeout is less than or equal to zero then the DefaultSessionPoolKeepAliveTimeout is used.
//
-// Deprecated: table client do not support background session keep-aliving now
+// Deprecated: table client do not supports background session keep-aliving now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (c *Config) KeepAliveTimeout() time.Duration {
return DefaultSessionPoolKeepAliveTimeout
}
diff --git a/internal/table/retry_test.go b/internal/table/retry_test.go
index 008633786..70d58ed8b 100644
--- a/internal/table/retry_test.go
+++ b/internal/table/retry_test.go
@@ -160,7 +160,11 @@ func TestRetryerSessionClosing(t *testing.T) {
config.New(),
func(ctx context.Context, s table.Session) error {
sessions = append(sessions, s)
- s.(*session).SetStatus(table.SessionClosing)
+ val, ok := s.(*session)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *session", val))
+ }
+ val.SetStatus(table.SessionClosing)
return nil
},
diff --git a/internal/table/scanner/result.go b/internal/table/scanner/result.go
index 1cbc88eb6..fdebc2859 100644
--- a/internal/table/scanner/result.go
+++ b/internal/table/scanner/result.go
@@ -170,7 +170,7 @@ func (r *unaryResult) NextResultSet(ctx context.Context, columns ...string) bool
func (r *streamResult) nextResultSetErr(ctx context.Context, columns ...string) (err error) {
// skipping second recv because first call of recv is from New Stream(), second call is from user
- if r.nextResultSetCounter.Add(1) == 2 {
+ if r.nextResultSetCounter.Add(1) == 2 { //nolint:gomnd
r.setColumnIndexes(columns)
return ctx.Err()
diff --git a/internal/table/scanner/result_test.go b/internal/table/scanner/result_test.go
index dc81b0203..a564e6dc6 100644
--- a/internal/table/scanner/result_test.go
+++ b/internal/table/scanner/result_test.go
@@ -264,18 +264,30 @@ func TestNewStreamWithRecvFirstResultSet(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, result)
require.EqualValues(t, 1, tt.recvCounter)
- require.EqualValues(t, 1, result.(*streamResult).nextResultSetCounter.Load())
+ val, ok := result.(*streamResult)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *streamResult", val))
+ }
+ require.EqualValues(t, 1, val.nextResultSetCounter.Load())
for i := range make([]struct{}, 1000) {
err = result.NextResultSetErr(tt.ctx)
require.NoError(t, err)
require.Equal(t, i+1, tt.recvCounter)
- require.Equal(t, i+2, int(result.(*streamResult).nextResultSetCounter.Load()))
+ val, check := result.(*streamResult)
+ if !check {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *streamResult", val))
+ }
+ require.Equal(t, i+2, int(val.nextResultSetCounter.Load()))
}
err = result.NextResultSetErr(tt.ctx)
require.ErrorIs(t, err, io.EOF)
require.True(t, err == io.EOF) //nolint:errorlint,testifylint
require.Equal(t, 1001, tt.recvCounter)
- require.Equal(t, 1002, int(result.(*streamResult).nextResultSetCounter.Load()))
+ res, ok := result.(*streamResult)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *streamResult", res))
+ }
+ require.Equal(t, 1002, int(res.nextResultSetCounter.Load()))
}
})
}
diff --git a/internal/table/scanner/scan_raw.go b/internal/table/scanner/scan_raw.go
index 7c0782f3c..c3b114c2d 100644
--- a/internal/table/scanner/scan_raw.go
+++ b/internal/table/scanner/scan_raw.go
@@ -2,6 +2,7 @@ package scanner
import (
"bytes"
+ "fmt"
"io"
"reflect"
"strconv"
@@ -584,8 +585,10 @@ func (s *rawConverter) IsDecimal() bool {
}
func isEqualDecimal(d *Ydb.DecimalType, t types.Type) bool {
- w := t.(*types.Decimal)
-
+ w, ok := t.(*types.Decimal)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *types.Decimal", w))
+ }
return d.GetPrecision() == w.Precision() && d.GetScale() == w.Scale()
}
diff --git a/internal/table/scanner/scanner.go b/internal/table/scanner/scanner.go
index f541a1235..8a3effb2b 100644
--- a/internal/table/scanner/scanner.go
+++ b/internal/table/scanner/scanner.go
@@ -1174,7 +1174,7 @@ func (s *valueScanner) errorf(depth int, f string, args ...interface{}) error {
func (s *valueScanner) typeError(act, exp interface{}) {
_ = s.errorf(
- 2,
+ 2, //nolint:gomnd
"unexpected types during scan at %q %s: %s; want %s",
s.path(),
s.getType(),
@@ -1186,7 +1186,7 @@ func (s *valueScanner) typeError(act, exp interface{}) {
func (s *valueScanner) valueTypeError(act, exp interface{}) {
// unexpected value during scan at \"migration_status\" Int64: NullFlag; want Int64
_ = s.errorf(
- 2,
+ 2, //nolint:gomnd
"unexpected value during scan at %q %s: %s; want %s",
s.path(),
s.getType(),
@@ -1197,7 +1197,7 @@ func (s *valueScanner) valueTypeError(act, exp interface{}) {
func (s *valueScanner) notFoundColumnByIndex(idx int) error {
return s.errorf(
- 2,
+ 2, //nolint:gomnd
"not found %d column",
idx,
)
@@ -1205,7 +1205,7 @@ func (s *valueScanner) notFoundColumnByIndex(idx int) error {
func (s *valueScanner) notFoundColumnName(name string) error {
return s.errorf(
- 2,
+ 2, //nolint:gomnd
"not found column '%s'",
name,
)
@@ -1213,7 +1213,7 @@ func (s *valueScanner) notFoundColumnName(name string) error {
func (s *valueScanner) noColumnError(name string) error {
return s.errorf(
- 2,
+ 2, //nolint:gomnd
"no column %q",
name,
)
@@ -1221,7 +1221,7 @@ func (s *valueScanner) noColumnError(name string) error {
func (s *valueScanner) overflowError(i, n interface{}) error {
return s.errorf(
- 2,
+ 2, //nolint:gomnd
"overflow error: %d overflows capacity of %t",
i,
n,
diff --git a/internal/table/session.go b/internal/table/session.go
index 0b8eba0ee..98e8ce4db 100644
--- a/internal/table/session.go
+++ b/internal/table/session.go
@@ -116,7 +116,9 @@ func (s *session) isClosing() bool {
func newSession(ctx context.Context, cc grpc.ClientConnInterface, config *config.Config) (
s *session, err error,
) {
- onDone := trace.TableOnSessionNew(config.Trace(), &ctx, stack.FunctionID(""))
+ onDone := trace.TableOnSessionNew(config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.newSession"),
+ )
defer func() {
onDone(s, err)
}()
@@ -179,7 +181,7 @@ func (s *session) Close(ctx context.Context) (err error) {
s.closeOnce.Do(func() {
onDone := trace.TableOnSessionDelete(s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Close"),
s,
)
defer func() {
@@ -231,7 +233,7 @@ func (s *session) KeepAlive(ctx context.Context) (err error) {
result Ydb_Table.KeepAliveResult
onDone = trace.TableOnSessionKeepAlive(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).KeepAlive"),
s,
)
)
@@ -485,7 +487,7 @@ func (s *session) checkError(err error) {
if err == nil {
return
}
- if m := retry.Check(err); m.MustDeleteSession() {
+ if m := retry.Check(err); m.IsRetryObjectValid() {
s.SetStatus(table.SessionClosing)
}
}
@@ -600,6 +602,56 @@ func (s *session) CopyTables(
return nil
}
+func renameTables(
+ ctx context.Context,
+ sessionID string,
+ operationTimeout time.Duration,
+ operationCancelAfter time.Duration,
+ service interface {
+ RenameTables(
+ ctx context.Context, in *Ydb_Table.RenameTablesRequest, opts ...grpc.CallOption,
+ ) (*Ydb_Table.RenameTablesResponse, error)
+ },
+ opts ...options.RenameTablesOption,
+) (err error) {
+ request := Ydb_Table.RenameTablesRequest{
+ SessionId: sessionID,
+ OperationParams: operation.Params(
+ ctx,
+ operationTimeout,
+ operationCancelAfter,
+ operation.ModeSync,
+ ),
+ }
+ for _, opt := range opts {
+ if opt != nil {
+ opt((*options.RenameTablesDesc)(&request))
+ }
+ }
+ if len(request.GetTables()) == 0 {
+ return xerrors.WithStackTrace(fmt.Errorf("no RenameTablesItem: %w", errParamsRequired))
+ }
+ _, err = service.RenameTables(ctx, &request)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
+// RenameTables renames tables.
+func (s *session) RenameTables(
+ ctx context.Context,
+ opts ...options.RenameTablesOption,
+) (err error) {
+ err = renameTables(ctx, s.id, s.config.OperationTimeout(), s.config.OperationCancelAfter(), s.tableService, opts...)
+ if err != nil {
+ return xerrors.WithStackTrace(err)
+ }
+
+ return nil
+}
+
// Explain explains data query represented by text.
func (s *session) Explain(
ctx context.Context,
@@ -613,7 +665,7 @@ func (s *session) Explain(
response *Ydb_Table.ExplainDataQueryResponse
onDone = trace.TableOnSessionQueryExplain(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Explain"),
s, query,
)
)
@@ -662,7 +714,7 @@ func (s *session) Prepare(ctx context.Context, queryText string) (_ table.Statem
result Ydb_Table.PrepareQueryResult
onDone = trace.TableOnSessionQueryPrepare(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Prepare"),
s, queryText,
)
)
@@ -745,7 +797,7 @@ func (s *session) Execute(
onDone := trace.TableOnSessionQueryExecute(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).Execute"),
s, q, parameters,
request.QueryCachePolicy.GetKeepInCache(),
)
@@ -984,8 +1036,8 @@ func (s *session) StreamReadTable(
opts ...options.ReadTableOption,
) (_ result.StreamResult, err error) {
var (
- onIntermediate = trace.TableOnSessionQueryStreamRead(s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ onDone = trace.TableOnSessionQueryStreamRead(s.config.Trace(), &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).StreamReadTable"),
s,
)
request = Ydb_Table.ReadTableRequest{
@@ -997,9 +1049,7 @@ func (s *session) StreamReadTable(
)
defer func() {
a.Free()
- if err != nil {
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
- }
+ onDone(xerrors.HideEOF(err))
}()
for _, opt := range opts {
@@ -1023,9 +1073,6 @@ func (s *session) StreamReadTable(
stats *Ydb_TableStats.QueryStats,
err error,
) {
- defer func() {
- onIntermediate(xerrors.HideEOF(err))
- }()
select {
case <-ctx.Done():
return nil, nil, xerrors.WithStackTrace(ctx.Err())
@@ -1042,7 +1089,7 @@ func (s *session) StreamReadTable(
},
func(err error) error {
cancel()
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
+ onDone(xerrors.HideEOF(err))
return err
},
@@ -1105,11 +1152,11 @@ func (s *session) StreamExecuteScanQuery(
opts ...options.ExecuteScanQueryOption,
) (_ result.StreamResult, err error) {
var (
- a = allocator.New()
- q = queryFromText(query)
- onIntermediate = trace.TableOnSessionQueryStreamExecute(
+ a = allocator.New()
+ q = queryFromText(query)
+ onDone = trace.TableOnSessionQueryStreamExecute(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).StreamExecuteScanQuery"),
s, q, parameters,
)
request = Ydb_Table.ExecuteScanQueryRequest{
@@ -1122,9 +1169,7 @@ func (s *session) StreamExecuteScanQuery(
)
defer func() {
a.Free()
- if err != nil {
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
- }
+ onDone(xerrors.HideEOF(err))
}()
for _, opt := range opts {
@@ -1148,9 +1193,6 @@ func (s *session) StreamExecuteScanQuery(
stats *Ydb_TableStats.QueryStats,
err error,
) {
- defer func() {
- onIntermediate(xerrors.HideEOF(err))
- }()
select {
case <-ctx.Done():
return nil, nil, xerrors.WithStackTrace(ctx.Err())
@@ -1167,7 +1209,7 @@ func (s *session) StreamExecuteScanQuery(
},
func(err error) error {
cancel()
- onIntermediate(xerrors.HideEOF(err))(xerrors.HideEOF(err))
+ onDone(xerrors.HideEOF(err))
return err
},
@@ -1185,7 +1227,7 @@ func (s *session) BulkUpsert(ctx context.Context, table string, rows value.Value
callOptions []grpc.CallOption
onDone = trace.TableOnSessionBulkUpsert(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).BulkUpsert"),
s,
)
)
@@ -1229,9 +1271,9 @@ func (s *session) BeginTransaction(
var (
result Ydb_Table.BeginTransactionResult
response *Ydb_Table.BeginTransactionResponse
- onDone = trace.TableOnSessionTransactionBegin(
+ onDone = trace.TableOnTxBegin(
s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*session).BeginTransaction"),
s,
)
)
diff --git a/internal/table/session_test.go b/internal/table/session_test.go
index 006086369..1c45a3c6a 100644
--- a/internal/table/session_test.go
+++ b/internal/table/session_test.go
@@ -462,7 +462,11 @@ func TestCreateTableRegression(t *testing.T) {
"attr": "attr_value",
},
}
- if !proto.Equal(exp, act.(proto.Message)) {
+ val, ok := act.(proto.Message)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to proto.Message", val))
+ }
+ if !proto.Equal(exp, val) {
//nolint:revive
return nil, fmt.Errorf("proto's not equal: \n\nact: %v\n\nexp: %s\n\n", act, exp)
}
@@ -639,7 +643,7 @@ func (mock *copyTablesMock) CopyTables(
return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String())
}
-func Test_copyTables(t *testing.T) {
+func TestCopyTables(t *testing.T) {
ctx := xtest.Context(t)
for _, tt := range []struct {
sessionID string
@@ -758,3 +762,137 @@ func Test_copyTables(t *testing.T) {
})
}
}
+
+type renameTablesMock struct {
+ *Ydb_Table.RenameTablesRequest
+}
+
+func (mock *renameTablesMock) RenameTables(
+ _ context.Context, in *Ydb_Table.RenameTablesRequest, opts ...grpc.CallOption,
+) (*Ydb_Table.RenameTablesResponse, error) {
+ if in.String() == mock.String() {
+ return &Ydb_Table.RenameTablesResponse{}, nil
+ }
+
+ return nil, fmt.Errorf("%w: %s, exp: %s", errUnexpectedRequest, in, mock.String())
+}
+
+func TestRenameTables(t *testing.T) {
+ ctx := xtest.Context(t)
+ for _, tt := range []struct {
+ sessionID string
+ operationTimeout time.Duration
+ operationCancelAfter time.Duration
+ service *renameTablesMock
+ opts []options.RenameTablesOption
+ err error
+ }{
+ {
+ sessionID: "1",
+ operationTimeout: time.Second,
+ operationCancelAfter: time.Second,
+ service: &renameTablesMock{
+ RenameTablesRequest: &Ydb_Table.RenameTablesRequest{
+ SessionId: "1",
+ Tables: []*Ydb_Table.RenameTableItem{
+ {
+ SourcePath: "from",
+ DestinationPath: "to",
+ ReplaceDestination: true,
+ },
+ },
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(time.Second),
+ CancelAfter: durationpb.New(time.Second),
+ },
+ },
+ },
+ opts: []options.RenameTablesOption{
+ options.RenameTablesItem("from", "to", true),
+ },
+ err: nil,
+ },
+ {
+ sessionID: "2",
+ operationTimeout: 2 * time.Second,
+ operationCancelAfter: 2 * time.Second,
+ service: &renameTablesMock{
+ RenameTablesRequest: &Ydb_Table.RenameTablesRequest{
+ SessionId: "2",
+ Tables: []*Ydb_Table.RenameTableItem{
+ {
+ SourcePath: "from1",
+ DestinationPath: "to1",
+ ReplaceDestination: true,
+ },
+ {
+ SourcePath: "from2",
+ DestinationPath: "to2",
+ ReplaceDestination: false,
+ },
+ {
+ SourcePath: "from3",
+ DestinationPath: "to3",
+ ReplaceDestination: true,
+ },
+ },
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(2 * time.Second),
+ CancelAfter: durationpb.New(2 * time.Second),
+ },
+ },
+ },
+ opts: []options.RenameTablesOption{
+ options.RenameTablesItem("from1", "to1", true),
+ options.RenameTablesItem("from2", "to2", false),
+ options.RenameTablesItem("from3", "to3", true),
+ },
+ err: nil,
+ },
+ {
+ sessionID: "3",
+ operationTimeout: time.Second,
+ operationCancelAfter: time.Second,
+ service: &renameTablesMock{
+ RenameTablesRequest: &Ydb_Table.RenameTablesRequest{
+ SessionId: "1",
+ Tables: []*Ydb_Table.RenameTableItem{
+ {
+ SourcePath: "from",
+ DestinationPath: "to",
+ ReplaceDestination: true,
+ },
+ },
+ OperationParams: &Ydb_Operations.OperationParams{
+ OperationMode: Ydb_Operations.OperationParams_SYNC,
+ OperationTimeout: durationpb.New(time.Second),
+ CancelAfter: durationpb.New(time.Second),
+ },
+ },
+ },
+ opts: []options.RenameTablesOption{
+ options.RenameTablesItem("from1", "to1", true),
+ },
+ err: errUnexpectedRequest,
+ },
+ {
+ sessionID: "4",
+ operationTimeout: time.Second,
+ operationCancelAfter: time.Second,
+ service: &renameTablesMock{},
+ opts: nil,
+ err: errParamsRequired,
+ },
+ } {
+ t.Run("", func(t *testing.T) {
+ err := renameTables(ctx, tt.sessionID, tt.operationTimeout, tt.operationCancelAfter, tt.service, tt.opts...)
+ if tt.err != nil {
+ require.ErrorIs(t, err, tt.err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/internal/table/statement.go b/internal/table/statement.go
index c203b36d5..eb797e2ef 100644
--- a/internal/table/statement.go
+++ b/internal/table/statement.go
@@ -62,7 +62,7 @@ func (s *statement) Execute(
onDone := trace.TableOnSessionQueryExecute(
s.session.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*statement).Execute"),
s.session, s.query, parameters,
request.QueryCachePolicy.GetKeepInCache(),
)
diff --git a/internal/table/transaction.go b/internal/table/transaction.go
index 83045706a..6ee77ad7d 100644
--- a/internal/table/transaction.go
+++ b/internal/table/transaction.go
@@ -61,9 +61,9 @@ func (tx *transaction) Execute(
query string, parameters *params.Parameters,
opts ...options.ExecuteDataQueryOption,
) (r result.Result, err error) {
- onDone := trace.TableOnSessionTransactionExecute(
+ onDone := trace.TableOnTxExecute(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).Execute"),
tx.s, tx, queryFromText(query), parameters,
)
defer func() {
@@ -98,7 +98,17 @@ func (tx *transaction) ExecuteStatement(
a := allocator.New()
defer a.Free()
- onDone := trace.TableOnSessionTransactionExecuteStatement(
+ val, ok := stmt.(*statement)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *statement", val))
+ }
+
+ val, ok := stmt.(*statement)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *statement", val))
+ }
+
+ onDone := trace.TableOnTxExecuteStatement(
tx.s.config.Trace(), &ctx,
stack.FunctionID(""),
tx.s, tx, stmt.(*statement).query, parameters,
@@ -131,9 +141,9 @@ func (tx *transaction) CommitTx(
ctx context.Context,
opts ...options.CommitTransactionOption,
) (r result.Result, err error) {
- onDone := trace.TableOnSessionTransactionCommit(
+ onDone := trace.TableOnTxCommit(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).CommitTx"),
tx.s, tx,
)
defer func() {
@@ -189,9 +199,9 @@ func (tx *transaction) CommitTx(
// Rollback performs a rollback of the specified active transaction.
func (tx *transaction) Rollback(ctx context.Context) (err error) {
- onDone := trace.TableOnSessionTransactionRollback(
+ onDone := trace.TableOnTxRollback(
tx.s.config.Trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/table.(*transaction).Rollback"),
tx.s, tx,
)
defer func() {
diff --git a/internal/topic/retriable_error.go b/internal/topic/retriable_error.go
index 23ef3c49c..744aca97a 100644
--- a/internal/topic/retriable_error.go
+++ b/internal/topic/retriable_error.go
@@ -13,7 +13,7 @@ import (
)
const (
- DefaultStartTimeout = time.Minute
+ DefaultStartTimeout = value.InfiniteDuration
connectionEstablishedTimeout = time.Minute
)
@@ -41,7 +41,7 @@ type PublicCheckRetryResult struct {
var (
PublicRetryDecisionDefault = PublicCheckRetryResult{val: 0}
PublicRetryDecisionRetry = PublicCheckRetryResult{val: 1}
- PublicRetryDecisionStop = PublicCheckRetryResult{val: 2}
+ PublicRetryDecisionStop = PublicCheckRetryResult{val: 2} //nolint:gomnd
)
func CheckResetReconnectionCounters(lastTry, now time.Time, connectionTimeout time.Duration) bool {
diff --git a/internal/topic/topicreaderinternal/batcher.go b/internal/topic/topicreaderinternal/batcher.go
index deebbb209..8eaa5eb6b 100644
--- a/internal/topic/topicreaderinternal/batcher.go
+++ b/internal/topic/topicreaderinternal/batcher.go
@@ -176,7 +176,7 @@ func (b *batcher) Pop(ctx context.Context, opts batcherGetOptions) (_ batcherMes
findRes = b.findNeedLock(opts)
if findRes.Ok {
- b.applyNeedLock(findRes)
+ b.applyNeedLock(&findRes)
return
}
@@ -279,7 +279,7 @@ func (b *batcher) applyForceFlagToOptions(options batcherGetOptions) batcherGetO
return res
}
-func (b *batcher) applyNeedLock(res batcherResultCandidate) {
+func (b *batcher) applyNeedLock(res *batcherResultCandidate) {
if res.Rest.IsEmpty() && res.WaiterIndex >= 0 {
delete(b.messages, res.Key)
} else {
diff --git a/internal/topic/topicreaderinternal/batcher_test.go b/internal/topic/topicreaderinternal/batcher_test.go
index 1bcdb33ef..1f7f0d0f0 100644
--- a/internal/topic/topicreaderinternal/batcher_test.go
+++ b/internal/topic/topicreaderinternal/batcher_test.go
@@ -3,6 +3,7 @@ package topicreaderinternal
import (
"context"
"errors"
+ "fmt"
"sync/atomic"
"testing"
"time"
@@ -338,11 +339,17 @@ func TestBatcherConcurency(t *testing.T) {
for i := 0; i < count; i++ {
res, err := b.Pop(ctx, batcherGetOptions{MinCount: 1})
+
+ val, ok := res.RawMessage.(*rawtopicreader.StartPartitionSessionRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicreader.StartPartitionSessionRequest", val))
+ }
+
require.NoError(tb, err)
require.Equal(
tb,
rawtopicreader.NewOffset(int64(i)),
- res.RawMessage.(*rawtopicreader.StartPartitionSessionRequest).CommittedOffset,
+ val.CommittedOffset,
)
}
})
@@ -407,7 +414,7 @@ func TestBatcher_Apply(t *testing.T) {
Key: session,
Rest: batcherMessageOrderItems{newBatcherItemBatch(batch)},
}
- b.applyNeedLock(foundRes)
+ b.applyNeedLock(&foundRes)
expectedMap := batcherMessagesMap{session: batcherMessageOrderItems{newBatcherItemBatch(batch)}}
require.Equal(t, expectedMap, b.messages)
@@ -426,7 +433,7 @@ func TestBatcher_Apply(t *testing.T) {
b.messages = batcherMessagesMap{session: batcherMessageOrderItems{newBatcherItemBatch(batch)}}
- b.applyNeedLock(foundRes)
+ b.applyNeedLock(&foundRes)
require.Empty(t, b.messages)
})
diff --git a/internal/topic/topicreaderinternal/commit_range.go b/internal/topic/topicreaderinternal/commit_range.go
index c744cd49b..18d00b0d8 100644
--- a/internal/topic/topicreaderinternal/commit_range.go
+++ b/internal/topic/topicreaderinternal/commit_range.go
@@ -158,9 +158,7 @@ func (r *CommitRanges) toRawPartitionCommitOffset() []rawtopicreader.PartitionCo
// PublicCommitRange contains data for commit messages range
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
type PublicCommitRange struct {
priv commitRange
}
diff --git a/internal/topic/topicreaderinternal/committer.go b/internal/topic/topicreaderinternal/committer.go
index c3f22849f..f0fa1c425 100644
--- a/internal/topic/topicreaderinternal/committer.go
+++ b/internal/topic/topicreaderinternal/committer.go
@@ -126,7 +126,7 @@ func (c *committer) pushCommitsLoop(ctx context.Context) {
var commits CommitRanges
c.m.WithLock(func() {
commits = c.commits
- c.commits = NewCommitRangesWithCapacity(commits.len() * 2)
+ c.commits = NewCommitRangesWithCapacity(commits.len() * 2) //nolint:gomnd
})
if commits.len() == 0 && c.backgroundWorker.Context().Err() != nil {
@@ -166,7 +166,10 @@ func (c *committer) waitSendTrigger(ctx context.Context) {
return
}
- finish := c.clock.After(c.BufferTimeLagTrigger)
+ bufferTimeLagTriggerTimer := c.clock.NewTimer(c.BufferTimeLagTrigger)
+ defer bufferTimeLagTriggerTimer.Stop()
+
+ finish := bufferTimeLagTriggerTimer.Chan()
if c.BufferCountTrigger == 0 {
select {
case <-ctxDone:
diff --git a/internal/topic/topicreaderinternal/committer_test.go b/internal/topic/topicreaderinternal/committer_test.go
index 7bf444d62..d94f7ec2a 100644
--- a/internal/topic/topicreaderinternal/committer_test.go
+++ b/internal/topic/topicreaderinternal/committer_test.go
@@ -3,6 +3,7 @@ package topicreaderinternal
import (
"context"
"errors"
+ "fmt"
"testing"
"time"
@@ -231,7 +232,11 @@ func TestCommitterBuffer(t *testing.T) {
c.clock = clock
c.BufferTimeLagTrigger = time.Second
c.send = func(msg rawtopicreader.ClientMessage) error {
- commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
+ val, ok := msg.(*rawtopicreader.CommitOffsetRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicreader.CommitOffsetRequest", val))
+ }
+ commitMess := val
require.Len(t, commitMess.CommitOffsets, 2)
close(sendCalled)
@@ -264,7 +269,10 @@ func TestCommitterBuffer(t *testing.T) {
c.BufferTimeLagTrigger = time.Second // for prevent send
c.BufferCountTrigger = 2
c.send = func(msg rawtopicreader.ClientMessage) error {
- commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
+ commitMess, ok := msg.(*rawtopicreader.CommitOffsetRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicreader.CommitOffsetRequest", commitMess))
+ }
require.Len(t, commitMess.CommitOffsets, 4)
close(sendCalled)
@@ -299,7 +307,10 @@ func TestCommitterBuffer(t *testing.T) {
c.BufferTimeLagTrigger = time.Second // for prevent send
c.BufferCountTrigger = 4
c.send = func(msg rawtopicreader.ClientMessage) error {
- commitMess := msg.(*rawtopicreader.CommitOffsetRequest)
+ commitMess, ok := msg.(*rawtopicreader.CommitOffsetRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicreader.CommitOffsetRequest", commitMess))
+ }
require.Len(t, commitMess.CommitOffsets, 4)
close(sendCalled)
diff --git a/internal/topic/topicreaderinternal/stream_reader_impl.go b/internal/topic/topicreaderinternal/stream_reader_impl.go
index 381ccd690..fec186ffc 100644
--- a/internal/topic/topicreaderinternal/stream_reader_impl.go
+++ b/internal/topic/topicreaderinternal/stream_reader_impl.go
@@ -22,6 +22,8 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
+const defaultBufferSize = 1024 * 1024
+
var (
PublicErrCommitSessionToExpiredSession = xerrors.Wrap(errors.New("ydb: commit to expired session"))
@@ -73,7 +75,7 @@ type topicStreamReaderConfig struct {
func newTopicStreamReaderConfig() topicStreamReaderConfig {
return topicStreamReaderConfig{
BaseContext: context.Background(),
- BufferSizeProtoBytes: 1024 * 1024,
+ BufferSizeProtoBytes: defaultBufferSize,
Cred: credentials.NewAnonymousCredentials(),
CredUpdateInterval: time.Hour,
CommitMode: CommitModeAsync,
diff --git a/internal/topic/topicreaderinternal/stream_reconnector.go b/internal/topic/topicreaderinternal/stream_reconnector.go
index 393b0ecea..ec601ba67 100644
--- a/internal/topic/topicreaderinternal/stream_reconnector.go
+++ b/internal/topic/topicreaderinternal/stream_reconnector.go
@@ -328,9 +328,12 @@ func (r *readerReconnector) connectWithTimeout() (_ batchedStreamReader, err err
result <- connectResult{stream: stream, err: err}
}()
+ connectionTimoutTimer := r.clock.NewTimer(r.connectTimeout)
+ defer connectionTimoutTimer.Stop()
+
var res connectResult
select {
- case <-r.clock.After(r.connectTimeout):
+ case <-connectionTimoutTimer.Chan():
// cancel connection context only if timeout exceed while connection
// because if cancel context after connect - it will break
cancel()
diff --git a/internal/topic/topicwriterinternal/encoders.go b/internal/topic/topicwriterinternal/encoders.go
index 7ae89d534..a1ca73ad9 100644
--- a/internal/topic/topicwriterinternal/encoders.go
+++ b/internal/topic/topicwriterinternal/encoders.go
@@ -225,7 +225,7 @@ func cacheMessages(messages []messageWithDataContent, codec rawtopiccommon.Codec
}
// no need goroutines and synchronization for zero or one worker
- if workerCount < 2 {
+ if workerCount < 2 { //nolint:gomnd
for i := range messages {
if _, err := messages[i].GetEncodedBytes(codec); err != nil {
return err
diff --git a/internal/topic/topicwriterinternal/queue.go b/internal/topic/topicwriterinternal/queue.go
index 25ff072d3..799b02d16 100644
--- a/internal/topic/topicwriterinternal/queue.go
+++ b/internal/topic/topicwriterinternal/queue.go
@@ -21,6 +21,7 @@ var (
)
const (
+ //nolint:gomnd
intSize = 32 << (^uint(0) >> 63) // copy from math package for use in go <= 1.16
maxInt = 1<<(intSize-1) - 1 // copy from math package for use in go <= 1.16
minInt = -1 << (intSize - 1) // copy from math package for use in go <= 1.16
diff --git a/internal/topic/topicwriterinternal/writer_grpc_mock_test.go b/internal/topic/topicwriterinternal/writer_grpc_mock_test.go
index 1a977cb75..14e4e9598 100644
--- a/internal/topic/topicwriterinternal/writer_grpc_mock_test.go
+++ b/internal/topic/topicwriterinternal/writer_grpc_mock_test.go
@@ -101,8 +101,12 @@ func (t *topicWriterOperationUnavailable) StreamWrite(server Ydb_Topic_V1.TopicS
return errors.New("failed to read messages block")
}
- if len(messagesMsg.GetClientMessage().(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest).
- WriteRequest.GetMessages()) == 0 {
+ tt, ok := messagesMsg.GetClientMessage().(*Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb_Topic.StreamWriteMessage_FromClient_WriteRequest", tt))
+ }
+
+ if len(tt.WriteRequest.GetMessages()) == 0 {
return errors.New("received zero messages block")
}
diff --git a/internal/topic/topicwriterinternal/writer_options.go b/internal/topic/topicwriterinternal/writer_options.go
index 51b21b93d..5c88bdbb3 100644
--- a/internal/topic/topicwriterinternal/writer_options.go
+++ b/internal/topic/topicwriterinternal/writer_options.go
@@ -51,9 +51,7 @@ func WithTokenUpdateInterval(interval time.Duration) PublicWriterOption {
// WithCommonConfig
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithCommonConfig(common config.Common) PublicWriterOption {
return func(cfg *WriterReconnectorConfig) {
cfg.Common = common
diff --git a/internal/topic/topicwriterinternal/writer_reconnector.go b/internal/topic/topicwriterinternal/writer_reconnector.go
index a3427b81e..dd119e1c3 100644
--- a/internal/topic/topicwriterinternal/writer_reconnector.go
+++ b/internal/topic/topicwriterinternal/writer_reconnector.go
@@ -84,8 +84,8 @@ func newWriterReconnectorConfig(options ...PublicWriterOption) WriterReconnector
},
AutoSetSeqNo: true,
AutoSetCreatedTime: true,
- MaxMessageSize: 50 * 1024 * 1024,
- MaxQueueLen: 1000,
+ MaxMessageSize: 50 * 1024 * 1024, //nolint:gomnd
+ MaxQueueLen: 1000, //nolint:gomnd
RetrySettings: topic.RetrySettings{
StartTimeout: topic.DefaultStartTimeout,
},
@@ -350,7 +350,7 @@ func (w *WriterReconnector) connectionLoop(ctx context.Context) {
createStreamContext := func() (context.Context, context.CancelFunc) {
// need suppress parent context cancelation for flush buffer while close writer
- return xcontext.WithCancel(xcontext.WithoutDeadline(ctx))
+ return xcontext.WithCancel(xcontext.ValueOnly(ctx))
}
//nolint:ineffassign,staticcheck,wastedassign
@@ -380,16 +380,21 @@ func (w *WriterReconnector) connectionLoop(ctx context.Context) {
prevAttemptTime = now
if reconnectReason != nil {
- if backoff, retry := topic.CheckRetryMode(reconnectReason, w.retrySettings, w.clock.Since(startOfRetries)); retry {
+ retryDuration := w.clock.Since(startOfRetries)
+ if backoff, retry := topic.CheckRetryMode(reconnectReason, w.retrySettings, retryDuration); retry {
delay := backoff.Delay(attempt)
+ delayTimer := w.clock.NewTimer(delay)
select {
case <-doneCtx:
+ delayTimer.Stop()
+
return
- case <-w.clock.After(delay):
+ case <-delayTimer.Chan():
+ delayTimer.Stop() // no really need, stop for common style only
// pass
}
} else {
- _ = w.close(ctx, reconnectReason)
+ _ = w.close(ctx, fmt.Errorf("%w, was retried (%v)", reconnectReason, retryDuration))
return
}
diff --git a/internal/topic/topicwriterinternal/writer_reconnector_test.go b/internal/topic/topicwriterinternal/writer_reconnector_test.go
index 4bf18c6ff..27247d4e9 100644
--- a/internal/topic/topicwriterinternal/writer_reconnector_test.go
+++ b/internal/topic/topicwriterinternal/writer_reconnector_test.go
@@ -187,7 +187,10 @@ func TestWriterImpl_WriteCodecs(t *testing.T) {
messReceived := make(chan rawtopiccommon.Codec, 2)
e.stream.EXPECT().Send(gomock.Any()).Do(func(message rawtopicwriter.ClientMessage) {
- writeReq := message.(*rawtopicwriter.WriteRequest)
+ writeReq, ok := message.(*rawtopicwriter.WriteRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicwriter.WriteRequest", writeReq))
+ }
messReceived <- writeReq.Codec
})
@@ -215,7 +218,10 @@ func TestWriterImpl_WriteCodecs(t *testing.T) {
messReceived := make(chan rawtopiccommon.Codec, 2)
e.stream.EXPECT().Send(gomock.Any()).Do(func(message rawtopicwriter.ClientMessage) {
- writeReq := message.(*rawtopicwriter.WriteRequest)
+ writeReq, ok := message.(*rawtopicwriter.WriteRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicwriter.WriteRequest", writeReq))
+ }
messReceived <- writeReq.Codec
})
@@ -240,7 +246,10 @@ func TestWriterImpl_WriteCodecs(t *testing.T) {
messReceived := make(chan rawtopiccommon.Codec, 2)
e.stream.EXPECT().Send(gomock.Any()).Do(func(message rawtopicwriter.ClientMessage) {
- writeReq := message.(*rawtopicwriter.WriteRequest)
+ writeReq, ok := message.(*rawtopicwriter.WriteRequest)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *rawtopicwriter.WriteRequest", writeReq))
+ }
messReceived <- writeReq.Codec
}).Times(codecMeasureIntervalBatches * 2)
diff --git a/internal/topic/topicwriterinternal/writer_single_stream.go b/internal/topic/topicwriterinternal/writer_single_stream.go
index fa048b1ab..4f01c56d1 100644
--- a/internal/topic/topicwriterinternal/writer_single_stream.go
+++ b/internal/topic/topicwriterinternal/writer_single_stream.go
@@ -83,7 +83,7 @@ func newSingleStreamWriterStopped(
) *SingleStreamWriter {
return &SingleStreamWriter{
cfg: cfg,
- background: *background.NewWorker(xcontext.WithoutDeadline(ctxForPProfLabelsOnly)),
+ background: *background.NewWorker(xcontext.ValueOnly(ctxForPProfLabelsOnly)),
closeCompleted: make(empty.Chan),
}
}
diff --git a/internal/types/types.go b/internal/types/types.go
index 536ab7ada..ae8bffeea 100644
--- a/internal/types/types.go
+++ b/internal/types/types.go
@@ -479,7 +479,7 @@ func (v PgType) String() string {
}
func (v PgType) Yql() string {
- return "pgunknown"
+ return fmt.Sprintf("PgType(%v)", v.OID)
}
func (v PgType) ToYDB(a *allocator.Allocator) *Ydb.Type {
@@ -823,7 +823,11 @@ func (v *VariantStruct) ToYDB(a *allocator.Allocator) *Ydb.Type {
typeVariant.VariantType = a.Variant()
structItems := a.VariantStructItems()
- structItems.StructItems = v.Struct.ToYDB(a).GetType().(*Ydb.Type_StructType).StructType
+ tt, ok := v.Struct.ToYDB(a).GetType().(*Ydb.Type_StructType)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Type_StructType", tt))
+ }
+ structItems.StructItems = tt.StructType
typeVariant.VariantType.Type = structItems
@@ -876,7 +880,11 @@ func (v *VariantTuple) ToYDB(a *allocator.Allocator) *Ydb.Type {
typeVariant.VariantType = a.Variant()
tupleItems := a.VariantTupleItems()
- tupleItems.TupleItems = v.Tuple.ToYDB(a).GetType().(*Ydb.Type_TupleType).TupleType
+ tt, ok := v.Tuple.ToYDB(a).GetType().(*Ydb.Type_TupleType)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Type_TupleType", tt))
+ }
+ tupleItems.TupleItems = tt.TupleType
typeVariant.VariantType.Type = tupleItems
diff --git a/internal/types/types_test.go b/internal/types/types_test.go
index c2f81373e..3c9936a2a 100644
--- a/internal/types/types_test.go
+++ b/internal/types/types_test.go
@@ -271,7 +271,7 @@ func TestTypeToString(t *testing.T) {
},
{
t: PgType{OID: pg.OIDUnknown},
- s: "pgunknown",
+ s: "PgType(705)",
},
} {
t.Run(tt.s, func(t *testing.T) {
diff --git a/internal/value/nullable.go b/internal/value/nullable.go
index 1553d3eb1..ed03db18a 100644
--- a/internal/value/nullable.go
+++ b/internal/value/nullable.go
@@ -303,27 +303,71 @@ func NullableDyNumberValue(v *string) Value {
func Nullable(t types.Type, v interface{}) Value {
switch t {
case types.Bool:
- return NullableBoolValue(v.(*bool))
+ tt, ok := v.(*bool)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeBool", tt))
+ }
+ return NullableBoolValue(tt)
case types.Int8:
- return NullableInt8Value(v.(*int8))
+ tt, ok := v.(*int8)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeBool", tt))
+ }
+ return NullableInt8Value(tt)
case types.Uint8:
- return NullableUint8Value(v.(*uint8))
+ tt, ok := v.(*uint8)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeUint8", tt))
+ }
+ return NullableUint8Value(tt)
case types.Int16:
- return NullableInt16Value(v.(*int16))
+ tt, ok := v.(*int16)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeInt16", tt))
+ }
+ return NullableInt16Value(tt)
case types.Uint16:
- return NullableUint16Value(v.(*uint16))
+ tt, ok := v.(*uint16)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeUint16", tt))
+ }
+ return NullableUint16Value(tt)
case types.Int32:
- return NullableInt32Value(v.(*int32))
+ tt, ok := v.(*int32)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeInt32", tt))
+ }
+ return NullableInt32Value(tt)
case types.Uint32:
- return NullableUint32Value(v.(*uint32))
+ tt, ok := v.(*uint32)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to Uint32", tt))
+ }
+ return NullableUint32Value(tt)
case types.Int64:
- return NullableInt64Value(v.(*int64))
+ tt, ok := v.(*int64)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeInt64", tt))
+ }
+ return NullableInt64Value(tt)
case types.Uint64:
- return NullableUint64Value(v.(*uint64))
+ tt, ok := v.(*uint64)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeUint64", tt))
+ }
+ return NullableUint64Value(tt)
case types.Float:
- return NullableFloatValue(v.(*float32))
+ tt, ok := v.(*float32)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeFloat", tt))
+ }
+ return NullableFloatValue(tt)
case types.Double:
- return NullableDoubleValue(v.(*float64))
+ tt, ok := v.(*float64)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to TypeDouble", tt))
+ }
+ return NullableDoubleValue(tt)
case types.Date:
switch tt := v.(type) {
case *uint32:
diff --git a/internal/value/time.go b/internal/value/time.go
index 37f7aa374..f8d836098 100644
--- a/internal/value/time.go
+++ b/internal/value/time.go
@@ -12,9 +12,11 @@ import (
const InfiniteDuration = time.Duration(math.MaxInt64)
const (
- secondsPerMinute uint64 = 60
- secondsPerHour = 60 * secondsPerMinute
- secondsPerDay = 24 * secondsPerHour
+ secondsPerMinute uint64 = 60
+ secondsPerHour = 60 * secondsPerMinute
+ secondsPerDay = 24 * secondsPerHour
+ microsecondsPerSecond = 1e6
+ nanosecondsPerMicrosecond = 1000
)
// Date format layouts described in time.Format and time.ANSIC docs.
@@ -52,15 +54,15 @@ func DatetimeToTime(n uint32) time.Time {
// TimestampToTime converts given microseconds to time.Time
// Up to 586524-01-19 08:01:49.000551615 +0000 UTC.
func TimestampToTime(n uint64) time.Time {
- sec := n / 1e6
- nsec := (n - (sec * 1e6)) * 1000
+ sec := n / microsecondsPerSecond
+ nsec := (n - (sec * microsecondsPerSecond)) * nanosecondsPerMicrosecond
return time.Unix(int64(sec), int64(nsec))
}
func TzDateToTime(s string) (t time.Time, err error) {
ss := strings.Split(s, ",")
- if len(ss) != 2 {
+ if len(ss) != 2 { //nolint:gomnd
return t, xerrors.WithStackTrace(fmt.Errorf("not found timezone location in '%s'", s))
}
location, err := time.LoadLocation(ss[1])
@@ -77,7 +79,7 @@ func TzDateToTime(s string) (t time.Time, err error) {
func TzDatetimeToTime(s string) (t time.Time, err error) {
ss := strings.Split(s, ",")
- if len(ss) != 2 {
+ if len(ss) != 2 { //nolint:gomnd
return t, xerrors.WithStackTrace(fmt.Errorf("not found timezone location in '%s'", s))
}
location, err := time.LoadLocation(ss[1])
@@ -94,7 +96,7 @@ func TzDatetimeToTime(s string) (t time.Time, err error) {
func TzTimestampToTime(s string) (t time.Time, err error) {
ss := strings.Split(s, ",")
- if len(ss) != 2 {
+ if len(ss) != 2 { //nolint:gomnd
return t, xerrors.WithStackTrace(fmt.Errorf("not found timezone location in '%s'", s))
}
location, err := time.LoadLocation(ss[1])
diff --git a/internal/value/value.go b/internal/value/value.go
index 77ff3d856..d424af060 100644
--- a/internal/value/value.go
+++ b/internal/value/value.go
@@ -19,6 +19,11 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xstring"
)
+const (
+ decimalPrecision uint32 = 22
+ decimalScale uint32 = 9
+)
+
type Value interface {
Type() types.Type
Yql() string
@@ -183,7 +188,11 @@ func fromYDB(t *Ydb.Type, v *Ydb.Value) (Value, error) {
return DecimalValue(BigEndianUint128(v.GetHigh_128(), v.GetLow_128()), ttt.Precision(), ttt.Scale()), nil
case types.Optional:
- t = t.GetType().(*Ydb.Type_OptionalType).OptionalType.GetItem()
+ tt, ok := t.GetType().(*Ydb.Type_OptionalType)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Type_OptionalType", tt))
+ }
+ t = tt.OptionalType.GetItem()
if nestedValue, ok := v.GetValue().(*Ydb.Value_NestedValue); ok {
return OptionalValue(FromYDB(t, nestedValue.NestedValue)), nil
}
@@ -260,10 +269,15 @@ func fromYDB(t *Ydb.Type, v *Ydb.Value) (Value, error) {
a := allocator.New()
defer a.Free()
+ tt, ok := v.GetValue().(*Ydb.Value_NestedValue)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Value_NestedValue", tt))
+ }
+
return VariantValueStruct(
FromYDB(
ttt.Struct.Field(int(v.GetVariantIndex())).T.ToYDB(a),
- v.GetValue().(*Ydb.Value_NestedValue).NestedValue,
+ tt.NestedValue,
),
ttt.Struct.Field(int(v.GetVariantIndex())).Name,
ttt.Struct,
@@ -273,10 +287,15 @@ func fromYDB(t *Ydb.Type, v *Ydb.Value) (Value, error) {
a := allocator.New()
defer a.Free()
+ tt, ok := v.GetValue().(*Ydb.Value_NestedValue)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Value_NestedValue", tt))
+ }
+
return VariantValueTuple(
FromYDB(
ttt.Tuple.ItemType(int(v.GetVariantIndex())).ToYDB(a),
- v.GetValue().(*Ydb.Value_NestedValue).NestedValue,
+ tt.NestedValue,
),
v.GetVariantIndex(),
ttt.Tuple,
@@ -1037,6 +1056,7 @@ func (v intervalValue) Yql() string {
d = -d
}
buffer.WriteByte('P')
+ //nolint:gomnd
if days := d / time.Hour / 24; days > 0 {
d -= days * time.Hour * 24 //nolint:durationcheck
buffer.WriteString(strconv.FormatInt(int64(days), 10))
@@ -1267,7 +1287,7 @@ func (v pgValue) Yql() string {
//nolint:godox
// TODO: call special function for unknown oids
// https://github.com/ydb-platform/ydb/issues/2706
- return fmt.Sprintf("PgUnknown(%q)", v.val)
+ return fmt.Sprintf(`PgConst("%v", PgType(%v))`, v.val, v.t.OID)
}
type setValue struct {
@@ -2420,7 +2440,7 @@ func ZeroValue(t types.Type) Value {
return values
}()...)
case *types.Decimal:
- return DecimalValue([16]byte{}, 22, 9)
+ return DecimalValue([16]byte{}, decimalPrecision, decimalScale)
default:
panic(fmt.Sprintf("type '%T' have not a zero value", t))
diff --git a/internal/value/value_test.go b/internal/value/value_test.go
index e1dd3bde6..f7adfc7e9 100644
--- a/internal/value/value_test.go
+++ b/internal/value/value_test.go
@@ -502,7 +502,7 @@ func TestValueYql(t *testing.T) {
},
{
value: PgValue(pg.OIDUnknown, "123"),
- literal: `PgUnknown("123")`,
+ literal: `PgConst("123", PgType(705))`,
},
} {
t.Run(strconv.Itoa(i)+"."+tt.literal, func(t *testing.T) {
diff --git a/internal/version/parse.go b/internal/version/parse.go
index e901ed031..a57a14718 100644
--- a/internal/version/parse.go
+++ b/internal/version/parse.go
@@ -68,6 +68,7 @@ func Gte(lhs, rhs string) bool {
return true
}
+//nolint:gomnd
func parse(s string) (v version, err error) {
ss := strings.SplitN(s, "-", 2)
if len(ss) == 2 {
diff --git a/internal/version/version.go b/internal/version/version.go
index 2483581c6..90e60ca06 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -2,8 +2,8 @@ package version
const (
Major = "3"
- Minor = "58"
- Patch = "2"
+ Minor = "65"
+ Patch = "0"
Prefix = "ydb-go-sdk"
)
diff --git a/internal/xcontext/cancels_quard.go b/internal/xcontext/cancels_quard.go
new file mode 100644
index 000000000..7fd344696
--- /dev/null
+++ b/internal/xcontext/cancels_quard.go
@@ -0,0 +1,38 @@
+package xcontext
+
+import (
+ "context"
+ "sync"
+)
+
+type CancelsGuard struct {
+ mu sync.Mutex
+ cancels map[*context.CancelFunc]struct{}
+}
+
+func NewCancelsGuard() *CancelsGuard {
+ return &CancelsGuard{
+ cancels: make(map[*context.CancelFunc]struct{}),
+ }
+}
+
+func (g *CancelsGuard) Remember(cancel *context.CancelFunc) {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+ g.cancels[cancel] = struct{}{}
+}
+
+func (g *CancelsGuard) Forget(cancel *context.CancelFunc) {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+ delete(g.cancels, cancel)
+}
+
+func (g *CancelsGuard) Cancel() {
+ g.mu.Lock()
+ defer g.mu.Unlock()
+ for cancel := range g.cancels {
+ (*cancel)()
+ }
+ g.cancels = make(map[*context.CancelFunc]struct{})
+}
diff --git a/internal/xcontext/cancels_quard_test.go b/internal/xcontext/cancels_quard_test.go
new file mode 100644
index 000000000..98c2faf2c
--- /dev/null
+++ b/internal/xcontext/cancels_quard_test.go
@@ -0,0 +1,24 @@
+package xcontext
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+ "golang.org/x/net/context"
+)
+
+func TestCancelsGuard(t *testing.T) {
+ g := NewCancelsGuard()
+ ctx, cancel1 := context.WithCancel(context.Background())
+ g.Remember(&cancel1)
+ require.Len(t, g.cancels, 1)
+ g.Forget(&cancel1)
+ require.Empty(t, g.cancels, 0)
+ cancel2 := context.CancelFunc(func() {
+ cancel1()
+ })
+ g.Remember(&cancel2)
+ require.Len(t, g.cancels, 1)
+ g.Cancel()
+ require.Error(t, ctx.Err())
+}
diff --git a/internal/xcontext/local_dc.go b/internal/xcontext/local_dc.go
index 01f0602fd..c8de6cef7 100644
--- a/internal/xcontext/local_dc.go
+++ b/internal/xcontext/local_dc.go
@@ -1,6 +1,9 @@
package xcontext
-import "context"
+import (
+ "context"
+ "fmt"
+)
type localDcKey struct{}
@@ -10,7 +13,11 @@ func WithLocalDC(ctx context.Context, dc string) context.Context {
func ExtractLocalDC(ctx context.Context) string {
if val := ctx.Value(localDcKey{}); val != nil {
- return val.(string)
+ res, ok := val.(string)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to string", res))
+ }
+ return res
}
return ""
diff --git a/internal/xcontext/without_deadline.go b/internal/xcontext/without_deadline.go
index c0d92045c..2e80a284f 100644
--- a/internal/xcontext/without_deadline.go
+++ b/internal/xcontext/without_deadline.go
@@ -13,7 +13,7 @@ func (valueOnlyContext) Done() <-chan struct{} { return nil }
func (valueOnlyContext) Err() error { return nil }
-// WithoutDeadline helps to clear derived deadline from deadline
-func WithoutDeadline(ctx context.Context) context.Context {
+// ValueOnly helps to clear parent context from deadlines/cancels
+func ValueOnly(ctx context.Context) context.Context {
return valueOnlyContext{ctx}
}
diff --git a/internal/xerrors/check.go b/internal/xerrors/check.go
index a6afc4c0c..2c6895f6b 100644
--- a/internal/xerrors/check.go
+++ b/internal/xerrors/check.go
@@ -9,7 +9,7 @@ func Check(err error) (
code int64,
errType Type,
backoffType backoff.Type,
- deleteSession bool,
+ invalidObject bool,
) {
if err == nil {
return -1,
@@ -19,7 +19,7 @@ func Check(err error) (
}
var e Error
if As(err, &e) {
- return int64(e.Code()), e.Type(), e.BackoffType(), e.MustDeleteSession()
+ return int64(e.Code()), e.Type(), e.BackoffType(), e.IsRetryObjectValid()
}
return -1,
@@ -28,16 +28,15 @@ func Check(err error) (
false
}
-func MustDeleteSession(err error) bool {
+func IsRetryObjectValid(err error) bool {
if err == nil {
- return false
+ return true
}
var e Error
-
if As(err, &e) {
- return e.MustDeleteSession()
+ return !e.IsRetryObjectValid()
}
- return false
+ return true
}
diff --git a/internal/xerrors/join_test.go b/internal/xerrors/join_test.go
index a9ff7e297..762b38cfe 100644
--- a/internal/xerrors/join_test.go
+++ b/internal/xerrors/join_test.go
@@ -2,6 +2,7 @@ package xerrors
import (
"context"
+ "fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -50,7 +51,10 @@ func TestUnwrapJoined(t *testing.T) {
var joined error = Join(err1, err2)
- unwrappable := joined.(interface{ Unwrap() []error }) //nolint:errorlint
+ unwrappable, ok := joined.(interface{ Unwrap() []error }) //nolint:errorlint
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to string", unwrappable))
+ }
inners := unwrappable.Unwrap()
assert.Contains(t, inners, err1)
assert.Contains(t, inners, err2)
diff --git a/internal/xerrors/operation.go b/internal/xerrors/operation.go
index ded028e9f..7020e4f42 100644
--- a/internal/xerrors/operation.go
+++ b/internal/xerrors/operation.go
@@ -192,7 +192,7 @@ func (e *operationError) BackoffType() backoff.Type {
}
}
-func (e *operationError) MustDeleteSession() bool {
+func (e *operationError) IsRetryObjectValid() bool {
switch e.code {
case
Ydb.StatusIds_BAD_SESSION,
diff --git a/internal/xerrors/retryable.go b/internal/xerrors/retryable.go
index 03b8a894d..1c3141e8f 100644
--- a/internal/xerrors/retryable.go
+++ b/internal/xerrors/retryable.go
@@ -7,11 +7,11 @@ import (
)
type retryableError struct {
- name string
- err error
- backoffType backoff.Type
- mustDeleteSession bool
- code int32
+ name string
+ err error
+ backoffType backoff.Type
+ isRetryObjectValid bool
+ code int32
}
func (e *retryableError) Code() int32 {
@@ -30,8 +30,8 @@ func (e *retryableError) BackoffType() backoff.Type {
return e.backoffType
}
-func (e *retryableError) MustDeleteSession() bool {
- return e.mustDeleteSession
+func (e *retryableError) IsRetryObjectValid() bool {
+ return e.isRetryObjectValid
}
func (e *retryableError) Error() string {
@@ -56,9 +56,9 @@ func WithName(name string) RetryableErrorOption {
}
}
-func WithDeleteSession() RetryableErrorOption {
+func InvalidObject() RetryableErrorOption {
return func(e *retryableError) {
- e.mustDeleteSession = true
+ e.isRetryObjectValid = true
}
}
@@ -66,14 +66,15 @@ func Retryable(err error, opts ...RetryableErrorOption) error {
var (
e Error
re = &retryableError{
- err: err,
- name: "CUSTOM",
- code: -1,
+ err: err,
+ name: "CUSTOM",
+ code: -1,
+ isRetryObjectValid: true,
}
)
if As(err, &e) {
re.backoffType = e.BackoffType()
- re.mustDeleteSession = e.MustDeleteSession()
+ re.isRetryObjectValid = e.IsRetryObjectValid()
re.code = e.Code()
re.name = e.Name()
}
diff --git a/internal/xerrors/transport.go b/internal/xerrors/transport.go
index ad2bf00a6..b66f7735c 100644
--- a/internal/xerrors/transport.go
+++ b/internal/xerrors/transport.go
@@ -98,7 +98,7 @@ func (e *transportError) BackoffType() backoff.Type {
}
}
-func (e *transportError) MustDeleteSession() bool {
+func (e *transportError) IsRetryObjectValid() bool {
switch e.status.Code() {
case
grpcCodes.ResourceExhausted,
@@ -141,7 +141,7 @@ func Transport(err error, opts ...teOpt) error {
}
var te *transportError
if errors.As(err, &te) {
- return err
+ return te
}
if s, ok := grpcStatus.FromError(err); ok {
te = &transportError{
diff --git a/internal/xerrors/xerrors.go b/internal/xerrors/xerrors.go
index a15bf85f8..ce6a20260 100644
--- a/internal/xerrors/xerrors.go
+++ b/internal/xerrors/xerrors.go
@@ -19,7 +19,7 @@ type Error interface {
Name() string
Type() Type
BackoffType() backoff.Type
- MustDeleteSession() bool
+ IsRetryObjectValid() bool
}
func IsTimeoutError(err error) bool {
@@ -99,3 +99,7 @@ func Is(err error, targets ...error) bool {
return false
}
+
+func IsContextError(err error) bool {
+ return Is(err, context.Canceled, context.DeadlineExceeded)
+}
diff --git a/internal/xresolver/xresolver.go b/internal/xresolver/xresolver.go
index 5d78a7a55..7eb2046a1 100644
--- a/internal/xresolver/xresolver.go
+++ b/internal/xresolver/xresolver.go
@@ -33,7 +33,7 @@ func (c *clientConn) Endpoint() string {
func (c *clientConn) UpdateState(state resolver.State) (err error) {
onDone := trace.DriverOnResolve(c.trace,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xresolver.(*clientConn).UpdateState"),
c.Endpoint(), func() (addrs []string) {
for i := range state.Addresses {
addrs = append(addrs, state.Addresses[i].Addr)
diff --git a/internal/xsql/badconn/badconn.go b/internal/xsql/badconn/badconn.go
index 0b91649ec..54f5deb8c 100644
--- a/internal/xsql/badconn/badconn.go
+++ b/internal/xsql/badconn/badconn.go
@@ -43,7 +43,7 @@ func Map(err error) error {
return nil
case xerrors.Is(err, io.EOF):
return io.EOF
- case xerrors.MustDeleteSession(err):
+ case !xerrors.IsRetryObjectValid(err):
return Error{err: err}
default:
return err
diff --git a/internal/xsql/badconn/badconn_test.go b/internal/xsql/badconn/badconn_test.go
index 1d252c051..7366542e2 100644
--- a/internal/xsql/badconn/badconn_test.go
+++ b/internal/xsql/badconn/badconn_test.go
@@ -45,12 +45,12 @@ var errsToCheck = []error{
xerrors.Retryable(
xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, "")),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
xerrors.Retryable(
grpcStatus.Error(grpcCodes.Unavailable, ""),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
xerrors.Transport(grpcStatus.Error(grpcCodes.DataLoss, "")),
xerrors.Transport(grpcStatus.Error(grpcCodes.Unauthenticated, "")),
@@ -112,7 +112,7 @@ var errsToCheck = []error{
xerrors.WithStatusCode(Ydb.StatusIds_SESSION_BUSY),
),
xerrors.Retryable(errors.New("retryable error")),
- xerrors.Retryable(errors.New("retryable error"), xerrors.WithDeleteSession()),
+ xerrors.Retryable(errors.New("retryable error"), xerrors.InvalidObject()),
io.EOF,
xerrors.WithStackTrace(io.EOF),
}
@@ -122,7 +122,7 @@ func Test_badConnError_Is(t *testing.T) {
t.Run(err.Error(), func(t *testing.T) {
err = Map(err)
require.Equal(t,
- xerrors.MustDeleteSession(err),
+ !xerrors.IsRetryObjectValid(err),
xerrors.Is(err, driver.ErrBadConn),
)
})
diff --git a/internal/xsql/conn.go b/internal/xsql/conn.go
index a07a6400e..c5d670517 100644
--- a/internal/xsql/conn.go
+++ b/internal/xsql/conn.go
@@ -155,7 +155,7 @@ func (c *conn) PrepareContext(ctx context.Context, query string) (_ driver.Stmt,
return c.currentTx.PrepareContext(ctx, query)
}
onDone := trace.DatabaseSQLOnConnPrepare(c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).PrepareContext"),
query,
)
defer func() {
@@ -198,7 +198,7 @@ func (c *conn) execContext(ctx context.Context, query string, args []driver.Name
m = queryModeFromContext(ctx, c.defaultQueryMode)
onDone = trace.DatabaseSQLOnConnExec(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).execContext"),
query, m.String(), xcontext.IsIdempotent(ctx), c.sinceLastUsage(),
)
)
@@ -308,7 +308,7 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
m = queryModeFromContext(ctx, c.defaultQueryMode)
onDone = trace.DatabaseSQLOnConnQuery(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).queryContext"),
query, m.String(), xcontext.IsIdempotent(ctx), c.sinceLastUsage(),
)
)
@@ -395,7 +395,9 @@ func (c *conn) queryContext(ctx context.Context, query string, args []driver.Nam
}
func (c *conn) Ping(ctx context.Context) (finalErr error) {
- onDone := trace.DatabaseSQLOnConnPing(c.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnConnPing(c.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).Ping"),
+ )
defer func() {
onDone(finalErr)
}()
@@ -414,7 +416,7 @@ func (c *conn) Close() (finalErr error) {
c.connector.detach(c)
onDone := trace.DatabaseSQLOnConnClose(
c.trace, &c.openConnCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).Close"),
)
defer func() {
onDone(finalErr)
@@ -422,7 +424,7 @@ func (c *conn) Close() (finalErr error) {
if c.currentTx != nil {
_ = c.currentTx.Rollback()
}
- err := c.session.Close(xcontext.WithoutDeadline(c.openConnCtx))
+ err := c.session.Close(xcontext.ValueOnly(c.openConnCtx))
if err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
}
@@ -457,7 +459,9 @@ func (c *conn) ID() string {
func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ driver.Tx, finalErr error) {
var tx currentTx
- onDone := trace.DatabaseSQLOnConnBegin(c.trace, &ctx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnConnBegin(c.trace, &ctx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).BeginTx"),
+ )
defer func() {
onDone(tx, finalErr)
}()
@@ -468,7 +472,7 @@ func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ drive
&ConnAlreadyHaveTxError{
currentTx: c.currentTx.ID(),
},
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
)
}
@@ -481,7 +485,7 @@ func (c *conn) BeginTx(ctx context.Context, txOptions driver.TxOptions) (_ drive
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
@@ -506,7 +510,7 @@ func (c *conn) Version(_ context.Context) (_ string, _ error) {
func (c *conn) IsTableExists(ctx context.Context, tableName string) (tableExists bool, finalErr error) {
tableName = c.normalizePath(tableName)
onDone := trace.DatabaseSQLOnConnIsTableExists(c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*conn).IsTableExists"),
tableName,
)
defer func() {
diff --git a/internal/xsql/connector.go b/internal/xsql/connector.go
index a00246969..8009f66d1 100644
--- a/internal/xsql/connector.go
+++ b/internal/xsql/connector.go
@@ -262,10 +262,14 @@ func (c *Connector) idleCloser() (idleStopper func()) {
ctx, idleStopper = xcontext.WithCancel(context.Background())
go func() {
for {
+ idleThresholdTimer := c.clock.NewTimer(c.idleThreshold)
select {
case <-ctx.Done():
+ idleThresholdTimer.Stop()
+
return
- case <-c.clock.After(c.idleThreshold):
+ case <-idleThresholdTimer.Chan():
+ idleThresholdTimer.Stop() // no really need, stop for common style only
c.connsMtx.RLock()
conns := make([]*conn, 0, len(c.conns))
for cc := range c.conns {
@@ -313,7 +317,7 @@ func (c *Connector) Connect(ctx context.Context) (_ driver.Conn, err error) {
var (
onDone = trace.DatabaseSQLOnConnectorConnect(
c.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*Connector).Connect"),
)
session table.ClosableSession
)
diff --git a/internal/xsql/errors.go b/internal/xsql/errors.go
index 922f7fd4c..8dbcc7ce9 100644
--- a/internal/xsql/errors.go
+++ b/internal/xsql/errors.go
@@ -10,8 +10,8 @@ import (
var (
ErrUnsupported = driver.ErrSkip
errDeprecated = driver.ErrSkip
- errConnClosedEarly = xerrors.Retryable(errors.New("conn closed early"), xerrors.WithDeleteSession())
- errNotReadyConn = xerrors.Retryable(errors.New("conn not ready"), xerrors.WithDeleteSession())
+ errConnClosedEarly = xerrors.Retryable(errors.New("conn closed early"), xerrors.InvalidObject())
+ errNotReadyConn = xerrors.Retryable(errors.New("conn not ready"), xerrors.InvalidObject())
)
type ConnAlreadyHaveTxError struct {
diff --git a/internal/xsql/rows.go b/internal/xsql/rows.go
index a9bb1572e..0451b8378 100644
--- a/internal/xsql/rows.go
+++ b/internal/xsql/rows.go
@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"database/sql/driver"
+ "fmt"
"io"
"strings"
"sync"
@@ -128,7 +129,11 @@ func (r *rows) Next(dst []driver.Value) error {
return badconn.Map(xerrors.WithStackTrace(err))
}
for i := range values {
- dst[i] = values[i].(*valuer).Value()
+ val, ok := values[i].(*valuer)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *valuer", val))
+ }
+ dst[i] = val.Value()
}
if err = r.result.Err(); err != nil {
return badconn.Map(xerrors.WithStackTrace(err))
diff --git a/internal/xsql/stmt.go b/internal/xsql/stmt.go
index 82d80a916..75b571acd 100644
--- a/internal/xsql/stmt.go
+++ b/internal/xsql/stmt.go
@@ -31,7 +31,7 @@ var (
func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (_ driver.Rows, finalErr error) {
onDone := trace.DatabaseSQLOnStmtQuery(s.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).QueryContext"),
s.stmtCtx, s.query,
)
defer func() {
@@ -50,7 +50,7 @@ func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (_ dr
func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (_ driver.Result, finalErr error) {
onDone := trace.DatabaseSQLOnStmtExec(s.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).ExecContext"),
s.stmtCtx, s.query,
)
defer func() {
@@ -72,7 +72,9 @@ func (s *stmt) NumInput() int {
}
func (s *stmt) Close() (finalErr error) {
- onDone := trace.DatabaseSQLOnStmtClose(s.trace, &s.stmtCtx, stack.FunctionID(""))
+ onDone := trace.DatabaseSQLOnStmtClose(s.trace, &s.stmtCtx,
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*stmt).Close"),
+ )
defer func() {
onDone(finalErr)
}()
diff --git a/internal/xsql/tx.go b/internal/xsql/tx.go
index 24afe529a..d67813437 100644
--- a/internal/xsql/tx.go
+++ b/internal/xsql/tx.go
@@ -74,7 +74,7 @@ func (tx *tx) checkTxState() error {
func (tx *tx) Commit() (finalErr error) {
onDone := trace.DatabaseSQLOnTxCommit(tx.conn.trace, &tx.txCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).Commit"),
tx,
)
defer func() {
@@ -96,7 +96,7 @@ func (tx *tx) Commit() (finalErr error) {
func (tx *tx) Rollback() (finalErr error) {
onDone := trace.DatabaseSQLOnTxRollback(tx.conn.trace, &tx.txCtx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).Rollback"),
tx,
)
defer func() {
@@ -120,7 +120,7 @@ func (tx *tx) QueryContext(ctx context.Context, query string, args []driver.Name
_ driver.Rows, finalErr error,
) {
onDone := trace.DatabaseSQLOnTxQuery(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).QueryContext"),
tx.txCtx, tx, query,
)
defer func() {
@@ -132,7 +132,7 @@ func (tx *tx) QueryContext(ctx context.Context, query string, args []driver.Name
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
@@ -162,7 +162,7 @@ func (tx *tx) ExecContext(ctx context.Context, query string, args []driver.Named
_ driver.Result, finalErr error,
) {
onDone := trace.DatabaseSQLOnTxExec(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).ExecContext"),
tx.txCtx, tx, query,
)
defer func() {
@@ -174,7 +174,7 @@ func (tx *tx) ExecContext(ctx context.Context, query string, args []driver.Named
xerrors.WithStackTrace(
xerrors.Retryable(
fmt.Errorf("wrong query mode: %s", m.String()),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
xerrors.WithName("WRONG_QUERY_MODE"),
),
),
@@ -196,7 +196,7 @@ func (tx *tx) ExecContext(ctx context.Context, query string, args []driver.Named
func (tx *tx) PrepareContext(ctx context.Context, query string) (_ driver.Stmt, finalErr error) {
onDone := trace.DatabaseSQLOnTxPrepare(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*tx).PrepareContext"),
&tx.txCtx, tx, query,
)
defer func() {
diff --git a/internal/xsql/tx_fake.go b/internal/xsql/tx_fake.go
index 7909bf521..459aba718 100644
--- a/internal/xsql/tx_fake.go
+++ b/internal/xsql/tx_fake.go
@@ -19,7 +19,7 @@ type txFake struct {
func (tx *txFake) PrepareContext(ctx context.Context, query string) (_ driver.Stmt, finalErr error) {
onDone := trace.DatabaseSQLOnTxPrepare(tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).PrepareContext"),
&tx.beginCtx, tx, query,
)
defer func() {
@@ -58,7 +58,7 @@ func (tx *txFake) ID() string {
func (tx *txFake) Commit() (err error) {
onDone := trace.DatabaseSQLOnTxCommit(tx.conn.trace, &tx.ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).Commit"),
tx,
)
defer func() {
@@ -76,7 +76,7 @@ func (tx *txFake) Commit() (err error) {
func (tx *txFake) Rollback() (err error) {
onDone := trace.DatabaseSQLOnTxRollback(tx.conn.trace, &tx.ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).Rollback"),
tx,
)
defer func() {
@@ -97,7 +97,7 @@ func (tx *txFake) QueryContext(ctx context.Context, query string, args []driver.
) {
onDone := trace.DatabaseSQLOnTxQuery(
tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).QueryContext"),
tx.ctx, tx, query,
)
defer func() {
@@ -116,7 +116,7 @@ func (tx *txFake) ExecContext(ctx context.Context, query string, args []driver.N
) {
onDone := trace.DatabaseSQLOnTxExec(
tx.conn.trace, &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/internal/xsql.(*txFake).ExecContext"),
tx.ctx, tx, query,
)
defer func() {
diff --git a/internal/xstring/buffer.go b/internal/xstring/buffer.go
index acd4dbc01..da47a7756 100644
--- a/internal/xstring/buffer.go
+++ b/internal/xstring/buffer.go
@@ -2,6 +2,7 @@ package xstring
import (
"bytes"
+ "fmt"
"sync"
)
@@ -19,5 +20,10 @@ func (b *buffer) Free() {
}
func Buffer() *buffer {
- return buffersPool.Get().(*buffer)
+ val, ok := buffersPool.Get().(*buffer)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *buffer", val))
+ }
+
+ return val
}
diff --git a/internal/xsync/last_usage_guard.go b/internal/xsync/last_usage_guard.go
new file mode 100644
index 000000000..f11d5ba49
--- /dev/null
+++ b/internal/xsync/last_usage_guard.go
@@ -0,0 +1,62 @@
+package xsync
+
+import (
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/jonboulle/clockwork"
+)
+
+type (
+ LastUsage interface {
+ Get() time.Time
+ Start() (stop func())
+ }
+ lastUsage struct {
+ locks atomic.Int64
+ t atomic.Pointer[time.Time]
+ clock clockwork.Clock
+ }
+ lastUsageOption func(g *lastUsage)
+)
+
+func WithClock(clock clockwork.Clock) lastUsageOption {
+ return func(g *lastUsage) {
+ g.clock = clock
+ }
+}
+
+func NewLastUsage(opts ...lastUsageOption) *lastUsage {
+ lastUsage := &lastUsage{
+ clock: clockwork.NewRealClock(),
+ }
+ for _, opt := range opts {
+ opt(lastUsage)
+ }
+
+ now := lastUsage.clock.Now()
+
+ lastUsage.t.Store(&now)
+
+ return lastUsage
+}
+
+func (g *lastUsage) Get() time.Time {
+ if g.locks.Load() == 0 {
+ return *g.t.Load()
+ }
+
+ return g.clock.Now()
+}
+
+func (g *lastUsage) Start() (stop func()) {
+ g.locks.Add(1)
+
+ return sync.OnceFunc(func() {
+ if g.locks.Add(-1) == 0 {
+ now := g.clock.Now()
+ g.t.Store(&now)
+ }
+ })
+}
diff --git a/internal/xsync/last_usage_guard_test.go b/internal/xsync/last_usage_guard_test.go
new file mode 100644
index 000000000..52b390a8d
--- /dev/null
+++ b/internal/xsync/last_usage_guard_test.go
@@ -0,0 +1,98 @@
+package xsync
+
+import (
+ "testing"
+ "time"
+
+ "github.com/jonboulle/clockwork"
+ "github.com/stretchr/testify/require"
+)
+
+func TestLastUsageGuardLock(t *testing.T) {
+ t.Run("NowFromLocked", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ f := lu.Start()
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start.Add(time.Hour), t2)
+ clock.Advance(time.Hour)
+ f()
+ t3 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t4)
+ })
+ t.Run("UpdateAfterLastUnlock", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ f1 := lu.Start()
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start.Add(time.Hour), t2)
+ f2 := lu.Start()
+ clock.Advance(time.Hour)
+ f1()
+ f3 := lu.Start()
+ clock.Advance(time.Hour)
+ t3 := lu.Get()
+ require.Equal(t, start.Add(3*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t4)
+ f3()
+ t5 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t5)
+ clock.Advance(time.Hour)
+ t6 := lu.Get()
+ require.Equal(t, start.Add(5*time.Hour), t6)
+ clock.Advance(time.Hour)
+ f2()
+ t7 := lu.Get()
+ require.Equal(t, start.Add(6*time.Hour), t7)
+ clock.Advance(time.Hour)
+ f2()
+ t8 := lu.Get()
+ require.Equal(t, start.Add(6*time.Hour), t8)
+ })
+ t.Run("DeferRelease", func(t *testing.T) {
+ start := time.Unix(0, 0)
+ clock := clockwork.NewFakeClockAt(start)
+ lu := &lastUsage{
+ clock: clock,
+ }
+ lu.t.Store(&start)
+
+ func() {
+ t1 := lu.Get()
+ require.Equal(t, start, t1)
+ clock.Advance(time.Hour)
+ t2 := lu.Get()
+ require.Equal(t, start, t2)
+ clock.Advance(time.Hour)
+ defer lu.Start()()
+ t3 := lu.Get()
+ require.Equal(t, start.Add(2*time.Hour), t3)
+ clock.Advance(time.Hour)
+ t4 := lu.Get()
+ require.Equal(t, start.Add(3*time.Hour), t4)
+ clock.Advance(time.Hour)
+ }()
+ clock.Advance(time.Hour)
+ t5 := lu.Get()
+ require.Equal(t, start.Add(4*time.Hour), t5)
+ })
+}
diff --git a/internal/xsync/locked.go b/internal/xsync/locked.go
deleted file mode 100644
index 24639f439..000000000
--- a/internal/xsync/locked.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package xsync
-
-import "sync"
-
-type Locked[T any] struct {
- v T
- mu sync.RWMutex
-}
-
-func NewLocked[T any](v T) *Locked[T] {
- return &Locked[T]{
- v: v,
- }
-}
-
-func (l *Locked[T]) Get() T {
- l.mu.RLock()
- defer l.mu.RUnlock()
-
- return l.v
-}
-
-func (l *Locked[T]) Change(f func(prev T) T) T {
- l.mu.Lock()
- defer l.mu.Unlock()
-
- l.v = f(l.v)
-
- return l.v
-}
diff --git a/internal/xsync/locked_test.go b/internal/xsync/locked_test.go
deleted file mode 100644
index b0e5aa6e9..000000000
--- a/internal/xsync/locked_test.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package xsync
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestLocked(t *testing.T) {
- l := NewLocked[int](1)
- require.Equal(t, 1, l.Get())
- require.Equal(t, 2, l.Change(func(v int) int {
- return 2
- }))
- require.Equal(t, 2, l.Get())
-}
diff --git a/internal/xtest/call_method_test.go b/internal/xtest/call_method_test.go
index fe721761d..3f922ddbf 100644
--- a/internal/xtest/call_method_test.go
+++ b/internal/xtest/call_method_test.go
@@ -2,6 +2,7 @@ package xtest
import (
"bytes"
+ "fmt"
"testing"
"github.com/stretchr/testify/require"
@@ -11,7 +12,10 @@ func TestCallMethod(t *testing.T) {
object := bytes.NewBuffer(nil)
result := CallMethod(object, "WriteString", "Hello world!")
- n := result[0].(int)
+ n, ok := result[0].(int)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to int", n))
+ }
err := result[1]
require.Equal(t, 12, n)
diff --git a/internal/xtest/to_json.go b/internal/xtest/to_json.go
new file mode 100644
index 000000000..add66425c
--- /dev/null
+++ b/internal/xtest/to_json.go
@@ -0,0 +1,9 @@
+package xtest
+
+import "encoding/json"
+
+func ToJSON(v interface{}) string {
+ b, _ := json.MarshalIndent(v, "", "\t") //nolint:errchkjson
+
+ return string(b)
+}
diff --git a/internal/xtest/to_json_test.go b/internal/xtest/to_json_test.go
new file mode 100644
index 000000000..861640068
--- /dev/null
+++ b/internal/xtest/to_json_test.go
@@ -0,0 +1,58 @@
+package xtest
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestToJSON(t *testing.T) {
+ for _, tt := range []struct {
+ name string
+ v interface{}
+ s string
+ }{
+ {
+ name: CurrentFileLine(),
+ v: int64(123),
+ s: "123",
+ },
+ {
+ name: CurrentFileLine(),
+ v: struct {
+ A string
+ B int64
+ C bool
+ }{
+ A: "123",
+ B: 123,
+ C: true,
+ },
+ s: "{\n\t\"A\": \"123\",\n\t\"B\": 123,\n\t\"C\": true\n}",
+ },
+ {
+ name: CurrentFileLine(),
+ v: map[string]struct {
+ A string
+ B int64
+ C bool
+ }{
+ "abc": {
+ A: "123",
+ B: 123,
+ C: true,
+ },
+ "def": {
+ A: "456",
+ B: 456,
+ C: false,
+ },
+ },
+ s: "{\n\t\"abc\": {\n\t\t\"A\": \"123\",\n\t\t\"B\": 123,\n\t\t\"C\": true\n\t},\n\t\"def\": {\n\t\t\"A\": \"456\",\n\t\t\"B\": 456,\n\t\t\"C\": false\n\t}\n}", //nolint:lll
+ },
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ require.Equal(t, tt.s, ToJSON(tt.v))
+ })
+ }
+}
diff --git a/log/coordination.go b/log/coordination.go
index 1485118de..865b8cd9c 100644
--- a/log/coordination.go
+++ b/log/coordination.go
@@ -1,10 +1,348 @@
package log
import (
+ "context"
+ "strconv"
+ "time"
+
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
// Coordination makes trace.Coordination with logging events from details
func Coordination(l Logger, d trace.Detailer, opts ...Option) (t trace.Coordination) {
- return t
+ return internalCoordination(wrapLogger(l, opts...), d)
+}
+
+func internalCoordination(
+ l *wrapper, //nolint:interfacer
+ d trace.Detailer,
+) trace.Coordination {
+ return trace.Coordination{
+ OnNew: func(info trace.CoordinationNewStartInfo) func(trace.CoordinationNewDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "new")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.CoordinationNewDoneInfo) {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ },
+ OnCreateNode: func(info trace.CoordinationCreateNodeStartInfo) func(trace.CoordinationCreateNodeDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "node", "create")
+ l.Log(ctx, "start",
+ String("path", info.Path),
+ )
+ start := time.Now()
+
+ return func(info trace.CoordinationCreateNodeDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnAlterNode: func(info trace.CoordinationAlterNodeStartInfo) func(trace.CoordinationAlterNodeDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "node", "alter")
+ l.Log(ctx, "start",
+ String("path", info.Path),
+ )
+ start := time.Now()
+
+ return func(info trace.CoordinationAlterNodeDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnDropNode: func(info trace.CoordinationDropNodeStartInfo) func(trace.CoordinationDropNodeDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "node", "drop")
+ l.Log(ctx, "start",
+ String("path", info.Path),
+ )
+ start := time.Now()
+
+ return func(info trace.CoordinationDropNodeDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnDescribeNode: func(info trace.CoordinationDescribeNodeStartInfo) func(trace.CoordinationDescribeNodeDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "node", "describe")
+ l.Log(ctx, "start",
+ String("path", info.Path),
+ )
+ start := time.Now()
+
+ return func(info trace.CoordinationDescribeNodeDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnSession: func(info trace.CoordinationSessionStartInfo) func(trace.CoordinationSessionDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "node", "describe")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.CoordinationSessionDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnClose: func(info trace.CoordinationCloseStartInfo) func(trace.CoordinationCloseDoneInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(*info.Context, TRACE, "ydb", "coordination", "close")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.CoordinationCloseDoneInfo) {
+ if info.Error == nil {
+ l.Log(WithLevel(ctx, INFO), "done",
+ latencyField(start),
+ )
+ } else {
+ l.Log(WithLevel(ctx, ERROR), "fail",
+ latencyField(start),
+ versionField(),
+ )
+ }
+ }
+ },
+ OnStreamNew: func(
+ info trace.CoordinationStreamNewStartInfo,
+ ) func(
+ info trace.CoordinationStreamNewDoneInfo,
+ ) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "stream", "new")
+ l.Log(ctx, "stream")
+ start := time.Now()
+
+ return func(info trace.CoordinationStreamNewDoneInfo) {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ },
+ OnSessionStarted: func(info trace.CoordinationSessionStartedInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "started")
+ l.Log(ctx, "",
+ String("sessionID", strconv.FormatUint(info.SessionID, 10)),
+ String("expectedSessionID", strconv.FormatUint(info.SessionID, 10)),
+ )
+ },
+ OnSessionStartTimeout: func(info trace.CoordinationSessionStartTimeoutInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "start", "timeout")
+ l.Log(ctx, "",
+ Stringer("timeout", info.Timeout),
+ )
+ },
+ OnSessionKeepAliveTimeout: func(info trace.CoordinationSessionKeepAliveTimeoutInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "keepAlive", "timeout")
+ l.Log(ctx, "",
+ Stringer("timeout", info.Timeout),
+ Stringer("lastGoodResponseTime", info.LastGoodResponseTime),
+ )
+ },
+ OnSessionStopped: func(info trace.CoordinationSessionStoppedInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "stopped")
+ l.Log(ctx, "",
+ String("sessionID", strconv.FormatUint(info.SessionID, 10)),
+ String("expectedSessionID", strconv.FormatUint(info.SessionID, 10)),
+ )
+ },
+ OnSessionStopTimeout: func(info trace.CoordinationSessionStopTimeoutInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "stop", "timeout")
+ l.Log(ctx, "",
+ Stringer("timeout", info.Timeout),
+ )
+ },
+ OnSessionClientTimeout: func(info trace.CoordinationSessionClientTimeoutInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "client", "timeout")
+ l.Log(ctx, "",
+ Stringer("timeout", info.Timeout),
+ Stringer("lastGoodResponseTime", info.LastGoodResponseTime),
+ )
+ },
+ OnSessionServerExpire: func(info trace.CoordinationSessionServerExpireInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "server", "expire")
+ l.Log(ctx, "",
+ Stringer("failure", info.Failure),
+ )
+ },
+ OnSessionServerError: func(info trace.CoordinationSessionServerErrorInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "server", "error")
+ l.Log(ctx, "",
+ Stringer("failure", info.Failure),
+ )
+ },
+ OnSessionReceive: func(
+ info trace.CoordinationSessionReceiveStartInfo,
+ ) func(
+ info trace.CoordinationSessionReceiveDoneInfo,
+ ) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "receive")
+ l.Log(ctx, "receive")
+ start := time.Now()
+
+ return func(info trace.CoordinationSessionReceiveDoneInfo) {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Error(info.Error),
+ Stringer("response", info.Response),
+ versionField(),
+ )
+ }
+ },
+ OnSessionReceiveUnexpected: func(info trace.CoordinationSessionReceiveUnexpectedInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "receive", "unexpected")
+ l.Log(ctx, "",
+ Stringer("response", info.Response),
+ )
+ },
+ OnSessionStop: func(info trace.CoordinationSessionStopInfo) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "stop")
+ l.Log(ctx, "",
+ String("sessionID", strconv.FormatUint(info.SessionID, 10)),
+ )
+ },
+ OnSessionStart: func(
+ info trace.CoordinationSessionStartStartInfo,
+ ) func(
+ info trace.CoordinationSessionStartDoneInfo,
+ ) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "start")
+ l.Log(ctx, "start")
+ start := time.Now()
+
+ return func(info trace.CoordinationSessionStartDoneInfo) {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ },
+ OnSessionSend: func(
+ info trace.CoordinationSessionSendStartInfo,
+ ) func(
+ info trace.CoordinationSessionSendDoneInfo,
+ ) {
+ if d.Details()&trace.CoordinationEvents == 0 {
+ return nil
+ }
+ ctx := with(context.Background(), TRACE, "ydb", "coordination", "session", "send")
+ l.Log(ctx, "start",
+ Stringer("request", info.Request),
+ )
+ start := time.Now()
+
+ return func(info trace.CoordinationSessionSendDoneInfo) {
+ l.Log(ctx, "done",
+ latencyField(start),
+ Error(info.Error),
+ versionField(),
+ )
+ }
+ },
+ }
}
diff --git a/log/field.go b/log/field.go
index af6f65598..a44990826 100644
--- a/log/field.go
+++ b/log/field.go
@@ -90,7 +90,11 @@ func (f Field) StringsValue() []string {
return nil
}
- return f.vany.([]string)
+ res, ok := f.vany.([]string)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to []string", res))
+ }
+ return res
}
// ErrorValue is a value getter for fields with ErrorType type
@@ -100,7 +104,11 @@ func (f Field) ErrorValue() error {
return nil
}
- return f.vany.(error)
+ res, ok := f.vany.(error)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to error", res))
+ }
+ return res
}
// AnyValue is a value getter for fields with AnyType type
@@ -136,7 +144,11 @@ func (f Field) Stringer() fmt.Stringer {
return nil
}
- return f.vany.(fmt.Stringer)
+ res, ok := f.vany.(fmt.Stringer)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to fmt.Stringer", res))
+ }
+ return res
}
// Panics on type mismatch
@@ -161,10 +173,15 @@ func (f Field) String() string {
case StringsType:
return fmt.Sprintf("%v", f.StringsValue())
case ErrorType:
- if f.vany == nil || f.vany.(error) == nil {
+ if f.vany == nil {
return ""
}
+ val, ok := f.vany.(error)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to error", val))
+ }
+
return f.ErrorValue().Error()
case AnyType:
if f.vany == nil {
diff --git a/log/logger_test.go b/log/logger_test.go
index f7b12a71c..38e9afb75 100644
--- a/log/logger_test.go
+++ b/log/logger_test.go
@@ -9,9 +9,9 @@ import (
)
func TestColoring(t *testing.T) {
- zeroClock := clockwork.NewFakeClock()
- fullDuration := zeroClock.Now().Sub(time.Date(1984, 4, 4, 0, 0, 0, 0, time.UTC))
- zeroClock.Advance(-fullDuration) // set zero time
+ zeroClock := clockwork.NewFakeClockAt(
+ time.Date(1984, 4, 4, 0, 0, 0, 0, time.UTC),
+ )
for _, tt := range []struct {
l *defaultLogger
msg string
diff --git a/log/retry.go b/log/retry.go
index 8b52911b7..df772bdb3 100644
--- a/log/retry.go
+++ b/log/retry.go
@@ -14,13 +14,7 @@ func Retry(l Logger, d trace.Detailer, opts ...Option) (t trace.Retry) {
}
func internalRetry(l Logger, d trace.Detailer) (t trace.Retry) {
- t.OnRetry = func(
- info trace.RetryLoopStartInfo,
- ) func(
- trace.RetryLoopIntermediateInfo,
- ) func(
- trace.RetryLoopDoneInfo,
- ) {
+ t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
if d.Details()&trace.RetryEvents == 0 {
return nil
}
@@ -33,11 +27,12 @@ func internalRetry(l Logger, d trace.Detailer) (t trace.Retry) {
)
start := time.Now()
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "attempt done",
+ l.Log(ctx, "done",
String("label", label),
latencyField(start),
+ Int("attempts", info.Attempts),
)
} else {
lvl := ERROR
@@ -45,42 +40,17 @@ func internalRetry(l Logger, d trace.Detailer) (t trace.Retry) {
lvl = DEBUG
}
m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "attempt failed",
+ l.Log(WithLevel(ctx, lvl), "failed",
Error(info.Error),
String("label", label),
latencyField(start),
+ Int("attempts", info.Attempts),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
-
- return func(info trace.RetryLoopDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- String("label", label),
- latencyField(start),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := ERROR
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "failed",
- Error(info.Error),
- String("label", label),
- latencyField(start),
- Int("attempts", info.Attempts),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
diff --git a/log/sql.go b/log/sql.go
index 3a71f3cb7..5ef2a56f3 100644
--- a/log/sql.go
+++ b/log/sql.go
@@ -165,7 +165,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
String("query", query),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
Error(info.Error),
latencyField(start),
versionField(),
@@ -200,7 +200,7 @@ func internalDatabaseSQL(l *wrapper, d trace.Detailer) (t trace.DatabaseSQL) {
String("query", query),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
Error(info.Error),
latencyField(start),
versionField(),
diff --git a/log/table.go b/log/table.go
index 5afa72bee..c12dd30ad 100644
--- a/log/table.go
+++ b/log/table.go
@@ -18,8 +18,6 @@ func Table(l Logger, d trace.Detailer, opts ...Option) (t trace.Table) {
func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
t.OnDo = func(
info trace.TableDoStartInfo,
- ) func(
- info trace.TableDoIntermediateInfo,
) func(
trace.TableDoDoneInfo,
) {
@@ -35,64 +33,36 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
+ return func(info trace.TableDoDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
)
} else {
- lvl := WARN
+ lvl := ERROR
if !xerrors.IsYdb(info.Error) {
lvl = DEBUG
}
m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "failed",
+ l.Log(WithLevel(ctx, lvl), "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
Error(info.Error),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
-
- return func(info trace.TableDoDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := ERROR
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- Error(info.Error),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
t.OnDoTx = func(
info trace.TableDoTxStartInfo,
- ) func(
- info trace.TableDoTxIntermediateInfo,
) func(
trace.TableDoTxDoneInfo,
) {
@@ -108,15 +78,16 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(info trace.TableDoTxIntermediateInfo) func(trace.TableDoTxDoneInfo) {
+ return func(info trace.TableDoTxDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
)
} else {
- lvl := ERROR
+ lvl := WARN
if !xerrors.IsYdb(info.Error) {
lvl = DEBUG
}
@@ -125,47 +96,18 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
latencyField(start),
Bool("idempotent", idempotent),
String("label", label),
+ Int("attempts", info.Attempts),
Error(info.Error),
Bool("retryable", m.MustRetry(idempotent)),
Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
+ Bool("deleteSession", m.IsRetryObjectValid()),
versionField(),
)
}
-
- return func(info trace.TableDoTxDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- )
- } else {
- lvl := WARN
- if !xerrors.IsYdb(info.Error) {
- lvl = DEBUG
- }
- m := retry.Check(info.Error)
- l.Log(WithLevel(ctx, lvl), "done",
- latencyField(start),
- Bool("idempotent", idempotent),
- String("label", label),
- Int("attempts", info.Attempts),
- Error(info.Error),
- Bool("retryable", m.MustRetry(idempotent)),
- Int64("code", m.StatusCode()),
- Bool("deleteSession", m.MustDeleteSession()),
- versionField(),
- )
- }
- }
}
}
t.OnCreateSession = func(
info trace.TableCreateSessionStartInfo,
- ) func(
- info trace.TableCreateSessionIntermediateInfo,
) func(
trace.TableCreateSessionDoneInfo,
) {
@@ -176,36 +118,22 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
l.Log(ctx, "start")
start := time.Now()
- return func(info trace.TableCreateSessionIntermediateInfo) func(trace.TableCreateSessionDoneInfo) {
+ return func(info trace.TableCreateSessionDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate",
+ l.Log(ctx, "done",
latencyField(start),
+ Int("attempts", info.Attempts),
+ String("session_id", info.Session.ID()),
+ String("session_status", info.Session.Status()),
)
} else {
- l.Log(WithLevel(ctx, ERROR), "intermediate",
+ l.Log(WithLevel(ctx, ERROR), "failed",
latencyField(start),
+ Int("attempts", info.Attempts),
Error(info.Error),
versionField(),
)
}
-
- return func(info trace.TableCreateSessionDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- Int("attempts", info.Attempts),
- String("session_id", info.Session.ID()),
- String("session_status", info.Session.Status()),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- latencyField(start),
- Int("attempts", info.Attempts),
- Error(info.Error),
- versionField(),
- )
- }
- }
}
}
t.OnSessionNew = func(info trace.TableSessionNewStartInfo) func(trace.TableSessionNewDoneInfo) {
@@ -396,8 +324,6 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
t.OnSessionQueryStreamExecute = func(
info trace.TableSessionQueryStreamExecuteStartInfo,
- ) func(
- trace.TableSessionQueryStreamExecuteIntermediateInfo,
) func(
trace.TableSessionQueryStreamExecuteDoneInfo,
) {
@@ -416,50 +342,33 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(
- info trace.TableSessionQueryStreamExecuteIntermediateInfo,
- ) func(
- trace.TableSessionQueryStreamExecuteDoneInfo,
- ) {
+ return func(info trace.TableSessionQueryStreamExecuteDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate")
+ l.Log(ctx, "done",
+ appendFieldByCondition(l.logQuery,
+ Stringer("query", query),
+ Error(info.Error),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ latencyField(start),
+ )...,
+ )
} else {
- l.Log(WithLevel(ctx, WARN), "failed",
- Error(info.Error),
- versionField(),
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ appendFieldByCondition(l.logQuery,
+ Stringer("query", query),
+ Error(info.Error),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ latencyField(start),
+ versionField(),
+ )...,
)
}
-
- return func(info trace.TableSessionQueryStreamExecuteDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- appendFieldByCondition(l.logQuery,
- Stringer("query", query),
- Error(info.Error),
- String("id", session.ID()),
- String("status", session.Status()),
- latencyField(start),
- )...,
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- appendFieldByCondition(l.logQuery,
- Stringer("query", query),
- Error(info.Error),
- String("id", session.ID()),
- String("status", session.Status()),
- latencyField(start),
- versionField(),
- )...,
- )
- }
- }
}
}
t.OnSessionQueryStreamRead = func(
info trace.TableSessionQueryStreamReadStartInfo,
- ) func(
- intermediateInfo trace.TableSessionQueryStreamReadIntermediateInfo,
) func(
trace.TableSessionQueryStreamReadDoneInfo,
) {
@@ -474,43 +383,28 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(
- info trace.TableSessionQueryStreamReadIntermediateInfo,
- ) func(
- trace.TableSessionQueryStreamReadDoneInfo,
- ) {
+ return func(info trace.TableSessionQueryStreamReadDoneInfo) {
if info.Error == nil {
- l.Log(ctx, "intermediate")
+ l.Log(ctx, "done",
+ latencyField(start),
+ String("id", session.ID()),
+ String("status", session.Status()),
+ )
} else {
- l.Log(WithLevel(ctx, WARN), "failed",
+ l.Log(WithLevel(ctx, ERROR), "failed",
+ latencyField(start),
+ String("id", session.ID()),
+ String("status", session.Status()),
Error(info.Error),
versionField(),
)
}
-
- return func(info trace.TableSessionQueryStreamReadDoneInfo) {
- if info.Error == nil {
- l.Log(ctx, "done",
- latencyField(start),
- String("id", session.ID()),
- String("status", session.Status()),
- )
- } else {
- l.Log(WithLevel(ctx, ERROR), "failed",
- latencyField(start),
- String("id", session.ID()),
- String("status", session.Status()),
- Error(info.Error),
- versionField(),
- )
- }
- }
}
}
- t.OnSessionTransactionBegin = func(
- info trace.TableSessionTransactionBeginStartInfo,
+ t.OnTxBegin = func(
+ info trace.TableTxBeginStartInfo,
) func(
- trace.TableSessionTransactionBeginDoneInfo,
+ trace.TableTxBeginDoneInfo,
) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
@@ -523,7 +417,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(info trace.TableSessionTransactionBeginDoneInfo) {
+ return func(info trace.TableTxBeginDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
@@ -542,11 +436,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
}
}
- t.OnSessionTransactionCommit = func(
- info trace.TableSessionTransactionCommitStartInfo,
- ) func(
- trace.TableSessionTransactionCommitDoneInfo,
- ) {
+ t.OnTxCommit = func(info trace.TableTxCommitStartInfo) func(trace.TableTxCommitDoneInfo) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
}
@@ -560,7 +450,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(info trace.TableSessionTransactionCommitDoneInfo) {
+ return func(info trace.TableTxCommitDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
@@ -580,10 +470,10 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
}
}
}
- t.OnSessionTransactionRollback = func(
- info trace.TableSessionTransactionRollbackStartInfo,
+ t.OnTxRollback = func(
+ info trace.TableTxRollbackStartInfo,
) func(
- trace.TableSessionTransactionRollbackDoneInfo,
+ trace.TableTxRollbackDoneInfo,
) {
if d.Details()&trace.TableSessionTransactionEvents == 0 {
return nil
@@ -598,7 +488,7 @@ func internalTable(l *wrapper, d trace.Detailer) (t trace.Table) {
)
start := time.Now()
- return func(info trace.TableSessionTransactionRollbackDoneInfo) {
+ return func(info trace.TableTxRollbackDoneInfo) {
if info.Error == nil {
l.Log(ctx, "done",
latencyField(start),
diff --git a/meta.go b/meta.go
index f039f40fe..34f192053 100644
--- a/meta.go
+++ b/meta.go
@@ -8,14 +8,18 @@ import (
// WithTraceID returns a copy of parent context with traceID
//
-// Deprecated: use meta.WithTraceID instead
+// Deprecated: use meta.WithTraceID instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithTraceID(ctx context.Context, traceID string) context.Context {
return meta.WithTraceID(ctx, traceID)
}
// WithRequestType returns a copy of parent context with custom request type
//
-// Deprecated: use meta.WithRequestType instead
+// Deprecated: use meta.WithRequestType instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithRequestType(ctx context.Context, requestType string) context.Context {
return meta.WithRequestType(ctx, requestType)
}
diff --git a/meta/context.go b/meta/context.go
index 5ea200db6..3f8673003 100644
--- a/meta/context.go
+++ b/meta/context.go
@@ -15,7 +15,9 @@ func WithTraceID(ctx context.Context, traceID string) context.Context {
// WithUserAgent returns a copy of parent context with custom user-agent info
//
-// Deprecated: use WithApplicationName instead
+// Deprecated: use WithApplicationName instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithUserAgent(ctx context.Context, _ string) context.Context {
return ctx
}
diff --git a/metrics/config.go b/metrics/config.go
index 85902821f..e87f190c7 100644
--- a/metrics/config.go
+++ b/metrics/config.go
@@ -2,7 +2,9 @@ package metrics
import "github.com/ydb-platform/ydb-go-sdk/v3/trace"
-// Config is experimental interface for metrics registry config
+// Config is interface for metrics registry config
+//
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
type Config interface {
Registry
diff --git a/metrics/driver.go b/metrics/driver.go
index 5b2f12fbc..b477f8f3d 100644
--- a/metrics/driver.go
+++ b/metrics/driver.go
@@ -11,7 +11,7 @@ import (
// driver makes driver with New publishing
func driver(config Config) (t trace.Driver) {
config = config.WithSystem("driver")
- endpoints := config.WithSystem("balancer").GaugeVec("endpoints", "local_dc", "az")
+ endpoints := config.WithSystem("balancer").GaugeVec("endpoints", "az")
balancersDiscoveries := config.WithSystem("balancer").CounterVec("discoveries", "status", "cause")
balancerUpdates := config.WithSystem("balancer").CounterVec("updates", "cause")
conns := config.GaugeVec("conns", "endpoint", "node_id")
@@ -20,8 +20,7 @@ func driver(config Config) (t trace.Driver) {
tli := config.CounterVec("transaction_locks_invalidated")
type endpointKey struct {
- localDC bool
- az string
+ az string
}
knownEndpoints := make(map[endpointKey]struct{})
@@ -100,8 +99,7 @@ func driver(config Config) (t trace.Driver) {
newEndpoints := make(map[endpointKey]int, len(info.Endpoints))
for _, e := range info.Endpoints {
e := endpointKey{
- localDC: e.LocalDC(),
- az: e.Location(),
+ az: e.Location(),
}
newEndpoints[e]++
}
@@ -109,16 +107,14 @@ func driver(config Config) (t trace.Driver) {
if _, has := newEndpoints[e]; !has {
delete(knownEndpoints, e)
endpoints.With(map[string]string{
- "local_dc": strconv.FormatBool(e.localDC),
- "az": e.az,
+ "az": e.az,
}).Set(0)
}
}
for e, count := range newEndpoints {
knownEndpoints[e] = struct{}{}
endpoints.With(map[string]string{
- "local_dc": strconv.FormatBool(e.localDC),
- "az": e.az,
+ "az": e.az,
}).Set(float64(count))
}
}
diff --git a/metrics/registry.go b/metrics/registry.go
index 738afd886..efadda86f 100644
--- a/metrics/registry.go
+++ b/metrics/registry.go
@@ -1,6 +1,8 @@
package metrics
-// Registry is experimental interface for metrics registry
+// Registry is interface for metrics registry
+//
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
type Registry interface {
// CounterVec returns CounterVec by name, subsystem and labels
// If counter by args already created - return counter from cache
diff --git a/metrics/retry.go b/metrics/retry.go
index 35b0fe9a0..994fd493e 100644
--- a/metrics/retry.go
+++ b/metrics/retry.go
@@ -11,36 +11,26 @@ func retry(config Config) (t trace.Retry) {
errs := config.CounterVec("errors", "status", "retry_label", "final")
attempts := config.HistogramVec("attempts", []float64{0, 1, 2, 3, 4, 5, 7, 10}, "retry_label")
latency := config.TimerVec("latency", "retry_label")
- t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ t.OnRetry = func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
label := info.Label
if label == "" {
return nil
}
start := time.Now()
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- if info.Error != nil && config.Details()&trace.RetryEvents != 0 {
+ return func(info trace.RetryLoopDoneInfo) {
+ if config.Details()&trace.RetryEvents != 0 {
+ attempts.With(map[string]string{
+ "retry_label": label,
+ }).Record(float64(info.Attempts))
errs.With(map[string]string{
"status": errorBrief(info.Error),
"retry_label": label,
- "final": "false",
+ "final": "true",
}).Inc()
- }
-
- return func(info trace.RetryLoopDoneInfo) {
- if config.Details()&trace.RetryEvents != 0 {
- attempts.With(map[string]string{
- "retry_label": label,
- }).Record(float64(info.Attempts))
- errs.With(map[string]string{
- "status": errorBrief(info.Error),
- "retry_label": label,
- "final": "true",
- }).Inc()
- latency.With(map[string]string{
- "retry_label": label,
- }).Record(time.Since(start))
- }
+ latency.With(map[string]string{
+ "retry_label": label,
+ }).Record(time.Since(start))
}
}
}
diff --git a/metrics/table.go b/metrics/table.go
index 80dda3cec..c72cde245 100644
--- a/metrics/table.go
+++ b/metrics/table.go
@@ -72,7 +72,11 @@ func table(config Config) (t trace.Table) {
if !ok {
panic(fmt.Sprintf("unknown session '%s'", info.Session.ID()))
}
- inflightLatency.With(nil).Record(time.Since(start.(time.Time)))
+ val, ok := start.(time.Time)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to time.Time", val))
+ }
+ inflightLatency.With(nil).Record(time.Since(val))
}
return nil
diff --git a/options.go b/options.go
index 13bcabc70..305f700fc 100644
--- a/options.go
+++ b/options.go
@@ -54,6 +54,19 @@ func WithAccessTokenCredentials(accessToken string) Option {
)
}
+// WithOauth2TokenExchangeCredentials adds credentials that exchange token using
+// OAuth 2.0 token exchange protocol:
+// https://www.rfc-editor.org/rfc/rfc8693
+func WithOauth2TokenExchangeCredentials(
+ opts ...credentials.Oauth2TokenExchangeCredentialsOption,
+) Option {
+ opts = append(opts, credentials.WithSourceInfo("ydb.WithOauth2TokenExchangeCredentials(opts)"))
+
+ return WithCreateCredentialsFunc(func(context.Context) (credentials.Credentials, error) {
+ return credentials.NewOauth2TokenExchangeCredentials(opts...)
+ })
+}
+
// WithApplicationName add provided application name to all api requests
func WithApplicationName(applicationName string) Option {
return func(ctx context.Context, c *Driver) error {
@@ -65,7 +78,9 @@ func WithApplicationName(applicationName string) Option {
// WithUserAgent add provided user agent value to all api requests
//
-// Deprecated: use WithApplicationName instead
+// Deprecated: use WithApplicationName instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithUserAgent(userAgent string) Option {
return func(ctx context.Context, c *Driver) error {
c.options = append(c.options, config.WithApplicationName(userAgent))
@@ -108,10 +123,10 @@ func WithConnectionString(connectionString string) Option {
}
// WithConnectionTTL defines duration for parking idle connections
-//
-// Deprecated: background connection parking not available
-func WithConnectionTTL(time.Duration) Option {
+func WithConnectionTTL(ttl time.Duration) Option {
return func(ctx context.Context, c *Driver) error {
+ c.options = append(c.options, config.WithConnectionTTL(ttl))
+
return nil
}
}
@@ -393,15 +408,7 @@ func WithQueryConfigOption(option queryConfig.Option) Option {
func WithSessionPoolSizeLimit(sizeLimit int) Option {
return func(ctx context.Context, c *Driver) error {
c.tableOptions = append(c.tableOptions, tableConfig.WithSizeLimit(sizeLimit))
-
- return nil
- }
-}
-
-// WithSessionPoolLimit set min size of internal sessions pool in query.Client
-func WithSessionPoolLimit(size int) Option {
- return func(ctx context.Context, c *Driver) error {
- c.queryOptions = append(c.queryOptions, queryConfig.WithPoolLimit(size))
+ c.queryOptions = append(c.queryOptions, queryConfig.WithPoolLimit(sizeLimit))
return nil
}
@@ -440,6 +447,24 @@ func WithSessionPoolDeleteTimeout(deleteTimeout time.Duration) Option {
}
}
+// WithSessionPoolKeepAliveMinSize set minimum sessions should be keeped alive in table.Client
+//
+// Deprecated: use WithApplicationName instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+func WithSessionPoolKeepAliveMinSize(keepAliveMinSize int) Option {
+ return func(ctx context.Context, c *Driver) error { return nil }
+}
+
+// WithSessionPoolKeepAliveTimeout set timeout of keep alive requests for session in table.Client
+//
+// Deprecated: use WithApplicationName instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+func WithSessionPoolKeepAliveTimeout(keepAliveTimeout time.Duration) Option {
+ return func(ctx context.Context, c *Driver) error { return nil }
+}
+
// WithIgnoreTruncated disables errors on truncated flag
func WithIgnoreTruncated() Option {
return func(ctx context.Context, c *Driver) error {
@@ -542,12 +567,12 @@ func WithTraceScheme(t trace.Scheme, opts ...trace.SchemeComposeOption) Option {
}
// WithTraceCoordination returns coordination trace option
-func WithTraceCoordination(t trace.Coordination, opts ...trace.CoordinationComposeOption) Option {
+func WithTraceCoordination(t trace.Coordination, opts ...trace.CoordinationComposeOption) Option { //nolint:gocritic
return func(ctx context.Context, c *Driver) error {
c.coordinationOptions = append(
c.coordinationOptions,
coordinationConfig.WithTrace(
- t,
+ &t,
append(
[]trace.CoordinationComposeOption{
trace.WithCoordinationPanicCallback(c.panicCallback),
diff --git a/params_builder.go b/params_builder.go
index e9e3f5dfb..64768b55c 100644
--- a/params_builder.go
+++ b/params_builder.go
@@ -4,9 +4,7 @@ import "github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
// ParamsBuilder used for create query arguments instead of tons options.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func ParamsBuilder() params.Builder {
return params.Builder{}
}
diff --git a/query/session.go b/query/session.go
index 9a92449eb..14da2f3d5 100644
--- a/query/session.go
+++ b/query/session.go
@@ -23,7 +23,7 @@ type (
// Execute executes query.
//
// Execute used by default:
- // - DefaultTxControl
+ // - DefaultTxControl (NoTx)
// - flag WithKeepInCache(true) if params is not empty.
Execute(ctx context.Context, query string, opts ...options.ExecuteOption) (tx Transaction, r Result, err error)
diff --git a/retry/context.go b/retry/context.go
index a3898fc0b..282d9543e 100644
--- a/retry/context.go
+++ b/retry/context.go
@@ -7,19 +7,28 @@ type (
)
// WithIdempotentOperation returns a copy of parent context with idempotent operation feature
-// Deprecated: use retry.WithIdempotent option instead
+//
+// Deprecated: use retry.WithIdempotent option instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithIdempotentOperation(ctx context.Context) context.Context {
return context.WithValue(ctx, ctxIsOperationIdempotentKey{}, true)
}
// WithNonIdempotentOperation returns a copy of parent context with non-idempotent operation feature
-// Deprecated: idempotent flag is false by default
+//
+// Deprecated: idempotent flag is false by default.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithNonIdempotentOperation(ctx context.Context) context.Context {
return context.WithValue(ctx, ctxIsOperationIdempotentKey{}, false)
}
// IsOperationIdempotent returns the flag for retry with no idempotent errors
-// Deprecated: context cannot store idempotent value now
+//
+// Deprecated: context cannot store idempotent value now.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func IsOperationIdempotent(ctx context.Context) bool {
v, ok := ctx.Value(ctxIsOperationIdempotentKey{}).(bool)
diff --git a/retry/errors_data_test.go b/retry/errors_data_test.go
index a2ffafa91..5253b505f 100644
--- a/retry/errors_data_test.go
+++ b/retry/errors_data_test.go
@@ -208,7 +208,7 @@ var errsToCheck = []struct {
err: xerrors.Retryable(
xerrors.Transport(grpcStatus.Error(grpcCodes.Unavailable, "")),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
backoff: backoff.TypeFast,
deleteSession: true,
@@ -221,7 +221,7 @@ var errsToCheck = []struct {
err: xerrors.Retryable(
grpcStatus.Error(grpcCodes.Unavailable, ""),
xerrors.WithBackoff(backoff.TypeFast),
- xerrors.WithDeleteSession(),
+ xerrors.InvalidObject(),
),
backoff: backoff.TypeFast,
deleteSession: true,
diff --git a/retry/mode.go b/retry/mode.go
index 385cf170b..32736e9c3 100644
--- a/retry/mode.go
+++ b/retry/mode.go
@@ -7,10 +7,10 @@ import (
// retryMode reports whether operation is able retried and with which properties.
type retryMode struct {
- code int64
- errType xerrors.Type
- backoff backoff.Type
- deleteSession bool
+ code int64
+ errType xerrors.Type
+ backoff backoff.Type
+ isRetryObjectValid bool
}
func (m retryMode) MustRetry(isOperationIdempotent bool) bool {
@@ -33,4 +33,6 @@ func (m retryMode) MustBackoff() bool { return m.backoff&backoff.TypeAny != 0 }
func (m retryMode) BackoffType() backoff.Type { return m.backoff }
-func (m retryMode) MustDeleteSession() bool { return m.deleteSession }
+func (m retryMode) MustDeleteSession() bool { return !m.isRetryObjectValid }
+
+func (m retryMode) IsRetryObjectValid() bool { return m.isRetryObjectValid }
diff --git a/retry/retry.go b/retry/retry.go
index 364e6076b..65e88ce91 100644
--- a/retry/retry.go
+++ b/retry/retry.go
@@ -227,12 +227,12 @@ func WithPanicCallback(panicCallback func(e interface{})) panicCallbackOption {
//
// - retry operation returned nil as error
//
-// Warning: if deadline without deadline or cancellation func Retry will be worked infinite
+// Warning: if context without deadline or cancellation func was passed, Retry will work infinitely.
//
// If you need to retry your op func on some logic errors - you must return RetryableError() from retryOperation
func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr error) {
options := &retryOptions{
- call: stack.FunctionID(""),
+ call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.Retry"),
trace: &trace.Retry{},
fastBackoff: backoff.Fast,
slowBackoff: backoff.Slow,
@@ -245,8 +245,10 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
if options.idempotent {
ctx = xcontext.WithIdempotent(ctx, options.idempotent)
}
+
defer func() {
if finalErr != nil && options.stackTrace {
+ //nolint:gomnd
finalErr = xerrors.WithStackTrace(finalErr,
xerrors.WithSkipDepth(2), // 1 - exit from defer, 1 - exit from Retry call
)
@@ -256,13 +258,13 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
i int
attempts int
- code = int64(0)
- onIntermediate = trace.RetryOnRetry(options.trace, &ctx,
+ code = int64(0)
+ onDone = trace.RetryOnRetry(options.trace, &ctx,
options.call, options.label, options.idempotent, xcontext.IsNestedCall(ctx),
)
)
defer func() {
- onIntermediate(finalErr)(attempts, finalErr)
+ onDone(attempts, finalErr)
}()
for {
i++
@@ -329,8 +331,6 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
}
code = m.StatusCode()
-
- onIntermediate(err)
}
}
}
@@ -340,9 +340,9 @@ func Check(err error) (m retryMode) {
code, errType, backoffType, deleteSession := xerrors.Check(err)
return retryMode{
- code: code,
- errType: errType,
- backoff: backoffType,
- deleteSession: deleteSession,
+ code: code,
+ errType: errType,
+ backoff: backoffType,
+ isRetryObjectValid: deleteSession,
}
}
diff --git a/retry/retry_test.go b/retry/retry_test.go
index 71638e6e9..770f2ea65 100644
--- a/retry/retry_test.go
+++ b/retry/retry_test.go
@@ -45,10 +45,10 @@ func TestRetryModes(t *testing.T) {
tt.backoff,
)
}
- if m.MustDeleteSession() != tt.deleteSession {
+ if m.IsRetryObjectValid() != tt.deleteSession {
t.Errorf(
"unexpected delete session status: %v, want: %v",
- m.MustDeleteSession(),
+ m.IsRetryObjectValid(),
tt.deleteSession,
)
}
diff --git a/retry/retryable_error.go b/retry/retryable_error.go
index 7501223dc..ca273aac7 100644
--- a/retry/retryable_error.go
+++ b/retry/retryable_error.go
@@ -20,7 +20,7 @@ func WithBackoff(t backoff.Type) retryableErrorOption {
// WithDeleteSession makes retryable error option with delete session flag
func WithDeleteSession() retryableErrorOption {
- return retryableErrorOption(xerrors.WithDeleteSession())
+ return retryableErrorOption(xerrors.InvalidObject())
}
// RetryableError makes retryable error from options
diff --git a/retry/sql.go b/retry/sql.go
index 115b685ad..9b826a1ca 100644
--- a/retry/sql.go
+++ b/retry/sql.go
@@ -32,7 +32,9 @@ func (retryOptions doRetryOptionsOption) ApplyDoOption(opts *doOptions) {
}
// WithDoRetryOptions specified retry options
-// Deprecated: use implicit options instead
+// Deprecated: use explicit options instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithDoRetryOptions(opts ...Option) doRetryOptionsOption {
return opts
}
@@ -42,7 +44,7 @@ func Do(ctx context.Context, db *sql.DB, op func(ctx context.Context, cc *sql.Co
var (
options = doOptions{
retryOptions: []Option{
- withCaller(stack.FunctionID("")),
+ withCaller(stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.Do")),
},
}
attempts = 0
@@ -102,7 +104,9 @@ func (doTxRetryOptions doTxRetryOptionsOption) ApplyDoTxOption(o *doTxOptions) {
}
// WithDoTxRetryOptions specified retry options
-// Deprecated: use implicit options instead
+// Deprecated: use explicit options instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithDoTxRetryOptions(opts ...Option) doTxRetryOptionsOption {
return opts
}
@@ -129,7 +133,7 @@ func DoTx(ctx context.Context, db *sql.DB, op func(context.Context, *sql.Tx) err
var (
options = doTxOptions{
retryOptions: []Option{
- withCaller(stack.FunctionID("")),
+ withCaller(stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.DoTx")),
},
txOptions: &sql.TxOptions{
Isolation: sql.LevelDefault,
diff --git a/retry/sql_test.go b/retry/sql_test.go
index 935179834..d6552493b 100644
--- a/retry/sql_test.go
+++ b/retry/sql_test.go
@@ -11,7 +11,6 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/stack"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn"
- "github.com/ydb-platform/ydb-go-sdk/v3/trace"
)
type mockConnector struct {
@@ -104,7 +103,7 @@ func (m *mockConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.T
func (m *mockConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
m.t.Log(stack.Record(0))
- if xerrors.MustDeleteSession(m.execErr) {
+ if !xerrors.IsRetryObjectValid(m.execErr) {
m.closed = true
}
@@ -113,7 +112,7 @@ func (m *mockConn) QueryContext(ctx context.Context, query string, args []driver
func (m *mockConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
m.t.Log(stack.Record(0))
- if xerrors.MustDeleteSession(m.execErr) {
+ if !xerrors.IsRetryObjectValid(m.execErr) {
m.closed = true
}
@@ -215,18 +214,6 @@ func TestDoTx(t *testing.T) {
WithIdempotent(bool(idempotentType)),
WithFastBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))),
WithSlowBackoff(backoff.New(backoff.WithSlotDuration(time.Nanosecond))),
- WithTrace(&trace.Retry{
- //nolint:lll
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- t.Logf("attempt %d, conn %d, mode: %+v", attempts, m.conns, Check(m.queryErr))
-
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- t.Logf("attempt %d, conn %d, mode: %+v", attempts, m.conns, Check(m.queryErr))
-
- return nil
- }
- },
- }),
)
if tt.canRetry[idempotentType] {
if err != nil {
diff --git a/sugar/params.go b/sugar/params.go
index 612268260..4285969a5 100644
--- a/sugar/params.go
+++ b/sugar/params.go
@@ -18,7 +18,10 @@ type constraint interface {
// GenerateDeclareSection generates DECLARE section text in YQL query by params
//
-// Deprecated: use testutil.QueryBind(ydb.WithAutoDeclare()) helper
+// Deprecated: use testutil.QueryBind(ydb.WithAutoDeclare()) helper.
+// In YDB since version 24.1 declare sections not requires.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func GenerateDeclareSection[T constraint](parameters T) (string, error) {
switch v := any(parameters).(type) {
case *params.Parameters:
@@ -36,7 +39,7 @@ func GenerateDeclareSection[T constraint](parameters T) (string, error) {
// ToYdbParam converts
//
-// Deprecated: use testutil/QueryBind helper
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func ToYdbParam(param sql.NamedArg) (*params.Parameter, error) {
params, err := bind.Params(param)
if err != nil {
diff --git a/sugar/result.go b/sugar/result.go
index 33c2339d9..4a2275dcf 100644
--- a/sugar/result.go
+++ b/sugar/result.go
@@ -73,9 +73,7 @@ func (r *result) Close() error {
// Result converts query.Result to iterable result for compatibility with table/result.Result usage
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func Result(r query.Result) *result {
return &result{
r: r,
diff --git a/table/options/models.go b/table/options/models.go
index c993affbc..eb875e63d 100644
--- a/table/options/models.go
+++ b/table/options/models.go
@@ -43,15 +43,6 @@ type IndexDescription struct {
Type IndexType
}
-//nolint:unused
-func (i IndexDescription) toYDB() *Ydb_Table.TableIndexDescription {
- return &Ydb_Table.TableIndexDescription{
- Name: i.Name,
- IndexColumns: i.IndexColumns,
- Status: i.Status,
- }
-}
-
type Description struct {
Name string
Columns []Column
@@ -430,7 +421,8 @@ func (kr KeyRange) String() string {
}
// Deprecated: use TimeToLiveSettings instead.
-// Will be removed after Jan 2022.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
type TTLSettings struct {
DateTimeColumn string
TTLSeconds uint32
diff --git a/table/options/options.go b/table/options/options.go
index db85556a7..922333a17 100644
--- a/table/options/options.go
+++ b/table/options/options.go
@@ -518,7 +518,9 @@ func WithPartitioningPolicyMode(mode PartitioningMode) PartitioningPolicyOption
}
}
-// Deprecated: use WithUniformPartitions instead
+// Deprecated: use WithUniformPartitions instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithPartitioningPolicyUniformPartitions(n uint64) PartitioningPolicyOption {
return func(p *partitioningPolicy, a *allocator.Allocator) {
p.Partitions = &Ydb_Table.PartitioningPolicy_UniformPartitions{
@@ -527,7 +529,9 @@ func WithPartitioningPolicyUniformPartitions(n uint64) PartitioningPolicyOption
}
}
-// Deprecated: use WithExplicitPartitions instead
+// Deprecated: use WithExplicitPartitions instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithPartitioningPolicyExplicitPartitions(splitPoints ...value.Value) PartitioningPolicyOption {
return func(p *partitioningPolicy, a *allocator.Allocator) {
values := make([]*Ydb.TypedValue, len(splitPoints))
@@ -806,6 +810,21 @@ func CopyTablesItem(src, dst string, omitIndexes bool) CopyTablesOption {
}
}
+type (
+ RenameTablesDesc Ydb_Table.RenameTablesRequest
+ RenameTablesOption func(desc *RenameTablesDesc)
+)
+
+func RenameTablesItem(src, dst string, replaceDestination bool) RenameTablesOption {
+ return func(desc *RenameTablesDesc) {
+ desc.Tables = append(desc.Tables, &Ydb_Table.RenameTableItem{
+ SourcePath: src,
+ DestinationPath: dst,
+ ReplaceDestination: replaceDestination,
+ })
+ }
+}
+
type (
ExecuteSchemeQueryDesc Ydb_Table.ExecuteSchemeQueryRequest
ExecuteSchemeQueryOption func(*ExecuteSchemeQueryDesc)
@@ -892,7 +911,8 @@ func WithIgnoreTruncated() ExecuteDataQueryOption {
// WithQueryCachePolicyKeepInCache manages keep-in-cache policy
//
// Deprecated: data queries always executes with enabled keep-in-cache policy.
-// Use WithKeepInCache for disabling keep-in-cache policy
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithQueryCachePolicyKeepInCache() QueryCachePolicyOption {
return withQueryCachePolicyKeepInCache(true)
}
@@ -905,7 +925,9 @@ func withQueryCachePolicyKeepInCache(keepInCache bool) QueryCachePolicyOption {
// WithQueryCachePolicy manages query cache policy
//
-// Deprecated: use WithKeepInCache for disabling keep-in-cache policy
+// Deprecated: use WithKeepInCache for disabling keep-in-cache policy.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithQueryCachePolicy(opts ...QueryCachePolicyOption) ExecuteDataQueryOption {
return withQueryCachePolicy(opts...)
}
diff --git a/table/table.go b/table/table.go
index 6d2305a1e..1cb1ed8e0 100644
--- a/table/table.go
+++ b/table/table.go
@@ -39,8 +39,9 @@ type Client interface {
// - context was canceled or deadlined
// - session was created
//
- // Deprecated: don't use CreateSession explicitly. This method only for ORM's compatibility.
- // Use Do for queries with session
+ // Deprecated: not for public usage. Because explicit session often leaked on server-side due to bad client-side usage.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
CreateSession(ctx context.Context, opts ...Option) (s ClosableSession, err error)
// Do provide the best effort for execute operation.
@@ -111,6 +112,9 @@ type Session interface {
opts ...options.AlterTableOption,
) (err error)
+ // Deprecated: use CopyTables method instead
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
CopyTable(
ctx context.Context,
dst, src string,
@@ -122,6 +126,11 @@ type Session interface {
opts ...options.CopyTablesOption,
) (err error)
+ RenameTables(
+ ctx context.Context,
+ opts ...options.RenameTablesOption,
+ ) (err error)
+
Explain(
ctx context.Context,
query string,
diff --git a/table/types/cast.go b/table/types/cast.go
index 71d8476ea..064967678 100644
--- a/table/types/cast.go
+++ b/table/types/cast.go
@@ -93,7 +93,9 @@ func VariantValue(v Value) (name string, idx uint32, _ Value, _ error) {
// DictFields returns dict values from abstract Value
//
-// Deprecated: use DictValues instead
+// Deprecated: use DictValues instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func DictFields(v Value) (map[Value]Value, error) {
return DictValues(v)
}
diff --git a/table/types/types.go b/table/types/types.go
index cca6b5c09..530ed77b0 100644
--- a/table/types/types.go
+++ b/table/types/types.go
@@ -7,6 +7,11 @@ import (
"github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
)
+const (
+ decimalPrecision uint32 = 22
+ decimalScale uint32 = 9
+)
+
// Type describes YDB data types.
type Type = types.Type
@@ -76,7 +81,7 @@ func Optional(t Type) Type {
return types.NewOptional(t)
}
-var DefaultDecimal = DecimalType(22, 9)
+var DefaultDecimal = DecimalType(decimalPrecision, decimalScale)
func DecimalType(precision, scale uint32) Type {
return types.NewDecimal(precision, scale)
@@ -120,7 +125,9 @@ const (
// WriteTypeStringTo writes ydb type string representation into buffer
//
-// Deprecated: use types.Type.Yql() instead
+// Deprecated: use types.Type.Yql() instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WriteTypeStringTo(buf *bytes.Buffer, t Type) { //nolint: interfacer
buf.WriteString(t.Yql())
}
diff --git a/table/types/value.go b/table/types/value.go
index 9249c4e3c..8f1ed8cb4 100644
--- a/table/types/value.go
+++ b/table/types/value.go
@@ -47,7 +47,9 @@ func IntervalValueFromMicroseconds(v int64) Value { return value.IntervalValue(v
// IntervalValue makes Value from given microseconds value
//
-// Deprecated: use IntervalValueFromMicroseconds instead
+// Deprecated: use IntervalValueFromMicroseconds instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func IntervalValue(v int64) Value { return value.IntervalValue(v) }
// TzDateValue makes TzDate value from string
@@ -117,7 +119,9 @@ func TzTimestampValueFromTime(t time.Time) Value {
// StringValue returns bytes value
//
-// Deprecated: use BytesValue instead
+// Deprecated: use BytesValue instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func StringValue(v []byte) Value { return value.BytesValue(v) }
func BytesValue(v []byte) Value { return value.BytesValue(v) }
@@ -345,7 +349,9 @@ func NullableTzTimestampValueFromTime(v *time.Time) Value {
// NullableIntervalValue makes Value which maybe nil or valued
//
-// Deprecated: use NullableIntervalValueFromMicroseconds instead
+// Deprecated: use NullableIntervalValueFromMicroseconds instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func NullableIntervalValue(v *int64) Value {
return value.NullableIntervalValueFromMicroseconds(v)
}
@@ -360,7 +366,9 @@ func NullableIntervalValueFromDuration(v *time.Duration) Value {
// NullableStringValue
//
-// Deprecated: use NullableBytesValue instead
+// Deprecated: use NullableBytesValue instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func NullableStringValue(v *[]byte) Value {
return value.NullableBytesValue(v)
}
diff --git a/tests/integration/coordination_test.go b/tests/integration/coordination_test.go
new file mode 100644
index 000000000..c3551e604
--- /dev/null
+++ b/tests/integration/coordination_test.go
@@ -0,0 +1,102 @@
+//go:build integration
+// +build integration
+
+package integration
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination"
+ "github.com/ydb-platform/ydb-go-sdk/v3/coordination/options"
+ "github.com/ydb-platform/ydb-go-sdk/v3/log"
+ "github.com/ydb-platform/ydb-go-sdk/v3/trace"
+)
+
+//nolint:errcheck
+func TestCoordinationSemaphore(t *testing.T) {
+ ctx := context.TODO()
+ db, err := ydb.Open(ctx,
+ os.Getenv("YDB_CONNECTION_STRING"),
+ ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
+ ydb.WithLogger(
+ log.Default(os.Stderr, log.WithMinLevel(log.TRACE)),
+ trace.MatchDetails(`ydb\.(coordination).*`),
+ ),
+ )
+ if err != nil {
+ t.Fatalf("failed to connect: %v", err)
+ }
+ defer db.Close(ctx) // cleanup resources
+
+ const nodePath = "/local/coordination/node/test"
+
+ // create node
+ err = db.Coordination().CreateNode(ctx, nodePath, coordination.NodeConfig{
+ Path: "",
+ SelfCheckPeriodMillis: 1000,
+ SessionGracePeriodMillis: 1000,
+ ReadConsistencyMode: coordination.ConsistencyModeStrict,
+ AttachConsistencyMode: coordination.ConsistencyModeStrict,
+ RatelimiterCountersMode: coordination.RatelimiterCountersModeDetailed,
+ })
+ if err != nil {
+ t.Fatalf("failed to create node: %v", err)
+ }
+ defer db.Coordination().DropNode(ctx, nodePath)
+ e, c, err := db.Coordination().DescribeNode(ctx, nodePath)
+ if err != nil {
+ t.Fatalf("failed to describe node: %v\n", err)
+ }
+ fmt.Printf("node description: %+v\nnode config: %+v\n", e, c)
+
+ s, err := db.Coordination().Session(ctx, nodePath)
+ if err != nil {
+ t.Fatalf("failed to create session: %v\n", err)
+ }
+ defer s.Close(ctx)
+ fmt.Printf("session 1 created, id: %d\n", s.SessionID())
+
+ err = s.CreateSemaphore(ctx, "my-semaphore", 20, options.WithCreateData([]byte{1, 2, 3}))
+ if err != nil {
+ t.Fatalf("failed to create semaphore: %v", err)
+ }
+ fmt.Printf("semaphore my-semaphore created\n")
+
+ lease, err := s.AcquireSemaphore(ctx, "my-semaphore", 10)
+ if err != nil {
+ t.Fatalf("failed to acquire semaphore: %v", err)
+ }
+ defer lease.Release()
+ fmt.Printf("session 1 acquired semaphore 10\n")
+
+ s.Reconnect()
+ fmt.Printf("session 1 reconnected\n")
+
+ desc, err := s.DescribeSemaphore(
+ ctx,
+ "my-semaphore",
+ options.WithDescribeOwners(true),
+ options.WithDescribeWaiters(true),
+ )
+ if err != nil {
+ t.Fatalf("failed to describe semaphore: %v", err)
+ }
+ fmt.Printf("session 1 described semaphore %v\n", desc)
+
+ err = lease.Release()
+ if err != nil {
+ t.Fatalf("failed to release semaphore: %v", err)
+ }
+ fmt.Printf("session 1 released semaphore my-semaphore\n")
+
+ err = s.DeleteSemaphore(ctx, "my-semaphore", options.WithForceDelete(true))
+ if err != nil {
+ t.Fatalf("failed to delete semaphore: %v", err)
+ }
+
+ fmt.Printf("deleted semaphore my-semaphore\n")
+}
diff --git a/tests/integration/discovery_test.go b/tests/integration/discovery_test.go
index ebd5a054e..511043ebd 100644
--- a/tests/integration/discovery_test.go
+++ b/tests/integration/discovery_test.go
@@ -46,7 +46,8 @@ func TestDiscovery(t *testing.T) {
t.Fatalf("unknown request type: %s", requestTypes[0])
}
}
- ctx = xtest.Context(t)
+ parking = make(chan struct{})
+ ctx = xtest.Context(t)
)
db, err := ydb.Open(ctx,
@@ -59,6 +60,7 @@ func TestDiscovery(t *testing.T) {
config.WithOperationCancelAfter(time.Second*2),
),
ydb.WithBalancer(balancers.SingleConn()),
+ ydb.WithConnectionTTL(time.Second*1),
ydb.WithMinTLSVersion(tls.VersionTLS10),
ydb.WithLogger(
newLoggerWithMinLevel(t, log.WARN),
@@ -92,6 +94,13 @@ func TestDiscovery(t *testing.T) {
}),
),
),
+ ydb.WithTraceDriver(trace.Driver{
+ OnConnPark: func(info trace.DriverConnParkStartInfo) func(trace.DriverConnParkDoneInfo) {
+ return func(info trace.DriverConnParkDoneInfo) {
+ parking <- struct{}{}
+ }
+ },
+ }),
)
if err != nil {
t.Fatal(err)
@@ -108,5 +117,17 @@ func TestDiscovery(t *testing.T) {
} else {
t.Log(endpoints)
}
+ t.Run("wait", func(t *testing.T) {
+ t.Run("parking", func(t *testing.T) {
+ <-parking // wait for parking conn
+ t.Run("re-discover", func(t *testing.T) {
+ if endpoints, err := db.Discovery().Discover(ctx); err != nil {
+ t.Fatal(err)
+ } else {
+ t.Log(endpoints)
+ }
+ })
+ })
+ })
})
}
diff --git a/tests/integration/helpers_test.go b/tests/integration/helpers_test.go
index 83fd412f6..73363250d 100644
--- a/tests/integration/helpers_test.go
+++ b/tests/integration/helpers_test.go
@@ -85,9 +85,9 @@ func (scope *scopeT) Driver(opts ...ydb.Option) *ydb.Driver {
token := scope.AuthToken()
if token == "" {
- scope.Logf("Change empty auth token")
+ scope.Logf("With empty auth token")
} else {
- scope.Logf("Change auth token")
+ scope.Logf("With auth token")
}
connectionContext, cancel := context.WithTimeout(scope.Ctx, time.Second*10)
diff --git a/tests/integration/query_execute_test.go b/tests/integration/query_execute_test.go
index b3d6c0339..81687bae8 100644
--- a/tests/integration/query_execute_test.go
+++ b/tests/integration/query_execute_test.go
@@ -31,6 +31,7 @@ func TestQueryExecute(t *testing.T) {
db, err := ydb.Open(ctx,
os.Getenv("YDB_CONNECTION_STRING"),
ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")),
+ ydb.WithSessionPoolSizeLimit(10),
ydb.WithTraceQuery(
log.Query(
log.Default(os.Stdout,
@@ -43,6 +44,11 @@ func TestQueryExecute(t *testing.T) {
),
)
require.NoError(t, err)
+ t.Run("Stats", func(t *testing.T) {
+ s, err := query.Stats(db.Query())
+ require.NoError(t, err)
+ require.EqualValues(t, 10, s.Limit)
+ })
t.Run("Scan", func(t *testing.T) {
var (
p1 string
diff --git a/tests/integration/topic_grpc_stopper_helper_test.go b/tests/integration/topic_grpc_stopper_helper_test.go
index f08930a83..d9b521bed 100644
--- a/tests/integration/topic_grpc_stopper_helper_test.go
+++ b/tests/integration/topic_grpc_stopper_helper_test.go
@@ -19,8 +19,8 @@ import (
//
// db, err := ydb.Open(context.Background(), connectionString,
// ...
-// ydb.Change(config.WithGrpcOptions(grpc.WithChainUnaryInterceptor(grpcStopper.UnaryClientInterceptor)),
-// ydb.Change(config.WithGrpcOptions(grpc.WithStreamInterceptor(grpcStopper.StreamClientInterceptor)),
+// ydb.With(config.WithGrpcOptions(grpc.WithChainUnaryInterceptor(grpcStopper.UnaryClientInterceptor)),
+// ydb.With(config.WithGrpcOptions(grpc.WithStreamInterceptor(grpcStopper.StreamClientInterceptor)),
// ),
//
// grpcStopper.Stop(errors.New("test error"))
diff --git a/tests/integration/with_trace_retry_test.go b/tests/integration/with_trace_retry_test.go
index 42bc1958b..1cb5b6564 100644
--- a/tests/integration/with_trace_retry_test.go
+++ b/tests/integration/with_trace_retry_test.go
@@ -26,9 +26,7 @@ func TestWithTraceRetry(t *testing.T) {
scope = newScope(t)
db = scope.Driver(
ydb.WithTraceRetry(trace.Retry{
- OnRetry: func(
- info trace.RetryLoopStartInfo,
- ) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
retryCalled[info.Label] = true
return nil
},
@@ -64,9 +62,7 @@ func TestWithTraceRetry(t *testing.T) {
scope = newScope(t)
nativeDb = scope.Driver(
ydb.WithTraceRetry(trace.Retry{
- OnRetry: func(
- info trace.RetryLoopStartInfo,
- ) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
retryCalled[info.Label] = true
return nil
},
diff --git a/tests/slo/database/sql/storage.go b/tests/slo/database/sql/storage.go
index 1fe6a2c38..8c740803c 100755
--- a/tests/slo/database/sql/storage.go
+++ b/tests/slo/database/sql/storage.go
@@ -77,7 +77,7 @@ type Storage struct {
}
func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (s *Storage, err error) {
- ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
+ ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
defer cancel()
s = &Storage{
@@ -139,11 +139,9 @@ func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (res genera
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -179,11 +177,9 @@ func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, err
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
diff --git a/tests/slo/go.mod b/tests/slo/go.mod
index e8f010142..b39213d88 100644
--- a/tests/slo/go.mod
+++ b/tests/slo/go.mod
@@ -6,7 +6,6 @@ require (
github.com/prometheus/client_golang v1.14.0
github.com/ydb-platform/gorm-driver v0.1.1
github.com/ydb-platform/ydb-go-sdk/v3 v3.58.0
- go.opentelemetry.io/otel v1.21.0
golang.org/x/sync v0.6.0
golang.org/x/time v0.3.0
gorm.io/gorm v1.25.1
@@ -16,13 +15,12 @@ require (
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/go-logr/logr v1.4.1 // indirect
- github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
@@ -41,9 +39,7 @@ require (
github.com/ydb-platform/ydb-go-sdk-auth-environ v0.2.0 // indirect
github.com/ydb-platform/ydb-go-yc v0.10.2 // indirect
github.com/ydb-platform/ydb-go-yc-metadata v0.5.3 // indirect
- go.opentelemetry.io/otel/metric v1.21.0 // indirect
- go.opentelemetry.io/otel/trace v1.21.0 // indirect
- golang.org/x/net v0.20.0 // indirect
+ golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect
diff --git a/tests/slo/go.sum b/tests/slo/go.sum
index 78bb98723..970122056 100644
--- a/tests/slo/go.sum
+++ b/tests/slo/go.sum
@@ -733,11 +733,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
-github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
-github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -1227,12 +1222,6 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
-go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
-go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
-go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
-go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
-go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
-go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -1269,7 +1258,7 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1398,9 +1387,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
-golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1550,7 +1538,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1564,7 +1552,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/tests/slo/gorm/storage.go b/tests/slo/gorm/storage.go
index 2481014f1..b2cf92211 100644
--- a/tests/slo/gorm/storage.go
+++ b/tests/slo/gorm/storage.go
@@ -110,11 +110,9 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (r generator.Row
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -158,11 +156,9 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
diff --git a/tests/slo/internal/config/config.go b/tests/slo/internal/config/config.go
index b858d27b8..612bc0ae3 100644
--- a/tests/slo/internal/config/config.go
+++ b/tests/slo/internal/config/config.go
@@ -35,6 +35,7 @@ type Config struct {
ShutdownTime int
}
+//nolint:gomnd
func New() (*Config, error) {
cfg := &Config{}
diff --git a/tests/slo/internal/metrics/metrics.go b/tests/slo/internal/metrics/metrics.go
index ee7778152..67b4af470 100644
--- a/tests/slo/internal/metrics/metrics.go
+++ b/tests/slo/internal/metrics/metrics.go
@@ -63,7 +63,7 @@ func New(url, label, jobName string) (*Metrics, error) {
0.99: 0,
1.0: 0,
},
- MaxAge: 15 * time.Second,
+ MaxAge: 15 * time.Second, //nolint:gomnd
},
[]string{"status", "jobName"},
)
@@ -71,7 +71,7 @@ func New(url, label, jobName string) (*Metrics, error) {
prometheus.HistogramOpts{
Name: "attempts",
Help: "summary of amount for request",
- Buckets: prometheus.LinearBuckets(1, 1, 10),
+ Buckets: prometheus.LinearBuckets(1, 1, 10), //nolint:gomnd
},
[]string{"status", "jobName"},
)
diff --git a/tests/slo/native/query/main.go b/tests/slo/native/query/main.go
index 9d5df4e72..138187877 100644
--- a/tests/slo/native/query/main.go
+++ b/tests/slo/native/query/main.go
@@ -41,8 +41,16 @@ func main() {
panic(fmt.Errorf("create storage failed: %w", err))
}
defer func() {
- shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(),
- time.Duration(cfg.ShutdownTime)*time.Second)
+ var (
+ shutdownCtx context.Context
+ shutdownCancel context.CancelFunc
+ )
+ if cfg.ShutdownTime > 0 {
+ shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(),
+ time.Duration(cfg.ShutdownTime)*time.Second)
+ } else {
+ shutdownCtx, shutdownCancel = context.WithCancel(context.Background())
+ }
defer shutdownCancel()
_ = s.close(shutdownCtx)
diff --git a/tests/slo/native/query/storage.go b/tests/slo/native/query/storage.go
index b5e08a309..4c0132adc 100755
--- a/tests/slo/native/query/storage.go
+++ b/tests/slo/native/query/storage.go
@@ -5,10 +5,12 @@ import (
"errors"
"fmt"
"io"
+ "os"
"path"
"time"
ydb "github.com/ydb-platform/ydb-go-sdk/v3"
+ "github.com/ydb-platform/ydb-go-sdk/v3/log"
"github.com/ydb-platform/ydb-go-sdk/v3/query"
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
@@ -64,12 +66,13 @@ DROP TABLE %s
`
func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (*Storage, error) {
- ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
+ ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
defer cancel()
db, err := ydb.Open(ctx,
cfg.Endpoint+cfg.DB,
- ydb.WithSessionPoolLimit(poolSize),
+ ydb.WithSessionPoolSizeLimit(poolSize),
+ ydb.WithLogger(log.Default(os.Stderr, log.WithMinLevel(log.ERROR)), trace.DetailsAll),
)
if err != nil {
return nil, err
@@ -251,8 +254,16 @@ func (s *Storage) dropTable(ctx context.Context) error {
}
func (s *Storage) close(ctx context.Context) error {
- ctx, cancel := context.WithTimeout(ctx, time.Duration(s.cfg.ShutdownTime)*time.Second)
- defer cancel()
+ var (
+ shutdownCtx context.Context
+ shutdownCancel context.CancelFunc
+ )
+ if s.cfg.ShutdownTime > 0 {
+ shutdownCtx, shutdownCancel = context.WithTimeout(ctx, time.Duration(s.cfg.ShutdownTime)*time.Second)
+ } else {
+ shutdownCtx, shutdownCancel = context.WithCancel(ctx)
+ }
+ defer shutdownCancel()
- return s.db.Close(ctx)
+ return s.db.Close(shutdownCtx)
}
diff --git a/tests/slo/native/table/storage.go b/tests/slo/native/table/storage.go
index 4a438bf10..220054aa0 100755
--- a/tests/slo/native/table/storage.go
+++ b/tests/slo/native/table/storage.go
@@ -65,7 +65,7 @@ type Storage struct {
}
func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (*Storage, error) {
- ctx, cancel := context.WithTimeout(ctx, time.Minute*5)
+ ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
defer cancel()
db, err := ydb.Open(
@@ -142,11 +142,9 @@ func (s *Storage) Read(ctx context.Context, entryID generator.RowID) (_ generato
},
table.WithIdempotent(),
table.WithTrace(trace.Table{
- OnDo: func(info trace.TableDoStartInfo) func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoDoneInfo) {
- attempts = info.Attempts
- }
+ OnDo: func(info trace.TableDoStartInfo) func(trace.TableDoDoneInfo) {
+ return func(info trace.TableDoDoneInfo) {
+ attempts = info.Attempts
}
},
}),
@@ -190,11 +188,9 @@ func (s *Storage) Write(ctx context.Context, e generator.Row) (attempts int, _ e
},
table.WithIdempotent(),
table.WithTrace(trace.Table{
- OnDo: func(info trace.TableDoStartInfo) func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoIntermediateInfo) func(trace.TableDoDoneInfo) {
- return func(info trace.TableDoDoneInfo) {
- attempts = info.Attempts
- }
+ OnDo: func(info trace.TableDoStartInfo) func(trace.TableDoDoneInfo) {
+ return func(info trace.TableDoDoneInfo) {
+ attempts = info.Attempts
}
},
}),
diff --git a/tests/slo/xorm/storage.go b/tests/slo/xorm/storage.go
index 87409a738..4550374c9 100644
--- a/tests/slo/xorm/storage.go
+++ b/tests/slo/xorm/storage.go
@@ -141,11 +141,9 @@ func (s *Storage) Read(ctx context.Context, id generator.RowID) (row generator.R
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
@@ -176,11 +174,9 @@ func (s *Storage) Write(ctx context.Context, row generator.Row) (attempts int, e
retry.WithIdempotent(true),
retry.WithTrace(
&trace.Retry{
- OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopIntermediateInfo) func(trace.RetryLoopDoneInfo) {
- return func(info trace.RetryLoopDoneInfo) {
- attempts = info.Attempts
- }
+ OnRetry: func(info trace.RetryLoopStartInfo) func(trace.RetryLoopDoneInfo) {
+ return func(info trace.RetryLoopDoneInfo) {
+ attempts = info.Attempts
}
},
},
diff --git a/testutil/compare.go b/testutil/compare.go
index a021ff909..8caf4b9bf 100644
--- a/testutil/compare.go
+++ b/testutil/compare.go
@@ -309,11 +309,11 @@ func compareBool(l, r *Ydb.Value) int {
func compareDyNumber(l, r *Ydb.Value) (int, error) {
ll := l.GetTextValue()
rr := r.GetTextValue()
- lf, _, err := big.ParseFloat(ll, 10, 127, big.ToNearestEven)
+ lf, _, err := big.ParseFloat(ll, 10, 127, big.ToNearestEven) //nolint:gomnd
if err != nil {
return 0, xerrors.WithStackTrace(err)
}
- rf, _, err := big.ParseFloat(rr, 10, 127, big.ToNearestEven)
+ rf, _, err := big.ParseFloat(rr, 10, 127, big.ToNearestEven) //nolint:gomnd
if err != nil {
return 0, err
}
diff --git a/testutil/compare_test.go b/testutil/compare_test.go
index 45f2ed2c1..6d10fdcf1 100644
--- a/testutil/compare_test.go
+++ b/testutil/compare_test.go
@@ -2,6 +2,7 @@ package testutil
import (
"errors"
+ "fmt"
"testing"
"github.com/ydb-platform/ydb-go-genproto/protos/Ydb"
@@ -21,7 +22,11 @@ func TestUnwrapOptionalValue(t *testing.T) {
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- textValue := val.GetValue().GetValue().(*Ydb.Value_TextValue)
+ textValue, ok := val.GetValue().GetValue().(*Ydb.Value_TextValue)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Value_TextValue", val))
+ }
+
text := textValue.TextValue
if text != "a" {
t.Errorf("Values are different: expected %q, actual %q", "a", text)
@@ -37,7 +42,10 @@ func TestUnwrapPrimitiveValue(t *testing.T) {
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- textValue := val.GetValue().GetValue().(*Ydb.Value_TextValue)
+ textValue, ok := val.GetValue().GetValue().(*Ydb.Value_TextValue)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Value_TextValue", val))
+ }
text := textValue.TextValue
if text != "a" {
t.Errorf("Values are different: expected %q, actual %q", "a", text)
@@ -53,7 +61,10 @@ func TestUnwrapNullValue(t *testing.T) {
if typeID != Ydb.Type_UTF8 {
t.Errorf("Types are different: expected %d, actual %d", Ydb.Type_UTF8, typeID)
}
- nullFlagValue := val.GetValue().GetValue().(*Ydb.Value_NullFlagValue)
+ nullFlagValue, ok := val.GetValue().GetValue().(*Ydb.Value_NullFlagValue)
+ if !ok {
+ panic(fmt.Sprintf("unsupported type conversion from %T to *Ydb.Value_NullFlagValue", nullFlagValue))
+ }
if nullFlagValue.NullFlagValue != structpb.NullValue_NULL_VALUE {
t.Errorf("Values are different: expected %d, actual %d", structpb.NullValue_NULL_VALUE, nullFlagValue.NullFlagValue)
}
diff --git a/topic/topicoptions/topicoptions_reader.go b/topic/topicoptions/topicoptions_reader.go
index 549211688..862f4e7de 100644
--- a/topic/topicoptions/topicoptions_reader.go
+++ b/topic/topicoptions/topicoptions_reader.go
@@ -26,9 +26,7 @@ type ReaderOption = topicreaderinternal.PublicReaderOption
// WithReaderOperationTimeout
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithReaderOperationTimeout(timeout time.Duration) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
config.SetOperationTimeout(&cfg.Common, timeout)
@@ -37,9 +35,7 @@ func WithReaderOperationTimeout(timeout time.Duration) ReaderOption {
// WithReaderStartTimeout mean timeout for connect to reader stream and work some time without errors
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithReaderStartTimeout(timeout time.Duration) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
cfg.RetrySettings.StartTimeout = timeout
@@ -58,9 +54,7 @@ func WithReaderCheckRetryErrorFunction(callback CheckErrorRetryFunction) ReaderO
// WithReaderOperationCancelAfter
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithReaderOperationCancelAfter(cancelAfter time.Duration) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
config.SetOperationCancelAfter(&cfg.Common, cancelAfter)
@@ -69,9 +63,7 @@ func WithReaderOperationCancelAfter(cancelAfter time.Duration) ReaderOption {
// WithCommonConfig
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithCommonConfig(common config.Common) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
cfg.Common = common
@@ -79,8 +71,11 @@ func WithCommonConfig(common config.Common) ReaderOption {
}
// WithCommitTimeLagTrigger
-// Deprecated: (was experimental) will be removed soon.
-// Use WithReaderCommitTimeLagTrigger instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithReaderCommitTimeLagTrigger instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithCommitTimeLagTrigger(lag time.Duration) ReaderOption {
return WithReaderCommitTimeLagTrigger(lag)
}
@@ -96,8 +91,11 @@ func WithReaderCommitTimeLagTrigger(lag time.Duration) ReaderOption {
}
// WithCommitCountTrigger
-// Deprecated: (was experimental) will be removed soon.
-// Use WithReaderCommitCountTrigger instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithReaderCommitCountTrigger instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithCommitCountTrigger(count int) ReaderOption {
return WithReaderCommitCountTrigger(count)
}
@@ -115,9 +113,10 @@ func WithReaderCommitCountTrigger(count int) ReaderOption {
// prefer min count messages in batch
// sometimes batch can contain fewer messages, for example if local buffer is full and SDK can't receive more messages
//
-// Deprecated: (was experimental) the method will be removed soon.
-//
-// The option will be removed for simplify code internals
+// Deprecated: was experimental and not actual now.
+// The option will be removed for simplify code internals.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithBatchReadMinCount(count int) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
cfg.DefaultBatchConfig.MinCount = count
@@ -125,8 +124,11 @@ func WithBatchReadMinCount(count int) ReaderOption {
}
// WithBatchReadMaxCount
-// Deprecated: (was experimental) will be removed soon.
+//
+// Deprecated: was experimental and not actual now.
// Use WithReaderBatchMaxCount instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithBatchReadMaxCount(count int) ReaderOption {
return func(cfg *topicreaderinternal.ReaderConfig) {
cfg.DefaultBatchConfig.MaxCount = count
@@ -141,8 +143,11 @@ func WithReaderBatchMaxCount(count int) ReaderOption {
}
// WithMessagesBufferSize
-// Deprecated: (was experimental) will be removed soon
+//
+// Deprecated: was experimental and not actual now.
// Use WithReaderBufferSizeBytes instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithMessagesBufferSize(size int) ReaderOption {
return WithReaderBufferSizeBytes(size)
}
@@ -191,8 +196,11 @@ const (
)
// WithCommitMode
-// Deprecated: (was experimental) will be removed soon.
+//
+// Deprecated: was experimental and not actual now.
// Use WithReaderCommitMode instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithCommitMode(mode CommitMode) ReaderOption {
return WithReaderCommitMode(mode)
}
@@ -217,8 +225,11 @@ type (
)
// WithGetPartitionStartOffset
-// Deprecated: (was experimental) will be removed soon.
-// Use WithReaderGetPartitionStartOffset instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithReaderGetPartitionStartOffset instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithGetPartitionStartOffset(f GetPartitionStartOffsetFunc) ReaderOption {
return WithReaderGetPartitionStartOffset(f)
}
@@ -233,9 +244,7 @@ func WithReaderGetPartitionStartOffset(f GetPartitionStartOffsetFunc) ReaderOpti
// WithReaderTrace set tracer for the topic reader
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithReaderTrace(t trace.Topic) ReaderOption { //nolint:gocritic
return func(cfg *topicreaderinternal.ReaderConfig) {
cfg.Trace = cfg.Trace.Compose(&t)
diff --git a/topic/topicoptions/topicoptions_topic.go b/topic/topicoptions/topicoptions_topic.go
index f79b710e2..f14522866 100644
--- a/topic/topicoptions/topicoptions_topic.go
+++ b/topic/topicoptions/topicoptions_topic.go
@@ -10,16 +10,12 @@ import (
// TopicOption
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
type TopicOption func(c *topic.Config)
// WithTrace defines trace over persqueue client calls
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithTrace(trace trace.Topic, opts ...trace.TopicComposeOption) TopicOption { //nolint:gocritic
return func(c *topic.Config) {
c.Trace = c.Trace.Compose(&trace, opts...)
@@ -32,9 +28,7 @@ func WithTrace(trace trace.Topic, opts ...trace.TopicComposeOption) TopicOption
// the client.
// If OperationTimeout is zero then no timeout is used.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithOperationTimeout(operationTimeout time.Duration) TopicOption {
return func(c *topic.Config) {
config.SetOperationTimeout(&c.Common, operationTimeout)
@@ -47,9 +41,7 @@ func WithOperationTimeout(operationTimeout time.Duration) TopicOption {
// processing will be continued.
// If OperationCancelAfter is zero then no timeout is used.
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithOperationCancelAfter(operationCancelAfter time.Duration) TopicOption {
return func(c *topic.Config) {
config.SetOperationCancelAfter(&c.Common, operationCancelAfter)
diff --git a/topic/topicoptions/topicoptions_writer.go b/topic/topicoptions/topicoptions_writer.go
index a29c501cb..86d4b9c57 100644
--- a/topic/topicoptions/topicoptions_writer.go
+++ b/topic/topicoptions/topicoptions_writer.go
@@ -45,9 +45,7 @@ func WithWriterCompressorCount(num int) WriterOption {
// WithWriterMaxQueueLen set max len of queue for wait ack
//
-// # Experimental
-//
-// Notice: This API is EXPERIMENTAL and may be changed or removed in a later release.
+// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
func WithWriterMaxQueueLen(num int) WriterOption {
return topicwriterinternal.WithMaxQueueLen(num)
}
@@ -61,8 +59,11 @@ func WithWriterMessageMaxBytesSize(size int) WriterOption {
}
// WithWriteSessionMeta
-// Deprecated: (was experimental) will be removed soon.
-// Use WithWriterSessionMeta instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithWriterSessionMeta instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithWriteSessionMeta(meta map[string]string) WriterOption {
return WithWriterSessionMeta(meta)
}
@@ -73,8 +74,11 @@ func WithWriterSessionMeta(meta map[string]string) WriterOption {
}
// WithProducerID
-// Deprecated: (was experimental) will be removed soon.
-// Use WithWriterProducerID instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithWriterProducerID instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithProducerID(producerID string) WriterOption {
return WithWriterProducerID(producerID)
}
@@ -85,8 +89,11 @@ func WithWriterProducerID(producerID string) WriterOption {
}
// WithPartitionID
-// Deprecated: (was experimental) will be removed soon
-// Use WithWriterPartitionID instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithWriterPartitionID instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithPartitionID(partitionID int64) WriterOption {
return WithWriterPartitionID(partitionID)
}
@@ -97,7 +104,11 @@ func WithWriterPartitionID(partitionID int64) WriterOption {
}
// WithSyncWrite
-// Deprecated: (was experimental) use WithWriterWaitServerAck instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithWriterWaitServerAck instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithSyncWrite(sync bool) WriterOption {
return WithWriterWaitServerAck(sync)
}
@@ -110,17 +121,26 @@ func WithWriterWaitServerAck(wait bool) WriterOption {
type (
// WithOnWriterConnectedInfo present information, received from server
- // Deprecated: (was experimental) will be removed soon
+ //
+ // Deprecated: was experimental and not actual now.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
WithOnWriterConnectedInfo = topicwriterinternal.PublicWithOnWriterConnectedInfo
// OnWriterInitResponseCallback
- // Deprecated: (was experimental) will be removed soon.
+ //
+ // Deprecated: was experimental and not actual now.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
OnWriterInitResponseCallback = topicwriterinternal.PublicOnWriterInitResponseCallback
)
// WithOnWriterFirstConnected set callback f, which will called once - after first successfully init topic writer stream
-// Deprecated: (was experimental) will be removed soon.
-// Use Writer.WaitInit function instead
+//
+// Deprecated: was experimental and not actual now.
+// Use Writer.WaitInit function instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithOnWriterFirstConnected(f OnWriterInitResponseCallback) WriterOption {
return func(cfg *topicwriterinternal.WriterReconnectorConfig) {
cfg.OnWriterInitResponseCallback = f
@@ -128,8 +148,11 @@ func WithOnWriterFirstConnected(f OnWriterInitResponseCallback) WriterOption {
}
// WithCodec
-// Deprecated: (was experimental) will be removed soon.
-// Use WithWriterCodec instead
+//
+// Deprecated: was experimental and not actual now.
+// Use WithWriterCodec instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithCodec(codec topictypes.Codec) WriterOption {
return WithWriterCodec(codec)
}
@@ -140,8 +163,11 @@ func WithWriterCodec(codec topictypes.Codec) WriterOption {
}
// WithCodecAutoSelect
-// Deprecated: (was experimental) will be removed soon.
+//
+// Deprecated: was experimental and not actual now.
// Use WithWriterCodecAutoSelect instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func WithCodecAutoSelect() WriterOption {
return topicwriterinternal.WithAutoCodec()
}
diff --git a/topic/topicreader/batch_options.go b/topic/topicreader/batch_options.go
index 166432535..2566f161c 100644
--- a/topic/topicreader/batch_options.go
+++ b/topic/topicreader/batch_options.go
@@ -22,8 +22,10 @@ func (count WithBatchMaxCount) Apply(
// count must be 1 or greater
// it will panic if count < 1
//
-// Deprecated: (was experimental) will be removed soon.
-// The option will be removed for simplify code internals
+// Deprecated: was experimental and not actual now.
+// The option will be removed for simplify code internals.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
type WithBatchPreferMinCount int
// Apply implements ReadBatchOption interface
diff --git a/topic/topicreader/reader.go b/topic/topicreader/reader.go
index 9c50d4a51..ec8f43b5e 100644
--- a/topic/topicreader/reader.go
+++ b/topic/topicreader/reader.go
@@ -75,8 +75,11 @@ func (r *Reader) Commit(ctx context.Context, obj CommitRangeGetter) error {
type CommitRangeGetter = topicreaderinternal.PublicCommitRangeGetter
// ReadMessageBatch
-// Deprecated: (was experimental) will be removed soon.
+//
+// Deprecated: was experimental and not actual now.
// Use ReadMessagesBatch instead.
+// Will be removed after Oct 2024.
+// Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
func (r *Reader) ReadMessageBatch(ctx context.Context, opts ...ReadBatchOption) (*Batch, error) {
if err := r.inCall(&r.readInFlyght); err != nil {
return nil, err
diff --git a/trace/coordination.go b/trace/coordination.go
index 551064671..41ca39d2c 100644
--- a/trace/coordination.go
+++ b/trace/coordination.go
@@ -1,5 +1,12 @@
package trace
+import (
+ "context"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+)
+
// tool gtrace used from ./internal/cmd/gtrace
//go:generate gtrace
@@ -7,5 +14,221 @@ package trace
type (
// Coordination specified trace of coordination client activity.
// gtrace:gen
- Coordination struct{}
+ Coordination struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnNew func(CoordinationNewStartInfo) func(CoordinationNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnCreateNode func(CoordinationCreateNodeStartInfo) func(CoordinationCreateNodeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnAlterNode func(CoordinationAlterNodeStartInfo) func(CoordinationAlterNodeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDropNode func(CoordinationDropNodeStartInfo) func(CoordinationDropNodeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDescribeNode func(CoordinationDescribeNodeStartInfo) func(CoordinationDescribeNodeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSession func(CoordinationSessionStartInfo) func(CoordinationSessionDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnClose func(CoordinationCloseStartInfo) func(CoordinationCloseDoneInfo)
+
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnStreamNew func(CoordinationStreamNewStartInfo) func(CoordinationStreamNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStarted func(CoordinationSessionStartedInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStartTimeout func(CoordinationSessionStartTimeoutInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionKeepAliveTimeout func(CoordinationSessionKeepAliveTimeoutInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStopped func(CoordinationSessionStoppedInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStopTimeout func(CoordinationSessionStopTimeoutInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionClientTimeout func(CoordinationSessionClientTimeoutInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionServerExpire func(CoordinationSessionServerExpireInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionServerError func(CoordinationSessionServerErrorInfo)
+
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionReceive func(CoordinationSessionReceiveStartInfo) func(CoordinationSessionReceiveDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionReceiveUnexpected func(CoordinationSessionReceiveUnexpectedInfo)
+
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStop func(CoordinationSessionStopInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionStart func(CoordinationSessionStartStartInfo) func(CoordinationSessionStartDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionSend func(CoordinationSessionSendStartInfo) func(CoordinationSessionSendDoneInfo)
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationNewStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationNewDoneInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationCloseStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationCloseDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationCreateNodeStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Path string
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationCreateNodeDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationAlterNodeStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Path string
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationAlterNodeDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationDropNodeStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Path string
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationDropNodeDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationDescribeNodeStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Path string
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationDescribeNodeDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+
+ Path string
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationStreamNewStartInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationStreamNewDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStartedInfo struct {
+ SessionID uint64
+ ExpectedSessionID uint64
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStartTimeoutInfo struct {
+ Timeout time.Duration
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionKeepAliveTimeoutInfo struct {
+ LastGoodResponseTime time.Time
+ Timeout time.Duration
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStoppedInfo struct {
+ SessionID uint64
+ ExpectedSessionID uint64
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStopTimeoutInfo struct {
+ Timeout time.Duration
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionClientTimeoutInfo struct {
+ LastGoodResponseTime time.Time
+ Timeout time.Duration
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionServerExpireInfo struct {
+ Failure *Ydb_Coordination.SessionResponse_Failure
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionServerErrorInfo struct {
+ Failure *Ydb_Coordination.SessionResponse_Failure
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionReceiveStartInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionReceiveDoneInfo struct {
+ Response *Ydb_Coordination.SessionResponse
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionReceiveUnexpectedInfo struct {
+ Response *Ydb_Coordination.SessionResponse
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStartStartInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStartDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionStopInfo struct {
+ SessionID uint64
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionSendStartInfo struct {
+ Request *Ydb_Coordination.SessionRequest
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ CoordinationSessionSendDoneInfo struct {
+ Error error
+ }
)
diff --git a/trace/coordination_gtrace.go b/trace/coordination_gtrace.go
index 609198059..422f61153 100644
--- a/trace/coordination_gtrace.go
+++ b/trace/coordination_gtrace.go
@@ -2,15 +2,24 @@
package trace
+import (
+ "context"
+ "time"
+
+ "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Coordination"
+)
+
// coordinationComposeOptions is a holder of options
type coordinationComposeOptions struct {
panicCallback func(e interface{})
}
// CoordinationOption specified Coordination compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type CoordinationComposeOption func(o *coordinationComposeOptions)
// WithCoordinationPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithCoordinationPanicCallback(cb func(e interface{})) CoordinationComposeOption {
return func(o *coordinationComposeOptions) {
o.panicCallback = cb
@@ -18,7 +27,1018 @@ func WithCoordinationPanicCallback(cb func(e interface{})) CoordinationComposeOp
}
// Compose returns a new Coordination which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Coordination) Compose(x *Coordination, opts ...CoordinationComposeOption) *Coordination {
var ret Coordination
+ options := coordinationComposeOptions{}
+ for _, opt := range opts {
+ if opt != nil {
+ opt(&options)
+ }
+ }
+ {
+ h1 := t.OnNew
+ h2 := x.OnNew
+ ret.OnNew = func(c CoordinationNewStartInfo) func(CoordinationNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationNewDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnCreateNode
+ h2 := x.OnCreateNode
+ ret.OnCreateNode = func(c CoordinationCreateNodeStartInfo) func(CoordinationCreateNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationCreateNodeDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationCreateNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnAlterNode
+ h2 := x.OnAlterNode
+ ret.OnAlterNode = func(c CoordinationAlterNodeStartInfo) func(CoordinationAlterNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationAlterNodeDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationAlterNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnDropNode
+ h2 := x.OnDropNode
+ ret.OnDropNode = func(c CoordinationDropNodeStartInfo) func(CoordinationDropNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationDropNodeDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationDropNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnDescribeNode
+ h2 := x.OnDescribeNode
+ ret.OnDescribeNode = func(c CoordinationDescribeNodeStartInfo) func(CoordinationDescribeNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationDescribeNodeDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationDescribeNodeDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSession
+ h2 := x.OnSession
+ ret.OnSession = func(c CoordinationSessionStartInfo) func(CoordinationSessionDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationSessionDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationSessionDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnClose
+ h2 := x.OnClose
+ ret.OnClose = func(c CoordinationCloseStartInfo) func(CoordinationCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationCloseDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationCloseDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnStreamNew
+ h2 := x.OnStreamNew
+ ret.OnStreamNew = func(c CoordinationStreamNewStartInfo) func(CoordinationStreamNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationStreamNewDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationStreamNewDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStarted
+ h2 := x.OnSessionStarted
+ ret.OnSessionStarted = func(c CoordinationSessionStartedInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStartTimeout
+ h2 := x.OnSessionStartTimeout
+ ret.OnSessionStartTimeout = func(c CoordinationSessionStartTimeoutInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionKeepAliveTimeout
+ h2 := x.OnSessionKeepAliveTimeout
+ ret.OnSessionKeepAliveTimeout = func(c CoordinationSessionKeepAliveTimeoutInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStopped
+ h2 := x.OnSessionStopped
+ ret.OnSessionStopped = func(c CoordinationSessionStoppedInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStopTimeout
+ h2 := x.OnSessionStopTimeout
+ ret.OnSessionStopTimeout = func(c CoordinationSessionStopTimeoutInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionClientTimeout
+ h2 := x.OnSessionClientTimeout
+ ret.OnSessionClientTimeout = func(c CoordinationSessionClientTimeoutInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionServerExpire
+ h2 := x.OnSessionServerExpire
+ ret.OnSessionServerExpire = func(c CoordinationSessionServerExpireInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionServerError
+ h2 := x.OnSessionServerError
+ ret.OnSessionServerError = func(c CoordinationSessionServerErrorInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionReceive
+ h2 := x.OnSessionReceive
+ ret.OnSessionReceive = func(c CoordinationSessionReceiveStartInfo) func(CoordinationSessionReceiveDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationSessionReceiveDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationSessionReceiveDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionReceiveUnexpected
+ h2 := x.OnSessionReceiveUnexpected
+ ret.OnSessionReceiveUnexpected = func(c CoordinationSessionReceiveUnexpectedInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStop
+ h2 := x.OnSessionStop
+ ret.OnSessionStop = func(c CoordinationSessionStopInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if h1 != nil {
+ h1(c)
+ }
+ if h2 != nil {
+ h2(c)
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionStart
+ h2 := x.OnSessionStart
+ ret.OnSessionStart = func(c CoordinationSessionStartStartInfo) func(CoordinationSessionStartDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationSessionStartDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationSessionStartDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
+ {
+ h1 := t.OnSessionSend
+ h2 := x.OnSessionSend
+ ret.OnSessionSend = func(c CoordinationSessionSendStartInfo) func(CoordinationSessionSendDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(CoordinationSessionSendDoneInfo)
+ if h1 != nil {
+ r = h1(c)
+ }
+ if h2 != nil {
+ r1 = h2(c)
+ }
+ return func(c CoordinationSessionSendDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(c)
+ }
+ if r1 != nil {
+ r1(c)
+ }
+ }
+ }
+ }
return &ret
}
+func (t *Coordination) onNew(c CoordinationNewStartInfo) func(CoordinationNewDoneInfo) {
+ fn := t.OnNew
+ if fn == nil {
+ return func(CoordinationNewDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationNewDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onCreateNode(c CoordinationCreateNodeStartInfo) func(CoordinationCreateNodeDoneInfo) {
+ fn := t.OnCreateNode
+ if fn == nil {
+ return func(CoordinationCreateNodeDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationCreateNodeDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onAlterNode(c CoordinationAlterNodeStartInfo) func(CoordinationAlterNodeDoneInfo) {
+ fn := t.OnAlterNode
+ if fn == nil {
+ return func(CoordinationAlterNodeDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationAlterNodeDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onDropNode(c CoordinationDropNodeStartInfo) func(CoordinationDropNodeDoneInfo) {
+ fn := t.OnDropNode
+ if fn == nil {
+ return func(CoordinationDropNodeDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationDropNodeDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onDescribeNode(c CoordinationDescribeNodeStartInfo) func(CoordinationDescribeNodeDoneInfo) {
+ fn := t.OnDescribeNode
+ if fn == nil {
+ return func(CoordinationDescribeNodeDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationDescribeNodeDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onSession(c CoordinationSessionStartInfo) func(CoordinationSessionDoneInfo) {
+ fn := t.OnSession
+ if fn == nil {
+ return func(CoordinationSessionDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationSessionDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onClose(c CoordinationCloseStartInfo) func(CoordinationCloseDoneInfo) {
+ fn := t.OnClose
+ if fn == nil {
+ return func(CoordinationCloseDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationCloseDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onStreamNew(c CoordinationStreamNewStartInfo) func(CoordinationStreamNewDoneInfo) {
+ fn := t.OnStreamNew
+ if fn == nil {
+ return func(CoordinationStreamNewDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationStreamNewDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onSessionStarted(c CoordinationSessionStartedInfo) {
+ fn := t.OnSessionStarted
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionStartTimeout(c CoordinationSessionStartTimeoutInfo) {
+ fn := t.OnSessionStartTimeout
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionKeepAliveTimeout(c CoordinationSessionKeepAliveTimeoutInfo) {
+ fn := t.OnSessionKeepAliveTimeout
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionStopped(c CoordinationSessionStoppedInfo) {
+ fn := t.OnSessionStopped
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionStopTimeout(c CoordinationSessionStopTimeoutInfo) {
+ fn := t.OnSessionStopTimeout
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionClientTimeout(c CoordinationSessionClientTimeoutInfo) {
+ fn := t.OnSessionClientTimeout
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionServerExpire(c CoordinationSessionServerExpireInfo) {
+ fn := t.OnSessionServerExpire
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionServerError(c CoordinationSessionServerErrorInfo) {
+ fn := t.OnSessionServerError
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionReceive(c CoordinationSessionReceiveStartInfo) func(CoordinationSessionReceiveDoneInfo) {
+ fn := t.OnSessionReceive
+ if fn == nil {
+ return func(CoordinationSessionReceiveDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationSessionReceiveDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onSessionReceiveUnexpected(c CoordinationSessionReceiveUnexpectedInfo) {
+ fn := t.OnSessionReceiveUnexpected
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionStop(c CoordinationSessionStopInfo) {
+ fn := t.OnSessionStop
+ if fn == nil {
+ return
+ }
+ fn(c)
+}
+func (t *Coordination) onSessionStart(c CoordinationSessionStartStartInfo) func(CoordinationSessionStartDoneInfo) {
+ fn := t.OnSessionStart
+ if fn == nil {
+ return func(CoordinationSessionStartDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationSessionStartDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+func (t *Coordination) onSessionSend(c CoordinationSessionSendStartInfo) func(CoordinationSessionSendDoneInfo) {
+ fn := t.OnSessionSend
+ if fn == nil {
+ return func(CoordinationSessionSendDoneInfo) {
+ return
+ }
+ }
+ res := fn(c)
+ if res == nil {
+ return func(CoordinationSessionSendDoneInfo) {
+ return
+ }
+ }
+ return res
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnNew(t *Coordination, c *context.Context, call call) func() {
+ var p CoordinationNewStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onNew(p)
+ return func() {
+ var p CoordinationNewDoneInfo
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnCreateNode(t *Coordination, c *context.Context, call call, path string) func(error) {
+ var p CoordinationCreateNodeStartInfo
+ p.Context = c
+ p.Call = call
+ p.Path = path
+ res := t.onCreateNode(p)
+ return func(e error) {
+ var p CoordinationCreateNodeDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnAlterNode(t *Coordination, c *context.Context, call call, path string) func(error) {
+ var p CoordinationAlterNodeStartInfo
+ p.Context = c
+ p.Call = call
+ p.Path = path
+ res := t.onAlterNode(p)
+ return func(e error) {
+ var p CoordinationAlterNodeDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnDropNode(t *Coordination, c *context.Context, call call, path string) func(error) {
+ var p CoordinationDropNodeStartInfo
+ p.Context = c
+ p.Call = call
+ p.Path = path
+ res := t.onDropNode(p)
+ return func(e error) {
+ var p CoordinationDropNodeDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnDescribeNode(t *Coordination, c *context.Context, call call, path string) func(error) {
+ var p CoordinationDescribeNodeStartInfo
+ p.Context = c
+ p.Call = call
+ p.Path = path
+ res := t.onDescribeNode(p)
+ return func(e error) {
+ var p CoordinationDescribeNodeDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSession(t *Coordination, c *context.Context, call call, path string) func(error) {
+ var p CoordinationSessionStartInfo
+ p.Context = c
+ p.Call = call
+ p.Path = path
+ res := t.onSession(p)
+ return func(e error) {
+ var p CoordinationSessionDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnClose(t *Coordination, c *context.Context, call call) func(error) {
+ var p CoordinationCloseStartInfo
+ p.Context = c
+ p.Call = call
+ res := t.onClose(p)
+ return func(e error) {
+ var p CoordinationCloseDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnStreamNew(t *Coordination) func(error) {
+ var p CoordinationStreamNewStartInfo
+ res := t.onStreamNew(p)
+ return func(e error) {
+ var p CoordinationStreamNewDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStarted(t *Coordination, sessionID uint64, expectedSessionID uint64) {
+ var p CoordinationSessionStartedInfo
+ p.SessionID = sessionID
+ p.ExpectedSessionID = expectedSessionID
+ t.onSessionStarted(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStartTimeout(t *Coordination, timeout time.Duration) {
+ var p CoordinationSessionStartTimeoutInfo
+ p.Timeout = timeout
+ t.onSessionStartTimeout(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionKeepAliveTimeout(t *Coordination, lastGoodResponseTime time.Time, timeout time.Duration) {
+ var p CoordinationSessionKeepAliveTimeoutInfo
+ p.LastGoodResponseTime = lastGoodResponseTime
+ p.Timeout = timeout
+ t.onSessionKeepAliveTimeout(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStopped(t *Coordination, sessionID uint64, expectedSessionID uint64) {
+ var p CoordinationSessionStoppedInfo
+ p.SessionID = sessionID
+ p.ExpectedSessionID = expectedSessionID
+ t.onSessionStopped(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStopTimeout(t *Coordination, timeout time.Duration) {
+ var p CoordinationSessionStopTimeoutInfo
+ p.Timeout = timeout
+ t.onSessionStopTimeout(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionClientTimeout(t *Coordination, lastGoodResponseTime time.Time, timeout time.Duration) {
+ var p CoordinationSessionClientTimeoutInfo
+ p.LastGoodResponseTime = lastGoodResponseTime
+ p.Timeout = timeout
+ t.onSessionClientTimeout(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionServerExpire(t *Coordination, failure *Ydb_Coordination.SessionResponse_Failure) {
+ var p CoordinationSessionServerExpireInfo
+ p.Failure = failure
+ t.onSessionServerExpire(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionServerError(t *Coordination, failure *Ydb_Coordination.SessionResponse_Failure) {
+ var p CoordinationSessionServerErrorInfo
+ p.Failure = failure
+ t.onSessionServerError(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionReceive(t *Coordination) func(response *Ydb_Coordination.SessionResponse, _ error) {
+ var p CoordinationSessionReceiveStartInfo
+ res := t.onSessionReceive(p)
+ return func(response *Ydb_Coordination.SessionResponse, e error) {
+ var p CoordinationSessionReceiveDoneInfo
+ p.Response = response
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionReceiveUnexpected(t *Coordination, response *Ydb_Coordination.SessionResponse) {
+ var p CoordinationSessionReceiveUnexpectedInfo
+ p.Response = response
+ t.onSessionReceiveUnexpected(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStop(t *Coordination, sessionID uint64) {
+ var p CoordinationSessionStopInfo
+ p.SessionID = sessionID
+ t.onSessionStop(p)
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionStart(t *Coordination) func(error) {
+ var p CoordinationSessionStartStartInfo
+ res := t.onSessionStart(p)
+ return func(e error) {
+ var p CoordinationSessionStartDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func CoordinationOnSessionSend(t *Coordination, request *Ydb_Coordination.SessionRequest) func(error) {
+ var p CoordinationSessionSendStartInfo
+ p.Request = request
+ res := t.onSessionSend(p)
+ return func(e error) {
+ var p CoordinationSessionSendDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
diff --git a/trace/discovery.go b/trace/discovery.go
index 5b0496eef..e2888cb46 100644
--- a/trace/discovery.go
+++ b/trace/discovery.go
@@ -9,10 +9,14 @@ import "context"
type (
// Discovery specified trace of discovery client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Discovery struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnDiscover func(DiscoveryDiscoverStartInfo) func(DiscoveryDiscoverDoneInfo)
- OnWhoAmI func(DiscoveryWhoAmIStartInfo) func(DiscoveryWhoAmIDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWhoAmI func(DiscoveryWhoAmIStartInfo) func(DiscoveryWhoAmIDoneInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DiscoveryDiscoverStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -23,11 +27,13 @@ type (
Address string
Database string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DiscoveryDiscoverDoneInfo struct {
Location string
Endpoints []EndpointInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DiscoveryWhoAmIStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -36,6 +42,7 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DiscoveryWhoAmIDoneInfo struct {
User string
Groups []string
diff --git a/trace/discovery_gtrace.go b/trace/discovery_gtrace.go
index 362d5c0e5..20d40ebda 100644
--- a/trace/discovery_gtrace.go
+++ b/trace/discovery_gtrace.go
@@ -12,9 +12,11 @@ type discoveryComposeOptions struct {
}
// DiscoveryOption specified Discovery compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type DiscoveryComposeOption func(o *discoveryComposeOptions)
// WithDiscoveryPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithDiscoveryPanicCallback(cb func(e interface{})) DiscoveryComposeOption {
return func(o *discoveryComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithDiscoveryPanicCallback(cb func(e interface{})) DiscoveryComposeOption {
}
// Compose returns a new Discovery which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Discovery) Compose(x *Discovery, opts ...DiscoveryComposeOption) *Discovery {
var ret Discovery
options := discoveryComposeOptions{}
@@ -132,6 +135,7 @@ func (t *Discovery) onWhoAmI(d DiscoveryWhoAmIStartInfo) func(DiscoveryWhoAmIDon
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DiscoveryOnDiscover(t *Discovery, c *context.Context, call call, address string, database string) func(location string, endpoints []EndpointInfo, _ error) {
var p DiscoveryDiscoverStartInfo
p.Context = c
@@ -147,6 +151,7 @@ func DiscoveryOnDiscover(t *Discovery, c *context.Context, call call, address st
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DiscoveryOnWhoAmI(t *Discovery, c *context.Context, call call) func(user string, groups []string, _ error) {
var p DiscoveryWhoAmIStartInfo
p.Context = c
diff --git a/trace/driver.go b/trace/driver.go
index e9ece8712..8cf5dedc3 100644
--- a/trace/driver.go
+++ b/trace/driver.go
@@ -14,48 +14,73 @@ import (
type (
// Driver specified trace of common driver activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Driver struct {
// Driver runtime events
- OnInit func(DriverInitStartInfo) func(DriverInitDoneInfo)
- OnWith func(DriverWithStartInfo) func(DriverWithDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnInit func(DriverInitStartInfo) func(DriverInitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWith func(DriverWithStartInfo) func(DriverWithDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnClose func(DriverCloseStartInfo) func(DriverCloseDoneInfo)
// Pool of connections
- OnPoolNew func(DriverConnPoolNewStartInfo) func(DriverConnPoolNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolNew func(DriverConnPoolNewStartInfo) func(DriverConnPoolNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnPoolRelease func(DriverConnPoolReleaseStartInfo) func(DriverConnPoolReleaseDoneInfo)
// Resolver events
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnResolve func(DriverResolveStartInfo) func(DriverResolveDoneInfo)
// Conn events
- OnConnStateChange func(DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo)
- OnConnInvoke func(DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo)
- OnConnNewStream func(DriverConnNewStreamStartInfo) func(DriverConnNewStreamDoneInfo)
- OnConnStreamRecvMsg func(DriverConnStreamRecvMsgStartInfo) func(DriverConnStreamRecvMsgDoneInfo)
- OnConnStreamSendMsg func(DriverConnStreamSendMsgStartInfo) func(DriverConnStreamSendMsgDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnStateChange func(DriverConnStateChangeStartInfo) func(DriverConnStateChangeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnInvoke func(DriverConnInvokeStartInfo) func(DriverConnInvokeDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnNewStream func(DriverConnNewStreamStartInfo) func(DriverConnNewStreamDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnStreamRecvMsg func(DriverConnStreamRecvMsgStartInfo) func(DriverConnStreamRecvMsgDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnStreamSendMsg func(DriverConnStreamSendMsgStartInfo) func(DriverConnStreamSendMsgDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnConnStreamCloseSend func(DriverConnStreamCloseSendStartInfo) func(DriverConnStreamCloseSendDoneInfo)
- OnConnDial func(DriverConnDialStartInfo) func(DriverConnDialDoneInfo)
- OnConnBan func(DriverConnBanStartInfo) func(DriverConnBanDoneInfo)
- OnConnAllow func(DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo)
- OnConnClose func(DriverConnCloseStartInfo) func(DriverConnCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnDial func(DriverConnDialStartInfo) func(DriverConnDialDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnBan func(DriverConnBanStartInfo) func(DriverConnBanDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnAllow func(DriverConnAllowStartInfo) func(DriverConnAllowDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnPark func(DriverConnParkStartInfo) func(DriverConnParkDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnClose func(DriverConnCloseStartInfo) func(DriverConnCloseDoneInfo)
// Repeater events
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnRepeaterWakeUp func(DriverRepeaterWakeUpStartInfo) func(DriverRepeaterWakeUpDoneInfo)
// Balancer events
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnBalancerInit func(DriverBalancerInitStartInfo) func(DriverBalancerInitDoneInfo)
- OnBalancerClose func(DriverBalancerCloseStartInfo) func(DriverBalancerCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnBalancerClose func(DriverBalancerCloseStartInfo) func(DriverBalancerCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnBalancerChooseEndpoint func(
DriverBalancerChooseEndpointStartInfo,
) func(
DriverBalancerChooseEndpointDoneInfo,
)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnBalancerClusterDiscoveryAttempt func(
DriverBalancerClusterDiscoveryAttemptStartInfo,
) func(
DriverBalancerClusterDiscoveryAttemptDoneInfo,
)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnBalancerUpdate func(DriverBalancerUpdateStartInfo) func(DriverBalancerUpdateDoneInfo)
// Credentials events
@@ -64,9 +89,11 @@ type (
)
// Method represents rpc method.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type Method string
// Name returns the rpc method name.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (m Method) Name() (s string) {
_, s = m.Split()
@@ -74,6 +101,7 @@ func (m Method) Name() (s string) {
}
// Service returns the rpc service name.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (m Method) Service() (s string) {
s, _ = m.Split()
@@ -81,6 +109,7 @@ func (m Method) Service() (s string) {
}
// Issue declare interface of operation error issues
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type Issue interface {
GetMessage() string
GetIssueCode() uint32
@@ -88,6 +117,7 @@ type Issue interface {
}
// Split returns service name and method.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (m Method) Split() (service, method string) {
i := strings.LastIndex(string(m), "/")
if i == -1 {
@@ -97,6 +127,7 @@ func (m Method) Split() (service, method string) {
return strings.TrimPrefix(string(m[:i]), "/"), string(m[i+1:])
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type ConnState interface {
fmt.Stringer
@@ -104,18 +135,25 @@ type ConnState interface {
Code() int
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type EndpointInfo interface {
fmt.Stringer
NodeID() uint32
Address() string
- LocalDC() bool
Location() string
LoadFactor() float32
LastUpdated() time.Time
+
+ // Deprecated: LocalDC check "local" by compare endpoint location with discovery "selflocation" field.
+ // It work good only if connection url always point to local dc.
+ // Will be removed after Oct 2024.
+ // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated
+ LocalDC() bool
}
type (
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStateChangeStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -126,17 +164,21 @@ type (
Endpoint EndpointInfo
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStateChangeDoneInfo struct {
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverResolveStartInfo struct {
Call call
Target string
Resolved []string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverResolveDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerUpdateStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -146,12 +188,14 @@ type (
Call call
NeedLocalDC bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerUpdateDoneInfo struct {
Endpoints []EndpointInfo
Added []EndpointInfo
Dropped []EndpointInfo
LocalDC string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerClusterDiscoveryAttemptStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -161,27 +205,33 @@ type (
Call call
Address string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerClusterDiscoveryAttemptDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetReadStartInfo struct {
Call call
Address string
Buffer int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetReadDoneInfo struct {
Received int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetWriteStartInfo struct {
Call call
Address string
Bytes int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetWriteDoneInfo struct {
Sent int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetDialStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -191,16 +241,20 @@ type (
Call call
Address string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetDialDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetCloseStartInfo struct {
Call call
Address string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverNetCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnTakeStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -210,9 +264,11 @@ type (
Call call
Endpoint EndpointInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnTakeDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnDialStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -222,9 +278,25 @@ type (
Call call
Endpoint EndpointInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnDialDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ DriverConnParkStartInfo struct {
+ // Context make available context in trace callback function.
+ // Pointer to context provide replacement of context in trace callback function.
+ // Warning: concurrent access to pointer on client side must be excluded.
+ // Safe replacement of context are provided only inside callback function
+ Context *context.Context
+ Call call
+ Endpoint EndpointInfo
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ DriverConnParkDoneInfo struct {
+ Error error
+ }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -234,9 +306,11 @@ type (
Call call
Endpoint EndpointInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnBanStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -248,9 +322,11 @@ type (
State ConnState
Cause error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnBanDoneInfo struct {
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnAllowStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -261,9 +337,11 @@ type (
Endpoint EndpointInfo
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnAllowDoneInfo struct {
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnInvokeStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -274,6 +352,7 @@ type (
Endpoint EndpointInfo
Method Method
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnInvokeDoneInfo struct {
Error error
Issues []Issue
@@ -281,6 +360,7 @@ type (
State ConnState
Metadata map[string][]string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnNewStreamStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -291,10 +371,12 @@ type (
Endpoint EndpointInfo
Method Method
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnNewStreamDoneInfo struct {
Error error
State ConnState
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamRecvMsgStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -303,9 +385,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamRecvMsgDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamSendMsgStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -314,9 +398,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamSendMsgDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamCloseSendStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -325,9 +411,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnStreamCloseSendDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerInitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -337,9 +425,11 @@ type (
Call call
Name string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerInitDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerDialEntrypointStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -349,9 +439,11 @@ type (
Call call
Address string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerDialEntrypointDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -360,9 +452,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerChooseEndpointStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -371,10 +465,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverBalancerChooseEndpointDoneInfo struct {
Endpoint EndpointInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverRepeaterWakeUpStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -385,9 +481,11 @@ type (
Name string
Event string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverRepeaterWakeUpDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverGetCredentialsStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -396,10 +494,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverGetCredentialsDoneInfo struct {
Token string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverInitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -411,9 +511,11 @@ type (
Database string
Secure bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverInitDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverWithStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -425,9 +527,11 @@ type (
Database string
Secure bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverWithDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnPoolNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -436,7 +540,9 @@ type (
Context *context.Context
Call call
}
- DriverConnPoolNewDoneInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ DriverConnPoolNewDoneInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnPoolReleaseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -445,9 +551,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverConnPoolReleaseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -456,6 +564,7 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DriverCloseDoneInfo struct {
Error error
}
diff --git a/trace/driver_gtrace.go b/trace/driver_gtrace.go
index bb2e951c0..50491225a 100644
--- a/trace/driver_gtrace.go
+++ b/trace/driver_gtrace.go
@@ -12,9 +12,11 @@ type driverComposeOptions struct {
}
// DriverOption specified Driver compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type DriverComposeOption func(o *driverComposeOptions)
// WithDriverPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithDriverPanicCallback(cb func(e interface{})) DriverComposeOption {
return func(o *driverComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithDriverPanicCallback(cb func(e interface{})) DriverComposeOption {
}
// Compose returns a new Driver which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
var ret Driver
options := driverComposeOptions{}
@@ -555,6 +558,41 @@ func (t *Driver) Compose(x *Driver, opts ...DriverComposeOption) *Driver {
}
}
}
+ {
+ h1 := t.OnConnPark
+ h2 := x.OnConnPark
+ ret.OnConnPark = func(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ var r, r1 func(DriverConnParkDoneInfo)
+ if h1 != nil {
+ r = h1(d)
+ }
+ if h2 != nil {
+ r1 = h2(d)
+ }
+ return func(d DriverConnParkDoneInfo) {
+ if options.panicCallback != nil {
+ defer func() {
+ if e := recover(); e != nil {
+ options.panicCallback(e)
+ }
+ }()
+ }
+ if r != nil {
+ r(d)
+ }
+ if r1 != nil {
+ r1(d)
+ }
+ }
+ }
+ }
{
h1 := t.OnConnClose
h2 := x.OnConnClose
@@ -1062,6 +1100,21 @@ func (t *Driver) onConnAllow(d DriverConnAllowStartInfo) func(DriverConnAllowDon
}
return res
}
+func (t *Driver) onConnPark(d DriverConnParkStartInfo) func(DriverConnParkDoneInfo) {
+ fn := t.OnConnPark
+ if fn == nil {
+ return func(DriverConnParkDoneInfo) {
+ return
+ }
+ }
+ res := fn(d)
+ if res == nil {
+ return func(DriverConnParkDoneInfo) {
+ return
+ }
+ }
+ return res
+}
func (t *Driver) onConnClose(d DriverConnCloseStartInfo) func(DriverConnCloseDoneInfo) {
fn := t.OnConnClose
if fn == nil {
@@ -1182,6 +1235,7 @@ func (t *Driver) onGetCredentials(d DriverGetCredentialsStartInfo) func(DriverGe
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnInit(t *Driver, c *context.Context, call call, endpoint string, database string, secure bool) func(error) {
var p DriverInitStartInfo
p.Context = c
@@ -1196,6 +1250,7 @@ func DriverOnInit(t *Driver, c *context.Context, call call, endpoint string, dat
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnWith(t *Driver, c *context.Context, call call, endpoint string, database string, secure bool) func(error) {
var p DriverWithStartInfo
p.Context = c
@@ -1210,6 +1265,7 @@ func DriverOnWith(t *Driver, c *context.Context, call call, endpoint string, dat
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnClose(t *Driver, c *context.Context, call call) func(error) {
var p DriverCloseStartInfo
p.Context = c
@@ -1221,6 +1277,7 @@ func DriverOnClose(t *Driver, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnPoolNew(t *Driver, c *context.Context, call call) func() {
var p DriverConnPoolNewStartInfo
p.Context = c
@@ -1231,6 +1288,7 @@ func DriverOnPoolNew(t *Driver, c *context.Context, call call) func() {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnPoolRelease(t *Driver, c *context.Context, call call) func(error) {
var p DriverConnPoolReleaseStartInfo
p.Context = c
@@ -1242,6 +1300,7 @@ func DriverOnPoolRelease(t *Driver, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnResolve(t *Driver, call call, target string, resolved []string) func(error) {
var p DriverResolveStartInfo
p.Call = call
@@ -1254,6 +1313,7 @@ func DriverOnResolve(t *Driver, call call, target string, resolved []string) fun
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnStateChange(t *Driver, c *context.Context, call call, endpoint EndpointInfo, state ConnState) func(state ConnState) {
var p DriverConnStateChangeStartInfo
p.Context = c
@@ -1267,6 +1327,7 @@ func DriverOnConnStateChange(t *Driver, c *context.Context, call call, endpoint
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnInvoke(t *Driver, c *context.Context, call call, endpoint EndpointInfo, m Method) func(_ error, issues []Issue, opID string, state ConnState, metadata map[string][]string) {
var p DriverConnInvokeStartInfo
p.Context = c
@@ -1284,6 +1345,7 @@ func DriverOnConnInvoke(t *Driver, c *context.Context, call call, endpoint Endpo
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnNewStream(t *Driver, c *context.Context, call call, endpoint EndpointInfo, m Method) func(_ error, state ConnState) {
var p DriverConnNewStreamStartInfo
p.Context = c
@@ -1298,6 +1360,7 @@ func DriverOnConnNewStream(t *Driver, c *context.Context, call call, endpoint En
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnStreamRecvMsg(t *Driver, c *context.Context, call call) func(error) {
var p DriverConnStreamRecvMsgStartInfo
p.Context = c
@@ -1309,6 +1372,7 @@ func DriverOnConnStreamRecvMsg(t *Driver, c *context.Context, call call) func(er
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnStreamSendMsg(t *Driver, c *context.Context, call call) func(error) {
var p DriverConnStreamSendMsgStartInfo
p.Context = c
@@ -1320,6 +1384,7 @@ func DriverOnConnStreamSendMsg(t *Driver, c *context.Context, call call) func(er
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnStreamCloseSend(t *Driver, c *context.Context, call call) func(error) {
var p DriverConnStreamCloseSendStartInfo
p.Context = c
@@ -1331,6 +1396,7 @@ func DriverOnConnStreamCloseSend(t *Driver, c *context.Context, call call) func(
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnDial(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
var p DriverConnDialStartInfo
p.Context = c
@@ -1343,6 +1409,7 @@ func DriverOnConnDial(t *Driver, c *context.Context, call call, endpoint Endpoin
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnBan(t *Driver, c *context.Context, call call, endpoint EndpointInfo, state ConnState, cause error) func(state ConnState) {
var p DriverConnBanStartInfo
p.Context = c
@@ -1357,6 +1424,7 @@ func DriverOnConnBan(t *Driver, c *context.Context, call call, endpoint Endpoint
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnAllow(t *Driver, c *context.Context, call call, endpoint EndpointInfo, state ConnState) func(state ConnState) {
var p DriverConnAllowStartInfo
p.Context = c
@@ -1370,6 +1438,20 @@ func DriverOnConnAllow(t *Driver, c *context.Context, call call, endpoint Endpoi
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func DriverOnConnPark(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
+ var p DriverConnParkStartInfo
+ p.Context = c
+ p.Call = call
+ p.Endpoint = endpoint
+ res := t.onConnPark(p)
+ return func(e error) {
+ var p DriverConnParkDoneInfo
+ p.Error = e
+ res(p)
+ }
+}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnConnClose(t *Driver, c *context.Context, call call, endpoint EndpointInfo) func(error) {
var p DriverConnCloseStartInfo
p.Context = c
@@ -1382,6 +1464,7 @@ func DriverOnConnClose(t *Driver, c *context.Context, call call, endpoint Endpoi
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnRepeaterWakeUp(t *Driver, c *context.Context, call call, name string, event string) func(error) {
var p DriverRepeaterWakeUpStartInfo
p.Context = c
@@ -1395,6 +1478,7 @@ func DriverOnRepeaterWakeUp(t *Driver, c *context.Context, call call, name strin
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnBalancerInit(t *Driver, c *context.Context, call call, name string) func(error) {
var p DriverBalancerInitStartInfo
p.Context = c
@@ -1407,6 +1491,7 @@ func DriverOnBalancerInit(t *Driver, c *context.Context, call call, name string)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnBalancerClose(t *Driver, c *context.Context, call call) func(error) {
var p DriverBalancerCloseStartInfo
p.Context = c
@@ -1418,6 +1503,7 @@ func DriverOnBalancerClose(t *Driver, c *context.Context, call call) func(error)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnBalancerChooseEndpoint(t *Driver, c *context.Context, call call) func(endpoint EndpointInfo, _ error) {
var p DriverBalancerChooseEndpointStartInfo
p.Context = c
@@ -1430,6 +1516,7 @@ func DriverOnBalancerChooseEndpoint(t *Driver, c *context.Context, call call) fu
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnBalancerClusterDiscoveryAttempt(t *Driver, c *context.Context, call call, address string) func(error) {
var p DriverBalancerClusterDiscoveryAttemptStartInfo
p.Context = c
@@ -1442,6 +1529,7 @@ func DriverOnBalancerClusterDiscoveryAttempt(t *Driver, c *context.Context, call
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnBalancerUpdate(t *Driver, c *context.Context, call call, needLocalDC bool) func(endpoints []EndpointInfo, added []EndpointInfo, dropped []EndpointInfo, localDC string) {
var p DriverBalancerUpdateStartInfo
p.Context = c
@@ -1457,6 +1545,7 @@ func DriverOnBalancerUpdate(t *Driver, c *context.Context, call call, needLocalD
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DriverOnGetCredentials(t *Driver, c *context.Context, call call) func(token string, _ error) {
var p DriverGetCredentialsStartInfo
p.Context = c
diff --git a/trace/query.go b/trace/query.go
index aefb54ddd..3fbaef522 100644
--- a/trace/query.go
+++ b/trace/query.go
@@ -20,25 +20,42 @@ type (
// Query specified trace of retry call activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Query struct {
- OnNew func(QueryNewStartInfo) func(info QueryNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnNew func(QueryNewStartInfo) func(info QueryNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnClose func(QueryCloseStartInfo) func(info QueryCloseDoneInfo)
- OnPoolNew func(QueryPoolNewStartInfo) func(QueryPoolNewDoneInfo)
- OnPoolClose func(QueryPoolCloseStartInfo) func(QueryPoolCloseDoneInfo)
- OnPoolTry func(QueryPoolTryStartInfo) func(QueryPoolTryDoneInfo)
- OnPoolWith func(QueryPoolWithStartInfo) func(QueryPoolWithDoneInfo)
- OnPoolPut func(QueryPoolPutStartInfo) func(QueryPoolPutDoneInfo)
- OnPoolGet func(QueryPoolGetStartInfo) func(QueryPoolGetDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolNew func(QueryPoolNewStartInfo) func(QueryPoolNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolClose func(QueryPoolCloseStartInfo) func(QueryPoolCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolTry func(QueryPoolTryStartInfo) func(QueryPoolTryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolWith func(QueryPoolWithStartInfo) func(QueryPoolWithDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolPut func(QueryPoolPutStartInfo) func(QueryPoolPutDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolGet func(QueryPoolGetStartInfo) func(QueryPoolGetDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnPoolChange func(QueryPoolChange)
- OnDo func(QueryDoStartInfo) func(QueryDoDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDo func(QueryDoStartInfo) func(QueryDoDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnDoTx func(QueryDoTxStartInfo) func(QueryDoTxDoneInfo)
- OnSessionCreate func(QuerySessionCreateStartInfo) func(info QuerySessionCreateDoneInfo)
- OnSessionAttach func(QuerySessionAttachStartInfo) func(info QuerySessionAttachDoneInfo)
- OnSessionDelete func(QuerySessionDeleteStartInfo) func(info QuerySessionDeleteDoneInfo)
- OnSessionExecute func(QuerySessionExecuteStartInfo) func(info QuerySessionExecuteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionCreate func(QuerySessionCreateStartInfo) func(info QuerySessionCreateDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionAttach func(QuerySessionAttachStartInfo) func(info QuerySessionAttachDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionDelete func(QuerySessionDeleteStartInfo) func(info QuerySessionDeleteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionExecute func(QuerySessionExecuteStartInfo) func(info QuerySessionExecuteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnSessionBegin func(QuerySessionBeginStartInfo) func(info QuerySessionBeginDoneInfo)
OnTxExecute func(QueryTxExecuteStartInfo) func(info QueryTxExecuteDoneInfo)
OnResultNew func(QueryResultNewStartInfo) func(info QueryResultNewDoneInfo)
@@ -51,6 +68,7 @@ type (
OnRowScanStruct func(QueryRowScanStructStartInfo) func(info QueryRowScanStructDoneInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryDoStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -59,10 +77,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryDoDoneInfo struct {
Attempts int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryDoTxStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -71,10 +91,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryDoTxDoneInfo struct {
Attempts int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionCreateStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -83,10 +105,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionCreateDoneInfo struct {
Session querySessionInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -98,9 +122,11 @@ type (
Session querySessionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionExecuteDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryTxExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -113,9 +139,11 @@ type (
Tx queryTransactionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryTxExecuteDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionAttachStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -125,9 +153,11 @@ type (
Call call
Session querySessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionAttachDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionBeginStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -137,10 +167,12 @@ type (
Call call
Session querySessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionBeginDoneInfo struct {
Error error
Tx queryTransactionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -149,9 +181,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNewDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -160,9 +194,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNextPartStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -171,9 +207,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNextPartDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNextResultSetStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -182,9 +220,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultNextResultSetDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultSetNextRowStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -193,9 +233,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryResultSetNextRowDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -204,9 +246,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanNamedStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -215,9 +259,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanNamedDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanStructStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -226,9 +272,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryRowScanStructDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionDeleteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -238,9 +286,11 @@ type (
Call call
Session querySessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QuerySessionDeleteDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -249,7 +299,9 @@ type (
Context *context.Context
Call call
}
- QueryNewDoneInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ QueryNewDoneInfo struct{}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -258,9 +310,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -269,9 +323,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolNewDoneInfo struct {
Limit int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -280,9 +336,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolTryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -291,9 +349,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolTryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolWithStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -302,11 +362,13 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolWithDoneInfo struct {
Error error
Attempts int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolPutStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -315,9 +377,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolPutDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolGetStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -326,9 +390,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolGetDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
QueryPoolChange struct {
Limit int
Index int
diff --git a/trace/query_gtrace.go b/trace/query_gtrace.go
index 2353b77b4..2bbc46f3c 100644
--- a/trace/query_gtrace.go
+++ b/trace/query_gtrace.go
@@ -12,9 +12,11 @@ type queryComposeOptions struct {
}
// QueryOption specified Query compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type QueryComposeOption func(o *queryComposeOptions)
// WithQueryPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithQueryPanicCallback(cb func(e interface{})) QueryComposeOption {
return func(o *queryComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithQueryPanicCallback(cb func(e interface{})) QueryComposeOption {
}
// Compose returns a new Query which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Query) Compose(x *Query, opts ...QueryComposeOption) *Query {
var ret Query
options := queryComposeOptions{}
@@ -1258,6 +1261,7 @@ func (t *Query) onRowScanStruct(q QueryRowScanStructStartInfo) func(info QueryRo
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnNew(t *Query, c *context.Context, call call) func() {
var p QueryNewStartInfo
p.Context = c
@@ -1268,6 +1272,7 @@ func QueryOnNew(t *Query, c *context.Context, call call) func() {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnClose(t *Query, c *context.Context, call call) func(error) {
var p QueryCloseStartInfo
p.Context = c
@@ -1279,6 +1284,7 @@ func QueryOnClose(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolNew(t *Query, c *context.Context, call call) func(limit int) {
var p QueryPoolNewStartInfo
p.Context = c
@@ -1290,6 +1296,7 @@ func QueryOnPoolNew(t *Query, c *context.Context, call call) func(limit int) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolClose(t *Query, c *context.Context, call call) func(error) {
var p QueryPoolCloseStartInfo
p.Context = c
@@ -1301,6 +1308,7 @@ func QueryOnPoolClose(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolTry(t *Query, c *context.Context, call call) func(error) {
var p QueryPoolTryStartInfo
p.Context = c
@@ -1312,6 +1320,7 @@ func QueryOnPoolTry(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolWith(t *Query, c *context.Context, call call) func(_ error, attempts int) {
var p QueryPoolWithStartInfo
p.Context = c
@@ -1324,6 +1333,7 @@ func QueryOnPoolWith(t *Query, c *context.Context, call call) func(_ error, atte
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolPut(t *Query, c *context.Context, call call) func(error) {
var p QueryPoolPutStartInfo
p.Context = c
@@ -1335,6 +1345,7 @@ func QueryOnPoolPut(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolGet(t *Query, c *context.Context, call call) func(error) {
var p QueryPoolGetStartInfo
p.Context = c
@@ -1346,6 +1357,7 @@ func QueryOnPoolGet(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnPoolChange(t *Query, limit int, index int, idle int, inUse int) {
var p QueryPoolChange
p.Limit = limit
@@ -1354,6 +1366,7 @@ func QueryOnPoolChange(t *Query, limit int, index int, idle int, inUse int) {
p.InUse = inUse
t.onPoolChange(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnDo(t *Query, c *context.Context, call call) func(attempts int, _ error) {
var p QueryDoStartInfo
p.Context = c
@@ -1366,6 +1379,7 @@ func QueryOnDo(t *Query, c *context.Context, call call) func(attempts int, _ err
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnDoTx(t *Query, c *context.Context, call call) func(attempts int, _ error) {
var p QueryDoTxStartInfo
p.Context = c
@@ -1378,6 +1392,7 @@ func QueryOnDoTx(t *Query, c *context.Context, call call) func(attempts int, _ e
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnSessionCreate(t *Query, c *context.Context, call call) func(session querySessionInfo, _ error) {
var p QuerySessionCreateStartInfo
p.Context = c
@@ -1390,6 +1405,7 @@ func QueryOnSessionCreate(t *Query, c *context.Context, call call) func(session
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnSessionAttach(t *Query, c *context.Context, call call, session querySessionInfo) func(error) {
var p QuerySessionAttachStartInfo
p.Context = c
@@ -1402,6 +1418,7 @@ func QueryOnSessionAttach(t *Query, c *context.Context, call call, session query
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnSessionDelete(t *Query, c *context.Context, call call, session querySessionInfo) func(error) {
var p QuerySessionDeleteStartInfo
p.Context = c
@@ -1414,6 +1431,7 @@ func QueryOnSessionDelete(t *Query, c *context.Context, call call, session query
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnSessionExecute(t *Query, c *context.Context, call call, session querySessionInfo, query string) func(error) {
var p QuerySessionExecuteStartInfo
p.Context = c
@@ -1427,6 +1445,7 @@ func QueryOnSessionExecute(t *Query, c *context.Context, call call, session quer
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnSessionBegin(t *Query, c *context.Context, call call, session querySessionInfo) func(_ error, tx queryTransactionInfo) {
var p QuerySessionBeginStartInfo
p.Context = c
@@ -1440,6 +1459,7 @@ func QueryOnSessionBegin(t *Query, c *context.Context, call call, session queryS
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnTxExecute(t *Query, c *context.Context, call call, session querySessionInfo, tx queryTransactionInfo, query string) func(error) {
var p QueryTxExecuteStartInfo
p.Context = c
@@ -1454,6 +1474,7 @@ func QueryOnTxExecute(t *Query, c *context.Context, call call, session querySess
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnResultNew(t *Query, c *context.Context, call call) func(error) {
var p QueryResultNewStartInfo
p.Context = c
@@ -1465,6 +1486,7 @@ func QueryOnResultNew(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnResultNextPart(t *Query, c *context.Context, call call) func(error) {
var p QueryResultNextPartStartInfo
p.Context = c
@@ -1476,6 +1498,7 @@ func QueryOnResultNextPart(t *Query, c *context.Context, call call) func(error)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnResultNextResultSet(t *Query, c *context.Context, call call) func(error) {
var p QueryResultNextResultSetStartInfo
p.Context = c
@@ -1487,6 +1510,7 @@ func QueryOnResultNextResultSet(t *Query, c *context.Context, call call) func(er
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnResultClose(t *Query, c *context.Context, call call) func(error) {
var p QueryResultCloseStartInfo
p.Context = c
@@ -1498,6 +1522,7 @@ func QueryOnResultClose(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnResultSetNextRow(t *Query, c *context.Context, call call) func(error) {
var p QueryResultSetNextRowStartInfo
p.Context = c
@@ -1509,6 +1534,7 @@ func QueryOnResultSetNextRow(t *Query, c *context.Context, call call) func(error
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnRowScan(t *Query, c *context.Context, call call) func(error) {
var p QueryRowScanStartInfo
p.Context = c
@@ -1520,6 +1546,7 @@ func QueryOnRowScan(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnRowScanNamed(t *Query, c *context.Context, call call) func(error) {
var p QueryRowScanNamedStartInfo
p.Context = c
@@ -1531,6 +1558,7 @@ func QueryOnRowScanNamed(t *Query, c *context.Context, call call) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func QueryOnRowScanStruct(t *Query, c *context.Context, call call) func(error) {
var p QueryRowScanStructStartInfo
p.Context = c
diff --git a/trace/ratelimiter.go b/trace/ratelimiter.go
index 5aae16b93..6d411d13c 100644
--- a/trace/ratelimiter.go
+++ b/trace/ratelimiter.go
@@ -7,5 +7,6 @@ package trace
type (
// Ratelimiter specified trace of ratelimiter client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Ratelimiter struct{}
)
diff --git a/trace/ratelimiter_gtrace.go b/trace/ratelimiter_gtrace.go
index 015dba417..607e8a33d 100644
--- a/trace/ratelimiter_gtrace.go
+++ b/trace/ratelimiter_gtrace.go
@@ -8,9 +8,11 @@ type ratelimiterComposeOptions struct {
}
// RatelimiterOption specified Ratelimiter compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type RatelimiterComposeOption func(o *ratelimiterComposeOptions)
// WithRatelimiterPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithRatelimiterPanicCallback(cb func(e interface{})) RatelimiterComposeOption {
return func(o *ratelimiterComposeOptions) {
o.panicCallback = cb
@@ -18,6 +20,7 @@ func WithRatelimiterPanicCallback(cb func(e interface{})) RatelimiterComposeOpti
}
// Compose returns a new Ratelimiter which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Ratelimiter) Compose(x *Ratelimiter, opts ...RatelimiterComposeOption) *Ratelimiter {
var ret Ratelimiter
return &ret
diff --git a/trace/retry.go b/trace/retry.go
index 21307fe34..200ba783f 100644
--- a/trace/retry.go
+++ b/trace/retry.go
@@ -11,9 +11,12 @@ import (
type (
// Retry specified trace of retry call activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Retry struct {
- OnRetry func(RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnRetry func(RetryLoopStartInfo) func(RetryLoopDoneInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
RetryLoopStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -27,9 +30,7 @@ type (
NestedCall bool // a sign for detect Retry calls inside head Retry
}
- RetryLoopIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
RetryLoopDoneInfo struct {
Attempts int
Error error
diff --git a/trace/retry_gtrace.go b/trace/retry_gtrace.go
index c6fa15dd8..a8a6ba50e 100644
--- a/trace/retry_gtrace.go
+++ b/trace/retry_gtrace.go
@@ -12,9 +12,11 @@ type retryComposeOptions struct {
}
// RetryOption specified Retry compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type RetryComposeOption func(o *retryComposeOptions)
// WithRetryPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithRetryPanicCallback(cb func(e interface{})) RetryComposeOption {
return func(o *retryComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithRetryPanicCallback(cb func(e interface{})) RetryComposeOption {
}
// Compose returns a new Retry which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
var ret Retry
options := retryComposeOptions{}
@@ -33,7 +36,7 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
{
h1 := t.OnRetry
h2 := x.OnRetry
- ret.OnRetry = func(r RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+ ret.OnRetry = func(r RetryLoopStartInfo) func(RetryLoopDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -41,14 +44,14 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
}
}()
}
- var r1, r2 func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo)
+ var r1, r2 func(RetryLoopDoneInfo)
if h1 != nil {
r1 = h1(r)
}
if h2 != nil {
r2 = h2(r)
}
- return func(r RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+ return func(r RetryLoopDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -56,61 +59,34 @@ func (t *Retry) Compose(x *Retry, opts ...RetryComposeOption) *Retry {
}
}()
}
- var r3, r4 func(RetryLoopDoneInfo)
if r1 != nil {
- r3 = r1(r)
+ r1(r)
}
if r2 != nil {
- r4 = r2(r)
- }
- return func(r RetryLoopDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r3 != nil {
- r3(r)
- }
- if r4 != nil {
- r4(r)
- }
+ r2(r)
}
}
}
}
return &ret
}
-func (t *Retry) onRetry(r RetryLoopStartInfo) func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
+func (t *Retry) onRetry(r RetryLoopStartInfo) func(RetryLoopDoneInfo) {
fn := t.OnRetry
if fn == nil {
- return func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- return func(RetryLoopDoneInfo) {
- return
- }
+ return func(RetryLoopDoneInfo) {
+ return
}
}
res := fn(r)
if res == nil {
- return func(RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- return func(RetryLoopDoneInfo) {
- return
- }
+ return func(RetryLoopDoneInfo) {
+ return
}
}
- return func(r RetryLoopIntermediateInfo) func(RetryLoopDoneInfo) {
- res := res(r)
- if res == nil {
- return func(RetryLoopDoneInfo) {
- return
- }
- }
- return res
- }
+ return res
}
-func RetryOnRetry(t *Retry, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func RetryOnRetry(t *Retry, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p RetryLoopStartInfo
p.Context = c
p.Call = call
@@ -118,15 +94,10 @@ func RetryOnRetry(t *Retry, c *context.Context, call call, label string, idempot
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onRetry(p)
- return func(e error) func(int, error) {
- var p RetryLoopIntermediateInfo
+ return func(attempts int, e error) {
+ var p RetryLoopDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p RetryLoopDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
diff --git a/trace/scheme.go b/trace/scheme.go
index 2f4c6f48b..ed70a527e 100644
--- a/trace/scheme.go
+++ b/trace/scheme.go
@@ -11,14 +11,21 @@ import (
type (
// Scheme specified trace of scheme client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Scheme struct {
- OnListDirectory func(SchemeListDirectoryStartInfo) func(SchemeListDirectoryDoneInfo)
- OnDescribePath func(SchemeDescribePathStartInfo) func(SchemeDescribePathDoneInfo)
- OnMakeDirectory func(SchemeMakeDirectoryStartInfo) func(SchemeMakeDirectoryDoneInfo)
- OnRemoveDirectory func(SchemeRemoveDirectoryStartInfo) func(SchemeRemoveDirectoryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnListDirectory func(SchemeListDirectoryStartInfo) func(SchemeListDirectoryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDescribePath func(SchemeDescribePathStartInfo) func(SchemeDescribePathDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnMakeDirectory func(SchemeMakeDirectoryStartInfo) func(SchemeMakeDirectoryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnRemoveDirectory func(SchemeRemoveDirectoryStartInfo) func(SchemeRemoveDirectoryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnModifyPermissions func(SchemeModifyPermissionsStartInfo) func(SchemeModifyPermissionsDoneInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeListDirectoryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -27,9 +34,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeListDirectoryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeDescribePathStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -39,10 +48,12 @@ type (
Call call
Path string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeDescribePathDoneInfo struct {
EntryType string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeMakeDirectoryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -52,9 +63,11 @@ type (
Call call
Path string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeMakeDirectoryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeRemoveDirectoryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -64,9 +77,11 @@ type (
Call call
Path string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeRemoveDirectoryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeModifyPermissionsStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -76,6 +91,7 @@ type (
Call call
Path string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
SchemeModifyPermissionsDoneInfo struct {
Error error
}
diff --git a/trace/scheme_gtrace.go b/trace/scheme_gtrace.go
index 0001d9e17..e960696ca 100644
--- a/trace/scheme_gtrace.go
+++ b/trace/scheme_gtrace.go
@@ -12,9 +12,11 @@ type schemeComposeOptions struct {
}
// SchemeOption specified Scheme compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type SchemeComposeOption func(o *schemeComposeOptions)
// WithSchemePanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithSchemePanicCallback(cb func(e interface{})) SchemeComposeOption {
return func(o *schemeComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithSchemePanicCallback(cb func(e interface{})) SchemeComposeOption {
}
// Compose returns a new Scheme which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Scheme) Compose(x *Scheme, opts ...SchemeComposeOption) *Scheme {
var ret Scheme
options := schemeComposeOptions{}
@@ -282,6 +285,7 @@ func (t *Scheme) onModifyPermissions(s SchemeModifyPermissionsStartInfo) func(Sc
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func SchemeOnListDirectory(t *Scheme, c *context.Context, call call) func(error) {
var p SchemeListDirectoryStartInfo
p.Context = c
@@ -293,6 +297,7 @@ func SchemeOnListDirectory(t *Scheme, c *context.Context, call call) func(error)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func SchemeOnDescribePath(t *Scheme, c *context.Context, call call, path string) func(entryType string, _ error) {
var p SchemeDescribePathStartInfo
p.Context = c
@@ -306,6 +311,7 @@ func SchemeOnDescribePath(t *Scheme, c *context.Context, call call, path string)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func SchemeOnMakeDirectory(t *Scheme, c *context.Context, call call, path string) func(error) {
var p SchemeMakeDirectoryStartInfo
p.Context = c
@@ -318,6 +324,7 @@ func SchemeOnMakeDirectory(t *Scheme, c *context.Context, call call, path string
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func SchemeOnRemoveDirectory(t *Scheme, c *context.Context, call call, path string) func(error) {
var p SchemeRemoveDirectoryStartInfo
p.Context = c
@@ -330,6 +337,7 @@ func SchemeOnRemoveDirectory(t *Scheme, c *context.Context, call call, path stri
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func SchemeOnModifyPermissions(t *Scheme, c *context.Context, call call, path string) func(error) {
var p SchemeModifyPermissionsStartInfo
p.Context = c
diff --git a/trace/scripting.go b/trace/scripting.go
index 4e018e07d..51f672d79 100644
--- a/trace/scripting.go
+++ b/trace/scripting.go
@@ -11,8 +11,11 @@ import (
type (
// Scripting specified trace of scripting client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Scripting struct {
- OnExecute func(ScriptingExecuteStartInfo) func(ScriptingExecuteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnExecute func(ScriptingExecuteStartInfo) func(ScriptingExecuteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnStreamExecute func(
ScriptingStreamExecuteStartInfo,
) func(
@@ -20,8 +23,10 @@ type (
) func(
ScriptingStreamExecuteDoneInfo,
)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnExplain func(ScriptingExplainStartInfo) func(ScriptingExplainDoneInfo)
- OnClose func(ScriptingCloseStartInfo) func(ScriptingCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnClose func(ScriptingCloseStartInfo) func(ScriptingCloseDoneInfo)
}
scriptingQueryParameters interface {
String() string
@@ -33,6 +38,7 @@ type (
scriptingResultErr
ResultSetCount() int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -43,10 +49,12 @@ type (
Query string
Parameters scriptingQueryParameters
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingExecuteDoneInfo struct {
Result scriptingResult
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingStreamExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -57,12 +65,15 @@ type (
Query string
Parameters scriptingQueryParameters
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingStreamExecuteIntermediateInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingStreamExecuteDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingExplainStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -72,10 +83,12 @@ type (
Call call
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingExplainDoneInfo struct {
Plan string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -84,6 +97,7 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
ScriptingCloseDoneInfo struct {
Error error
}
diff --git a/trace/scripting_gtrace.go b/trace/scripting_gtrace.go
index 8af5fd07e..c3de7b27f 100644
--- a/trace/scripting_gtrace.go
+++ b/trace/scripting_gtrace.go
@@ -12,9 +12,11 @@ type scriptingComposeOptions struct {
}
// ScriptingOption specified Scripting compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type ScriptingComposeOption func(o *scriptingComposeOptions)
// WithScriptingPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithScriptingPanicCallback(cb func(e interface{})) ScriptingComposeOption {
return func(o *scriptingComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithScriptingPanicCallback(cb func(e interface{})) ScriptingComposeOption {
}
// Compose returns a new Scripting which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Scripting) Compose(x *Scripting, opts ...ScriptingComposeOption) *Scripting {
var ret Scripting
options := scriptingComposeOptions{}
@@ -260,6 +263,7 @@ func (t *Scripting) onClose(s ScriptingCloseStartInfo) func(ScriptingCloseDoneIn
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func ScriptingOnExecute(t *Scripting, c *context.Context, call call, query string, parameters scriptingQueryParameters) func(result scriptingResult, _ error) {
var p ScriptingExecuteStartInfo
p.Context = c
@@ -274,6 +278,7 @@ func ScriptingOnExecute(t *Scripting, c *context.Context, call call, query strin
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func ScriptingOnStreamExecute(t *Scripting, c *context.Context, call call, query string, parameters scriptingQueryParameters) func(error) func(error) {
var p ScriptingStreamExecuteStartInfo
p.Context = c
@@ -292,6 +297,7 @@ func ScriptingOnStreamExecute(t *Scripting, c *context.Context, call call, query
}
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func ScriptingOnExplain(t *Scripting, c *context.Context, call call, query string) func(plan string, _ error) {
var p ScriptingExplainStartInfo
p.Context = c
@@ -305,6 +311,7 @@ func ScriptingOnExplain(t *Scripting, c *context.Context, call call, query strin
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func ScriptingOnClose(t *Scripting, c *context.Context, call call) func(error) {
var p ScriptingCloseStartInfo
p.Context = c
diff --git a/trace/sql.go b/trace/sql.go
index e6d5de6ec..9ee597a39 100644
--- a/trace/sql.go
+++ b/trace/sql.go
@@ -10,30 +10,49 @@ import (
type (
// DatabaseSQL specified trace of `database/sql` call activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQL struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnConnectorConnect func(DatabaseSQLConnectorConnectStartInfo) func(DatabaseSQLConnectorConnectDoneInfo)
- OnConnPing func(DatabaseSQLConnPingStartInfo) func(DatabaseSQLConnPingDoneInfo)
- OnConnPrepare func(DatabaseSQLConnPrepareStartInfo) func(DatabaseSQLConnPrepareDoneInfo)
- OnConnClose func(DatabaseSQLConnCloseStartInfo) func(DatabaseSQLConnCloseDoneInfo)
- OnConnBegin func(DatabaseSQLConnBeginStartInfo) func(DatabaseSQLConnBeginDoneInfo)
- OnConnQuery func(DatabaseSQLConnQueryStartInfo) func(DatabaseSQLConnQueryDoneInfo)
- OnConnExec func(DatabaseSQLConnExecStartInfo) func(DatabaseSQLConnExecDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnPing func(DatabaseSQLConnPingStartInfo) func(DatabaseSQLConnPingDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnPrepare func(DatabaseSQLConnPrepareStartInfo) func(DatabaseSQLConnPrepareDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnClose func(DatabaseSQLConnCloseStartInfo) func(DatabaseSQLConnCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnBegin func(DatabaseSQLConnBeginStartInfo) func(DatabaseSQLConnBeginDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnQuery func(DatabaseSQLConnQueryStartInfo) func(DatabaseSQLConnQueryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnConnExec func(DatabaseSQLConnExecStartInfo) func(DatabaseSQLConnExecDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnConnIsTableExists func(DatabaseSQLConnIsTableExistsStartInfo) func(DatabaseSQLConnIsTableExistsDoneInfo)
- OnTxQuery func(DatabaseSQLTxQueryStartInfo) func(DatabaseSQLTxQueryDoneInfo)
- OnTxExec func(DatabaseSQLTxExecStartInfo) func(DatabaseSQLTxExecDoneInfo)
- OnTxPrepare func(DatabaseSQLTxPrepareStartInfo) func(DatabaseSQLTxPrepareDoneInfo)
- OnTxCommit func(DatabaseSQLTxCommitStartInfo) func(DatabaseSQLTxCommitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxQuery func(DatabaseSQLTxQueryStartInfo) func(DatabaseSQLTxQueryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxExec func(DatabaseSQLTxExecStartInfo) func(DatabaseSQLTxExecDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxPrepare func(DatabaseSQLTxPrepareStartInfo) func(DatabaseSQLTxPrepareDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxCommit func(DatabaseSQLTxCommitStartInfo) func(DatabaseSQLTxCommitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnTxRollback func(DatabaseSQLTxRollbackStartInfo) func(DatabaseSQLTxRollbackDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnStmtQuery func(DatabaseSQLStmtQueryStartInfo) func(DatabaseSQLStmtQueryDoneInfo)
- OnStmtExec func(DatabaseSQLStmtExecStartInfo) func(DatabaseSQLStmtExecDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnStmtExec func(DatabaseSQLStmtExecStartInfo) func(DatabaseSQLStmtExecDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnStmtClose func(DatabaseSQLStmtCloseStartInfo) func(DatabaseSQLStmtCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnDoTx func(DatabaseSQLDoTxStartInfo) func(DatabaseSQLDoTxIntermediateInfo) func(DatabaseSQLDoTxDoneInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnectorConnectStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -42,10 +61,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnectorConnectDoneInfo struct {
Error error
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnPingStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -54,9 +75,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnPingDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnPrepareStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -66,9 +89,11 @@ type (
Call call
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnPrepareDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxPrepareStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -80,9 +105,11 @@ type (
Tx tableTransactionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxPrepareDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -91,9 +118,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnBeginStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -102,10 +131,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnBeginDoneInfo struct {
Tx tableTransactionInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -118,9 +149,11 @@ type (
Idempotent bool
IdleTime time.Duration
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnQueryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnExecStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -133,9 +166,11 @@ type (
Idempotent bool
IdleTime time.Duration
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnExecDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnIsTableExistsStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -145,10 +180,12 @@ type (
Call call
TableName string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLConnIsTableExistsDoneInfo struct {
Exists bool
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -160,9 +197,11 @@ type (
Tx tableTransactionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxQueryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxExecStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -174,9 +213,11 @@ type (
Tx tableTransactionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxExecDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxCommitStartInfo struct {
// TxContext make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -186,9 +227,11 @@ type (
Call call
Tx tableTransactionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxCommitDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxRollbackStartInfo struct {
// TxContext make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -198,16 +241,20 @@ type (
Call call
Tx tableTransactionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLTxRollbackDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtCloseStartInfo struct {
StmtContext *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -218,9 +265,11 @@ type (
StmtContext context.Context
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtQueryDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtExecStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -231,9 +280,11 @@ type (
StmtContext context.Context
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLStmtExecDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLDoTxStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -244,9 +295,11 @@ type (
ID string
Idempotent bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLDoTxIntermediateInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
DatabaseSQLDoTxDoneInfo struct {
Attempts int
Error error
diff --git a/trace/sql_gtrace.go b/trace/sql_gtrace.go
index e5d2a484f..c4a686e1d 100644
--- a/trace/sql_gtrace.go
+++ b/trace/sql_gtrace.go
@@ -13,9 +13,11 @@ type databaseSQLComposeOptions struct {
}
// DatabaseSQLOption specified DatabaseSQL compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type DatabaseSQLComposeOption func(o *databaseSQLComposeOptions)
// WithDatabaseSQLPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithDatabaseSQLPanicCallback(cb func(e interface{})) DatabaseSQLComposeOption {
return func(o *databaseSQLComposeOptions) {
o.panicCallback = cb
@@ -23,6 +25,7 @@ func WithDatabaseSQLPanicCallback(cb func(e interface{})) DatabaseSQLComposeOpti
}
// Compose returns a new DatabaseSQL which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *DatabaseSQL) Compose(x *DatabaseSQL, opts ...DatabaseSQLComposeOption) *DatabaseSQL {
var ret DatabaseSQL
options := databaseSQLComposeOptions{}
@@ -911,6 +914,7 @@ func (t *DatabaseSQL) onDoTx(d DatabaseSQLDoTxStartInfo) func(DatabaseSQLDoTxInt
return res
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnectorConnect(t *DatabaseSQL, c *context.Context, call call) func(_ error, session tableSessionInfo) {
var p DatabaseSQLConnectorConnectStartInfo
p.Context = c
@@ -923,6 +927,7 @@ func DatabaseSQLOnConnectorConnect(t *DatabaseSQL, c *context.Context, call call
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnPing(t *DatabaseSQL, c *context.Context, call call) func(error) {
var p DatabaseSQLConnPingStartInfo
p.Context = c
@@ -934,6 +939,7 @@ func DatabaseSQLOnConnPing(t *DatabaseSQL, c *context.Context, call call) func(e
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnPrepare(t *DatabaseSQL, c *context.Context, call call, query string) func(error) {
var p DatabaseSQLConnPrepareStartInfo
p.Context = c
@@ -946,6 +952,7 @@ func DatabaseSQLOnConnPrepare(t *DatabaseSQL, c *context.Context, call call, que
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnClose(t *DatabaseSQL, c *context.Context, call call) func(error) {
var p DatabaseSQLConnCloseStartInfo
p.Context = c
@@ -957,6 +964,7 @@ func DatabaseSQLOnConnClose(t *DatabaseSQL, c *context.Context, call call) func(
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnBegin(t *DatabaseSQL, c *context.Context, call call) func(tx tableTransactionInfo, _ error) {
var p DatabaseSQLConnBeginStartInfo
p.Context = c
@@ -969,6 +977,7 @@ func DatabaseSQLOnConnBegin(t *DatabaseSQL, c *context.Context, call call) func(
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnQuery(t *DatabaseSQL, c *context.Context, call call, query string, mode string, idempotent bool, idleTime time.Duration) func(error) {
var p DatabaseSQLConnQueryStartInfo
p.Context = c
@@ -984,6 +993,7 @@ func DatabaseSQLOnConnQuery(t *DatabaseSQL, c *context.Context, call call, query
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnExec(t *DatabaseSQL, c *context.Context, call call, query string, mode string, idempotent bool, idleTime time.Duration) func(error) {
var p DatabaseSQLConnExecStartInfo
p.Context = c
@@ -999,6 +1009,7 @@ func DatabaseSQLOnConnExec(t *DatabaseSQL, c *context.Context, call call, query
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnConnIsTableExists(t *DatabaseSQL, c *context.Context, call call, tableName string) func(exists bool, _ error) {
var p DatabaseSQLConnIsTableExistsStartInfo
p.Context = c
@@ -1012,6 +1023,7 @@ func DatabaseSQLOnConnIsTableExists(t *DatabaseSQL, c *context.Context, call cal
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnTxQuery(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string) func(error) {
var p DatabaseSQLTxQueryStartInfo
p.Context = c
@@ -1026,6 +1038,7 @@ func DatabaseSQLOnTxQuery(t *DatabaseSQL, c *context.Context, call call, txConte
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnTxExec(t *DatabaseSQL, c *context.Context, call call, txContext context.Context, tx tableTransactionInfo, query string) func(error) {
var p DatabaseSQLTxExecStartInfo
p.Context = c
@@ -1040,6 +1053,7 @@ func DatabaseSQLOnTxExec(t *DatabaseSQL, c *context.Context, call call, txContex
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnTxPrepare(t *DatabaseSQL, c *context.Context, call call, txContext *context.Context, tx tableTransactionInfo, query string) func(error) {
var p DatabaseSQLTxPrepareStartInfo
p.Context = c
@@ -1054,6 +1068,7 @@ func DatabaseSQLOnTxPrepare(t *DatabaseSQL, c *context.Context, call call, txCon
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnTxCommit(t *DatabaseSQL, c *context.Context, call call, tx tableTransactionInfo) func(error) {
var p DatabaseSQLTxCommitStartInfo
p.Context = c
@@ -1066,6 +1081,7 @@ func DatabaseSQLOnTxCommit(t *DatabaseSQL, c *context.Context, call call, tx tab
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnTxRollback(t *DatabaseSQL, c *context.Context, call call, tx tableTransactionInfo) func(error) {
var p DatabaseSQLTxRollbackStartInfo
p.Context = c
@@ -1078,6 +1094,7 @@ func DatabaseSQLOnTxRollback(t *DatabaseSQL, c *context.Context, call call, tx t
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnStmtQuery(t *DatabaseSQL, c *context.Context, call call, stmtContext context.Context, query string) func(error) {
var p DatabaseSQLStmtQueryStartInfo
p.Context = c
@@ -1091,6 +1108,7 @@ func DatabaseSQLOnStmtQuery(t *DatabaseSQL, c *context.Context, call call, stmtC
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnStmtExec(t *DatabaseSQL, c *context.Context, call call, stmtContext context.Context, query string) func(error) {
var p DatabaseSQLStmtExecStartInfo
p.Context = c
@@ -1104,6 +1122,7 @@ func DatabaseSQLOnStmtExec(t *DatabaseSQL, c *context.Context, call call, stmtCo
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnStmtClose(t *DatabaseSQL, stmtContext *context.Context, call call) func(error) {
var p DatabaseSQLStmtCloseStartInfo
p.StmtContext = stmtContext
@@ -1115,6 +1134,7 @@ func DatabaseSQLOnStmtClose(t *DatabaseSQL, stmtContext *context.Context, call c
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func DatabaseSQLOnDoTx(t *DatabaseSQL, c *context.Context, call call, iD string, idempotent bool) func(error) func(attempts int, _ error) {
var p DatabaseSQLDoTxStartInfo
p.Context = c
diff --git a/trace/table.go b/trace/table.go
index 59d4f2791..d8f0622e7 100644
--- a/trace/table.go
+++ b/trace/table.go
@@ -12,69 +12,75 @@ import (
type (
// Table specified trace of table client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Table struct {
// Client events
- OnInit func(TableInitStartInfo) func(TableInitDoneInfo)
- OnClose func(TableCloseStartInfo) func(TableCloseDoneInfo)
- OnDo func(TableDoStartInfo) func(info TableDoIntermediateInfo) func(TableDoDoneInfo)
- OnDoTx func(TableDoTxStartInfo) func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo)
- OnCreateSession func(
- TableCreateSessionStartInfo,
- ) func(
- info TableCreateSessionIntermediateInfo,
- ) func(
- TableCreateSessionDoneInfo,
- )
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnInit func(TableInitStartInfo) func(TableInitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnClose func(TableCloseStartInfo) func(TableCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDo func(TableDoStartInfo) func(TableDoDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnDoTx func(TableDoTxStartInfo) func(TableDoTxDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnCreateSession func(TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo)
// Session events
- OnSessionNew func(TableSessionNewStartInfo) func(TableSessionNewDoneInfo)
- OnSessionDelete func(TableSessionDeleteStartInfo) func(TableSessionDeleteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionNew func(TableSessionNewStartInfo) func(TableSessionNewDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionDelete func(TableSessionDeleteStartInfo) func(TableSessionDeleteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnSessionKeepAlive func(TableKeepAliveStartInfo) func(TableKeepAliveDoneInfo)
// Query events
- OnSessionBulkUpsert func(TableBulkUpsertStartInfo) func(TableBulkUpsertDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionBulkUpsert func(TableBulkUpsertStartInfo) func(TableBulkUpsertDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnSessionQueryPrepare func(TablePrepareDataQueryStartInfo) func(TablePrepareDataQueryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnSessionQueryExecute func(TableExecuteDataQueryStartInfo) func(TableExecuteDataQueryDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnSessionQueryExplain func(TableExplainQueryStartInfo) func(TableExplainQueryDoneInfo)
// Stream events
- OnSessionQueryStreamExecute func(
- TableSessionQueryStreamExecuteStartInfo,
- ) func(
- TableSessionQueryStreamExecuteIntermediateInfo,
- ) func(
- TableSessionQueryStreamExecuteDoneInfo,
- )
- OnSessionQueryStreamRead func(
- TableSessionQueryStreamReadStartInfo,
- ) func(
- TableSessionQueryStreamReadIntermediateInfo,
- ) func(
- TableSessionQueryStreamReadDoneInfo,
- )
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionQueryStreamExecute func(TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnSessionQueryStreamRead func(TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo)
// Transaction events
- OnSessionTransactionBegin func(TableSessionTransactionBeginStartInfo) func(
- TableSessionTransactionBeginDoneInfo,
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxBegin func(TableTxBeginStartInfo) func(
+ TableTxBeginDoneInfo,
)
- OnSessionTransactionExecute func(TableTransactionExecuteStartInfo) func(
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxExecute func(TableTransactionExecuteStartInfo) func(
TableTransactionExecuteDoneInfo,
)
- OnSessionTransactionExecuteStatement func(TableTransactionExecuteStatementStartInfo) func(
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxExecuteStatement func(TableTransactionExecuteStatementStartInfo) func(
TableTransactionExecuteStatementDoneInfo,
)
- OnSessionTransactionCommit func(TableSessionTransactionCommitStartInfo) func(
- TableSessionTransactionCommitDoneInfo,
- )
- OnSessionTransactionRollback func(TableSessionTransactionRollbackStartInfo) func(
- TableSessionTransactionRollbackDoneInfo,
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxCommit func(TableTxCommitStartInfo) func(
+ TableTxCommitDoneInfo,
)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnTxRollback func(TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo)
// Pool state event
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnPoolStateChange func(TablePoolStateChangeInfo)
// Pool session lifecycle events
- OnPoolSessionAdd func(info TablePoolSessionAddInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolSessionAdd func(info TablePoolSessionAddInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnPoolSessionRemove func(info TablePoolSessionRemoveInfo)
// Pool common API events
- OnPoolPut func(TablePoolPutStartInfo) func(TablePoolPutDoneInfo)
- OnPoolGet func(TablePoolGetStartInfo) func(TablePoolGetDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolPut func(TablePoolPutStartInfo) func(TablePoolPutDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnPoolGet func(TablePoolGetStartInfo) func(TablePoolGetDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnPoolWait func(TablePoolWaitStartInfo) func(TablePoolWaitDoneInfo)
}
)
@@ -104,6 +110,7 @@ type (
tableResultErr
ResultSetCount() int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -112,10 +119,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionNewDoneInfo struct {
Session tableSessionInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableKeepAliveStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -125,9 +134,11 @@ type (
Call call
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableKeepAliveDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableBulkUpsertStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -137,9 +148,11 @@ type (
Call call
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableBulkUpsertDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionDeleteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -149,9 +162,11 @@ type (
Call call
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionDeleteDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePrepareDataQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -162,10 +177,12 @@ type (
Session tableSessionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePrepareDataQueryDoneInfo struct {
Result tableDataQuery
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableExecuteDataQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -178,6 +195,7 @@ type (
Parameters tableQueryParameters
KeepInCache bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableTransactionExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -190,6 +208,7 @@ type (
Query tableDataQuery
Parameters tableQueryParameters
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableTransactionExecuteStatementStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -202,6 +221,7 @@ type (
StatementQuery tableDataQuery
Parameters tableQueryParameters
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableExplainQueryStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -212,25 +232,30 @@ type (
Session tableSessionInfo
Query string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableExplainQueryDoneInfo struct {
AST string
Plan string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableExecuteDataQueryDoneInfo struct {
Tx tableTransactionInfo
Prepared bool
Result tableResult
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableTransactionExecuteDoneInfo struct {
Result tableResult
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableTransactionExecuteStatementDoneInfo struct {
Result tableResult
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionQueryStreamReadStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -240,12 +265,11 @@ type (
Call call
Session tableSessionInfo
}
- TableSessionQueryStreamReadIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionQueryStreamReadDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionQueryStreamExecuteStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -257,13 +281,12 @@ type (
Query tableDataQuery
Parameters tableQueryParameters
}
- TableSessionQueryStreamExecuteIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableSessionQueryStreamExecuteDoneInfo struct {
Error error
}
- TableSessionTransactionBeginStartInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxBeginStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -272,11 +295,13 @@ type (
Call call
Session tableSessionInfo
}
- TableSessionTransactionBeginDoneInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxBeginDoneInfo struct {
Tx tableTransactionInfo
Error error
}
- TableSessionTransactionCommitStartInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxCommitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -286,10 +311,12 @@ type (
Session tableSessionInfo
Tx tableTransactionInfo
}
- TableSessionTransactionCommitDoneInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxCommitDoneInfo struct {
Error error
}
- TableSessionTransactionRollbackStartInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxRollbackStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
// Warning: concurrent access to pointer on client side must be excluded.
@@ -299,9 +326,11 @@ type (
Session tableSessionInfo
Tx tableTransactionInfo
}
- TableSessionTransactionRollbackDoneInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TableTxRollbackDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableInitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -310,13 +339,16 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableInitDoneInfo struct {
Limit int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolStateChangeInfo struct {
Size int
Event string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolSessionNewStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -325,10 +357,12 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolSessionNewDoneInfo struct {
Session tableSessionInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolGetStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -337,11 +371,13 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolGetDoneInfo struct {
Session tableSessionInfo
Attempts int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolWaitStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -353,10 +389,12 @@ type (
// TablePoolWaitDoneInfo means a wait iteration inside Get call is done
// Warning: Session and Error may be nil at the same time. This means
// that a wait iteration donned without any significant tableResultErr
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolWaitDoneInfo struct {
Session tableSessionInfo
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolPutStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -366,9 +404,11 @@ type (
Call call
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolPutDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolSessionCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -378,13 +418,17 @@ type (
Call call
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolSessionCloseDoneInfo struct{}
- TablePoolSessionAddInfo struct {
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TablePoolSessionAddInfo struct {
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TablePoolSessionRemoveInfo struct {
Session tableSessionInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableCloseStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -393,9 +437,11 @@ type (
Context *context.Context
Call call
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableDoStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -408,13 +454,12 @@ type (
Idempotent bool
NestedCall bool // flag when Retry called inside head Retry
}
- TableDoIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableDoDoneInfo struct {
Attempts int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableDoTxStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -427,13 +472,12 @@ type (
Idempotent bool
NestedCall bool // flag when Retry called inside head Retry
}
- TableDoTxIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableDoTxDoneInfo struct {
Attempts int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableCreateSessionStartInfo struct {
// Context make available context in trace callback function.
// Pointer to context provide replacement of context in trace callback function.
@@ -442,9 +486,7 @@ type (
Context *context.Context
Call call
}
- TableCreateSessionIntermediateInfo struct {
- Error error
- }
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TableCreateSessionDoneInfo struct {
Session tableSessionInfo
Attempts int
diff --git a/trace/table_gtrace.go b/trace/table_gtrace.go
index 3d50e4c40..e2cf30606 100644
--- a/trace/table_gtrace.go
+++ b/trace/table_gtrace.go
@@ -12,9 +12,11 @@ type tableComposeOptions struct {
}
// TableOption specified Table compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type TableComposeOption func(o *tableComposeOptions)
// WithTablePanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithTablePanicCallback(cb func(e interface{})) TableComposeOption {
return func(o *tableComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithTablePanicCallback(cb func(e interface{})) TableComposeOption {
}
// Compose returns a new Table which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
var ret Table
options := tableComposeOptions{}
@@ -103,7 +106,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnDo
h2 := x.OnDo
- ret.OnDo = func(t TableDoStartInfo) func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
+ ret.OnDo = func(t TableDoStartInfo) func(TableDoDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -111,14 +114,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableDoIntermediateInfo) func(TableDoDoneInfo)
+ var r, r1 func(TableDoDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
+ return func(t TableDoDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -126,27 +129,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableDoDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableDoDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -154,7 +141,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnDoTx
h2 := x.OnDoTx
- ret.OnDoTx = func(t TableDoTxStartInfo) func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+ ret.OnDoTx = func(t TableDoTxStartInfo) func(TableDoTxDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -162,14 +149,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo)
+ var r, r1 func(TableDoTxDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+ return func(t TableDoTxDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -177,27 +164,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableDoTxDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableDoTxDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -205,7 +176,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnCreateSession
h2 := x.OnCreateSession
- ret.OnCreateSession = func(t TableCreateSessionStartInfo) func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+ ret.OnCreateSession = func(t TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -213,14 +184,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo)
+ var r, r1 func(TableCreateSessionDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+ return func(t TableCreateSessionDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -228,27 +199,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableCreateSessionDoneInfo)
if r != nil {
- r2 = r(info)
+ r(t)
}
if r1 != nil {
- r3 = r1(info)
- }
- return func(t TableCreateSessionDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -501,7 +456,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnSessionQueryStreamExecute
h2 := x.OnSessionQueryStreamExecute
- ret.OnSessionQueryStreamExecute = func(t TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+ ret.OnSessionQueryStreamExecute = func(t TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -509,14 +464,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo)
+ var r, r1 func(TableSessionQueryStreamExecuteDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+ return func(t TableSessionQueryStreamExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -524,27 +479,11 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableSessionQueryStreamExecuteDoneInfo)
if r != nil {
- r2 = r(t)
+ r(t)
}
if r1 != nil {
- r3 = r1(t)
- }
- return func(t TableSessionQueryStreamExecuteDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
@@ -552,7 +491,7 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
{
h1 := t.OnSessionQueryStreamRead
h2 := x.OnSessionQueryStreamRead
- ret.OnSessionQueryStreamRead = func(t TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+ ret.OnSessionQueryStreamRead = func(t TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -560,14 +499,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo)
+ var r, r1 func(TableSessionQueryStreamReadDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+ return func(t TableSessionQueryStreamReadDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -575,35 +514,19 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r2, r3 func(TableSessionQueryStreamReadDoneInfo)
if r != nil {
- r2 = r(t)
+ r(t)
}
if r1 != nil {
- r3 = r1(t)
- }
- return func(t TableSessionQueryStreamReadDoneInfo) {
- if options.panicCallback != nil {
- defer func() {
- if e := recover(); e != nil {
- options.panicCallback(e)
- }
- }()
- }
- if r2 != nil {
- r2(t)
- }
- if r3 != nil {
- r3(t)
- }
+ r1(t)
}
}
}
}
{
- h1 := t.OnSessionTransactionBegin
- h2 := x.OnSessionTransactionBegin
- ret.OnSessionTransactionBegin = func(t TableSessionTransactionBeginStartInfo) func(TableSessionTransactionBeginDoneInfo) {
+ h1 := t.OnTxBegin
+ h2 := x.OnTxBegin
+ ret.OnTxBegin = func(t TableTxBeginStartInfo) func(TableTxBeginDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -611,14 +534,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionBeginDoneInfo)
+ var r, r1 func(TableTxBeginDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionBeginDoneInfo) {
+ return func(t TableTxBeginDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -636,9 +559,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionExecute
- h2 := x.OnSessionTransactionExecute
- ret.OnSessionTransactionExecute = func(t TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
+ h1 := t.OnTxExecute
+ h2 := x.OnTxExecute
+ ret.OnTxExecute = func(t TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -671,9 +594,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionExecuteStatement
- h2 := x.OnSessionTransactionExecuteStatement
- ret.OnSessionTransactionExecuteStatement = func(t TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
+ h1 := t.OnTxExecuteStatement
+ h2 := x.OnTxExecuteStatement
+ ret.OnTxExecuteStatement = func(t TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -706,9 +629,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionCommit
- h2 := x.OnSessionTransactionCommit
- ret.OnSessionTransactionCommit = func(t TableSessionTransactionCommitStartInfo) func(TableSessionTransactionCommitDoneInfo) {
+ h1 := t.OnTxCommit
+ h2 := x.OnTxCommit
+ ret.OnTxCommit = func(t TableTxCommitStartInfo) func(TableTxCommitDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -716,14 +639,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionCommitDoneInfo)
+ var r, r1 func(TableTxCommitDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionCommitDoneInfo) {
+ return func(t TableTxCommitDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -741,9 +664,9 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}
{
- h1 := t.OnSessionTransactionRollback
- h2 := x.OnSessionTransactionRollback
- ret.OnSessionTransactionRollback = func(t TableSessionTransactionRollbackStartInfo) func(TableSessionTransactionRollbackDoneInfo) {
+ h1 := t.OnTxRollback
+ h2 := x.OnTxRollback
+ ret.OnTxRollback = func(t TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -751,14 +674,14 @@ func (t *Table) Compose(x *Table, opts ...TableComposeOption) *Table {
}
}()
}
- var r, r1 func(TableSessionTransactionRollbackDoneInfo)
+ var r, r1 func(TableTxRollbackDoneInfo)
if h1 != nil {
r = h1(t)
}
if h2 != nil {
r1 = h2(t)
}
- return func(t TableSessionTransactionRollbackDoneInfo) {
+ return func(t TableTxRollbackDoneInfo) {
if options.panicCallback != nil {
defer func() {
if e := recover(); e != nil {
@@ -969,86 +892,50 @@ func (t *Table) onClose(t1 TableCloseStartInfo) func(TableCloseDoneInfo) {
}
return res
}
-func (t *Table) onDo(t1 TableDoStartInfo) func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
+func (t *Table) onDo(t1 TableDoStartInfo) func(TableDoDoneInfo) {
fn := t.OnDo
if fn == nil {
- return func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
- return func(TableDoDoneInfo) {
- return
- }
+ return func(TableDoDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableDoIntermediateInfo) func(TableDoDoneInfo) {
- return func(TableDoDoneInfo) {
- return
- }
- }
- }
- return func(info TableDoIntermediateInfo) func(TableDoDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableDoDoneInfo) {
- return
- }
+ return func(TableDoDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onDoTx(t1 TableDoTxStartInfo) func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
+func (t *Table) onDoTx(t1 TableDoTxStartInfo) func(TableDoTxDoneInfo) {
fn := t.OnDoTx
if fn == nil {
- return func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- return func(TableDoTxDoneInfo) {
- return
- }
+ return func(TableDoTxDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- return func(TableDoTxDoneInfo) {
- return
- }
- }
- }
- return func(info TableDoTxIntermediateInfo) func(TableDoTxDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableDoTxDoneInfo) {
- return
- }
+ return func(TableDoTxDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onCreateSession(t1 TableCreateSessionStartInfo) func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
+func (t *Table) onCreateSession(t1 TableCreateSessionStartInfo) func(TableCreateSessionDoneInfo) {
fn := t.OnCreateSession
if fn == nil {
- return func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- return func(TableCreateSessionDoneInfo) {
- return
- }
+ return func(TableCreateSessionDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- return func(TableCreateSessionDoneInfo) {
- return
- }
- }
- }
- return func(info TableCreateSessionIntermediateInfo) func(TableCreateSessionDoneInfo) {
- res := res(info)
- if res == nil {
- return func(TableCreateSessionDoneInfo) {
- return
- }
+ return func(TableCreateSessionDoneInfo) {
+ return
}
- return res
}
+ return res
}
func (t *Table) onSessionNew(t1 TableSessionNewStartInfo) func(TableSessionNewDoneInfo) {
fn := t.OnSessionNew
@@ -1155,77 +1042,53 @@ func (t *Table) onSessionQueryExplain(t1 TableExplainQueryStartInfo) func(TableE
}
return res
}
-func (t *Table) onSessionQueryStreamExecute(t1 TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
+func (t *Table) onSessionQueryStreamExecute(t1 TableSessionQueryStreamExecuteStartInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
fn := t.OnSessionQueryStreamExecute
if fn == nil {
- return func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamExecuteDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
- }
- }
- return func(t TableSessionQueryStreamExecuteIntermediateInfo) func(TableSessionQueryStreamExecuteDoneInfo) {
- res := res(t)
- if res == nil {
- return func(TableSessionQueryStreamExecuteDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamExecuteDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onSessionQueryStreamRead(t1 TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
+func (t *Table) onSessionQueryStreamRead(t1 TableSessionQueryStreamReadStartInfo) func(TableSessionQueryStreamReadDoneInfo) {
fn := t.OnSessionQueryStreamRead
if fn == nil {
- return func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamReadDoneInfo) {
+ return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
- }
- }
- return func(t TableSessionQueryStreamReadIntermediateInfo) func(TableSessionQueryStreamReadDoneInfo) {
- res := res(t)
- if res == nil {
- return func(TableSessionQueryStreamReadDoneInfo) {
- return
- }
+ return func(TableSessionQueryStreamReadDoneInfo) {
+ return
}
- return res
}
+ return res
}
-func (t *Table) onSessionTransactionBegin(t1 TableSessionTransactionBeginStartInfo) func(TableSessionTransactionBeginDoneInfo) {
- fn := t.OnSessionTransactionBegin
+func (t *Table) onTxBegin(t1 TableTxBeginStartInfo) func(TableTxBeginDoneInfo) {
+ fn := t.OnTxBegin
if fn == nil {
- return func(TableSessionTransactionBeginDoneInfo) {
+ return func(TableTxBeginDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionBeginDoneInfo) {
+ return func(TableTxBeginDoneInfo) {
return
}
}
return res
}
-func (t *Table) onSessionTransactionExecute(t1 TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
- fn := t.OnSessionTransactionExecute
+func (t *Table) onTxExecute(t1 TableTransactionExecuteStartInfo) func(TableTransactionExecuteDoneInfo) {
+ fn := t.OnTxExecute
if fn == nil {
return func(TableTransactionExecuteDoneInfo) {
return
@@ -1239,8 +1102,8 @@ func (t *Table) onSessionTransactionExecute(t1 TableTransactionExecuteStartInfo)
}
return res
}
-func (t *Table) onSessionTransactionExecuteStatement(t1 TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
- fn := t.OnSessionTransactionExecuteStatement
+func (t *Table) onTxExecuteStatement(t1 TableTransactionExecuteStatementStartInfo) func(TableTransactionExecuteStatementDoneInfo) {
+ fn := t.OnTxExecuteStatement
if fn == nil {
return func(TableTransactionExecuteStatementDoneInfo) {
return
@@ -1254,31 +1117,31 @@ func (t *Table) onSessionTransactionExecuteStatement(t1 TableTransactionExecuteS
}
return res
}
-func (t *Table) onSessionTransactionCommit(t1 TableSessionTransactionCommitStartInfo) func(TableSessionTransactionCommitDoneInfo) {
- fn := t.OnSessionTransactionCommit
+func (t *Table) onTxCommit(t1 TableTxCommitStartInfo) func(TableTxCommitDoneInfo) {
+ fn := t.OnTxCommit
if fn == nil {
- return func(TableSessionTransactionCommitDoneInfo) {
+ return func(TableTxCommitDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionCommitDoneInfo) {
+ return func(TableTxCommitDoneInfo) {
return
}
}
return res
}
-func (t *Table) onSessionTransactionRollback(t1 TableSessionTransactionRollbackStartInfo) func(TableSessionTransactionRollbackDoneInfo) {
- fn := t.OnSessionTransactionRollback
+func (t *Table) onTxRollback(t1 TableTxRollbackStartInfo) func(TableTxRollbackDoneInfo) {
+ fn := t.OnTxRollback
if fn == nil {
- return func(TableSessionTransactionRollbackDoneInfo) {
+ return func(TableTxRollbackDoneInfo) {
return
}
}
res := fn(t1)
if res == nil {
- return func(TableSessionTransactionRollbackDoneInfo) {
+ return func(TableTxRollbackDoneInfo) {
return
}
}
@@ -1350,6 +1213,7 @@ func (t *Table) onPoolWait(t1 TablePoolWaitStartInfo) func(TablePoolWaitDoneInfo
}
return res
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnInit(t *Table, c *context.Context, call call) func(limit int) {
var p TableInitStartInfo
p.Context = c
@@ -1361,6 +1225,7 @@ func TableOnInit(t *Table, c *context.Context, call call) func(limit int) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnClose(t *Table, c *context.Context, call call) func(error) {
var p TableCloseStartInfo
p.Context = c
@@ -1372,7 +1237,8 @@ func TableOnClose(t *Table, c *context.Context, call call) func(error) {
res(p)
}
}
-func TableOnDo(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnDo(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p TableDoStartInfo
p.Context = c
p.Call = call
@@ -1380,19 +1246,15 @@ func TableOnDo(t *Table, c *context.Context, call call, label string, idempotent
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onDo(p)
- return func(e error) func(int, error) {
- var p TableDoIntermediateInfo
+ return func(attempts int, e error) {
+ var p TableDoDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p TableDoDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnDoTx(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(error) func(attempts int, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnDoTx(t *Table, c *context.Context, call call, label string, idempotent bool, nestedCall bool) func(attempts int, _ error) {
var p TableDoTxStartInfo
p.Context = c
p.Call = call
@@ -1400,36 +1262,28 @@ func TableOnDoTx(t *Table, c *context.Context, call call, label string, idempote
p.Idempotent = idempotent
p.NestedCall = nestedCall
res := t.onDoTx(p)
- return func(e error) func(int, error) {
- var p TableDoTxIntermediateInfo
+ return func(attempts int, e error) {
+ var p TableDoTxDoneInfo
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(attempts int, e error) {
- var p TableDoTxDoneInfo
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnCreateSession(t *Table, c *context.Context, call call) func(error) func(session tableSessionInfo, attempts int, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnCreateSession(t *Table, c *context.Context, call call) func(session tableSessionInfo, attempts int, _ error) {
var p TableCreateSessionStartInfo
p.Context = c
p.Call = call
res := t.onCreateSession(p)
- return func(e error) func(tableSessionInfo, int, error) {
- var p TableCreateSessionIntermediateInfo
+ return func(session tableSessionInfo, attempts int, e error) {
+ var p TableCreateSessionDoneInfo
+ p.Session = session
+ p.Attempts = attempts
p.Error = e
- res := res(p)
- return func(session tableSessionInfo, attempts int, e error) {
- var p TableCreateSessionDoneInfo
- p.Session = session
- p.Attempts = attempts
- p.Error = e
- res(p)
- }
+ res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionNew(t *Table, c *context.Context, call call) func(session tableSessionInfo, _ error) {
var p TableSessionNewStartInfo
p.Context = c
@@ -1442,6 +1296,7 @@ func TableOnSessionNew(t *Table, c *context.Context, call call) func(session tab
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionDelete(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TableSessionDeleteStartInfo
p.Context = c
@@ -1454,6 +1309,7 @@ func TableOnSessionDelete(t *Table, c *context.Context, call call, session table
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionKeepAlive(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TableKeepAliveStartInfo
p.Context = c
@@ -1466,6 +1322,7 @@ func TableOnSessionKeepAlive(t *Table, c *context.Context, call call, session ta
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionBulkUpsert(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TableBulkUpsertStartInfo
p.Context = c
@@ -1478,6 +1335,7 @@ func TableOnSessionBulkUpsert(t *Table, c *context.Context, call call, session t
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionQueryPrepare(t *Table, c *context.Context, call call, session tableSessionInfo, query string) func(result tableDataQuery, _ error) {
var p TablePrepareDataQueryStartInfo
p.Context = c
@@ -1492,6 +1350,7 @@ func TableOnSessionQueryPrepare(t *Table, c *context.Context, call call, session
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionQueryExecute(t *Table, c *context.Context, call call, session tableSessionInfo, query tableDataQuery, parameters tableQueryParameters, keepInCache bool) func(tx tableTransactionInfo, prepared bool, result tableResult, _ error) {
var p TableExecuteDataQueryStartInfo
p.Context = c
@@ -1510,6 +1369,7 @@ func TableOnSessionQueryExecute(t *Table, c *context.Context, call call, session
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnSessionQueryExplain(t *Table, c *context.Context, call call, session tableSessionInfo, query string) func(aST string, plan string, _ error) {
var p TableExplainQueryStartInfo
p.Context = c
@@ -1525,7 +1385,8 @@ func TableOnSessionQueryExplain(t *Table, c *context.Context, call call, session
res(p)
}
}
-func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, session tableSessionInfo, query tableDataQuery, parameters tableQueryParameters) func(error) func(error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, session tableSessionInfo, query tableDataQuery, parameters tableQueryParameters) func(error) {
var p TableSessionQueryStreamExecuteStartInfo
p.Context = c
p.Call = call
@@ -1533,48 +1394,41 @@ func TableOnSessionQueryStreamExecute(t *Table, c *context.Context, call call, s
p.Query = query
p.Parameters = parameters
res := t.onSessionQueryStreamExecute(p)
- return func(e error) func(error) {
- var p TableSessionQueryStreamExecuteIntermediateInfo
+ return func(e error) {
+ var p TableSessionQueryStreamExecuteDoneInfo
p.Error = e
- res := res(p)
- return func(e error) {
- var p TableSessionQueryStreamExecuteDoneInfo
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnSessionQueryStreamRead(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) func(error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnSessionQueryStreamRead(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TableSessionQueryStreamReadStartInfo
p.Context = c
p.Call = call
p.Session = session
res := t.onSessionQueryStreamRead(p)
- return func(e error) func(error) {
- var p TableSessionQueryStreamReadIntermediateInfo
+ return func(e error) {
+ var p TableSessionQueryStreamReadDoneInfo
p.Error = e
- res := res(p)
- return func(e error) {
- var p TableSessionQueryStreamReadDoneInfo
- p.Error = e
- res(p)
- }
+ res(p)
}
}
-func TableOnSessionTransactionBegin(t *Table, c *context.Context, call call, session tableSessionInfo) func(tx tableTransactionInfo, _ error) {
- var p TableSessionTransactionBeginStartInfo
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnTxBegin(t *Table, c *context.Context, call call, session tableSessionInfo) func(tx tableTransactionInfo, _ error) {
+ var p TableTxBeginStartInfo
p.Context = c
p.Call = call
p.Session = session
- res := t.onSessionTransactionBegin(p)
+ res := t.onTxBegin(p)
return func(tx tableTransactionInfo, e error) {
- var p TableSessionTransactionBeginDoneInfo
+ var p TableTxBeginDoneInfo
p.Tx = tx
p.Error = e
res(p)
}
}
-func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, query tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnTxExecute(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, query tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
var p TableTransactionExecuteStartInfo
p.Context = c
p.Call = call
@@ -1582,7 +1436,7 @@ func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, s
p.Tx = tx
p.Query = query
p.Parameters = parameters
- res := t.onSessionTransactionExecute(p)
+ res := t.onTxExecute(p)
return func(result tableResult, e error) {
var p TableTransactionExecuteDoneInfo
p.Result = result
@@ -1590,7 +1444,8 @@ func TableOnSessionTransactionExecute(t *Table, c *context.Context, call call, s
res(p)
}
}
-func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, statementQuery tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnTxExecuteStatement(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo, statementQuery tableDataQuery, parameters tableQueryParameters) func(result tableResult, _ error) {
var p TableTransactionExecuteStatementStartInfo
p.Context = c
p.Call = call
@@ -1598,7 +1453,7 @@ func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, cal
p.Tx = tx
p.StatementQuery = statementQuery
p.Parameters = parameters
- res := t.onSessionTransactionExecuteStatement(p)
+ res := t.onTxExecuteStatement(p)
return func(result tableResult, e error) {
var p TableTransactionExecuteStatementDoneInfo
p.Result = result
@@ -1606,48 +1461,54 @@ func TableOnSessionTransactionExecuteStatement(t *Table, c *context.Context, cal
res(p)
}
}
-func TableOnSessionTransactionCommit(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
- var p TableSessionTransactionCommitStartInfo
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnTxCommit(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
+ var p TableTxCommitStartInfo
p.Context = c
p.Call = call
p.Session = session
p.Tx = tx
- res := t.onSessionTransactionCommit(p)
+ res := t.onTxCommit(p)
return func(e error) {
- var p TableSessionTransactionCommitDoneInfo
+ var p TableTxCommitDoneInfo
p.Error = e
res(p)
}
}
-func TableOnSessionTransactionRollback(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
- var p TableSessionTransactionRollbackStartInfo
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func TableOnTxRollback(t *Table, c *context.Context, call call, session tableSessionInfo, tx tableTransactionInfo) func(error) {
+ var p TableTxRollbackStartInfo
p.Context = c
p.Call = call
p.Session = session
p.Tx = tx
- res := t.onSessionTransactionRollback(p)
+ res := t.onTxRollback(p)
return func(e error) {
- var p TableSessionTransactionRollbackDoneInfo
+ var p TableTxRollbackDoneInfo
p.Error = e
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolStateChange(t *Table, size int, event string) {
var p TablePoolStateChangeInfo
p.Size = size
p.Event = event
t.onPoolStateChange(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolSessionAdd(t *Table, session tableSessionInfo) {
var p TablePoolSessionAddInfo
p.Session = session
t.onPoolSessionAdd(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolSessionRemove(t *Table, session tableSessionInfo) {
var p TablePoolSessionRemoveInfo
p.Session = session
t.onPoolSessionRemove(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolPut(t *Table, c *context.Context, call call, session tableSessionInfo) func(error) {
var p TablePoolPutStartInfo
p.Context = c
@@ -1660,6 +1521,7 @@ func TableOnPoolPut(t *Table, c *context.Context, call call, session tableSessio
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolGet(t *Table, c *context.Context, call call) func(session tableSessionInfo, attempts int, _ error) {
var p TablePoolGetStartInfo
p.Context = c
@@ -1673,6 +1535,7 @@ func TableOnPoolGet(t *Table, c *context.Context, call call) func(session tableS
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TableOnPoolWait(t *Table, c *context.Context, call call) func(session tableSessionInfo, _ error) {
var p TablePoolWaitStartInfo
p.Context = c
diff --git a/trace/topic.go b/trace/topic.go
index b6498b52e..53077a3b8 100644
--- a/trace/topic.go
+++ b/trace/topic.go
@@ -11,23 +11,29 @@ import (
type (
// Topic specified trace of topic reader client activity.
// gtrace:gen
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
Topic struct {
// TopicReaderCustomerEvents - upper level, on bridge with customer code
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderStart func(info TopicReaderStartInfo)
// TopicReaderStreamLifeCycleEvents
- OnReaderReconnect func(TopicReaderReconnectStartInfo) func(TopicReaderReconnectDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderReconnect func(TopicReaderReconnectStartInfo) func(TopicReaderReconnectDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderReconnectRequest func(TopicReaderReconnectRequestInfo)
// TopicReaderPartitionEvents
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderPartitionReadStartResponse func(
TopicReaderPartitionReadStartResponseStartInfo,
) func(
TopicReaderPartitionReadStartResponseDoneInfo,
)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderPartitionReadStopResponse func(
TopicReaderPartitionReadStopResponseStartInfo,
) func(
@@ -36,13 +42,20 @@ type (
// TopicReaderStreamEvents
- OnReaderCommit func(TopicReaderCommitStartInfo) func(TopicReaderCommitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderCommit func(TopicReaderCommitStartInfo) func(TopicReaderCommitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderSendCommitMessage func(TopicReaderSendCommitMessageStartInfo) func(TopicReaderSendCommitMessageDoneInfo)
- OnReaderCommittedNotify func(TopicReaderCommittedNotifyInfo)
- OnReaderClose func(TopicReaderCloseStartInfo) func(TopicReaderCloseDoneInfo)
- OnReaderInit func(TopicReaderInitStartInfo) func(TopicReaderInitDoneInfo)
- OnReaderError func(TopicReaderErrorInfo)
- OnReaderUpdateToken func(
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderCommittedNotify func(TopicReaderCommittedNotifyInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderClose func(TopicReaderCloseStartInfo) func(TopicReaderCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderInit func(TopicReaderInitStartInfo) func(TopicReaderInitDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderError func(TopicReaderErrorInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderUpdateToken func(
OnReadUpdateTokenStartInfo,
) func(
OnReadUpdateTokenMiddleTokenReceivedInfo,
@@ -52,24 +65,35 @@ type (
// TopicReaderMessageEvents
- OnReaderSentDataRequest func(TopicReaderSentDataRequestInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderSentDataRequest func(TopicReaderSentDataRequestInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReaderReceiveDataResponse func(TopicReaderReceiveDataResponseStartInfo) func(TopicReaderReceiveDataResponseDoneInfo)
- OnReaderReadMessages func(TopicReaderReadMessagesStartInfo) func(TopicReaderReadMessagesDoneInfo)
- OnReaderUnknownGrpcMessage func(OnReadUnknownGrpcMessageInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderReadMessages func(TopicReaderReadMessagesStartInfo) func(TopicReaderReadMessagesDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnReaderUnknownGrpcMessage func(OnReadUnknownGrpcMessageInfo)
// TopicWriterStreamLifeCycleEvents
- OnWriterReconnect func(TopicWriterReconnectStartInfo) func(TopicWriterReconnectDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWriterReconnect func(TopicWriterReconnectStartInfo) func(TopicWriterReconnectDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnWriterInitStream func(TopicWriterInitStreamStartInfo) func(TopicWriterInitStreamDoneInfo)
- OnWriterClose func(TopicWriterCloseStartInfo) func(TopicWriterCloseDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWriterClose func(TopicWriterCloseStartInfo) func(TopicWriterCloseDoneInfo)
// TopicWriterStreamEvents
- OnWriterCompressMessages func(TopicWriterCompressMessagesStartInfo) func(TopicWriterCompressMessagesDoneInfo)
- OnWriterSendMessages func(TopicWriterSendMessagesStartInfo) func(TopicWriterSendMessagesDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWriterCompressMessages func(TopicWriterCompressMessagesStartInfo) func(TopicWriterCompressMessagesDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnWriterSendMessages func(TopicWriterSendMessagesStartInfo) func(TopicWriterSendMessagesDoneInfo)
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnWriterReadUnknownGrpcMessage func(TopicOnWriterReadUnknownGrpcMessageInfo)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderPartitionReadStartResponseStartInfo struct {
ReaderConnectionID string
PartitionContext context.Context
@@ -78,17 +102,20 @@ type (
PartitionSessionID int64
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderStartInfo struct {
ReaderID int64
Consumer string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderPartitionReadStartResponseDoneInfo struct {
ReadOffset *int64
CommitOffset *int64
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderPartitionReadStopResponseStartInfo struct {
ReaderConnectionID string
PartitionContext context.Context
@@ -99,14 +126,17 @@ type (
Graceful bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderPartitionReadStopResponseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderSendCommitMessageStartInfo struct {
CommitsInfo TopicReaderStreamSendCommitMessageStartMessageInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderStreamCommitInfo struct {
Topic string
PartitionID int64
@@ -115,14 +145,17 @@ type (
EndOffset int64
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderStreamSendCommitMessageStartMessageInfo interface {
GetCommitsInfo() []TopicReaderStreamCommitInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderSendCommitMessageDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderCommittedNotifyInfo struct {
ReaderConnectionID string
Topic string
@@ -131,32 +164,38 @@ type (
CommittedOffset int64
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderErrorInfo struct {
ReaderConnectionID string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderSentDataRequestInfo struct {
ReaderConnectionID string
RequestBytes int
LocalBufferSizeAfterSent int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReceiveDataResponseStartInfo struct {
ReaderConnectionID string
LocalBufferSizeAfterReceive int
DataResponse TopicReaderDataResponseInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderDataResponseInfo interface {
GetBytesSize() int
GetPartitionBatchMessagesCounts() (partitionCount, batchCount, messagesCount int)
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReceiveDataResponseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReadMessagesStartInfo struct {
RequestContext context.Context
MinCount int
@@ -164,6 +203,7 @@ type (
FreeBufferCapacity int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReadMessagesDoneInfo struct {
MessagesCount int
Topic string
@@ -175,24 +215,29 @@ type (
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReadUnknownGrpcMessageInfo struct {
ReaderConnectionID string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReconnectStartInfo struct {
Reason error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReconnectDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderReconnectRequestInfo struct {
Reason error
WasSent bool
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderCommitStartInfo struct {
RequestContext context.Context
Topic string
@@ -202,43 +247,52 @@ type (
EndOffset int64
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderCommitDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderCloseStartInfo struct {
ReaderConnectionID string
CloseReason error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderCloseDoneInfo struct {
CloseError error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderInitStartInfo struct {
PreInitReaderConnectionID string
InitRequestInfo TopicReadStreamInitRequestInfo
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReadStreamInitRequestInfo interface {
GetConsumer() string
GetTopics() []string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicReaderInitDoneInfo struct {
ReaderConnectionID string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReadUpdateTokenStartInfo struct {
ReaderConnectionID string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReadUpdateTokenMiddleTokenReceivedInfo struct {
TokenLen int
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
OnReadStreamUpdateTokenDoneInfo struct {
Error error
}
@@ -247,6 +301,7 @@ type (
//////////// TopicWriter
////////////
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterReconnectStartInfo struct {
WriterInstanceID string
Topic string
@@ -254,30 +309,36 @@ type (
Attempt int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterReconnectDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterInitStreamStartInfo struct {
WriterInstanceID string
Topic string
ProducerID string
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterInitStreamDoneInfo struct {
SessionID string
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterCloseStartInfo struct {
WriterInstanceID string
Reason error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterCloseDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterCompressMessagesStartInfo struct {
WriterInstanceID string
SessionID string
@@ -287,10 +348,12 @@ type (
Reason TopicWriterCompressMessagesReason
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterCompressMessagesDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterSendMessagesStartInfo struct {
WriterInstanceID string
SessionID string
@@ -299,10 +362,12 @@ type (
MessagesCount int
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicWriterSendMessagesDoneInfo struct {
Error error
}
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
TopicOnWriterReadUnknownGrpcMessageInfo struct {
WriterInstanceID string
SessionID string
@@ -310,14 +375,19 @@ type (
}
)
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type TopicWriterCompressMessagesReason string
const (
- TopicWriterCompressMessagesReasonCompressData = TopicWriterCompressMessagesReason("compress-on-send") //nolint:lll
- TopicWriterCompressMessagesReasonCompressDataOnWriteReadData = TopicWriterCompressMessagesReason("compress-on-call-write") //nolint:lll
- TopicWriterCompressMessagesReasonCodecsMeasure = TopicWriterCompressMessagesReason("compress-on-codecs-measure") //nolint:lll
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TopicWriterCompressMessagesReasonCompressData = TopicWriterCompressMessagesReason("compress-on-send")
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TopicWriterCompressMessagesReasonCompressDataOnWriteReadData = TopicWriterCompressMessagesReason("compress-on-call-write") //nolint:lll
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ TopicWriterCompressMessagesReasonCodecsMeasure = TopicWriterCompressMessagesReason("compress-on-codecs-measure") //nolint:lll
)
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (r TopicWriterCompressMessagesReason) String() string {
return string(r)
}
diff --git a/trace/topic_gtrace.go b/trace/topic_gtrace.go
index 8fa1c6b45..5f9dcde80 100644
--- a/trace/topic_gtrace.go
+++ b/trace/topic_gtrace.go
@@ -12,9 +12,11 @@ type topicComposeOptions struct {
}
// TopicOption specified Topic compose option
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
type TopicComposeOption func(o *topicComposeOptions)
// WithTopicPanicCallback specified behavior on panic
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func WithTopicPanicCallback(cb func(e interface{})) TopicComposeOption {
return func(o *topicComposeOptions) {
o.panicCallback = cb
@@ -22,6 +24,7 @@ func WithTopicPanicCallback(cb func(e interface{})) TopicComposeOption {
}
// Compose returns a new Topic which has functional fields composed both from t and x.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func (t *Topic) Compose(x *Topic, opts ...TopicComposeOption) *Topic {
var ret Topic
options := topicComposeOptions{}
@@ -992,12 +995,14 @@ func (t *Topic) onWriterReadUnknownGrpcMessage(t1 TopicOnWriterReadUnknownGrpcMe
}
fn(t1)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderStart(t *Topic, readerID int64, consumer string) {
var p TopicReaderStartInfo
p.ReaderID = readerID
p.Consumer = consumer
t.onReaderStart(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderReconnect(t *Topic, reason error) func(error) {
var p TopicReaderReconnectStartInfo
p.Reason = reason
@@ -1008,12 +1013,14 @@ func TopicOnReaderReconnect(t *Topic, reason error) func(error) {
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderReconnectRequest(t *Topic, reason error, wasSent bool) {
var p TopicReaderReconnectRequestInfo
p.Reason = reason
p.WasSent = wasSent
t.onReaderReconnectRequest(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderPartitionReadStartResponse(t *Topic, readerConnectionID string, partitionContext context.Context, topic string, partitionID int64, partitionSessionID int64) func(readOffset *int64, commitOffset *int64, _ error) {
var p TopicReaderPartitionReadStartResponseStartInfo
p.ReaderConnectionID = readerConnectionID
@@ -1030,6 +1037,7 @@ func TopicOnReaderPartitionReadStartResponse(t *Topic, readerConnectionID string
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderPartitionReadStopResponse(t *Topic, readerConnectionID string, partitionContext context.Context, topic string, partitionID int64, partitionSessionID int64, committedOffset int64, graceful bool) func(error) {
var p TopicReaderPartitionReadStopResponseStartInfo
p.ReaderConnectionID = readerConnectionID
@@ -1046,6 +1054,7 @@ func TopicOnReaderPartitionReadStopResponse(t *Topic, readerConnectionID string,
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderCommit(t *Topic, requestContext context.Context, topic string, partitionID int64, partitionSessionID int64, startOffset int64, endOffset int64) func(error) {
var p TopicReaderCommitStartInfo
p.RequestContext = requestContext
@@ -1061,6 +1070,7 @@ func TopicOnReaderCommit(t *Topic, requestContext context.Context, topic string,
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderSendCommitMessage(t *Topic, commitsInfo TopicReaderStreamSendCommitMessageStartMessageInfo) func(error) {
var p TopicReaderSendCommitMessageStartInfo
p.CommitsInfo = commitsInfo
@@ -1071,6 +1081,7 @@ func TopicOnReaderSendCommitMessage(t *Topic, commitsInfo TopicReaderStreamSendC
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderCommittedNotify(t *Topic, readerConnectionID string, topic string, partitionID int64, partitionSessionID int64, committedOffset int64) {
var p TopicReaderCommittedNotifyInfo
p.ReaderConnectionID = readerConnectionID
@@ -1080,6 +1091,7 @@ func TopicOnReaderCommittedNotify(t *Topic, readerConnectionID string, topic str
p.CommittedOffset = committedOffset
t.onReaderCommittedNotify(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderClose(t *Topic, readerConnectionID string, closeReason error) func(closeError error) {
var p TopicReaderCloseStartInfo
p.ReaderConnectionID = readerConnectionID
@@ -1091,6 +1103,7 @@ func TopicOnReaderClose(t *Topic, readerConnectionID string, closeReason error)
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderInit(t *Topic, preInitReaderConnectionID string, initRequestInfo TopicReadStreamInitRequestInfo) func(readerConnectionID string, _ error) {
var p TopicReaderInitStartInfo
p.PreInitReaderConnectionID = preInitReaderConnectionID
@@ -1103,12 +1116,14 @@ func TopicOnReaderInit(t *Topic, preInitReaderConnectionID string, initRequestIn
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderError(t *Topic, readerConnectionID string, e error) {
var p TopicReaderErrorInfo
p.ReaderConnectionID = readerConnectionID
p.Error = e
t.onReaderError(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderUpdateToken(t *Topic, readerConnectionID string) func(tokenLen int, _ error) func(error) {
var p OnReadUpdateTokenStartInfo
p.ReaderConnectionID = readerConnectionID
@@ -1125,6 +1140,7 @@ func TopicOnReaderUpdateToken(t *Topic, readerConnectionID string) func(tokenLen
}
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderSentDataRequest(t *Topic, readerConnectionID string, requestBytes int, localBufferSizeAfterSent int) {
var p TopicReaderSentDataRequestInfo
p.ReaderConnectionID = readerConnectionID
@@ -1132,6 +1148,7 @@ func TopicOnReaderSentDataRequest(t *Topic, readerConnectionID string, requestBy
p.LocalBufferSizeAfterSent = localBufferSizeAfterSent
t.onReaderSentDataRequest(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderReceiveDataResponse(t *Topic, readerConnectionID string, localBufferSizeAfterReceive int, dataResponse TopicReaderDataResponseInfo) func(error) {
var p TopicReaderReceiveDataResponseStartInfo
p.ReaderConnectionID = readerConnectionID
@@ -1144,6 +1161,7 @@ func TopicOnReaderReceiveDataResponse(t *Topic, readerConnectionID string, local
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderReadMessages(t *Topic, requestContext context.Context, minCount int, maxCount int, freeBufferCapacity int) func(messagesCount int, topic string, partitionID int64, partitionSessionID int64, offsetStart int64, offsetEnd int64, freeBufferCapacity int, _ error) {
var p TopicReaderReadMessagesStartInfo
p.RequestContext = requestContext
@@ -1164,12 +1182,14 @@ func TopicOnReaderReadMessages(t *Topic, requestContext context.Context, minCoun
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnReaderUnknownGrpcMessage(t *Topic, readerConnectionID string, e error) {
var p OnReadUnknownGrpcMessageInfo
p.ReaderConnectionID = readerConnectionID
p.Error = e
t.onReaderUnknownGrpcMessage(p)
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterReconnect(t *Topic, writerInstanceID string, topic string, producerID string, attempt int) func(error) {
var p TopicWriterReconnectStartInfo
p.WriterInstanceID = writerInstanceID
@@ -1183,6 +1203,7 @@ func TopicOnWriterReconnect(t *Topic, writerInstanceID string, topic string, pro
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterInitStream(t *Topic, writerInstanceID string, topic string, producerID string) func(sessionID string, _ error) {
var p TopicWriterInitStreamStartInfo
p.WriterInstanceID = writerInstanceID
@@ -1196,6 +1217,7 @@ func TopicOnWriterInitStream(t *Topic, writerInstanceID string, topic string, pr
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterClose(t *Topic, writerInstanceID string, reason error) func(error) {
var p TopicWriterCloseStartInfo
p.WriterInstanceID = writerInstanceID
@@ -1207,6 +1229,7 @@ func TopicOnWriterClose(t *Topic, writerInstanceID string, reason error) func(er
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterCompressMessages(t *Topic, writerInstanceID string, sessionID string, codec int32, firstSeqNo int64, messagesCount int, reason TopicWriterCompressMessagesReason) func(error) {
var p TopicWriterCompressMessagesStartInfo
p.WriterInstanceID = writerInstanceID
@@ -1222,6 +1245,7 @@ func TopicOnWriterCompressMessages(t *Topic, writerInstanceID string, sessionID
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterSendMessages(t *Topic, writerInstanceID string, sessionID string, codec int32, firstSeqNo int64, messagesCount int) func(error) {
var p TopicWriterSendMessagesStartInfo
p.WriterInstanceID = writerInstanceID
@@ -1236,6 +1260,7 @@ func TopicOnWriterSendMessages(t *Topic, writerInstanceID string, sessionID stri
res(p)
}
}
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
func TopicOnWriterReadUnknownGrpcMessage(t *Topic, writerInstanceID string, sessionID string, e error) {
var p TopicOnWriterReadUnknownGrpcMessageInfo
p.WriterInstanceID = writerInstanceID
diff --git a/trace/trace_test.go b/trace/trace_test.go
index fbdf19668..b10945067 100644
--- a/trace/trace_test.go
+++ b/trace/trace_test.go
@@ -6,6 +6,82 @@ import (
"testing"
)
+// Stub is a helper function that stubs all functional fields of x with given f.
+func Stub(x interface{}, f func(name string, args ...interface{})) {
+ (FieldStubber{
+ OnCall: f,
+ }).Stub(reflect.ValueOf(x))
+}
+
+func ClearContext(x interface{}) interface{} {
+ p := reflect.ValueOf(x).Index(0)
+ t := p.Elem().Type()
+ f, has := t.FieldByName("Context")
+ if has && f.Type.Kind() == reflect.Interface {
+ x := reflect.New(t)
+ x.Elem().Set(p.Elem())
+ c := x.Elem().FieldByName(f.Name)
+ c.Set(reflect.Zero(c.Type()))
+ p.Set(x)
+ }
+
+ return p.Interface()
+}
+
+// FieldStubber contains options of filling all struct functional fields.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+type FieldStubber struct {
+ // OnStub is an optional callback that is called when field getting
+ // stubbed.
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnStub func(name string)
+
+ // OnCall is an optional callback that will be called for each stubbed
+ // field getting called.
+ // Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+ OnCall func(name string, args ...interface{})
+}
+
+// Stub fills in given x struct.
+// Internals: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#internals
+func (f FieldStubber) Stub(x reflect.Value) {
+ var (
+ v = x.Elem()
+ t = v.Type()
+ )
+ for i := 0; i < t.NumField(); i++ {
+ var (
+ fx = v.Field(i)
+ ft = fx.Type()
+ )
+ if ft.Kind() != reflect.Func {
+ continue
+ }
+ name := t.Field(i).Name
+ if f.OnStub != nil {
+ f.OnStub(name)
+ }
+ out := []reflect.Value{}
+ for i := 0; i < ft.NumOut(); i++ {
+ ti := reflect.New(ft.Out(i)).Elem()
+ out = append(out, ti)
+ }
+ fn := reflect.MakeFunc(ft, func(args []reflect.Value) []reflect.Value {
+ if f.OnCall == nil {
+ return out
+ }
+ params := make([]interface{}, len(args))
+ for i, arg := range args {
+ params[i] = arg.Interface()
+ }
+ f.OnCall(name, params...)
+
+ return out
+ })
+ fx.Set(fn)
+ }
+}
+
func TestTable(t *testing.T) {
testSingleTrace(t, &Table{}, "Table")
}
diff --git a/trace/traceutil.go b/trace/traceutil.go
deleted file mode 100644
index 8ad52bfb6..000000000
--- a/trace/traceutil.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package trace
-
-import (
- "reflect"
-)
-
-// Stub is a helper function that stubs all functional fields of x with given
-// f.
-func Stub(x interface{}, f func(name string, args ...interface{})) {
- (FieldStubber{
- OnCall: f,
- }).Stub(reflect.ValueOf(x))
-}
-
-func ClearContext(x interface{}) interface{} {
- p := reflect.ValueOf(x).Index(0)
- t := p.Elem().Type()
- f, has := t.FieldByName("Context")
- if has && f.Type.Kind() == reflect.Interface {
- x := reflect.New(t)
- x.Elem().Set(p.Elem())
- c := x.Elem().FieldByName(f.Name)
- c.Set(reflect.Zero(c.Type()))
- p.Set(x)
- }
-
- return p.Interface()
-}
-
-// FieldStubber contains options of filling all struct functional fields.
-type FieldStubber struct {
- // OnStub is an optional callback that is called when field getting
- // stubbed.
- OnStub func(name string)
-
- // OnCall is an optional callback that will be called for each stubbed
- // field getting called.
- OnCall func(name string, args ...interface{})
-}
-
-// Stub fills in given x struct.
-func (f FieldStubber) Stub(x reflect.Value) {
- var (
- v = x.Elem()
- t = v.Type()
- )
- for i := 0; i < t.NumField(); i++ {
- var (
- fx = v.Field(i)
- ft = fx.Type()
- )
- if ft.Kind() != reflect.Func {
- continue
- }
- name := t.Field(i).Name
- if f.OnStub != nil {
- f.OnStub(name)
- }
- out := []reflect.Value{}
- for i := 0; i < ft.NumOut(); i++ {
- ti := reflect.New(ft.Out(i)).Elem()
- out = append(out, ti)
- }
- fn := reflect.MakeFunc(ft, func(args []reflect.Value) []reflect.Value {
- if f.OnCall == nil {
- return out
- }
- params := make([]interface{}, len(args))
- for i, arg := range args {
- params[i] = arg.Interface()
- }
- f.OnCall(name, params...)
-
- return out
- })
- fx.Set(fn)
- }
-}
diff --git a/with.go b/with.go
index 248ae9435..c226db991 100644
--- a/with.go
+++ b/with.go
@@ -49,7 +49,7 @@ func (d *Driver) With(ctx context.Context, opts ...Option) (*Driver, error) {
onDone := trace.DriverOnWith(
d.trace(), &ctx,
- stack.FunctionID(""),
+ stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/ydb.(*Driver).With"),
d.config.Endpoint(), d.config.Database(), d.config.Secure(),
)
defer func() {