Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: implement VshardRouterCallResp.GetTransparent method (resolve #22) #23

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## Unreleased

CHANGES:
* All PR, issue references in #XYZ format in commits older than 42f363775dfb9eaf7ec2a6ed7a999847752cec00 refer to https://github.com/KaymeKaydex/go-vshard-router.

FEATURES:

* Implement VshardRouterCallResp.GetTransparent method to reuse custom msgpack decoders of direct call (#22).

TESTS:
* Tests for VshardRouterCallResp.GetTransparent.

## v1.3.2

CHANGES:
Expand Down
28 changes: 28 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vshard_router //nolint:revive

import (
"bytes"
"context"
"fmt"
"time"
Expand Down Expand Up @@ -228,6 +229,33 @@ func (r VshardRouterCallResp) GetTyped(result []interface{}) error {
return nil
}

// GetTransparent decodes a response from user defined function into result.
// The response has the same format as a direct call (without vshard router) to this function.
// If you have some custom decoder for some lua handler's response, you can reuse your decoder using this method.
// P.S. the maximum length of the response array is cut to 3 elements due to lua vshard storage implementation
// see https://github.com/tarantool/vshard/blob/dfa2cc8a2aff221d5f421298851a9a229b2e0434/vshard/storage/init.lua#L3130.
func (r VshardRouterCallResp) GetTransparent(result interface{}) error {
nurzhan-saktaganov marked this conversation as resolved.
Show resolved Hide resolved
// Make a msgpack binary with desired array length.
enc := msgpack.GetEncoder()
defer msgpack.PutEncoder(enc)

var buf bytes.Buffer
enc.Reset(&buf)

err := enc.EncodeArrayLen(len(r.rawMessages))
if err != nil {
return err
}

data := buf.Bytes()
for _, rawMessage := range r.rawMessages {
data = append(data, rawMessage...)
}

// Call users' custom decoder (if any).
return msgpack.Unmarshal(data, result)
}

// RouterCallImpl Perform shard operation function will restart operation
// after wrong bucket response until timeout is reached
// Deprecated: RouterCallImpl is deprecated.
Expand Down
53 changes: 52 additions & 1 deletion tests/tnt/router_call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/tarantool/go-vshard-router/providers/static"
)

func TestRouterCallProto(t *testing.T) {
func TestRouterCallImplProto(t *testing.T) {
skipOnInvalidRun(t)

t.Parallel()
Expand Down Expand Up @@ -111,3 +111,54 @@ func TestRouterCallProto(t *testing.T) {
_, _, err = router.RouterCallImpl(ctx, bucketID, callOpts, "echo", args)
require.Nil(t, err, "RouterCallImpl echo finished with no err even on dirty bucket map")
}

func TestRouterCallProto(t *testing.T) {
nurzhan-saktaganov marked this conversation as resolved.
Show resolved Hide resolved
skipOnInvalidRun(t)

t.Parallel()

ctx := context.Background()

cfg := getCfg()

router, err := vshardrouter.NewRouter(ctx, vshardrouter.Config{
TopologyProvider: static.NewProvider(cfg),
DiscoveryTimeout: 5 * time.Second,
DiscoveryMode: vshardrouter.DiscoveryModeOn,
TotalBucketCount: totalBucketCount,
User: defaultTntUser,
Password: defaultTntPassword,
})
require.NoError(t, err, "NewRouter finished successfully")

bucketID := randBucketID(totalBucketCount)

rs, err := router.BucketResolve(ctx, bucketID)
require.NoError(t, err, "BucketResolve with no err")

const maxRespLen = 3
for argLen := 0; argLen <= maxRespLen; argLen++ {
args := []interface{}{}

for i := 0; i < argLen; i++ {
args = append(args, "arg")
}

var routerOpts vshardrouter.VshardRouterCallOptions
resp, err := router.CallRW(ctx, bucketID, "echo", args, routerOpts)
require.NoError(t, err, "router.CallRW with no err")

var resViaVshard interface{}
var resDirect interface{}

err = resp.GetTransparent(&resViaVshard)
require.NoError(t, err, "GetTransparent with no err")

var rsOpts vshardrouter.ReplicasetCallOpts

err = rs.CallAsync(ctx, rsOpts, "echo", args).GetTyped(&resDirect)
require.NoError(t, err, "rs.CallAsync.GetTyped with no error")

require.Equalf(t, resDirect, resViaVshard, "resDirect != resViaVshard on argLen %d", argLen)
}
}
Loading