Skip to content

Commit 4164a29

Browse files
committed
api: proposal to add the context support
This patch adds the support of using context in API. The proposed API is based on using request objects. Added tests that cover almost all cases of using the context in a query. Added benchamrk tests are equivalent to other, that use the same query but without any context. to fix and squash
1 parent 017eb2a commit 4164a29

File tree

6 files changed

+348
-19
lines changed

6 files changed

+348
-19
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
1919
- Master discovery (#113)
2020
- SQL support (#62)
2121
- Add public API with a request object for Select/Update/Upstream (#126)
22+
- Context support for request objects
2223

2324
### Fixed
2425

config.lua

+6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ local function simple_incr(a)
110110
end
111111
rawset(_G, 'simple_incr', simple_incr)
112112

113+
local function simple_sleep(a)
114+
require('fiber').sleep(15)
115+
return a + 1
116+
end
117+
rawset(_G, 'simple_sleep', simple_sleep)
118+
113119
box.space.test:truncate()
114120

115121
--box.schema.user.revoke('guest', 'read,write,execute', 'universe')

connection.go

+24-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package tarantool
55
import (
66
"bufio"
77
"bytes"
8+
"context"
89
"errors"
910
"fmt"
1011
"io"
@@ -877,9 +878,14 @@ func (conn *Connection) nextRequestId() (requestId uint32) {
877878
// Do verifies, sends the request and returns a response.
878879
//
879880
// An error is returned if the request was formed incorrectly, or failure to
880-
// communicate by the connection, or unable to decode the response.
881-
func (conn *Connection) Do(req Request) (*Response, error) {
882-
fut, err := conn.DoAsync(req)
881+
// communicate by the connection, or unable to decode the response, or nil context is passed
882+
// or context is canceled or done.
883+
func (conn *Connection) Do(ctx context.Context, req Request) (*Response, error) {
884+
if ctx == nil {
885+
return nil, errors.New("passed nil context")
886+
}
887+
888+
fut, err := conn.DoAsync(ctx, req)
883889
if err != nil {
884890
return nil, err
885891
}
@@ -890,8 +896,12 @@ func (conn *Connection) Do(req Request) (*Response, error) {
890896
//
891897
// An error is returned if the request was formed incorrectly, or failure to
892898
// communicate by the connection, or unable to decode the response.
893-
func (conn *Connection) DoTyped(req Request, result interface{}) error {
894-
fut, err := conn.DoAsync(req)
899+
func (conn *Connection) DoTyped(ctx context.Context, req Request, result interface{}) error {
900+
if ctx == nil {
901+
return errors.New("passed nil context")
902+
}
903+
904+
fut, err := conn.DoAsync(ctx, req)
895905
if err != nil {
896906
return err
897907
}
@@ -902,12 +912,20 @@ func (conn *Connection) DoTyped(req Request, result interface{}) error {
902912
//
903913
// An error is returned if the request was formed incorrectly, or failure to
904914
// create the future.
905-
func (conn *Connection) DoAsync(req Request) (*Future, error) {
915+
func (conn *Connection) DoAsync(ctx context.Context, req Request) (*Future, error) {
906916
bodyFunc, err := req.BodyFunc(conn.Schema)
907917
if err != nil {
908918
return nil, err
909919
}
910920
future := conn.newFuture(req.Code())
921+
if ctx != nil {
922+
select {
923+
case <-ctx.Done():
924+
return nil, fmt.Errorf("context is done")
925+
default:
926+
future.WithCtx(ctx)
927+
}
928+
}
911929
return future.send(conn, bodyFunc), nil
912930
}
913931

example_test.go

+14-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tarantool_test
22

33
import (
4+
"context"
45
"fmt"
56
"github.com/tarantool/go-tarantool/test_helpers"
67
"time"
@@ -111,11 +112,13 @@ func ExampleConnection_SelectAsync() {
111112
func ExampleSelectRequest() {
112113
conn := example_connect()
113114
defer conn.Close()
115+
var ctx, cancel = context.WithCancel(context.Background())
116+
defer cancel()
114117

115118
req := tarantool.NewSelectRequest(517).
116119
Limit(100).
117120
Key(tarantool.IntKey{1111})
118-
resp, err := conn.Do(req)
121+
resp, err := conn.Do(ctx, req)
119122
if err != nil {
120123
fmt.Printf("error in do select request is %v", err)
121124
return
@@ -126,7 +129,7 @@ func ExampleSelectRequest() {
126129
Index("primary").
127130
Limit(100).
128131
Key(tarantool.IntKey{1111})
129-
fut, err := conn.DoAsync(req)
132+
fut, err := conn.DoAsync(ctx, req)
130133
if err != nil {
131134
fmt.Printf("error in do async select request is %v", err)
132135
}
@@ -144,11 +147,13 @@ func ExampleSelectRequest() {
144147
func ExampleUpdateRequest() {
145148
conn := example_connect()
146149
defer conn.Close()
150+
var ctx, cancel = context.WithCancel(context.Background())
151+
defer cancel()
147152

148153
req := tarantool.NewUpdateRequest(517).
149154
Key(tarantool.IntKey{1111}).
150155
Operations(tarantool.NewOperations().Assign(1, "bye"))
151-
resp, err := conn.Do(req)
156+
resp, err := conn.Do(ctx, req)
152157
if err != nil {
153158
fmt.Printf("error in do update request is %v", err)
154159
return
@@ -159,7 +164,7 @@ func ExampleUpdateRequest() {
159164
Index("primary").
160165
Key(tarantool.IntKey{1111}).
161166
Operations(tarantool.NewOperations().Assign(1, "hello"))
162-
fut, err := conn.DoAsync(req)
167+
fut, err := conn.DoAsync(ctx, req)
163168
if err != nil {
164169
fmt.Printf("error in do async update request is %v", err)
165170
}
@@ -177,12 +182,14 @@ func ExampleUpdateRequest() {
177182
func ExampleUpsertRequest() {
178183
conn := example_connect()
179184
defer conn.Close()
185+
var ctx, cancel = context.WithCancel(context.Background())
186+
defer cancel()
180187

181188
var req tarantool.Request
182189
req = tarantool.NewUpsertRequest(517).
183190
Tuple([]interface{}{uint(1113), "first", "first"}).
184191
Operations(tarantool.NewOperations().Assign(1, "updated"))
185-
resp, err := conn.Do(req)
192+
resp, err := conn.Do(ctx, req)
186193
if err != nil {
187194
fmt.Printf("error in do select upsert is %v", err)
188195
return
@@ -192,7 +199,7 @@ func ExampleUpsertRequest() {
192199
req = tarantool.NewUpsertRequest("test").
193200
Tuple([]interface{}{uint(1113), "second", "second"}).
194201
Operations(tarantool.NewOperations().Assign(2, "updated"))
195-
fut, err := conn.DoAsync(req)
202+
fut, err := conn.DoAsync(ctx, req)
196203
if err != nil {
197204
fmt.Printf("error in do async upsert request is %v", err)
198205
}
@@ -206,7 +213,7 @@ func ExampleUpsertRequest() {
206213
req = tarantool.NewSelectRequest(517).
207214
Limit(100).
208215
Key(tarantool.IntKey{1113})
209-
resp, err = conn.Do(req)
216+
resp, err = conn.Do(ctx, req)
210217
if err != nil {
211218
fmt.Printf("error in do select request is %v", err)
212219
return

future.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package tarantool
22

33
import (
4+
"context"
5+
"fmt"
46
"time"
57

68
"gopkg.in/vmihailenco/msgpack.v2"
@@ -15,6 +17,14 @@ type Future struct {
1517
err error
1618
ready chan struct{}
1719
next *Future
20+
ctx context.Context
21+
}
22+
23+
// WithCtx sets a passed context to Future object and
24+
// returns the same object with that context.
25+
func (fut *Future) WithCtx(ctx context.Context) *Future {
26+
fut.ctx = ctx
27+
return fut
1828
}
1929

2030
// Get waits for Future to be filled and returns Response and error.
@@ -122,5 +132,20 @@ func (fut *Future) wait() {
122132
if fut.ready == nil {
123133
return
124134
}
125-
<-fut.ready
135+
if fut.ctx == nil {
136+
<-fut.ready
137+
return
138+
}
139+
select {
140+
case <-fut.ready:
141+
default:
142+
select {
143+
case <-fut.ctx.Done():
144+
fut.err = fmt.Errorf("context is done")
145+
default:
146+
case <-fut.ready:
147+
case <-fut.ctx.Done():
148+
fut.err = fmt.Errorf("context is done")
149+
}
150+
}
126151
}

0 commit comments

Comments
 (0)