diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eabd67ea..68f38f15 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,9 +39,16 @@ jobs: run: cd tools/cli | go build -o cli . - name: Build example files run: find examples -name "*.go" -type f -print0 | xargs -0 -n1 go build - # - name: Build with Reflection code removed - # run: go run github.com/onsi/ginkgo/v2/ginkgo build -tags="as_performance" . - # - name: Build for Google App Engine (unsafe package removed) - # run: go run github.com/onsi/ginkgo/v2/ginkgo -tags="app_engine" . + - name: Build with Reflection code removed + run: go run github.com/onsi/ginkgo/v2/ginkgo build -tags="as_performance" . + - name: Build for Google App Engine (unsafe package removed) + run: go run github.com/onsi/ginkgo/v2/ginkgo build -tags="app_engine" . - name: Run the tests - run: go run github.com/onsi/ginkgo/v2/ginkgo -cover -race -keep-going -succinct -randomize-suites -skip="HyperLogLog" + run: go run github.com/onsi/ginkgo/v2/ginkgo -coverprofile=./cover_native.out -covermode=atomic -coverpkg=./... -race -keep-going -succinct -randomize-suites -skip="HyperLogLog" + - name: Combine Cover Profiles + run: go run github.com/wadey/gocovmerge cover_*.out > cover_all.out + - name: Check Code Coverage + uses: vladopajic/go-test-coverage@v2 + with: + # Configure action using config file (option 1) + config: ./.testcoverage.yml diff --git a/.gitignore b/.gitignore index 70722727..92c85e4c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ Dockerfile* .dockerignore docker-compose.yml golangci.yml -cover.out \ No newline at end of file +cover*.out diff --git a/.testcoverage.yml b/.testcoverage.yml new file mode 100644 index 00000000..5d2da411 --- /dev/null +++ b/.testcoverage.yml @@ -0,0 +1,69 @@ +# (mandatory) +# Path to coverprofile file (output of `go test -coverprofile` command). +# +# For cases where there are many coverage profiles, such as when running +# unit tests and integration tests separately, you can combine all those +# profiles into one. In this case, the profile should have a comma-separated list +# of profile files, e.g., 'cover_unit.out,cover_integration.out'. +profile: cover_all.out + +# (optional; but recommended to set) +# When specified reported file paths will not contain local prefix in the output +local-prefix: "github.com/aerospike/aerospike-client-go/v7" + +# Holds coverage thresholds percentages, values should be in range [0-100] +threshold: + # (optional; default 0) + # The minimum coverage that each file should have + file: 0 + + # (optional; default 0) + # The minimum coverage that each package should have + package: 0 + + # (optional; default 0) + # The minimum total coverage project should have + total: 0 + +# Holds regexp rules which will override thresholds for matched files or packages +# using their paths. +# +# First rule from this list that matches file or package is going to apply +# new threshold to it. If project has multiple rules that match same path, +# override rules should be listed in order from specific to more general rules. +override: + # Increase coverage threshold to 100% for `foo` package + # (default is 80, as configured above in this example) + #- threshold: 100 + # path: ^pkg/lib/foo$ + +# Holds regexp rules which will exclude matched files or packages +# from coverage statistics +exclude: + # Exclude files or packages matching their paths + paths: + # - \.pb\.go$ # excludes all protobuf generated files + - proto/* + - ^pkg/* # exclude package `pkg/bar` + - client_builder.go + - info_policy.go + - commit_policy.go + - generation_policy.go + - privilege.go + - read_mode_ap.go + - read_mode_sc.go + - record_exists_action.go + - replica_policy.go + - generics.go + - proxy_auth_interceptor.go + - proxy_client.go + - proxy_client_reflect.go + - proxy_query_partition_command.go + - proxy_scan_command.go + - login_command.go + - types/histogram/histogram.go + - types/rand/xor_shift128.go + - internal/atomic/array.go +# NOTES: +# - symbol `/` in all path regexps will be replaced by current OS file path separator +# to properly work on Windows diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e9e056..41260418 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,24 @@ # Change History +## May 16 2024: v7.4.0 + + This a minor fix release. We strongly suggest you upgrade to this version over the v7.3.0 if you use the `Client.BatchGetOperate` API. + +- **Improvements** + - Add code coverage tests to the Github Actions workflow. + - Call the `CancelFunc` for the `context.WithTimeout` per linter suggestions in grpc calls. + - Minor clean up and remove dead code. + +- **Fixes** + - [CLIENT-2943] `Client.BatchGetOperate` does not consider ops in single key transforms. + - [CLIENT-2704] Client dev tests failing with new server map key restrictions. + - Fix `as_performance` and `app_engine` build tags. + ## May 3 2024: v7.3.0 +> [!WARNING] +> Do not use this version if you are using the `Client.BatchGetOperate` API. + This is a major feature release of the Go client and touches some of the fundamental aspects of the inner workings of it. We suggest complete testing of your application before using it in production. diff --git a/batch_command_get.go b/batch_command_get.go index 9328c353..4ce85bcb 100644 --- a/batch_command_get.go +++ b/batch_command_get.go @@ -219,15 +219,18 @@ func (cmd *batchCommandGet) transactionType() transactionType { func (cmd *batchCommandGet) executeSingle(client *Client) Error { for _, offset := range cmd.batch.offsets { var err Error - if cmd.objects == nil { - if (cmd.readAttr & _INFO1_NOBINDATA) == _INFO1_NOBINDATA { - cmd.records[offset], err = client.GetHeader(&cmd.policy.BasePolicy, cmd.keys[offset]) - } else { - cmd.records[offset], err = client.Get(&cmd.policy.BasePolicy, cmd.keys[offset], cmd.binNames...) + if len(cmd.ops) > 0 { + // Validate that all operations are read + for i := range cmd.ops { + if cmd.ops[i].opType.isWrite { + return newError(types.PARAMETER_ERROR, "Write operations not allowed in batch read").setNode(cmd.node) + } } + cmd.records[offset], err = client.Operate(cmd.policy.toWritePolicy(), cmd.keys[offset], cmd.ops...) + } else if (cmd.readAttr & _INFO1_NOBINDATA) == _INFO1_NOBINDATA { + cmd.records[offset], err = client.GetHeader(&cmd.policy.BasePolicy, cmd.keys[offset]) } else { - err = client.getObjectDirect(&cmd.policy.BasePolicy, cmd.keys[offset], cmd.objects[offset]) - cmd.objectsFound[offset] = err == nil + cmd.records[offset], err = client.Get(&cmd.policy.BasePolicy, cmd.keys[offset], cmd.binNames...) } if err != nil { // Key not found is NOT an error for batch requests @@ -250,7 +253,7 @@ func (cmd *batchCommandGet) executeSingle(client *Client) Error { } func (cmd *batchCommandGet) Execute() Error { - if len(cmd.batch.offsets) == 1 { + if cmd.objects == nil && len(cmd.batch.offsets) == 1 { return cmd.executeSingle(cmd.node.cluster.client) } return cmd.execute(cmd) diff --git a/batch_command_operate.go b/batch_command_operate.go index e39c38b3..2ff0bfbd 100644 --- a/batch_command_operate.go +++ b/batch_command_operate.go @@ -326,7 +326,8 @@ func (cmd *batchCommandOperate) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() streamRes, gerr := client.BatchOperate(ctx, &req) if gerr != nil { diff --git a/batch_test.go b/batch_test.go index 87e51f36..1ded9f48 100644 --- a/batch_test.go +++ b/batch_test.go @@ -1,3 +1,6 @@ +//go:build !app_engine +// +build !app_engine + // Copyright 2014-2022 Aerospike, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,6 +33,38 @@ import ( // ALL tests are isolated by SetName and Key, which are 50 random characters var _ = gg.Describe("Aerospike", func() { + gg.Describe("BatchGetOperate operations", func() { + var ns = *namespace + var set = randString(50) + + gg.It("must return the result with same ordering", func() { + for _, keyCount := range []int{256, 1} { + var keys []*as.Key + for i := 0; i < keyCount; i++ { + key, _ := as.NewKey(ns, set, i) + client.PutBins(nil, key, as.NewBin("i", i), as.NewBin("j", i)) + + keys = append(keys, key) + } + + ops := []*as.Operation{as.GetBinOp("i"), as.PutOp(as.NewBin("h", 1))} + _, err := client.BatchGetOperate(nil, keys, ops...) + gm.Expect(err).To(gm.HaveOccurred()) + + ops = []*as.Operation{as.GetBinOp("i")} + recs, err := client.BatchGetOperate(nil, keys, ops...) + + gm.Expect(err).ToNot(gm.HaveOccurred()) + for i, rec := range recs { + gm.Expect(len(rec.Bins)).To(gm.Equal(1)) + gm.Expect(rec.Bins["i"]).To(gm.Equal(i)) + } + + } + }) // it + + }) // describe + gg.Describe("Batch Write operations", func() { var ns = *namespace var set = randString(50) @@ -257,6 +292,43 @@ var _ = gg.Describe("Aerospike", func() { }) + gg.It("must successfully execute a BatchOperate for many keys", func() { + if *dbaas { + gg.Skip("Not supported in DBAAS environment") + } + + gm.Expect(err).ToNot(gm.HaveOccurred()) + bwPolicy := as.NewBatchWritePolicy() + bdPolicy := as.NewBatchDeletePolicy() + + var keys []*as.Key + for i := 0; i < 64; i++ { + key, _ := as.NewKey(ns, set, i) + if i == 0 { + keys = append(keys, key) + } + bin0 := as.NewBin("count", i) + err := client.PutBins(nil, key, bin0) + gm.Expect(err).ToNot(gm.HaveOccurred()) + } + + for _, sendKey := range []bool{true, false} { + bwPolicy.SendKey = sendKey + bdPolicy.SendKey = sendKey + bpolicy.SendKey = !sendKey + + var brecs []as.BatchRecordIfc + for _, key := range keys { + brecs = append(brecs, as.NewBatchWrite(bwPolicy, key, as.PutOp(as.NewBin("bin1", "a")), as.PutOp(as.NewBin("bin2", "b")))) + brecs = append(brecs, as.NewBatchDelete(bdPolicy, key)) + brecs = append(brecs, as.NewBatchRead(nil, key, []string{"bin2"})) + } + + err := client.BatchOperate(bpolicy, brecs) + gm.Expect(err).ToNot(gm.HaveOccurred()) + } + }) + gg.It("must successfully execute a delete op", func() { if *dbaas { gg.Skip("Not supported in DBAAS environment") diff --git a/cdt_map_test.go b/cdt_map_test.go index 9c61ce06..94fed022 100644 --- a/cdt_map_test.go +++ b/cdt_map_test.go @@ -1,3 +1,6 @@ +//go:build !as_performance && !app_engine +// +build !as_performance,!app_engine + // Copyright 2014-2022 Aerospike, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/client.go b/client.go index ba8dec0b..d0af607e 100644 --- a/client.go +++ b/client.go @@ -137,6 +137,11 @@ func (clnt *Client) GetDefaultBatchWritePolicy() *BatchWritePolicy { return clnt.DefaultBatchWritePolicy } +// DefaultBatchReadPolicy returns corresponding default policy from the client +func (clnt *Client) GetDefaultBatchReadPolicy() *BatchReadPolicy { + return clnt.DefaultBatchReadPolicy +} + // DefaultBatchDeletePolicy returns corresponding default policy from the client func (clnt *Client) GetDefaultBatchDeletePolicy() *BatchDeletePolicy { return clnt.DefaultBatchDeletePolicy @@ -187,6 +192,11 @@ func (clnt *Client) SetDefaultBatchWritePolicy(policy *BatchWritePolicy) { clnt.DefaultBatchWritePolicy = policy } +// DefaultBatchReadPolicy returns corresponding default policy from the client +func (clnt *Client) SetDefaultBatchReadPolicy(policy *BatchReadPolicy) { + clnt.DefaultBatchReadPolicy = policy +} + // DefaultBatchDeletePolicy returns corresponding default policy from the client func (clnt *Client) SetDefaultBatchDeletePolicy(policy *BatchDeletePolicy) { clnt.DefaultBatchDeletePolicy = policy diff --git a/client_ifc_app_engine.go b/client_ifc_app_engine.go index b171e5f5..b817935e 100644 --- a/client_ifc_app_engine.go +++ b/client_ifc_app_engine.go @@ -103,8 +103,22 @@ type ClientIfc interface { // TODO: Synchronization here for the sake of dynamic config in the future + getUsablePolicy(*BasePolicy) *BasePolicy + getUsableWritePolicy(*WritePolicy) *WritePolicy + getUsableScanPolicy(*ScanPolicy) *ScanPolicy + getUsableQueryPolicy(*QueryPolicy) *QueryPolicy + getUsableAdminPolicy(*AdminPolicy) *AdminPolicy + getUsableInfoPolicy(*InfoPolicy) *InfoPolicy + + getUsableBatchPolicy(*BatchPolicy) *BatchPolicy + getUsableBatchReadPolicy(*BatchReadPolicy) *BatchReadPolicy + getUsableBatchWritePolicy(*BatchWritePolicy) *BatchWritePolicy + getUsableBatchDeletePolicy(*BatchDeletePolicy) *BatchDeletePolicy + getUsableBatchUDFPolicy(*BatchUDFPolicy) *BatchUDFPolicy + GetDefaultPolicy() *BasePolicy GetDefaultBatchPolicy() *BatchPolicy + GetDefaultBatchReadPolicy() *BatchReadPolicy GetDefaultBatchWritePolicy() *BatchWritePolicy GetDefaultBatchDeletePolicy() *BatchDeletePolicy GetDefaultBatchUDFPolicy() *BatchUDFPolicy @@ -116,6 +130,7 @@ type ClientIfc interface { SetDefaultPolicy(*BasePolicy) SetDefaultBatchPolicy(*BatchPolicy) + SetDefaultBatchReadPolicy(*BatchReadPolicy) SetDefaultBatchWritePolicy(*BatchWritePolicy) SetDefaultBatchDeletePolicy(*BatchDeletePolicy) SetDefaultBatchUDFPolicy(*BatchUDFPolicy) diff --git a/client_ifc_as_performance.go b/client_ifc_as_performance.go index 1e962c1a..f3504842 100644 --- a/client_ifc_as_performance.go +++ b/client_ifc_as_performance.go @@ -103,8 +103,22 @@ type ClientIfc interface { // TODO: Synchronization here for the sake of dynamic config in the future + getUsablePolicy(*BasePolicy) *BasePolicy + getUsableWritePolicy(*WritePolicy) *WritePolicy + getUsableScanPolicy(*ScanPolicy) *ScanPolicy + getUsableQueryPolicy(*QueryPolicy) *QueryPolicy + getUsableAdminPolicy(*AdminPolicy) *AdminPolicy + getUsableInfoPolicy(*InfoPolicy) *InfoPolicy + + getUsableBatchPolicy(*BatchPolicy) *BatchPolicy + getUsableBatchReadPolicy(*BatchReadPolicy) *BatchReadPolicy + getUsableBatchWritePolicy(*BatchWritePolicy) *BatchWritePolicy + getUsableBatchDeletePolicy(*BatchDeletePolicy) *BatchDeletePolicy + getUsableBatchUDFPolicy(*BatchUDFPolicy) *BatchUDFPolicy + GetDefaultPolicy() *BasePolicy GetDefaultBatchPolicy() *BatchPolicy + GetDefaultBatchReadPolicy() *BatchReadPolicy GetDefaultBatchWritePolicy() *BatchWritePolicy GetDefaultBatchDeletePolicy() *BatchDeletePolicy GetDefaultBatchUDFPolicy() *BatchUDFPolicy @@ -116,6 +130,7 @@ type ClientIfc interface { SetDefaultPolicy(*BasePolicy) SetDefaultBatchPolicy(*BatchPolicy) + SetDefaultBatchReadPolicy(*BatchReadPolicy) SetDefaultBatchWritePolicy(*BatchWritePolicy) SetDefaultBatchDeletePolicy(*BatchDeletePolicy) SetDefaultBatchUDFPolicy(*BatchUDFPolicy) diff --git a/client_object_test.go b/client_object_test.go index badb7bc2..b25f8431 100644 --- a/client_object_test.go +++ b/client_object_test.go @@ -1,5 +1,5 @@ -//go:build !as_performance -// +build !as_performance +//go:build !as_performance && !app_engine +// +build !as_performance,!app_engine // Copyright 2014-2022 Aerospike, Inc. // @@ -431,7 +431,7 @@ var _ = gg.Describe("Aerospike", func() { ArrayOfStructs: [1]SomeStruct{{A: 1, Self: &SomeStruct{A: 1}}}, SliceOfStructs: []SomeStruct{{A: 1, Self: &SomeStruct{A: 1}}}, - Map: map[interface{}]interface{}{1: "string", "string": nil, nil: map[interface{}]interface{}{"1": ip}, true: false}, + Map: map[interface{}]interface{}{1: "string", "string": nil /*nil: map[interface{}]interface{}{"1": ip}, true: false*/}, MapOfMaps: map[string]map[int64]byte{"1": {1: 1, 2: 2}}, MapOfSlices: map[string][]byte{"1": {1, 2}, "2": {3, 4}}, MapOfArrays: map[string][3]byte{"1": {1, 2, 3}, "2": {3, 4, 5}}, @@ -581,7 +581,7 @@ var _ = gg.Describe("Aerospike", func() { ArrayOfStructs: [1]SomeStruct{{A: 1, Self: &SomeStruct{A: 1}}}, SliceOfStructs: []SomeStruct{{A: 1, Self: &SomeStruct{A: 1}}}, - Map: map[interface{}]interface{}{1: "string", "string": nil, nil: map[interface{}]interface{}{"1": ip}, true: false}, + Map: map[interface{}]interface{}{1: "string", "string": nil /*nil: map[interface{}]interface{}{"1": ip}, true: false*/}, MapOfMaps: map[string]map[int64]byte{"1": {1: 1, 2: 2}}, MapOfSlices: map[string][]byte{"1": {1, 2}, "2": {3, 4}}, MapOfArrays: map[string][3]byte{"1": {1, 2, 3}, "2": {3, 4, 5}}, @@ -712,7 +712,7 @@ var _ = gg.Describe("Aerospike", func() { gm.Expect(rec.Bins).To(gm.Equal(as.BinMap{"name": t.Name, "inner": map[interface{}]interface{}{"v1": 0, "v2": ""}})) }) - gg.It("must save an object with the most complex structure possible", func() { + gg.It("must save an object with the most complex structure possible and retrieve it via BatchGetObject", func() { testObj := makeTestObject() err := client.PutObject(nil, key, &testObj) diff --git a/client_reflect.go b/client_reflect.go index d6dd4fef..2545dcb5 100644 --- a/client_reflect.go +++ b/client_reflect.go @@ -212,14 +212,6 @@ func (clnt *Client) ScanNodeObjects(apolicy *ScanPolicy, node *Node, objChan int return clnt.scanNodePartitionsObjects(apolicy, node, objChan, namespace, setName, binNames...) } -// scanNodeObjects reads all records in specified namespace and set for one node only, -// and marshalls the results into the objects of the provided channel in Recordset. -// If the policy is nil, the default relevant policy will be used. -func (clnt *Client) scanNodeObjects(policy *ScanPolicy, node *Node, recordset *Recordset, namespace string, setName string, binNames ...string) Error { - command := newScanObjectsCommand(node, policy, namespace, setName, binNames, recordset) - return command.Execute() -} - // QueryPartitionObjects executes a query for specified partitions and returns a recordset. // The query executor puts records on the channel from separate goroutines. // The caller can concurrently pop records off the channel through the diff --git a/client_reflect_test.go b/client_reflect_test.go index 0e7bc812..c4a9fee6 100644 --- a/client_reflect_test.go +++ b/client_reflect_test.go @@ -94,15 +94,15 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "true": true, - "false": false, - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []int{18, 41}, // array to complex map - "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "true": true, + "false": false, + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []int{18, 41}, // array to complex map + "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test }, }) @@ -144,12 +144,12 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []int{18, 41}, // array to complex map + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []int{18, 41}, // array to complex map // "longString": strings.Repeat("s", 32911), // bit-sign test "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test }) @@ -201,15 +201,15 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "true": true, - "false": false, - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []interface{}{18, 41}, // array to complex map - "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "true": true, + "false": false, + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []interface{}{18, 41}, // array to complex map + "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test }, }) @@ -251,14 +251,14 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []int{18, 41}, // array to complex map - "longString": strings.Repeat("s", 32911), // bit-sign test - "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []int{18, 41}, // array to complex map + "longString": strings.Repeat("s", 32911), // bit-sign test + "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test }) err = client.PutBins(wpolicy, key, bin1, bin2) diff --git a/client_test.go b/client_test.go index d41df5e4..628c5cfa 100644 --- a/client_test.go +++ b/client_test.go @@ -681,16 +681,16 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "true": true, - "false": false, - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []interface{}{18, 41}, // array to complex map - "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test - "intList": intList, + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "true": true, + "false": false, + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []interface{}{18, 41}, // array to complex map + "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test + "intList": intList, }, }) @@ -733,14 +733,14 @@ var _ = gg.Describe("Aerospike", func() { int64(math.MinInt64): int64(math.MinInt64), int64(math.MaxInt64): int64(math.MaxInt64), // uint64(math.MaxUint64): uint64(math.MaxUint64), - float32(-math.MaxFloat32): float32(-math.MaxFloat32), - float64(-math.MaxFloat64): float64(-math.MaxFloat64), - float32(math.MaxFloat32): float32(math.MaxFloat32), - float64(math.MaxFloat64): float64(math.MaxFloat64), - "string": map[interface{}]interface{}{nil: "string", "string": 19}, // map to complex array - nil: []interface{}{18, 41}, // array to complex map - "longString": strings.Repeat("s", 32911), // bit-sign test - "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test + // float32(-math.MaxFloat32): float32(-math.MaxFloat32), + // float64(-math.MaxFloat64): float64(-math.MaxFloat64), + // float32(math.MaxFloat32): float32(math.MaxFloat32), + // float64(math.MaxFloat64): float64(math.MaxFloat64), + "string": map[interface{}]interface{}{ /*nil: "string",*/ "string": 19}, // map to complex array + // nil: []interface{}{18, 41}, // array to complex map + "longString": strings.Repeat("s", 32911), // bit-sign test + "GeoJSON": as.NewGeoJSONValue(`{ "type": "Point", "coordinates": [0.00, 0.00] }"`), // bit-sign test }) err = client.PutBins(wpolicy, key, bin1, bin2) diff --git a/delete_command.go b/delete_command.go index 93ca0fc8..a916a5e8 100644 --- a/delete_command.go +++ b/delete_command.go @@ -139,7 +139,8 @@ func (cmd *deleteCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Delete(ctx, &req) if gerr != nil { diff --git a/examples/blob/blob.go b/examples/blob/blob.go index 509a16bd..6f9de262 100644 --- a/examples/blob/blob.go +++ b/examples/blob/blob.go @@ -25,7 +25,7 @@ type Person struct { // EncodeBlob defines The AerospikeBlob interface func (p Person) EncodeBlob() ([]byte, error) { - return append([]byte(p.name)), nil + return []byte(p.name), nil } // DecodeBlob is optional, and should be used manually diff --git a/execute_command.go b/execute_command.go index 6cbdc261..9c3d401a 100644 --- a/execute_command.go +++ b/execute_command.go @@ -108,7 +108,8 @@ func (cmd *executeCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Execute(ctx, &req) if gerr != nil { diff --git a/execute_task.go b/execute_task.go index 24269e1d..b9d39df9 100644 --- a/execute_task.go +++ b/execute_task.go @@ -180,7 +180,8 @@ func (etsk *ExecuteTask) grpcIsDone() (bool, Error) { client := kvs.NewQueryClient(conn) - ctx, _ := context.WithTimeout(context.Background(), NewInfoPolicy().Timeout) + ctx, cancel := context.WithTimeout(context.Background(), NewInfoPolicy().Timeout) + defer cancel() streamRes, gerr := client.BackgroundTaskStatus(ctx, &req) if gerr != nil { @@ -210,13 +211,5 @@ func (etsk *ExecuteTask) grpcIsDone() (bool, Error) { etsk.clnt.returnGrpcConnToPool(conn) return false, nil } - - if !res.GetHasNext() { - etsk.clnt.returnGrpcConnToPool(conn) - return false, nil - } } - - etsk.clnt.returnGrpcConnToPool(conn) - return true, nil } diff --git a/exists_command.go b/exists_command.go index ed2d98ff..c4d3c505 100644 --- a/exists_command.go +++ b/exists_command.go @@ -133,7 +133,8 @@ func (cmd *existsCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Exists(ctx, &req) if gerr != nil { diff --git a/go.mod b/go.mod index f66a6cda..1a0b58a4 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/stretchr/testify v1.8.4 // indirect + github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect @@ -27,3 +28,7 @@ require ( gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +retract ( + v7.3.0 // `Client.BatchGetOperate` issue +) diff --git a/go.sum b/go.sum index 20881279..16b99f85 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad h1:W0LEBv82YCGEtcmPA3uNZBI33/qF//HAAs3MawDjRa0= +github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad/go.mod h1:Hy8o65+MXnS6EwGElrSRjUzQDLXreJlzYLlWiHtt8hM= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= diff --git a/info_policy.go b/info_policy.go index 07df5196..574ddbc7 100644 --- a/info_policy.go +++ b/info_policy.go @@ -51,12 +51,14 @@ func (p *InfoPolicy) timeout() time.Duration { return _DEFAULT_TIMEOUT } -func (p *InfoPolicy) grpcDeadlineContext() context.Context { +var simpleCancelFunc = func() {} + +func (p *InfoPolicy) grpcDeadlineContext() (context.Context, context.CancelFunc) { timeout := p.timeout() if timeout <= 0 { - return context.Background() + return context.Background(), simpleCancelFunc } - ctx, _ := context.WithTimeout(context.Background(), timeout) - return ctx + ctx, cancel := context.WithTimeout(context.Background(), timeout) + return ctx, cancel } diff --git a/operate_command.go b/operate_command.go index 94a3adfc..f731f3e7 100644 --- a/operate_command.go +++ b/operate_command.go @@ -96,7 +96,8 @@ func (cmd *operateCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Operate(ctx, &req) if gerr != nil { diff --git a/policy.go b/policy.go index 26dcb99c..bcc55add 100644 --- a/policy.go +++ b/policy.go @@ -252,12 +252,12 @@ func (p *BasePolicy) grpc() *kvs.ReadPolicy { } } -func (p *BasePolicy) grpcDeadlineContext() context.Context { +func (p *BasePolicy) grpcDeadlineContext() (context.Context, context.CancelFunc) { timeout := p.timeout() if timeout <= 0 { - return context.Background() + return context.Background(), simpleCancelFunc } - ctx, _ := context.WithTimeout(context.Background(), timeout) - return ctx + ctx, cancel := context.WithTimeout(context.Background(), timeout) + return ctx, cancel } diff --git a/proxy_auth_interceptor.go b/proxy_auth_interceptor.go index 09668dab..8c9f8a63 100644 --- a/proxy_auth_interceptor.go +++ b/proxy_auth_interceptor.go @@ -129,7 +129,8 @@ func (interceptor *authInterceptor) login() Error { client := auth.NewAuthServiceClient(conn) - ctx, _ := context.WithTimeout(context.Background(), interceptor.clnt.clientPolicy.Timeout) + ctx, cancel := context.WithTimeout(context.Background(), interceptor.clnt.clientPolicy.Timeout) + defer cancel() res, gerr := client.Get(ctx, &req) if gerr != nil { diff --git a/proxy_client.go b/proxy_client.go index 7268a545..64e47ebf 100644 --- a/proxy_client.go +++ b/proxy_client.go @@ -151,6 +151,11 @@ func (clnt *ProxyClient) GetDefaultBatchWritePolicy() *BatchWritePolicy { return clnt.DefaultBatchWritePolicy } +// DefaultBatchReadPolicy returns corresponding default policy from the client +func (clnt *ProxyClient) GetDefaultBatchReadPolicy() *BatchReadPolicy { + return clnt.DefaultBatchReadPolicy +} + // DefaultBatchDeletePolicy returns corresponding default policy from the client func (clnt *ProxyClient) GetDefaultBatchDeletePolicy() *BatchDeletePolicy { return clnt.DefaultBatchDeletePolicy @@ -196,6 +201,11 @@ func (clnt *ProxyClient) SetDefaultBatchPolicy(policy *BatchPolicy) { clnt.DefaultBatchPolicy = policy } +// DefaultBatchReadPolicy returns corresponding default policy from the client +func (clnt *ProxyClient) SetDefaultBatchReadPolicy(policy *BatchReadPolicy) { + clnt.DefaultBatchReadPolicy = policy +} + // DefaultBatchWritePolicy returns corresponding default policy from the client func (clnt *ProxyClient) SetDefaultBatchWritePolicy(policy *BatchWritePolicy) { clnt.DefaultBatchWritePolicy = policy @@ -273,7 +283,8 @@ func (clnt *ProxyClient) createGrpcConn(noInterceptor bool) (*grpc.ClientConn, E dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) } - ctx, _ := context.WithTimeout(context.Background(), clnt.clientPolicy.Timeout) + ctx, cancel := context.WithTimeout(context.Background(), clnt.clientPolicy.Timeout) + defer cancel() allOptions := append(dialOptions, clnt.dialOptions...) if !noInterceptor { @@ -324,7 +335,8 @@ func (clnt *ProxyClient) ServerVersion(policy *InfoPolicy) (string, Error) { client := kvs.NewAboutClient(conn) - ctx := policy.grpcDeadlineContext() + ctx, cancel := policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Get(ctx, &req) if gerr != nil { diff --git a/proxy_query_partition_command.go b/proxy_query_partition_command.go index 2ddde09f..ed7be72d 100644 --- a/proxy_query_partition_command.go +++ b/proxy_query_partition_command.go @@ -105,7 +105,8 @@ func (cmd *grpcQueryPartitionCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewQueryClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() streamRes, gerr := client.Query(ctx, &req) if gerr != nil { diff --git a/proxy_scan_command.go b/proxy_scan_command.go index b110ad9a..897241e1 100644 --- a/proxy_scan_command.go +++ b/proxy_scan_command.go @@ -108,7 +108,8 @@ func (cmd *grpcScanPartitionCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewScanClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() streamRes, gerr := client.Scan(ctx, &req) if gerr != nil { diff --git a/query_objects_command.go b/query_objects_command.go deleted file mode 100644 index 346500de..00000000 --- a/query_objects_command.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014-2022 Aerospike, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package aerospike - -import "github.com/aerospike/aerospike-client-go/v7/types" - -type queryObjectsCommand struct { - queryCommand -} - -func newQueryObjectsCommand(node *Node, policy *QueryPolicy, statement *Statement, recordset *Recordset) *queryObjectsCommand { - cmd := &queryObjectsCommand{ - queryCommand: *newQueryCommand(node, policy, nil, statement, nil, recordset), - } - - cmd.terminationErrorType = types.QUERY_TERMINATED - - return cmd -} - -func (cmd *queryObjectsCommand) Execute() Error { - defer cmd.recordset.signalEnd() - err := cmd.execute(cmd) - if err != nil { - cmd.recordset.sendError(err) - } - return err -} diff --git a/query_record_command.go b/query_record_command.go deleted file mode 100644 index 998dbbec..00000000 --- a/query_record_command.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014-2022 Aerospike, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package aerospike - -type queryRecordCommand struct { - queryCommand -} - -func newQueryRecordCommand(node *Node, policy *QueryPolicy, statement *Statement, recordset *Recordset) *queryRecordCommand { - cmd := &queryRecordCommand{ - queryCommand: *newQueryCommand(node, policy, nil, statement, nil, recordset), - } - - cmd.terminationErrorType = statement.terminationError() - - return cmd -} diff --git a/read_command.go b/read_command.go index 21d91173..08949a01 100644 --- a/read_command.go +++ b/read_command.go @@ -294,7 +294,8 @@ func (cmd *readCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Read(ctx, &req) if gerr != nil { diff --git a/read_header_command.go b/read_header_command.go index e0879419..832b0f2a 100644 --- a/read_header_command.go +++ b/read_header_command.go @@ -130,7 +130,8 @@ func (cmd *readHeaderCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.GetHeader(ctx, &req) if gerr != nil { diff --git a/scan_objects_command.go b/scan_objects_command.go deleted file mode 100644 index 70c8fd46..00000000 --- a/scan_objects_command.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2014-2022 Aerospike, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package aerospike - -import "github.com/aerospike/aerospike-client-go/v7/types" - -type scanObjectsCommand struct { - baseMultiCommand - - policy *ScanPolicy - namespace string - setName string - binNames []string - taskID uint64 -} - -func newScanObjectsCommand( - node *Node, - policy *ScanPolicy, - namespace string, - setName string, - binNames []string, - recordset *Recordset, -) *scanObjectsCommand { - cmd := &scanObjectsCommand{ - baseMultiCommand: *newStreamingMultiCommand(node, recordset, namespace, false), - policy: policy, - namespace: namespace, - setName: setName, - binNames: binNames, - } - - cmd.terminationErrorType = types.SCAN_TERMINATED - - return cmd -} - -func (cmd *scanObjectsCommand) getPolicy(ifc command) Policy { - return cmd.policy -} - -func (cmd *scanObjectsCommand) writeBuffer(ifc command) Error { - return cmd.setScan(cmd.policy, &cmd.namespace, &cmd.setName, cmd.binNames, cmd.taskID, nil) -} - -func (cmd *scanObjectsCommand) parseResult(ifc command, conn *Connection) Error { - return cmd.baseMultiCommand.parseResult(ifc, conn) -} - -func (cmd *scanObjectsCommand) transactionType() transactionType { - return ttScan -} - -func (cmd *scanObjectsCommand) Execute() Error { - defer cmd.recordset.signalEnd() - err := cmd.execute(cmd) - if err != nil { - cmd.recordset.sendError(err) - } - return err -} diff --git a/scan_partition_objects_command.go b/scan_partition_objects_command.go index 6a734f64..6fc51234 100644 --- a/scan_partition_objects_command.go +++ b/scan_partition_objects_command.go @@ -16,7 +16,15 @@ package aerospike import "github.com/aerospike/aerospike-client-go/v7/types" -type scanPartitionObjectsCommand scanObjectsCommand +type scanPartitionObjectsCommand struct { + baseMultiCommand + + policy *ScanPolicy + namespace string + setName string + binNames []string + taskID uint64 +} func newScanPartitionObjectsCommand( policy *ScanPolicy, @@ -50,6 +58,10 @@ func (cmd *scanPartitionObjectsCommand) writeBuffer(ifc command) Error { return cmd.setScan(cmd.policy, &cmd.namespace, &cmd.setName, cmd.binNames, cmd.recordset.taskID, cmd.nodePartitions) } +func (cmd *scanPartitionObjectsCommand) parseResult(ifc command, conn *Connection) Error { + return cmd.baseMultiCommand.parseResult(ifc, conn) +} + func (cmd *scanPartitionObjectsCommand) shouldRetry(e Error) bool { return cmd.tracker != nil && cmd.tracker.shouldRetry(cmd.nodePartitions, e) } diff --git a/server_command.go b/server_command.go index 4bae2627..56fec97e 100644 --- a/server_command.go +++ b/server_command.go @@ -125,7 +125,8 @@ func (cmd *serverCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewQueryClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() streamRes, gerr := client.BackgroundExecute(ctx, &req) if gerr != nil { diff --git a/test_utils_test.go b/test_utils_test.go index 9787cdca..a46c8791 100644 --- a/test_utils_test.go +++ b/test_utils_test.go @@ -28,7 +28,7 @@ type testBLOB struct { } func (tb *testBLOB) EncodeBlob() ([]byte, error) { - return append([]byte(tb.name)), nil + return []byte(tb.name), nil } // generates a random string of specified length diff --git a/tools/benchmark/benchmark.go b/tools/benchmark/benchmark.go index 75f48a7a..07ab1450 100644 --- a/tools/benchmark/benchmark.go +++ b/tools/benchmark/benchmark.go @@ -673,7 +673,6 @@ func runBench_RU(client as.ClientIfc, ident int, times int) { time.Sleep(time.Second - time.Duration(time.Now().UnixNano()-atomic.LoadInt64(&lastReport))) } } - countReportChan <- &TStats{false, WCount, RCount, writeErr, readErr, writeTOErr, readTOErr, wMinLat, wMaxLat, rMinLat, rMaxLat, wLatTotal, rLatTotal, wLatList, rLatList} } // calculates transactions per second diff --git a/touch_command.go b/touch_command.go index 58b69d20..f5f31483 100644 --- a/touch_command.go +++ b/touch_command.go @@ -166,7 +166,8 @@ func (cmd *touchCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Touch(ctx, &req) if gerr != nil { diff --git a/udf_test.go b/udf_test.go index fd5dd4bd..80d3f430 100644 --- a/udf_test.go +++ b/udf_test.go @@ -1,3 +1,6 @@ +//go:build !app_engine +// +build !app_engine + // Copyright 2014-2022 Aerospike, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -368,7 +371,7 @@ var _ = gg.Describe("UDF/Query tests", func() { gg.It("must serialize map values to echo function and get the same value back", func() { v := map[interface{}]interface{}{ - nil: nil, + // nil: nil, math.MinInt64: math.MinInt64, math.MinInt32: math.MinInt32, math.MinInt16: math.MinInt16, @@ -388,7 +391,7 @@ var _ = gg.Describe("UDF/Query tests", func() { } vExpected := map[interface{}]interface{}{ - nil: nil, + // nil: nil, math.MinInt64: math.MinInt64, math.MinInt32: math.MinInt32, math.MinInt16: math.MinInt16, diff --git a/value_test.go b/value_test.go index 82d72089..7c92487d 100644 --- a/value_test.go +++ b/value_test.go @@ -30,7 +30,7 @@ type testBLOB struct { } func (b *testBLOB) EncodeBlob() ([]byte, error) { - return append([]byte(b.name)), nil + return []byte(b.name), nil } func isValidIntegerValue(i int, v Value) bool { diff --git a/write_command.go b/write_command.go index 61c428cf..67af862d 100644 --- a/write_command.go +++ b/write_command.go @@ -140,7 +140,8 @@ func (cmd *writeCommand) ExecuteGRPC(clnt *ProxyClient) Error { client := kvs.NewKVSClient(conn) - ctx := cmd.policy.grpcDeadlineContext() + ctx, cancel := cmd.policy.grpcDeadlineContext() + defer cancel() res, gerr := client.Write(ctx, &req) if gerr != nil {