Skip to content

Commit a07b3a9

Browse files
committed
api: allow Future.GetTyped() after Future.Get()
After the patch, a user can call Future.GetTyped() after Future.Get(). It can be useful at least after receiving push messages. Needed for tarantool/tt#54
1 parent 8b58928 commit a07b3a9

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
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

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: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,44 @@ func BenchmarkSQLSerial(b *testing.B) {
721721
}
722722
}
723723

724+
func TestFutMultipleGetGetTyped(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+
724762
///////////////////
725763

726764
func TestClient(t *testing.T) {
@@ -1069,7 +1107,7 @@ func TestClientSessionPush(t *testing.T) {
10691107
} else if len(resp.Data) < 1 {
10701108
t.Errorf("Response.Data is empty after Call17Async")
10711109
} else if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1072-
t.Errorf("result is not {{1}} : %v", resp.Data)
1110+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
10731111
}
10741112

10751113
// It will will be iterated with a timeout.
@@ -1103,7 +1141,7 @@ func TestClientSessionPush(t *testing.T) {
11031141
} else {
11041142
respCnt += 1
11051143
if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1106-
t.Errorf("result is not {{1}} : %v", resp.Data)
1144+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
11071145
}
11081146
}
11091147
}
@@ -1120,6 +1158,26 @@ func TestClientSessionPush(t *testing.T) {
11201158
t.Errorf("Expect %d responses but got %d", 1, respCnt)
11211159
}
11221160
}
1161+
1162+
// We can collect original responses after iterations.
1163+
for _, fut := range []*Future{fut0, fut1, fut2} {
1164+
resp, err := fut.Get()
1165+
if err != nil {
1166+
t.Errorf("Unable to call fut.Get(): %s", err)
1167+
} else if val, err := convertUint64(resp.Data[0]); err != nil || val != pushMax {
1168+
t.Errorf("Result is not %d: %v", pushMax, resp.Data)
1169+
}
1170+
1171+
tpl := struct {
1172+
Val int
1173+
}{}
1174+
err = fut.GetTyped(&tpl)
1175+
if err != nil {
1176+
t.Errorf("Unable to call fut.GetTyped(): %s", err)
1177+
} else if tpl.Val != pushMax {
1178+
t.Errorf("Result is not %d: %d", pushMax, tpl.Val)
1179+
}
1180+
}
11231181
}
11241182

11251183
const (

0 commit comments

Comments
 (0)