Skip to content

Commit c22ecc5

Browse files
committed
merged with other changes
2 parents 7a2ad8c + 0b1ca60 commit c22ecc5

File tree

2 files changed

+70
-48
lines changed

2 files changed

+70
-48
lines changed

SQL.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ Behind the scene, `database/sql` APIs are implemented using the native interface
99
1. [Initialization of `database/sql` driver](#init)
1010
* [Configure driver with `ydb.Connector` (recommended way)](#init-connector)
1111
* [Configure driver with data source name or connection string](#init-dsn)
12-
2. [Query execution](#queries)
12+
2. [Session pooling](#session-pool)
13+
3. [Query execution](#queries)
1314
* [Queries on database object](#queries-db)
1415
* [Queries on transaction object](#queries-tx)
15-
3. [Query modes (DDL, DML, DQL, etc.)](#query-modes)
16-
4. [Changing the transaction control mode](#tx-control)
17-
5. [Retry helpers for `YDB` `database/sql` driver](#retry)
16+
4. [Query modes (DDL, DML, DQL, etc.)](#query-modes)
17+
5. [Changing the transaction control mode](#tx-control)
18+
6. [Retry helpers for `YDB` `database/sql` driver](#retry)
1819
* [Retries over `sql.Conn` object](#retry-conn)
1920
* [Retries over `sql.Tx`](#retry-tx)
20-
6. [Specifying query parameters](#arg-types)
21-
7. [Accessing the native driver from `*sql.DB`](#unwrap)
21+
7. [Specifying query parameters](#arg-types)
22+
8. [Accessing the native driver from `*sql.DB`](#unwrap)
2223

2324
## Initialization of `database/sql` driver <a name="init"></a>
2425

@@ -61,6 +62,18 @@ Data source name parameters:
6162
* static credentials with authority part of URI, like `grpcs://root:password@localhost:2135/local`
6263
* `query_mode=scripting` - you can redefine default [DML](https://en.wikipedia.org/wiki/Data_manipulation_language) query mode
6364

65+
## Session pooling <a name="session-pool"></a>
66+
67+
Native driver `ydb-go-sdk/v3` implements the internal session pool, which uses with `db.Table().Do()` or `db.Table().DoTx()` methods.
68+
Internal session pool is configured with options like `ydb.WithSessionPoolSizeLimit()` and other.
69+
Unlike the session pool in the native driver, `database/sql` contains a different implementation of the session pool, which is configured with `*sql.DB.SetMaxOpenConns` and `*sql.DB.SetMaxIdleConns`.
70+
Lifetime of a `YDB` session depends on driver configuration and error occurance, such as `sql.driver.ErrBadConn`.
71+
`YDB` driver for `database/sql` includes the logic to transform the internal `YDB` error codes into `sql.driver.ErrBadConn` and other retryable and non-retryable error types.
72+
73+
In most cases the implementation of `database/sql` driver for YDB allows to complete queries without user-visible errors.
74+
But some errors need to be handled on the client side, by re-running not a single operation, but a complete transaction.
75+
Therefore the transaction logic needs to be wrapped with retry helpers, such as `retry.Do` or `retry.DoTx` (see more about retry helpers in the [retry section](#retry)).
76+
6477
## Query execution <a name="queries"></a>
6578

6679
### Queries on database object <a name="queries-db"></a>

internal/table/client.go

Lines changed: 51 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -138,54 +138,63 @@ func (c *Client) createSession(ctx context.Context, opts ...createSessionOption)
138138
return nil, xerrors.WithStackTrace(errClosedClient)
139139
}
140140

141-
c.spawnedGoroutines.Add(1)
142-
go func() {
143-
defer c.spawnedGoroutines.Done()
144-
145-
var (
146-
s *session
147-
err error
148-
)
149-
150-
createSessionCtx := xcontext.WithoutDeadline(ctx)
141+
select {
142+
case <-c.done:
143+
return nil, xerrors.WithStackTrace(errClosedClient)
151144

152-
if timeout := c.config.CreateSessionTimeout(); timeout > 0 {
153-
var cancel context.CancelFunc
154-
createSessionCtx, cancel = context.WithTimeout(createSessionCtx, timeout)
155-
defer cancel()
156-
}
145+
case <-ctx.Done():
146+
return nil, xerrors.WithStackTrace(ctx.Err())
157147

158-
s, err = c.build(createSessionCtx)
148+
default:
149+
c.spawnedGoroutines.Add(1)
150+
go func() {
151+
defer c.spawnedGoroutines.Done()
159152

160-
closeSession := func(s *session) {
161-
if s == nil {
162-
return
163-
}
153+
var (
154+
s *session
155+
err error
156+
)
164157

165-
closeSessionCtx := xcontext.WithoutDeadline(ctx)
158+
createSessionCtx := xcontext.WithoutDeadline(ctx)
166159

167-
if timeout := c.config.DeleteTimeout(); timeout > 0 {
160+
if timeout := c.config.CreateSessionTimeout(); timeout > 0 {
168161
var cancel context.CancelFunc
169-
createSessionCtx, cancel = context.WithTimeout(closeSessionCtx, timeout)
162+
createSessionCtx, cancel = context.WithTimeout(createSessionCtx, timeout)
170163
defer cancel()
171164
}
172165

173-
_ = s.Close(ctx)
174-
}
166+
s, err = c.build(createSessionCtx)
175167

176-
select {
177-
case ch <- result{
178-
s: s,
179-
err: err,
180-
}: // nop
168+
closeSession := func(s *session) {
169+
if s == nil {
170+
return
171+
}
181172

182-
case <-c.done:
183-
closeSession(s)
173+
closeSessionCtx := xcontext.WithoutDeadline(ctx)
184174

185-
case <-ctx.Done():
186-
closeSession(s)
187-
}
188-
}()
175+
if timeout := c.config.DeleteTimeout(); timeout > 0 {
176+
var cancel context.CancelFunc
177+
createSessionCtx, cancel = context.WithTimeout(closeSessionCtx, timeout)
178+
defer cancel()
179+
}
180+
181+
_ = s.Close(ctx)
182+
}
183+
184+
select {
185+
case ch <- result{
186+
s: s,
187+
err: err,
188+
}: // nop
189+
190+
case <-c.done:
191+
closeSession(s)
192+
193+
case <-ctx.Done():
194+
closeSession(s)
195+
}
196+
}()
197+
}
189198

190199
select {
191200
case <-c.done:
@@ -343,11 +352,7 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
343352
}()
344353

345354
const maxAttempts = 100
346-
for ; s == nil && err == nil && i < maxAttempts; i++ {
347-
if c.isClosed() {
348-
return nil, xerrors.WithStackTrace(errClosedClient)
349-
}
350-
355+
for ; s == nil && err == nil && i < maxAttempts && !c.isClosed(); i++ {
351356
// First, we try to internalPoolGet session from idle
352357
c.mu.WithLock(func() {
353358
s = c.internalPoolRemoveFirstIdle()
@@ -382,7 +387,11 @@ func (c *Client) internalPoolGet(ctx context.Context, opts ...getOption) (s *ses
382387
}
383388
}
384389
if s == nil && err == nil {
385-
err = xerrors.WithStackTrace(errNoProgress)
390+
if c.isClosed() {
391+
err = xerrors.WithStackTrace(errClosedClient)
392+
} else {
393+
err = xerrors.WithStackTrace(errNoProgress)
394+
}
386395
}
387396
if err != nil {
388397
var (

0 commit comments

Comments
 (0)