Skip to content

Commit

Permalink
api: support IPROTO_FEATURE_SPACE_AND_INDEX_NAMES
Browse files Browse the repository at this point in the history
Support `IPROTO_FEATURE_SPACE_AND_INDEX_NAMES` for Tarantool
version >= 3.0.0-alpha. It allows to use space and index names in requests
instead of their IDs.

`ResolveSpaceIndex` function for `SchemaResolver` interface split into two:
`ResolveSpace` and `ResolveIndex`. `NamesUseSupported` function added into the
interface to get information if usage of space and index names is supported.

Closes #338
  • Loading branch information
DerekBum committed Nov 7, 2023
1 parent a664c6b commit e96f793
Show file tree
Hide file tree
Showing 14 changed files with 1,187 additions and 291 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.
- Support `crud.schema` request (#336)
- Support `IPROTO_WATCH_ONCE` request type for Tarantool
version >= 3.0.0-alpha1 (#337)
- Support `IPROTO_FEATURE_SPACE_AND_INDEX_NAMES` for Tarantool
version >= 3.0.0-alpha1 (#338). It allows to use space and index names
in requests instead of their IDs

### Changed

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,13 @@ and user may cancel it in process.
* `iproto.Feature` type used instead of `ProtocolFeature`.
* `iproto.IPROTO_FEATURE_` constants used instead of local ones.

#### Schema changes

`ResolveSpaceIndex` function for `SchemaResolver` interface split into two:
`ResolveSpace` and `ResolveIndex`. `NamesUseSupported` function added into the
interface to get information if the usage of space and index names in requests
is supported.

## Contributing

See [the contributing guide](CONTRIBUTING.md) for detailed instructions on how
Expand Down
5 changes: 4 additions & 1 deletion connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ type Connection struct {
cond *sync.Cond
// Schema contains schema loaded on connection.
Schema *Schema
// schemaResolver contains a SchemaResolver implementation.
schemaResolver SchemaResolver
// requestId contains the last request ID for requests with nil context.
requestId uint32
// contextRequestId contains the last request ID for requests with context.
Expand Down Expand Up @@ -384,6 +386,7 @@ func Connect(ctx context.Context, addr string, opts Opts) (conn *Connection, err
control: make(chan struct{}),
opts: opts.Clone(),
dec: msgpack.NewDecoder(&smallBuf{}),
schemaResolver: &DefaultSchemaResolver{},
}
maxprocs := uint32(runtime.GOMAXPROCS(-1))
if conn.opts.Concurrency == 0 || conn.opts.Concurrency > maxprocs*128 {
Expand Down Expand Up @@ -1102,7 +1105,7 @@ func (conn *Connection) putFuture(fut *Future, req Request, streamId uint64) {
}
blen := shard.buf.Len()
reqid := fut.requestId
if err := pack(&shard.buf, shard.enc, reqid, req, streamId, conn.Schema); err != nil {
if err := pack(&shard.buf, shard.enc, reqid, req, streamId, conn.schemaResolver); err != nil {
shard.buf.Trunc(blen)
shard.bufmut.Unlock()
if f := conn.fetchFuture(reqid); f == fut {
Expand Down
20 changes: 13 additions & 7 deletions crud/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,27 +70,33 @@ var expectedOpts = map[string]interface{}{
}

type ValidSchemeResolver struct {
tarantool.SchemaResolver
}

func (*ValidSchemeResolver) ResolveSpaceIndex(s, i interface{}) (uint32, uint32, error) {
var spaceNo, indexNo uint32
func (*ValidSchemeResolver) ResolveSpace(s interface{}) (uint32, error) {
var spaceNo uint32
if s != nil {
spaceNo = uint32(s.(int))
} else {
spaceNo = defaultSpace
}
if spaceNo == invalidSpace {
return 0, errors.New(invalidSpaceMsg)
}
return spaceNo, nil
}

func (*ValidSchemeResolver) ResolveIndex(i interface{}, spaceNo uint32) (uint32, error) {
var indexNo uint32
if i != nil {
indexNo = uint32(i.(int))
} else {
indexNo = defaultIndex
}
if spaceNo == invalidSpace {
return 0, 0, errors.New(invalidSpaceMsg)
}
if indexNo == invalidIndex {
return 0, 0, errors.New(invalidIndexMsg)
return 0, errors.New(invalidIndexMsg)
}
return spaceNo, indexNo, nil
return indexNo, nil
}

var resolver ValidSchemeResolver
Expand Down
88 changes: 88 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,21 @@ func ExampleSelectRequest() {
// response is [{{} 1111 hello world}]
}

func ExampleSelectRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewSelectRequest(spaceName)
req.Index(indexName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleInsertRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -273,6 +288,20 @@ func ExampleInsertRequest() {
// Data [[32 test one]]
}

func ExampleInsertRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewInsertRequest(spaceName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleDeleteRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -316,6 +345,21 @@ func ExampleDeleteRequest() {
// Data [[36 test one]]
}

func ExampleDeleteRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewDeleteRequest(spaceName)
req.Index(indexName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleReplaceRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -375,6 +419,20 @@ func ExampleReplaceRequest() {
// Data [[13 test twelve]]
}

func ExampleReplaceRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewReplaceRequest(spaceName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleUpdateRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -411,6 +469,21 @@ func ExampleUpdateRequest() {
// response is []interface {}{[]interface {}{0x457, "hello", "world"}}
}

func ExampleUpdateRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewUpdateRequest(spaceName)
req.Index(indexName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleUpsertRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -452,6 +525,20 @@ func ExampleUpsertRequest() {
// response is []interface {}{[]interface {}{0x459, "first", "updated"}}
}

func ExampleUpsertRequest_spaceAndIndexNames() {
conn := exampleConnect(opts)
defer conn.Close()

req := tarantool.NewUpsertRequest(spaceName)
resp, err := conn.Do(req).Get()

if err != nil {
fmt.Printf("Failed to execute the request: %s\n", err)
} else {
fmt.Println(resp.Data)
}
}

func ExampleCallRequest() {
conn := exampleConnect(opts)
defer conn.Close()
Expand Down Expand Up @@ -634,6 +721,7 @@ func ExampleProtocolVersion() {
// Connector client protocol feature: IPROTO_FEATURE_ERROR_EXTENSION
// Connector client protocol feature: IPROTO_FEATURE_WATCHERS
// Connector client protocol feature: IPROTO_FEATURE_PAGINATION
// Connector client protocol feature: IPROTO_FEATURE_SPACE_AND_INDEX_NAMES
// Connector client protocol feature: IPROTO_FEATURE_WATCH_ONCE
}

Expand Down
67 changes: 54 additions & 13 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,80 @@ func RefImplPingBody(enc *msgpack.Encoder) error {

// RefImplSelectBody is reference implementation for filling of a select
// request's body.
func RefImplSelectBody(enc *msgpack.Encoder, space, index, offset, limit uint32, iterator Iter,
key, after interface{}, fetchPos bool) error {
return fillSelect(enc, space, index, offset, limit, iterator, key, after, fetchPos)
func RefImplSelectBody(enc *msgpack.Encoder, res SchemaResolver, space, index interface{},
offset, limit uint32, iterator Iter, key, after interface{}, fetchPos bool) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
if err != nil {
return err
}
return fillSelect(enc, spaceEnc, indexEnc, offset, limit, iterator, key, after, fetchPos)
}

// RefImplInsertBody is reference implementation for filling of an insert
// request's body.
func RefImplInsertBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
return fillInsert(enc, space, tuple)
func RefImplInsertBody(enc *msgpack.Encoder, res SchemaResolver, space,
tuple interface{}) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
return fillInsert(enc, spaceEnc, tuple)
}

// RefImplReplaceBody is reference implementation for filling of a replace
// request's body.
func RefImplReplaceBody(enc *msgpack.Encoder, space uint32, tuple interface{}) error {
return fillInsert(enc, space, tuple)
func RefImplReplaceBody(enc *msgpack.Encoder, res SchemaResolver, space,
tuple interface{}) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
return fillInsert(enc, spaceEnc, tuple)
}

// RefImplDeleteBody is reference implementation for filling of a delete
// request's body.
func RefImplDeleteBody(enc *msgpack.Encoder, space, index uint32, key interface{}) error {
return fillDelete(enc, space, index, key)
func RefImplDeleteBody(enc *msgpack.Encoder, res SchemaResolver, space, index,
key interface{}) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
if err != nil {
return err
}
return fillDelete(enc, spaceEnc, indexEnc, key)
}

// RefImplUpdateBody is reference implementation for filling of an update
// request's body.
func RefImplUpdateBody(enc *msgpack.Encoder, space, index uint32, key, ops interface{}) error {
return fillUpdate(enc, space, index, key, ops)
func RefImplUpdateBody(enc *msgpack.Encoder, res SchemaResolver, space, index,
key, ops interface{}) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
indexEnc, err := newIndexEncoder(res, index, spaceEnc.Id)
if err != nil {
return err
}
return fillUpdate(enc, spaceEnc, indexEnc, key, ops)
}

// RefImplUpsertBody is reference implementation for filling of an upsert
// request's body.
func RefImplUpsertBody(enc *msgpack.Encoder, space uint32, tuple, ops interface{}) error {
return fillUpsert(enc, space, tuple, ops)
func RefImplUpsertBody(enc *msgpack.Encoder, res SchemaResolver, space,
tuple, ops interface{}) error {
spaceEnc, err := newSpaceEncoder(res, space)
if err != nil {
return err
}
return fillUpsert(enc, spaceEnc, tuple, ops)
}

// RefImplCallBody is reference implementation for filling of a call or call17
Expand Down
1 change: 1 addition & 0 deletions protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ var clientProtocolInfo ProtocolInfo = ProtocolInfo{
iproto.IPROTO_FEATURE_ERROR_EXTENSION,
iproto.IPROTO_FEATURE_WATCHERS,
iproto.IPROTO_FEATURE_PAGINATION,
iproto.IPROTO_FEATURE_SPACE_AND_INDEX_NAMES,
iproto.IPROTO_FEATURE_WATCH_ONCE,
},
}
Expand Down
Loading

0 comments on commit e96f793

Please sign in to comment.