Skip to content

Commit d4905f5

Browse files
committed
bugfix: allow multiple Future.Get*()
After the patch, a user can call Future.GetTyped() or Future.Get() multiple times in any order. Needed for tarantool/tt#54
1 parent 8b58928 commit d4905f5

File tree

5 files changed

+120
-8
lines changed

5 files changed

+120
-8
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
2525
- Addresses in ConnectionPool may be changed from an external code (#208)
2626
- ConnectionPool recreates connections too often (#208)
2727
- A connection is still opened after ConnectionPool.Close() (#208)
28+
- Future.GetTyped() after Future.Get() does not decode response
29+
correctly (#213)
2830

2931
## [1.8.0] - 2022-08-17
3032

future.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,6 @@ func (fut *Future) Get() (*Response, error) {
184184
return fut.resp, fut.err
185185
}
186186
err := fut.resp.decodeBody()
187-
if err != nil {
188-
fut.err = err
189-
}
190187
return fut.resp, err
191188
}
192189

@@ -200,9 +197,6 @@ func (fut *Future) GetTyped(result interface{}) error {
200197
return fut.err
201198
}
202199
err := fut.resp.decodeBodyTyped(result)
203-
if err != nil {
204-
fut.err = err
205-
}
206200
return err
207201
}
208202

response.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ func (resp *Response) decodeHeader(d *decoder) (err error) {
144144

145145
func (resp *Response) decodeBody() (err error) {
146146
if resp.buf.Len() > 2 {
147+
offset := resp.buf.Offset()
148+
defer resp.buf.Seek(offset)
149+
147150
var l int
148151
var stmtID, bindCount uint64
149152

@@ -211,6 +214,9 @@ func (resp *Response) decodeBody() (err error) {
211214

212215
func (resp *Response) decodeBodyTyped(res interface{}) (err error) {
213216
if resp.buf.Len() > 0 {
217+
offset := resp.buf.Offset()
218+
defer resp.buf.Seek(offset)
219+
214220
var l int
215221
d := newDecoder(&resp.buf)
216222
if l, err = d.DecodeMapLen(); err != nil {

smallbuf.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ func (s *smallBuf) Bytes() []byte {
5151
return nil
5252
}
5353

54+
func (s *smallBuf) Offset() int {
55+
return s.p
56+
}
57+
58+
func (s *smallBuf) Seek(offset int) error {
59+
if offset < 0 {
60+
return errors.New("too small offset")
61+
}
62+
if offset > len(s.b) {
63+
return errors.New("too big offset")
64+
}
65+
s.p = offset
66+
return nil
67+
}
68+
5469
type smallWBuf struct {
5570
b []byte
5671
sum uint

tarantool_test.go

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,81 @@ func BenchmarkSQLSerial(b *testing.B) {
721721
}
722722
}
723723

724+
func TestFutureMultipleGetGetTyped(t *testing.T) {
725+
conn := test_helpers.ConnectWithValidation(t, server, opts)
726+
defer conn.Close()
727+
728+
fut := conn.Call17Async("simple_concat", []interface{}{"1"})
729+
730+
for i := 0; i < 30; i++ {
731+
// [0, 10) fut.Get()
732+
// [10, 20) fut.GetTyped()
733+
// [20, 30) Mix
734+
get := false
735+
if (i < 10) || (i >= 20 && i%2 == 0) {
736+
get = true
737+
}
738+
739+
if get {
740+
resp, err := fut.Get()
741+
if err != nil {
742+
t.Errorf("Failed to call Get(): %s", err)
743+
}
744+
if val, ok := resp.Data[0].(string); !ok || val != "11" {
745+
t.Errorf("Wrong Get() result: %v", resp.Data)
746+
}
747+
} else {
748+
tpl := struct {
749+
Val string
750+
}{}
751+
err := fut.GetTyped(&tpl)
752+
if err != nil {
753+
t.Errorf("Failed to call GetTyped(): %s", err)
754+
}
755+
if tpl.Val != "11" {
756+
t.Errorf("Wrong GetTyped() result: %v", tpl)
757+
}
758+
}
759+
}
760+
}
761+
762+
func TestFutureMultipleGetWithError(t *testing.T) {
763+
conn := test_helpers.ConnectWithValidation(t, server, opts)
764+
defer conn.Close()
765+
766+
fut := conn.Call17Async("non_exist", []interface{}{"1"})
767+
768+
for i := 0; i < 2; i++ {
769+
if _, err := fut.Get(); err == nil {
770+
t.Fatalf("An error expected")
771+
}
772+
}
773+
}
774+
775+
func TestFutureMultipleGetTypedWithError(t *testing.T) {
776+
conn := test_helpers.ConnectWithValidation(t, server, opts)
777+
defer conn.Close()
778+
779+
fut := conn.Call17Async("simple_concat", []interface{}{"1"})
780+
781+
wrongTpl := struct {
782+
Val int
783+
}{}
784+
goodTpl := struct {
785+
Val string
786+
}{}
787+
788+
if err := fut.GetTyped(&wrongTpl); err == nil {
789+
t.Fatalf("An error expected")
790+
}
791+
if err := fut.GetTyped(&goodTpl); err != nil {
792+
t.Fatalf("Unexpected error: %s", err)
793+
}
794+
if goodTpl.Val != "11" {
795+
t.Fatalf("Wrong result: %s", goodTpl.Val)
796+
}
797+
}
798+
724799
///////////////////
725800

726801
func TestClient(t *testing.T) {
@@ -1069,7 +1144,7 @@ func TestClientSessionPush(t *testing.T) {
10691144
} else if len(resp.Data) < 1 {
10701145
t.Errorf("Response.Data is empty after Call17Async")
10711146
} else if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1072-
t.Errorf("result is not {{1}} : %v", resp.Data)
1147+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
10731148
}
10741149

10751150
// It will will be iterated with a timeout.
@@ -1103,7 +1178,7 @@ func TestClientSessionPush(t *testing.T) {
11031178
} else {
11041179
respCnt += 1
11051180
if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1106-
t.Errorf("result is not {{1}} : %v", resp.Data)
1181+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
11071182
}
11081183
}
11091184
}
@@ -1120,6 +1195,26 @@ func TestClientSessionPush(t *testing.T) {
11201195
t.Errorf("Expect %d responses but got %d", 1, respCnt)
11211196
}
11221197
}
1198+
1199+
// We can collect original responses after iterations.
1200+
for _, fut := range []*Future{fut0, fut1, fut2} {
1201+
resp, err := fut.Get()
1202+
if err != nil {
1203+
t.Errorf("Unable to call fut.Get(): %s", err)
1204+
} else if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1205+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
1206+
}
1207+
1208+
tpl := struct {
1209+
Val int
1210+
}{}
1211+
err = fut.GetTyped(&tpl)
1212+
if err != nil {
1213+
t.Errorf("Unable to call fut.GetTyped(): %s", err)
1214+
} else if tpl.Val != pushMax {
1215+
t.Errorf("Result is not %d: %d", pushMax, tpl.Val)
1216+
}
1217+
}
11231218
}
11241219

11251220
const (

0 commit comments

Comments
 (0)