├── .build.yml ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .testcoverage.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── abort_status.go ├── admin_command.go ├── admin_policy.go ├── aerospike.go ├── aerospike_bench_reflect_test.go ├── aerospike_bench_test.go ├── aerospike_suite_test.go ├── anonymous_fields_test.go ├── auth_mode.go ├── base_read_command.go ├── base_write_command.go ├── batch_attr.go ├── batch_command.go ├── batch_command_delete.go ├── batch_command_exists.go ├── batch_command_get.go ├── batch_command_get_reflect.go ├── batch_command_operate.go ├── batch_command_reflect.go ├── batch_command_udf.go ├── batch_delete.go ├── batch_delete_policy.go ├── batch_executer.go ├── batch_index_command_get.go ├── batch_node.go ├── batch_node_list.go ├── batch_offsets.go ├── batch_policy.go ├── batch_read.go ├── batch_read_policy.go ├── batch_record.go ├── batch_test.go ├── batch_udf.go ├── batch_udf_policy.go ├── batch_write.go ├── batch_write_policy.go ├── bench_batchget_test.go ├── bench_cdt_list_test.go ├── bench_get_test.go ├── bench_interface_allocs_test.go ├── bench_key_test.go ├── bench_packing_test.go ├── bench_rand_gen_test.go ├── bench_read_command_test.go ├── bench_recordset_test.go ├── bench_values_test.go ├── bench_write_command_test.go ├── bin.go ├── bit_overflow_action.go ├── bit_policy.go ├── bit_resize_flags.go ├── bit_write_flags.go ├── buffered_connection.go ├── bytes_buffer.go ├── cdt.go ├── cdt_bitwise.go ├── cdt_bitwise_test.go ├── cdt_context.go ├── cdt_context_test.go ├── cdt_list.go ├── cdt_list_test.go ├── cdt_map.go ├── cdt_map_test.go ├── client.go ├── client_appengine_exclusions.go ├── client_object_test.go ├── client_policy.go ├── client_reflect.go ├── client_reflect_test.go ├── client_test.go ├── cluster.go ├── command.go ├── commit_error.go ├── commit_policy.go ├── commit_status.go ├── complex_index_test.go ├── complex_query_test.go ├── connection.go ├── connection_heap.go ├── connection_heap_test.go ├── connection_test.go ├── delete_command.go ├── docs ├── README.md ├── aerospike.md ├── client.md ├── datamodel.md ├── log.md ├── performance.md └── policies.md ├── error.go ├── error_test.go ├── example_client_test.go ├── example_listiter_int_test.go ├── example_listiter_string_test.go ├── example_listiter_time_test.go ├── example_mapiter_test.go ├── example_pagination_cursor_test.go ├── examples ├── add │ └── add.go ├── append │ └── append.go ├── batch │ └── batch.go ├── blob │ └── blob.go ├── count_set_objects │ └── count_set_objects_using_request_info.go ├── custom_list_iter │ └── custom_list_iter.go ├── expire │ └── expire.go ├── expressions │ └── expressions.go ├── generation │ └── generation.go ├── geojson_query │ └── geojson_query.go ├── get │ ├── .gitignore │ └── get.go ├── info │ └── info.go ├── list_map │ └── list_map.go ├── operate │ └── operate.go ├── prepend │ └── prepend.go ├── put │ ├── .gitignore │ └── put.go ├── putget │ └── putget.go ├── query-aggregate │ ├── average │ │ └── average.go │ ├── single_bin_sum │ │ └── single_bin_sum.go │ └── udf │ │ ├── average.lua │ │ └── sum_single_bin.lua ├── replace │ └── replace.go ├── scan_paginate │ └── scan_paginate.go ├── scan_parallel │ └── scan_parallel.go ├── scan_serial │ └── scan_serial.go ├── shared │ └── shared.go ├── simple │ └── simple.go ├── tls_secure_connection │ └── tls_secure_connection.go ├── touch │ └── touch.go └── udf │ └── udf.go ├── execute_command.go ├── execute_task.go ├── exists_command.go ├── exp_bit.go ├── exp_bit_test.go ├── exp_hll.go ├── exp_hll_test.go ├── exp_list.go ├── exp_list_test.go ├── exp_map.go ├── exp_map_test.go ├── exp_operation.go ├── exp_ops_test.go ├── expression.go ├── expression_ops_test.go ├── expression_test.go ├── field_type.go ├── filter.go ├── generation_policy.go ├── generics.go ├── geo_test.go ├── go.mod ├── go.sum ├── helper_test.go ├── hll_operation.go ├── hll_operation_test.go ├── hll_policy.go ├── hll_write_flags.go ├── host.go ├── host_test.go ├── index_collection_type.go ├── index_test.go ├── index_type.go ├── info.go ├── info_policy.go ├── internal ├── atomic │ ├── array.go │ ├── atomic_test.go │ ├── bool.go │ ├── bool_test.go │ ├── guard.go │ ├── guard_test.go │ ├── int.go │ ├── int_test.go │ ├── map │ │ └── map.go │ ├── queue.go │ ├── queue_test.go │ ├── sync_val.go │ ├── typed_val.go │ └── typed_val_test.go ├── lua │ ├── instance.go │ ├── lua.go │ ├── lua_aerospike.go │ ├── lua_aerospike_test.go │ ├── lua_list.go │ ├── lua_list_test.go │ ├── lua_map.go │ ├── lua_map_test.go │ ├── lua_stream.go │ ├── lua_suite_test.go │ └── resources │ │ ├── aerospike.go │ │ └── stream_ops.go └── seq │ └── seq.go ├── key.go ├── key_bench_test.go ├── key_helper.go ├── key_reflect_test.go ├── key_test.go ├── language.go ├── load_test.go ├── logger └── logger.go ├── login_command.go ├── marshal.go ├── metrics_policy.go ├── multi_command.go ├── multi_policy.go ├── node.go ├── node_stats.go ├── node_test.go ├── node_validator.go ├── operate_args.go ├── operate_command_read.go ├── operate_command_write.go ├── operation.go ├── packer.go ├── packer_reflect.go ├── packing_test.go ├── partition.go ├── partition_filter.go ├── partition_parser.go ├── partition_status.go ├── partition_tracker.go ├── partitions.go ├── peers.go ├── peers_parser.go ├── pkg ├── bcrypt │ ├── .gitignore │ ├── LICENSE │ ├── README │ ├── bcrypt.go │ └── cipher.go └── ripemd160 │ ├── ripemd160.go │ ├── ripemd160_test.go │ └── ripemd160block.go ├── policy.go ├── privilege.go ├── query_aggregate_command.go ├── query_aggregate_test.go ├── query_command.go ├── query_context_test.go ├── query_duration.go ├── query_executor.go ├── query_objects_executor.go ├── query_partition_command.go ├── query_partitiopn_objects_command.go ├── query_policy.go ├── query_test.go ├── random_operation_test.go ├── read_command.go ├── read_command_reflect.go ├── read_command_reflect_test.go ├── read_header_command.go ├── read_mode_ap.go ├── read_mode_sc.go ├── record.go ├── record_exists_action.go ├── record_parser.go ├── recordset.go ├── recordset_test.go ├── replica_policy.go ├── role.go ├── scan_executor.go ├── scan_objects_executor.go ├── scan_partition_command.go ├── scan_partition_objects_command.go ├── scan_policy.go ├── scan_test.go ├── security_test.go ├── server_command.go ├── single_command.go ├── statement.go ├── task.go ├── task_drop_index.go ├── task_index.go ├── task_register.go ├── task_remove.go ├── test └── resources │ ├── average.lua │ └── sum_single_bin.lua ├── test_utils_test.go ├── tools.go ├── tools ├── asinfo │ └── asinfo.go ├── benchmark │ ├── README.md │ ├── benchmark.go │ └── tls.go └── cli │ └── cli.go ├── touch_command.go ├── truncate_test.go ├── txn.go ├── txn_add_keys_command.go ├── txn_close.go ├── txn_error.go ├── txn_mark_roll_forward.go ├── txn_monitor.go ├── txn_roll.go ├── txn_roll_batch.go ├── txn_roll_batch_single.go ├── txn_roll_policy.go ├── txn_test.go ├── txn_verify_batch.go ├── txn_verify_batch_single.go ├── txn_verify_policy.go ├── types ├── epoc.go ├── histogram │ ├── bench_histogram_test.go │ ├── histogram.go │ ├── histogram_test.go │ ├── log2hist.go │ └── sync_histogram.go ├── message.go ├── particle_type │ └── particle_type.go ├── pool.go ├── pool │ ├── buffer_pool_test.go │ └── tiered_buffer.go ├── rand │ └── xor_shift128.go ├── result_code.go ├── types.go └── types_test.go ├── udf.go ├── udf_test.go ├── unpacker.go ├── user_roles.go ├── utils └── buffer │ └── buffer.go ├── value.go ├── value_helpers.go ├── value_reflect.go ├── value_test.go ├── werrgroup.go ├── write_command.go ├── write_payload_command.go └── write_policy.go /.build.yml: -------------------------------------------------------------------------------- 1 | name: aerospike-client-go 2 | dir: src/github.com/aerospike/aerospike-client-go 3 | 4 | container: 5 | - base: 6 | - docker.qe.aerospike.com/build/golang:1.11 7 | 8 | build: 9 | - name: build 10 | script: 11 | - go get -v github.com/aerospike/aerospike-client-go 12 | - go build -v -x github.com/aerospike/aerospike-client-go 13 | - go install -v -x github.com/aerospike/aerospike-client-go/tools/cli 14 | - go install -v -x github.com/aerospike/aerospike-client-go/tools/benchmark 15 | - go install -v -x github.com/aerospike/aerospike-client-go/tools/asinfo 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Aerospike Go Client Tests 2 | "on": 3 | push: 4 | pull_request: 5 | 6 | env: 7 | AEROSPIKE_HOSTS: "127.0.0.1:3000" 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | go-version: 14 | - "1.23" 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: "Setup Go ${{ matrix.go-version }}" 18 | uses: actions/setup-go@v3 19 | with: 20 | go-version: "${{ matrix.go-version }}" 21 | cache: true 22 | - name: Display Go version 23 | run: go version 24 | - name: Set up Aerospike Database 25 | uses: reugn/github-action-aerospike@v1 26 | - name: Test Lua Code 27 | run: go run github.com/onsi/ginkgo/v2/ginkgo -cover -race -r -keep-going -succinct -randomize-suites internal/lua 28 | - name: Test types package 29 | run: go run github.com/onsi/ginkgo/v2/ginkgo -cover -race -r -keep-going -succinct -randomize-suites types 30 | - name: Test pkg tests 31 | run: go run github.com/onsi/ginkgo/v2/ginkgo -cover -race -r -keep-going -succinct -randomize-suites pkg 32 | - name: Build Benchmark tool 33 | run: cd tools/benchmark | go build -tags as_proxy -o benchmark . 34 | - name: Build asinfo tool 35 | run: cd tools/asinfo | go build -o asinfo . 36 | - name: Build cli tool 37 | run: cd tools/cli | go build -o cli . 38 | - name: Build example files 39 | run: find examples -name "*.go" -type f -print0 | xargs -0 -n1 go build 40 | - name: Build with Reflection code removed 41 | run: go run github.com/onsi/ginkgo/v2/ginkgo build -tags="as_performance" . 42 | - name: Build for Google App Engine (unsafe package removed) 43 | run: go run github.com/onsi/ginkgo/v2/ginkgo build -tags="app_engine" . 44 | - name: Run the tests 45 | run: go run github.com/onsi/ginkgo/v2/ginkgo -coverprofile=./cover_native.out -covermode=atomic -coverpkg=./... -race -keep-going -succinct -randomize-suites -skip="HyperLogLog" 46 | - name: Download gocovmerge 47 | run: go mod download github.com/wadey/gocovmerge 48 | - name: Combine Cover Profiles 49 | run: go run github.com/wadey/gocovmerge cover_*.out > cover_all.out 50 | - name: Check Code Coverage 51 | uses: vladopajic/go-test-coverage@v2 52 | with: 53 | # Configure action using config file (option 1) 54 | config: ./.testcoverage.yml 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.prof 2 | *.test 3 | *.coverprofile* 4 | tools/benchmark/benchmark 5 | tools/asinfo/asinfo 6 | debug/ 7 | _debug/ 8 | tmp/ 9 | .DS_Store 10 | TODO 11 | PLAN.todo 12 | .go_metalinter 13 | .go_style 14 | .golangci.yml 15 | .travis/read-write-udf.ldif 16 | .travis/people.ldif 17 | .travis/modify.ldif 18 | .travis/badwan.ldif 19 | .travis/access.ldif 20 | tools/ 21 | cmd/ 22 | .revive.toml 23 | Makefile 24 | testdata/ 25 | Dockerfile* 26 | .dockerignore 27 | docker-compose.yml 28 | golangci.yml 29 | cover*.out 30 | .vscode/settings.json 31 | -------------------------------------------------------------------------------- /.testcoverage.yml: -------------------------------------------------------------------------------- 1 | # (mandatory) 2 | # Path to coverprofile file (output of `go test -coverprofile` command). 3 | # 4 | # For cases where there are many coverage profiles, such as when running 5 | # unit tests and integration tests separately, you can combine all those 6 | # profiles into one. In this case, the profile should have a comma-separated list 7 | # of profile files, e.g., 'cover_unit.out,cover_integration.out'. 8 | profile: cover_all.out 9 | 10 | # (optional; but recommended to set) 11 | # When specified reported file paths will not contain local prefix in the output 12 | local-prefix: "github.com/aerospike/aerospike-client-go/v8" 13 | 14 | # Holds coverage thresholds percentages, values should be in range [0-100] 15 | threshold: 16 | # (optional; default 0) 17 | # The minimum coverage that each file should have 18 | file: 0 19 | 20 | # (optional; default 0) 21 | # The minimum coverage that each package should have 22 | package: 0 23 | 24 | # (optional; default 0) 25 | # The minimum total coverage project should have 26 | total: 0 27 | 28 | # Holds regexp rules which will override thresholds for matched files or packages 29 | # using their paths. 30 | # 31 | # First rule from this list that matches file or package is going to apply 32 | # new threshold to it. If project has multiple rules that match same path, 33 | # override rules should be listed in order from specific to more general rules. 34 | override: 35 | # Increase coverage threshold to 100% for `foo` package 36 | # (default is 80, as configured above in this example) 37 | #- threshold: 100 38 | # path: ^pkg/lib/foo$ 39 | 40 | # Holds regexp rules which will exclude matched files or packages 41 | # from coverage statistics 42 | exclude: 43 | # Exclude files or packages matching their paths 44 | paths: 45 | # - \.pb\.go$ # excludes all protobuf generated files 46 | - proto/* 47 | - ^pkg/* # exclude package `pkg/bar` 48 | - client_builder.go 49 | - info_policy.go 50 | - commit_policy.go 51 | - generation_policy.go 52 | - privilege.go 53 | - read_mode_ap.go 54 | - read_mode_sc.go 55 | - record_exists_action.go 56 | - replica_policy.go 57 | - generics.go 58 | - login_command.go 59 | - types/histogram/histogram.go 60 | - types/rand/xor_shift128.go 61 | - internal/atomic/array.go 62 | # NOTES: 63 | # - symbol `/` in all path regexps will be replaced by current OS file path separator 64 | # to properly work on Windows 65 | -------------------------------------------------------------------------------- /abort_status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // Transaction abort status code. 18 | type AbortStatus string 19 | 20 | const ( 21 | AbortStatusOK AbortStatus = "Abort succeeded" 22 | AbortStatusAlreadyCommitted AbortStatus = "Already committed" 23 | AbortStatusAlreadyAborted AbortStatus = "Already aborted" 24 | AbortStatusRollBackAbandoned AbortStatus = "Transaction client roll back abandoned. Server will eventually abort the Transaction." 25 | AbortStatusCloseAbandoned AbortStatus = "Transaction has been rolled back, but Transaction client close was abandoned. Server will eventually close the Transaction." 26 | ) 27 | -------------------------------------------------------------------------------- /admin_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "time" 18 | 19 | // AdminPolicy contains attributes used for user administration commands. 20 | type AdminPolicy struct { 21 | 22 | // User administration command socket timeout. 23 | // Default is 2 seconds. 24 | Timeout time.Duration 25 | } 26 | 27 | // NewAdminPolicy generates a new AdminPolicy with default values. 28 | func NewAdminPolicy() *AdminPolicy { 29 | return &AdminPolicy{ 30 | Timeout: _DEFAULT_TIMEOUT, 31 | } 32 | } 33 | 34 | func (ap *AdminPolicy) deadline() (deadline time.Time) { 35 | if ap != nil && ap.Timeout > 0 { 36 | deadline = time.Now().Add(ap.Timeout) 37 | } 38 | 39 | return deadline 40 | } 41 | 42 | func (ap *AdminPolicy) timeout() time.Duration { 43 | if ap != nil && ap.Timeout > 0 { 44 | return ap.Timeout 45 | } 46 | 47 | return _DEFAULT_TIMEOUT 48 | } 49 | -------------------------------------------------------------------------------- /aerospike.go: -------------------------------------------------------------------------------- 1 | // Package aerospike provides a client to connect and interact with an Aerospike cluster. 2 | // This is the official Go implementation of the Aerospike Client. 3 | package aerospike 4 | -------------------------------------------------------------------------------- /aerospike_bench_reflect_test.go: -------------------------------------------------------------------------------- 1 | //go:build !as_performance 2 | 3 | // Copyright 2014-2022 Aerospike, Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package aerospike_test 18 | 19 | import ( 20 | "runtime" 21 | 22 | as "github.com/aerospike/aerospike-client-go/v8" 23 | 24 | "testing" 25 | ) 26 | 27 | func benchGetObj(times int, client *as.Client, key *as.Key, obj interface{}) { 28 | for i := 0; i < times; i++ { 29 | if err = client.GetObject(nil, key, obj); err != nil { 30 | panic(err) 31 | } 32 | } 33 | } 34 | 35 | func benchPutObj(times int, client *as.Client, key *as.Key, wp *as.WritePolicy, obj interface{}) { 36 | for i := 0; i < times; i++ { 37 | if err = client.PutObject(wp, key, obj); err != nil { 38 | panic(err) 39 | } 40 | } 41 | } 42 | 43 | func Benchmark_GetObject(b *testing.B) { 44 | client, err := as.NewClientWithPolicy(clientPolicy, *host, *port) 45 | if err != nil { 46 | b.Fail() 47 | } 48 | 49 | key, _ := as.NewKey(*namespace, "databases", "Aerospike") 50 | 51 | obj := &OBJECT{198, "Jack Shaftoe and Company", []int64{1, 2, 3, 4, 5, 6}} 52 | client.PutObject(nil, key, obj) 53 | 54 | b.N = 1 55 | runtime.GC() 56 | b.ResetTimer() 57 | benchGetObj(b.N, client, key, obj) 58 | } 59 | 60 | func Benchmark_PutObject(b *testing.B) { 61 | client, err := as.NewClient(*host, *port) 62 | if err != nil { 63 | b.Fail() 64 | } 65 | 66 | // obj := &OBJECT{198, "Jack Shaftoe and Company", []byte(bytes.Repeat([]byte{32}, 1000))} 67 | obj := &OBJECT{198, "Jack Shaftoe and Company", []int64{1, 2, 3, 4, 5, 6}} 68 | key, _ := as.NewKey(*namespace, "databases", "Aerospike") 69 | writepolicy := as.NewWritePolicy(0, 0) 70 | 71 | b.N = 100 72 | runtime.GC() 73 | b.ResetTimer() 74 | benchPutObj(b.N, client, key, writepolicy, obj) 75 | } 76 | -------------------------------------------------------------------------------- /auth_mode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // AuthMode determines authentication mode. 18 | type AuthMode int 19 | 20 | const ( 21 | // AuthModeInternal uses internal authentication only when user/password defined. Hashed password is stored 22 | // on the server. Do not send clear password. This is the default. 23 | AuthModeInternal AuthMode = iota 24 | 25 | // AuthModeExternal uses external authentication (like LDAP) when user/password defined. Specific external authentication is 26 | // configured on server. If TLSConfig is defined, sends clear password on node login via TLS. 27 | // Will return an error if TLSConfig is not defined. 28 | AuthModeExternal 29 | 30 | // AuthModePKI allows authentication and authorization based on a certificate. No user name or 31 | // password needs to be configured. Requires TLS and a client certificate. 32 | // Requires server version 5.7.0+ 33 | AuthModePKI 34 | ) 35 | -------------------------------------------------------------------------------- /batch_executer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // batchExecute Uses werrGroup to run commands using multiple goroutines, 18 | // and waits for their return 19 | func (clnt *Client) batchExecute(policy *BatchPolicy, batchNodes []*batchNode, cmd batcher) (int, Error) { 20 | maxConcurrentNodes := policy.ConcurrentNodes 21 | if maxConcurrentNodes <= 0 { 22 | maxConcurrentNodes = len(batchNodes) 23 | } 24 | 25 | // we need this list to count the number of filtered out records 26 | list := make([]batcher, 0, len(batchNodes)) 27 | 28 | weg := newWeightedErrGroup(maxConcurrentNodes) 29 | for _, batchNode := range batchNodes { 30 | newCmd := cmd.cloneBatchCommand(batchNode) 31 | list = append(list, newCmd) 32 | weg.execute(newCmd) 33 | } 34 | 35 | errs := weg.wait() 36 | 37 | // count the filtered out records 38 | filteredOut := 0 39 | for i := range list { 40 | filteredOut += list[i].filteredOut() 41 | } 42 | 43 | return filteredOut, errs 44 | } 45 | 46 | // batchExecuteSimple Uses werrGroup to run commands using multiple goroutines, 47 | // and waits for their return 48 | func (clnt *Client) batchExecuteSimple(policy *BatchPolicy, cmds []command) Error { 49 | maxConcurrentNodes := policy.ConcurrentNodes 50 | if maxConcurrentNodes <= 0 { 51 | maxConcurrentNodes = len(cmds) 52 | } 53 | 54 | // we need this list to count the number of filtered out records 55 | weg := newWeightedErrGroup(maxConcurrentNodes) 56 | for _, cmd := range cmds { 57 | weg.execute(cmd) 58 | } 59 | 60 | return weg.wait() 61 | } 62 | -------------------------------------------------------------------------------- /batch_node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "fmt" 18 | 19 | type batchNode struct { 20 | Node *Node 21 | offsets []int 22 | } 23 | 24 | func newBatchNode(node *Node, capacity int, offset int) *batchNode { 25 | res := &batchNode{ 26 | Node: node, 27 | offsets: make([]int, 1, capacity), 28 | } 29 | 30 | res.offsets[0] = offset 31 | return res 32 | } 33 | 34 | func (bn *batchNode) AddKey(offset int) { 35 | bn.offsets = append(bn.offsets, offset) 36 | } 37 | 38 | func (bn *batchNode) String() string { 39 | return fmt.Sprintf("Node: %s, Offsets: %v", bn.Node.String(), bn.offsets) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /batch_offsets.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | type BatchOffsets interface { 18 | size() int 19 | get(int) int 20 | } 21 | 22 | // enforce the interface 23 | var _ BatchOffsets = &batchOffsetsNative{} 24 | 25 | type batchOffsetsNative struct { 26 | offsets []int 27 | } 28 | 29 | func newBatchOffsetsNative(batch *batchNode) *batchOffsetsNative { 30 | return &batchOffsetsNative{ 31 | offsets: batch.offsets, 32 | } 33 | } 34 | 35 | func (bon *batchOffsetsNative) size() int { 36 | return len(bon.offsets) 37 | } 38 | 39 | func (bon *batchOffsetsNative) get(i int) int { 40 | return bon.offsets[i] 41 | } 42 | -------------------------------------------------------------------------------- /bench_key_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "strings" 19 | "testing" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | "github.com/aerospike/aerospike-client-go/v8/pkg/ripemd160" 23 | ParticleType "github.com/aerospike/aerospike-client-go/v8/types/particle_type" 24 | ) 25 | 26 | var str = strings.Repeat("abcd", 128) 27 | var strVal = as.NewValue(str) 28 | var buffer = []byte(str) 29 | var key *as.Key 30 | 31 | var res []byte 32 | 33 | // func hash_key_baseline(str string) { 34 | // hash := ripemd160.New() 35 | // for i := 0; i < b.N; i++ { 36 | // hash.Reset() 37 | // hash.Write(buffer) 38 | // res = hash.Sum(nil) 39 | // } 40 | // } 41 | 42 | func Benchmark_Key_Hash_BaseLine(b *testing.B) { 43 | hash := ripemd160.New() 44 | for i := 0; i < b.N; i++ { 45 | hash.Reset() 46 | hash.Write(buffer) 47 | res = hash.Sum(nil) 48 | } 49 | } 50 | 51 | func Benchmark_Key_NewKey(b *testing.B) { 52 | for i := 0; i < b.N; i++ { 53 | key, _ = as.NewKey(str, str, str) 54 | res = key.Digest() 55 | } 56 | } 57 | 58 | func Benchmark_K_ComputeDigest_Raw(b *testing.B) { 59 | h := ripemd160.New() 60 | setName := []byte(str) 61 | keyType := []byte{byte(ParticleType.STRING)} 62 | keyVal := []byte(str) 63 | for i := 0; i < b.N; i++ { 64 | h.Reset() 65 | 66 | // write will not fail; no error checking necessary 67 | h.Write(setName) 68 | h.Write(keyType) 69 | h.Write(keyVal) 70 | 71 | res = h.Sum(nil) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /bench_rand_gen_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "math/rand" 19 | "testing" 20 | "time" 21 | 22 | xor "github.com/aerospike/aerospike-client-go/v8/types/rand" 23 | ) 24 | 25 | func Benchmark_math_rand(b *testing.B) { 26 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 27 | for i := 0; i < b.N; i++ { 28 | r.Int63() 29 | } 30 | } 31 | 32 | func Benchmark_xor_rand(b *testing.B) { 33 | r := xor.NewXorRand() 34 | for i := 0; i < b.N; i++ { 35 | r.Int64() 36 | } 37 | } 38 | 39 | func Benchmark_math_rand_with_new(b *testing.B) { 40 | for i := 0; i < b.N; i++ { 41 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 42 | r.Int63() 43 | } 44 | } 45 | 46 | func Benchmark_xor_rand_with_new(b *testing.B) { 47 | for i := 0; i < b.N; i++ { 48 | r := xor.NewXorRand() 49 | r.Int64() 50 | } 51 | } 52 | 53 | func Benchmark_math_rand_synched(b *testing.B) { 54 | for i := 0; i < b.N; i++ { 55 | rand.Int63() 56 | } 57 | } 58 | 59 | func Benchmark_xor_rand_fast_pool(b *testing.B) { 60 | r := xor.NewXorRand() 61 | for i := 0; i < b.N; i++ { 62 | r.Int64() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /bench_recordset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "runtime" 19 | "testing" 20 | 21 | // "time" 22 | _ "net/http/pprof" 23 | 24 | as "github.com/aerospike/aerospike-client-go/v8" 25 | // _ "github.com/influxdata/influxdb/client" 26 | ) 27 | 28 | func doScan(b *testing.B) { 29 | runtime.GC() 30 | b.ResetTimer() 31 | b.SetBytes(0) 32 | 33 | policy := as.NewScanPolicy() 34 | 35 | n := 0 36 | for i := 0; i < 10; i++ { 37 | results, err := client.ScanAll(policy, *namespace, "test") 38 | if err != nil { 39 | b.Errorf("Scan error: %s", err) 40 | } 41 | 42 | for range results.Results() { 43 | n++ 44 | } 45 | } 46 | b.N = n 47 | } 48 | 49 | func doQuery(b *testing.B) { 50 | var err error 51 | 52 | runtime.GC() 53 | b.ResetTimer() 54 | b.SetBytes(0) 55 | 56 | n := 0 57 | //queries to aerospike 58 | policy := as.NewQueryPolicy() 59 | stmt := as.NewStatement(*namespace, "test") 60 | 61 | b.ResetTimer() 62 | b.SetBytes(0) 63 | results, err := client.Query(policy, stmt) 64 | if err != nil { 65 | b.Errorf("Query error: %s", err) 66 | } 67 | 68 | for range results.Results() { 69 | n++ 70 | } 71 | 72 | b.N = n 73 | } 74 | 75 | func Benchmark_Scan(b *testing.B) { 76 | initTestVars() 77 | go doScan(b) 78 | } 79 | 80 | func Benchmark_Query(b *testing.B) { 81 | initTestVars() 82 | doQuery(b) 83 | } 84 | -------------------------------------------------------------------------------- /bin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // BinMap is used to define a map of bin names to values. 18 | type BinMap map[string]interface{} 19 | 20 | // Bin encapsulates a field name/value pair. 21 | type Bin struct { 22 | // Bin name. Current limit is 14 characters. 23 | Name string 24 | 25 | // Bin value. 26 | Value Value 27 | } 28 | 29 | // NewBin generates a new Bin instance, specifying bin name and string value. 30 | // For servers configured as "single-bin", enter an empty name. 31 | func NewBin(name string, value interface{}) *Bin { 32 | return &Bin{ 33 | Name: name, 34 | Value: NewValue(value), 35 | } 36 | } 37 | 38 | // String implements Stringer interface. 39 | func (bn *Bin) String() string { 40 | return bn.Name + ":" + bn.Value.String() 41 | } 42 | -------------------------------------------------------------------------------- /bit_overflow_action.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // BitOverflowAction specifies the action to take when bitwise add/subtract results in overflow/underflow. 18 | type BitOverflowAction int 19 | 20 | const ( 21 | // BitOverflowActionFail specifies to fail operation with error. 22 | BitOverflowActionFail BitOverflowAction = 0 23 | 24 | // BitOverflowActionSaturate specifies that in add/subtract overflows/underflows, set to max/min value. 25 | // Example: MAXINT + 1 = MAXINT 26 | BitOverflowActionSaturate BitOverflowAction = 2 27 | 28 | // BitOverflowActionWrap specifies that in add/subtract overflows/underflows, wrap the value. 29 | // Example: MAXINT + 1 = -1 30 | BitOverflowActionWrap BitOverflowAction = 4 31 | ) 32 | -------------------------------------------------------------------------------- /bit_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // BitPolicy determines the Bit operation policy. 18 | type BitPolicy struct { 19 | flags int 20 | } 21 | 22 | // DefaultBitPolicy will return the default BitPolicy 23 | func DefaultBitPolicy() *BitPolicy { 24 | return &BitPolicy{BitWriteFlagsDefault} 25 | } 26 | 27 | // NewBitPolicy will return a BitPolicy will provided flags. 28 | func NewBitPolicy(flags int) *BitPolicy { 29 | return &BitPolicy{flags} 30 | } 31 | -------------------------------------------------------------------------------- /bit_resize_flags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // BitResizeFlags specifies the bitwise operation flags for resize. 18 | type BitResizeFlags int 19 | 20 | const ( 21 | // BitResizeFlagsDefault specifies the defalt flag. 22 | BitResizeFlagsDefault BitResizeFlags = 0 23 | 24 | // BitResizeFlagsFromFront Adds/removes bytes from the beginning instead of the end. 25 | BitResizeFlagsFromFront BitResizeFlags = 1 26 | 27 | // BitResizeFlagsGrowOnly will only allow the []byte size to increase. 28 | BitResizeFlagsGrowOnly BitResizeFlags = 2 29 | 30 | // BitResizeFlagsShrinkOnly will only allow the []byte size to decrease. 31 | BitResizeFlagsShrinkOnly BitResizeFlags = 4 32 | ) 33 | -------------------------------------------------------------------------------- /bit_write_flags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // BitWriteFlags specify bitwise operation policy write flags. 18 | 19 | const ( 20 | // BitWriteFlagsDefault allows create or update. 21 | BitWriteFlagsDefault = 0 22 | 23 | // BitWriteFlagsCreateOnly specifies that: 24 | // If the bin already exists, the operation will be denied. 25 | // If the bin does not exist, a new bin will be created. 26 | BitWriteFlagsCreateOnly = 1 27 | 28 | // BitWriteFlagsUpdateOnly specifies that: 29 | // If the bin already exists, the bin will be overwritten. 30 | // If the bin does not exist, the operation will be denied. 31 | BitWriteFlagsUpdateOnly = 2 32 | 33 | // BitWriteFlagsNoFail specifies not to raise error if operation is denied. 34 | BitWriteFlagsNoFail = 4 35 | 36 | // BitWriteFlagsPartial allows other valid operations to be committed if this operations is 37 | // denied due to flag constraints. 38 | BitWriteFlagsPartial = 8 39 | ) 40 | -------------------------------------------------------------------------------- /cdt_context_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | gg "github.com/onsi/ginkgo/v2" 19 | gm "github.com/onsi/gomega" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | ) 23 | 24 | var _ = gg.Describe("CDTContext Test", func() { 25 | 26 | gg.It("should convert to/from base64", func() { 27 | ctxl := []*as.CDTContext{ 28 | as.CtxMapKey(as.StringValue("key2")), 29 | as.CtxListRank(0), 30 | } 31 | 32 | b, err := as.CDTContextToBase64(ctxl) 33 | gm.Expect(err).ToNot(gm.HaveOccurred()) 34 | gm.Expect(b).ToNot(gm.BeNil()) 35 | 36 | ctxl2, err := as.Base64ToCDTContext(b) 37 | gm.Expect(err).ToNot(gm.HaveOccurred()) 38 | 39 | arraysEqual(ctxl2, ctxl) 40 | }) 41 | 42 | }) // describe 43 | -------------------------------------------------------------------------------- /commit_error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // Transaction error status. 18 | type CommitError string 19 | 20 | const ( 21 | CommitErrorVerifyFail CommitError = "Transaction verify failed. Transaction aborted." 22 | CommitErrorVerifyFailCloseAbandoned CommitError = "Transaction verify failed. Transaction aborted. Transaction client close abandoned. Server will eventually close the Transaction." 23 | CommitErrorVerifyFailAbortAbandoned CommitError = "Transaction verify failed. Transaction client abort abandoned. Server will eventually abort the Transaction." 24 | CommitErrorMarkRollForwardAbandoned CommitError = "Transaction client mark roll forward abandoned. Server will eventually abort the Transaction." 25 | ) 26 | -------------------------------------------------------------------------------- /commit_policy.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package aerospike 19 | 20 | // CommitLevel indicates the desired consistency guarantee when committing a command on the server. 21 | type CommitLevel int 22 | 23 | const ( 24 | // COMMIT_ALL indicates the server should wait until successfully committing master and all replicas. 25 | COMMIT_ALL CommitLevel = iota 26 | 27 | // COMMIT_MASTER indicates the server should wait until successfully committing master only. 28 | COMMIT_MASTER 29 | ) 30 | -------------------------------------------------------------------------------- /commit_status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // Transaction commit status code. 18 | type CommitStatus string 19 | 20 | const ( 21 | CommitStatusOK CommitStatus = "Commit succeeded" 22 | CommitStatusUnverified CommitStatus = "Commit process was disrupted on client side and unverified" 23 | CommitStatusAlreadyCommitted CommitStatus = "Already committed" 24 | CommitStatusAlreadyAborted CommitStatus = "Already aborted" 25 | CommitStatusRollForwardAbandoned CommitStatus = "Transaction client roll forward abandoned. Server will eventually commit the Transaction." 26 | CommitStatusCloseAbandoned CommitStatus = "Transaction has been rolled forward, but Transaction client close was abandoned. Server will eventually close the Transaction." 27 | ) 28 | -------------------------------------------------------------------------------- /delete_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee deleteCommand implements command interface 22 | var _ command = &deleteCommand{} 23 | 24 | type deleteCommand struct { 25 | baseWriteCommand 26 | 27 | existed bool 28 | } 29 | 30 | func newDeleteCommand( 31 | cluster *Cluster, 32 | policy *WritePolicy, 33 | key *Key, 34 | ) (*deleteCommand, Error) { 35 | bwc, err := newBaseWriteCommand(cluster, policy, key) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | newDeleteCmd := &deleteCommand{ 41 | baseWriteCommand: bwc, 42 | } 43 | 44 | return newDeleteCmd, nil 45 | } 46 | 47 | func (cmd *deleteCommand) writeBuffer(ifc command) Error { 48 | return cmd.setDelete(cmd.policy, cmd.key) 49 | } 50 | 51 | func (cmd *deleteCommand) parseResult(ifc command, conn *Connection) Error { 52 | resultCode, err := cmd.parseHeader() 53 | if err != nil { 54 | return newCustomNodeError(cmd.node, err.resultCode()) 55 | } 56 | 57 | switch types.ResultCode(resultCode) { 58 | case 0: 59 | cmd.existed = true 60 | case types.KEY_NOT_FOUND_ERROR: 61 | cmd.existed = false 62 | case types.FILTERED_OUT: 63 | cmd.existed = true 64 | return ErrFilteredOut.err() 65 | default: 66 | return newError(types.ResultCode(resultCode)) 67 | } 68 | 69 | return nil 70 | } 71 | 72 | func (cmd *deleteCommand) Existed() bool { 73 | return cmd.existed 74 | } 75 | 76 | func (cmd *deleteCommand) Execute() Error { 77 | return cmd.execute(cmd) 78 | } 79 | 80 | func (cmd *deleteCommand) commandType() commandType { 81 | return ttDelete 82 | } 83 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This package describes the Aerospike Go Client API in detail. 4 | 5 | 6 | ## Usage 7 | 8 | The aerospike Go client package is the main entry point to the client API. 9 | 10 | ```go 11 | import as "github.com/aerospike/aerospike-client-go/v8" 12 | ``` 13 | 14 | Before connecting to a cluster, you must import the package. 15 | 16 | You can then generate a client object for connecting to and operating against as cluster. 17 | 18 | ```go 19 | client, err := as.NewClient("127.0.0.1", 3000) 20 | ``` 21 | 22 | The application will use the client object to connect to a cluster, then perform operations such as writing and reading records. 23 | Client object is goroutine frinedly, so you can use it in goroutines without synchronization. 24 | It caches its connections and internal state automatically for optimal performance. These settings can also be changed. 25 | 26 | For more details on client operations, see [Client Class](client.md). 27 | 28 | ## API Reference 29 | 30 | - [Aerospike Go Client Library Overview](aerospike.md) 31 | - [Client Class](client.md) 32 | - [Object Model](datamodel.md) 33 | - [Policy Objects](policies.md) 34 | - [Logger Object](log.md) 35 | -------------------------------------------------------------------------------- /docs/log.md: -------------------------------------------------------------------------------- 1 | #log 2 | 3 | Various log levels available to log from the Aerospike API. 4 | Default is set to OFF. 5 | 6 | ```go 7 | import asl "github.com/aerospike/aerospike-client-go/v8/logger" 8 | 9 | asl.Logger.SetLevel(asl.OFF) 10 | ``` 11 | 12 | You can set the Logger to any object that supports log.Logger interface. 13 | 14 | ## Log levels: 15 | 16 | ##### ERROR 17 | 18 | ##### WARN 19 | 20 | ##### INFO 21 | 22 | ##### DEBUG 23 | 24 | ##### OFF 25 | -------------------------------------------------------------------------------- /example_listiter_int_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | ) 23 | 24 | /* 25 | myListInt 26 | */ 27 | var _ as.ListIter = myListInt([]int{}) 28 | 29 | // your custom list 30 | type myListInt []int 31 | 32 | func (ml myListInt) PackList(buf as.BufferEx) (int, error) { 33 | size := 0 34 | for _, elem := range ml { 35 | n, err := as.PackInt64(buf, int64(elem)) 36 | size += n 37 | if err != nil { 38 | return size, err 39 | } 40 | } 41 | 42 | return size, nil 43 | } 44 | 45 | func (ml myListInt) Len() int { 46 | return len(ml) 47 | } 48 | 49 | func ExampleListIter_int() { 50 | // Setup the client here 51 | // client, err := as.NewClient("127.0.0.1", 3000) 52 | // if err != nil { 53 | // log.Fatal(err) 54 | // } 55 | 56 | var v as.Value = as.NewValue(myListInt([]int{1, 2, 3})) 57 | key, err := as.NewKey(*namespace, "test", 1) 58 | if err != nil { 59 | log.Fatal(err) 60 | } 61 | 62 | err = client.Put(nil, key, as.BinMap{"myBin": v}) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | 67 | rec, err := client.Get(nil, key) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | 72 | fmt.Println(rec.Bins["myBin"]) 73 | // Output: 74 | // [1 2 3] 75 | } 76 | -------------------------------------------------------------------------------- /example_listiter_string_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | ) 23 | 24 | /* 25 | myListString 26 | */ 27 | var _ as.ListIter = myListString([]string{}) 28 | 29 | // your custom list 30 | type myListString []string 31 | 32 | func (ml myListString) PackList(buf as.BufferEx) (int, error) { 33 | size := 0 34 | for _, elem := range ml { 35 | n, err := as.PackString(buf, elem) 36 | size += n 37 | if err != nil { 38 | return size, err 39 | } 40 | } 41 | return size, nil 42 | } 43 | 44 | func (ml myListString) Len() int { 45 | return len(ml) 46 | } 47 | 48 | func ExampleListIter_string() { 49 | // Setup the client here 50 | // client, err := as.NewClient("127.0.0.1", 3000) 51 | // if err != nil { 52 | // log.Fatal(err) 53 | // } 54 | 55 | var v as.Value = as.NewValue(myListString([]string{"a", "b", "c"})) 56 | key, err := as.NewKey(*namespace, "test", 1) 57 | if err != nil { 58 | log.Fatal(err) 59 | } 60 | 61 | err = client.Put(nil, key, as.BinMap{"myBin": v}) 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | 66 | rec, err := client.Get(nil, key) 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | 71 | fmt.Println(rec.Bins["myBin"]) 72 | // Output: 73 | // [a b c] 74 | } 75 | -------------------------------------------------------------------------------- /example_listiter_time_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | "time" 21 | 22 | as "github.com/aerospike/aerospike-client-go/v8" 23 | ) 24 | 25 | /* 26 | myListTime 27 | */ 28 | var _ as.ListIter = myListTime([]time.Time{}) 29 | 30 | // your custom list 31 | type myListTime []time.Time 32 | 33 | func (ml myListTime) PackList(buf as.BufferEx) (int, error) { 34 | size := 0 35 | for _, elem := range ml { 36 | n, err := as.PackInt64(buf, elem.UnixNano()) 37 | size += n 38 | if err != nil { 39 | return size, err 40 | } 41 | } 42 | return size, nil 43 | } 44 | 45 | func (ml myListTime) Len() int { 46 | return len(ml) 47 | } 48 | 49 | func ExampleListIter_time() { 50 | // Setup the client here 51 | // client, err := as.NewClient("127.0.0.1", 3000) 52 | // if err != nil { 53 | // log.Fatal(err) 54 | // } 55 | 56 | now1 := time.Unix(123123123, 0) 57 | now2 := time.Unix(123123124, 0) 58 | now3 := time.Unix(123123125, 0) 59 | var v as.Value = as.NewValue(myListTime([]time.Time{now1, now2, now3})) 60 | key, err := as.NewKey(*namespace, "test", 1) 61 | if err != nil { 62 | log.Fatal(err) 63 | } 64 | 65 | err = client.Put(nil, key, as.BinMap{"myBin": v}) 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | 70 | rec, err := client.Get(nil, key) 71 | if err != nil { 72 | log.Fatal(err) 73 | } 74 | 75 | fmt.Println(rec.Bins["myBin"]) 76 | // Output: 77 | // [123123123000000000 123123124000000000 123123125000000000] 78 | } 79 | -------------------------------------------------------------------------------- /example_mapiter_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | "time" 21 | 22 | as "github.com/aerospike/aerospike-client-go/v8" 23 | ) 24 | 25 | /* 26 | myMapStringTime 27 | */ 28 | var _ as.MapIter = myMapStringTime(map[string]time.Time{}) 29 | 30 | // your custom list 31 | type myMapStringTime map[string]time.Time 32 | 33 | func (mm myMapStringTime) PackMap(buf as.BufferEx) (int, error) { 34 | size := 0 35 | for key, val := range mm { 36 | n, err := as.PackString(buf, key) 37 | size += n 38 | if err != nil { 39 | return size, err 40 | } 41 | 42 | n, err = as.PackInt64(buf, val.UnixNano()) 43 | size += n 44 | if err != nil { 45 | return size, err 46 | } 47 | } 48 | return size, nil 49 | } 50 | 51 | func (mm myMapStringTime) Len() int { 52 | return len(mm) 53 | } 54 | 55 | func ExampleMapIter() { 56 | // Setup the client here 57 | // client, err := as.NewClient("127.0.0.1", 3000) 58 | // if err != nil { 59 | // log.Fatal(err) 60 | // } 61 | 62 | now := time.Unix(123123123, 0) 63 | var v as.Value = as.NewValue(myMapStringTime(map[string]time.Time{"now": now})) 64 | key, err := as.NewKey(*namespace, "test", 1) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | 69 | err = client.Put(nil, key, as.BinMap{"myBin": v}) 70 | if err != nil { 71 | log.Fatal(err) 72 | } 73 | 74 | rec, err := client.Get(nil, key) 75 | if err != nil { 76 | log.Fatal(err) 77 | } 78 | 79 | fmt.Println(rec.Bins["myBin"]) 80 | // Output: 81 | // map[now:123123123000000000] 82 | } 83 | -------------------------------------------------------------------------------- /example_pagination_cursor_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | ) 23 | 24 | func ExamplePartitionFilter_EncodeCursor() { 25 | // Setup the client here 26 | // client, err := as.NewClient("127.0.0.1", 3000) 27 | // if err != nil { 28 | // log.Fatal(err) 29 | // } 30 | 31 | var ns = *namespace 32 | var set = randString(50) 33 | 34 | // initialize the records 35 | keyCount := 1000 36 | for i := 0; i < keyCount; i++ { 37 | key, err := as.NewKey(ns, set, i) 38 | if err != nil { 39 | log.Fatal(err) 40 | } 41 | 42 | err = client.Put(nil, key, as.BinMap{"bin": i}) 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | } 47 | 48 | // Set up the scan policy 49 | spolicy := as.NewScanPolicy() 50 | spolicy.MaxRecords = 30 51 | 52 | received := 0 53 | var buf []byte 54 | for received < keyCount { 55 | pf := as.NewPartitionFilterAll() 56 | 57 | if len(buf) > 0 { 58 | err = pf.DecodeCursor(buf) 59 | if err != nil { 60 | log.Fatal(err) 61 | } 62 | } 63 | 64 | recordset, err := client.ScanPartitions(spolicy, pf, ns, set) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | 69 | counter := 0 70 | for range recordset.Results() { 71 | counter++ 72 | received++ 73 | } 74 | 75 | if counter > 30 { 76 | log.Fatal("More records received than requested.") 77 | } 78 | 79 | buf, err = pf.EncodeCursor() 80 | if err != nil { 81 | log.Fatal(err) 82 | } 83 | } 84 | 85 | fmt.Println(received) 86 | // Output: 87 | // 1000 88 | } 89 | -------------------------------------------------------------------------------- /examples/append/append.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | 23 | as "github.com/aerospike/aerospike-client-go/v8" 24 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 25 | ) 26 | 27 | func main() { 28 | runExample(shared.Client) 29 | log.Println("Example finished successfully.") 30 | } 31 | 32 | func runExample(client *as.Client) { 33 | key, err := as.NewKey(*shared.Namespace, *shared.Set, "appendkey") 34 | shared.PanicOnError(err) 35 | 36 | binName := "appendbin" 37 | 38 | // Delete record if it already exists. 39 | client.Delete(shared.WritePolicy, key) 40 | 41 | bin := as.NewBin(binName, "Hello") 42 | log.Println("Initial append will create record. Initial value is ", bin.Value, ".") 43 | client.AppendBins(shared.WritePolicy, key, bin) 44 | 45 | bin = as.NewBin(binName, " World") 46 | log.Println("Append \"", bin.Value, "\" to existing record.") 47 | client.AppendBins(shared.WritePolicy, key, bin) 48 | 49 | record, err := client.Get(shared.Policy, key, bin.Name) 50 | shared.PanicOnError(err) 51 | 52 | if record == nil { 53 | log.Fatalf( 54 | "Failed to get: namespace=%s set=%s key=%s", 55 | key.Namespace(), key.SetName(), key.Value()) 56 | } 57 | 58 | received := record.Bins[bin.Name] 59 | expected := "Hello World" 60 | 61 | if received == expected { 62 | log.Printf("Append successful: ns=%s set=%s key=%s bin=%s value=%s", 63 | key.Namespace(), key.SetName(), key.Value(), bin.Name, received) 64 | } else { 65 | log.Fatalf("Append mismatch: Expected %s. Received %s.", expected, received) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/blob/blob.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | as "github.com/aerospike/aerospike-client-go/v8" 19 | ) 20 | 21 | // Person is a custom data type to be converted to a blob 22 | type Person struct { 23 | name string 24 | } 25 | 26 | // EncodeBlob defines The AerospikeBlob interface 27 | func (p Person) EncodeBlob() ([]byte, error) { 28 | return []byte(p.name), nil 29 | } 30 | 31 | // DecodeBlob is optional, and should be used manually 32 | func (p *Person) DecodeBlob(buf []byte) error { 33 | p.name = string(buf) 34 | return nil 35 | } 36 | 37 | func main() { 38 | // define a client to connect to 39 | client, err := as.NewClient("127.0.0.1", 3000) 40 | panicOnError(err) 41 | 42 | namespace := "test" 43 | setName := "people" 44 | key, err := as.NewKey(namespace, setName, "key") // user key can be of any supported type 45 | panicOnError(err) 46 | 47 | // define some bins 48 | bins := as.BinMap{ 49 | "bin1": Person{name: "Albert Einstein"}, 50 | "bin2": &Person{name: "Richard Feynman"}, 51 | } 52 | 53 | // write the bins 54 | writePolicy := as.NewWritePolicy(0, 0) 55 | err = client.Put(writePolicy, key, bins) 56 | panicOnError(err) 57 | 58 | // read it back! 59 | readPolicy := as.NewPolicy() 60 | rec, err := client.Get(readPolicy, key) 61 | panicOnError(err) 62 | 63 | result := &Person{} 64 | 65 | // decode first object 66 | result.DecodeBlob(rec.Bins["bin1"].([]byte)) 67 | 68 | // decode second object 69 | result.DecodeBlob(rec.Bins["bin2"].([]byte)) 70 | } 71 | 72 | func panicOnError(err error) { 73 | if err != nil { 74 | panic(err) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /examples/get/.gitignore: -------------------------------------------------------------------------------- 1 | get -------------------------------------------------------------------------------- /examples/get/get.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "fmt" 20 | "os" 21 | "strconv" 22 | 23 | as "github.com/aerospike/aerospike-client-go/v8" 24 | ) 25 | 26 | var ( 27 | host = "127.0.0.1" 28 | port = 3000 29 | namespace = "test" 30 | set = "demo" 31 | ) 32 | 33 | func main() { 34 | 35 | var err error 36 | 37 | // arguments 38 | flag.StringVar(&host, "host", host, "Remote host") 39 | flag.IntVar(&port, "port", port, "Remote port") 40 | flag.StringVar(&namespace, "namespace", namespace, "Namespace") 41 | flag.StringVar(&set, "set", set, "Set name") 42 | 43 | // parse flags 44 | flag.Parse() 45 | 46 | // args 47 | args := flag.Args() 48 | 49 | if len(args) < 1 { 50 | printError("Missing argument") 51 | } 52 | 53 | client, err := as.NewClient(host, port) 54 | panicOnError(err) 55 | 56 | var key *as.Key 57 | 58 | skey := flag.Arg(0) 59 | ikey, err := strconv.ParseInt(skey, 10, 64) 60 | if err == nil { 61 | key, err = as.NewKey(namespace, set, ikey) 62 | panicOnError(err) 63 | } else { 64 | key, err = as.NewKey(namespace, set, skey) 65 | panicOnError(err) 66 | } 67 | 68 | policy := as.NewPolicy() 69 | rec, err := client.Get(policy, key) 70 | panicOnError(err) 71 | if rec != nil { 72 | printOK("%v", rec.Bins) 73 | } else { 74 | printError("record not found: namespace=%s set=%s key=%v", key.Namespace(), key.SetName(), key.Value()) 75 | } 76 | } 77 | 78 | func panicOnError(err error) { 79 | if err != nil { 80 | panic(err) 81 | } 82 | } 83 | 84 | func printOK(format string, a ...interface{}) { 85 | fmt.Printf("ok: "+format+"\n", a...) 86 | os.Exit(0) 87 | } 88 | 89 | func printError(format string, a ...interface{}) { 90 | fmt.Printf("error: "+format+"\n", a...) 91 | os.Exit(1) 92 | } 93 | -------------------------------------------------------------------------------- /examples/info/info.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "log" 19 | "time" 20 | 21 | as "github.com/aerospike/aerospike-client-go/v8" 22 | ) 23 | 24 | func main() { 25 | // remove timestamps from log messages 26 | log.SetFlags(0) 27 | 28 | // connect to the host 29 | cp := as.NewClientPolicy() 30 | cp.Timeout = 10 * time.Second 31 | 32 | // cp.User = "admin" 33 | // cp.Password = "admin" 34 | 35 | conn, err := as.NewConnection(cp, as.NewHost("localhost", 3000)) 36 | if err != nil { 37 | log.Fatalln(err.Error()) 38 | } 39 | 40 | // Login if needed 41 | // if err := conn.Login(cp); err != nil { 42 | // log.Fatalln(err.Error()) 43 | // } 44 | 45 | infoMap, err := conn.RequestInfo("") 46 | if err != nil { 47 | log.Fatalln(err.Error()) 48 | } 49 | 50 | cnt := 1 51 | for k, v := range infoMap { 52 | log.Printf("%d : %s\n %s\n", cnt, k, v) 53 | cnt++ 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/operate/operate.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | 23 | as "github.com/aerospike/aerospike-client-go/v8" 24 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 25 | ) 26 | 27 | func main() { 28 | runExample(shared.Client) 29 | 30 | log.Println("Example finished successfully.") 31 | } 32 | 33 | func runExample(client *as.Client) { 34 | // Write initial record. 35 | key, _ := as.NewKey(*shared.Namespace, *shared.Set, "opkey") 36 | bin1 := as.NewBin("optintbin", 7) 37 | bin2 := as.NewBin("optstringbin", "string value") 38 | log.Printf("Put: namespace=%s set=%s key=%s bin1=%s value1=%s bin2=%s value2=%s", 39 | key.Namespace(), key.SetName(), key.Value(), bin1.Name, bin1.Value, bin2.Name, bin2.Value) 40 | client.PutBins(shared.WritePolicy, key, bin1, bin2) 41 | 42 | // Add integer, write new string and read record. 43 | bin3 := as.NewBin(bin1.Name, 4) 44 | bin4 := as.NewBin(bin2.Name, "new string") 45 | log.Println("Add: ", bin3.Value) 46 | log.Println("Write: ", bin4.Value) 47 | log.Println("Read:") 48 | 49 | record, err := client.Operate(shared.WritePolicy, key, as.AddOp(bin3), as.PutOp(bin4), as.GetOp()) 50 | shared.PanicOnError(err) 51 | 52 | if record == nil { 53 | log.Fatalf( 54 | "Failed to get: namespace=%s set=%s key=%s", 55 | key.Namespace(), key.SetName(), key.Value()) 56 | } 57 | 58 | binExpected := as.NewBin(bin3.Name, 11) 59 | shared.ValidateBin(key, binExpected, record) 60 | shared.ValidateBin(key, bin4, record) 61 | } 62 | -------------------------------------------------------------------------------- /examples/prepend/prepend.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | 23 | as "github.com/aerospike/aerospike-client-go/v8" 24 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 25 | ) 26 | 27 | func main() { 28 | runExample(shared.Client) 29 | log.Println("Example finished successfully.") 30 | } 31 | 32 | func runExample(client *as.Client) { 33 | key, err := as.NewKey(*shared.Namespace, *shared.Set, "prependkey") 34 | shared.PanicOnError(err) 35 | 36 | binName := "prependbin" 37 | 38 | // Delete record if it already exists. 39 | client.Delete(shared.WritePolicy, key) 40 | 41 | bin := as.NewBin(binName, "World") 42 | log.Println("Initial prepend will create record. Initial value is ", bin.Value, ".") 43 | client.PrependBins(shared.WritePolicy, key, bin) 44 | 45 | bin = as.NewBin(binName, "Hello ") 46 | log.Println("Prepend \"", bin.Value, "\" to existing record.") 47 | client.PrependBins(shared.WritePolicy, key, bin) 48 | 49 | record, err := client.Get(shared.Policy, key, bin.Name) 50 | shared.PanicOnError(err) 51 | 52 | if record == nil { 53 | log.Fatalf( 54 | "Failed to get: namespace=%s set=%s key=%s", 55 | key.Namespace(), key.SetName(), key.Value()) 56 | } 57 | 58 | // The value received from the server is an unsigned byte stream. 59 | // Convert to an integer before comparing with expected. 60 | received := record.Bins[bin.Name] 61 | expected := "Hello World" 62 | 63 | if received == expected { 64 | log.Printf("Prepend successful: ns=%s set=%s key=%s bin=%s value=%s", 65 | key.Namespace(), key.SetName(), key.Value(), bin.Name, received) 66 | } else { 67 | log.Fatalf("Prepend mismatch: Expected %s. Received %s.", expected, received) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/put/.gitignore: -------------------------------------------------------------------------------- 1 | put -------------------------------------------------------------------------------- /examples/query-aggregate/average/average.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | "os" 23 | "time" 24 | 25 | as "github.com/aerospike/aerospike-client-go/v8" 26 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 27 | ) 28 | 29 | const keyCount = 1000 30 | 31 | func main() { 32 | runExample(shared.Client) 33 | log.Println("Example finished successfully.") 34 | } 35 | 36 | func runExample(client *as.Client) { 37 | // Set LuaPath 38 | luaPath, _ := os.Getwd() 39 | luaPath += "/udf/" 40 | as.SetLuaPath(luaPath) 41 | 42 | filename := "average" 43 | regTask, err := client.RegisterUDFFromFile(nil, luaPath+filename+".lua", filename+".lua", as.LUA) 44 | shared.PanicOnError(err) 45 | 46 | // wait until UDF is created 47 | shared.PanicOnError(<-regTask.OnComplete()) 48 | 49 | sum := 0 50 | for i := 1; i <= keyCount; i++ { 51 | sum += i 52 | key, err := as.NewKey(*shared.Namespace, *shared.Set, i) 53 | shared.PanicOnError(err) 54 | 55 | bin1 := as.NewBin("bin1", i) 56 | client.PutBins(nil, key, bin1) 57 | } 58 | 59 | average := float64(sum) / float64(keyCount) 60 | 61 | t := time.Now() 62 | stm := as.NewStatement(*shared.Namespace, *shared.Set) 63 | res, err := client.QueryAggregate(nil, stm, filename, filename, as.StringValue("bin1")) 64 | shared.PanicOnError(err) 65 | 66 | for rec := range res.Results() { 67 | res := rec.Record.Bins["SUCCESS"].(map[interface{}]interface{}) 68 | log.Printf("Result from Map/Reduce: %v\n", res) 69 | log.Printf("Result %f should equal %f\n", res["sum"].(float64)/res["count"].(float64), average) 70 | } 71 | log.Println("Map/Reduce took", time.Now().Sub(t)) 72 | } 73 | -------------------------------------------------------------------------------- /examples/query-aggregate/single_bin_sum/single_bin_sum.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | "os" 23 | "time" 24 | 25 | as "github.com/aerospike/aerospike-client-go/v8" 26 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 27 | ) 28 | 29 | const keyCount = 1000 30 | 31 | func main() { 32 | runExample(shared.Client) 33 | log.Println("Example finished successfully.") 34 | } 35 | 36 | func runExample(client *as.Client) { 37 | // Set LuaPath 38 | luaPath, _ := os.Getwd() 39 | luaPath += "/udf/" 40 | as.SetLuaPath(luaPath) 41 | 42 | filename := "sum_single_bin" 43 | regTask, err := client.RegisterUDFFromFile(nil, luaPath+filename+".lua", filename+".lua", as.LUA) 44 | shared.PanicOnError(err) 45 | 46 | // wait until UDF is created 47 | shared.PanicOnError(<-regTask.OnComplete()) 48 | 49 | sum := 0 50 | for i := 1; i <= keyCount; i++ { 51 | sum += i 52 | key, err := as.NewKey(*shared.Namespace, *shared.Set, i) 53 | shared.PanicOnError(err) 54 | 55 | bin1 := as.NewBin("bin1", i) 56 | client.PutBins(nil, key, bin1) 57 | } 58 | 59 | t := time.Now() 60 | stm := as.NewStatement(*shared.Namespace, *shared.Set) 61 | res, err := client.QueryAggregate(nil, stm, filename, filename, as.StringValue("bin1")) 62 | shared.PanicOnError(err) 63 | 64 | for rec := range res.Results() { 65 | log.Printf("Result %f should equal %d\n", rec.Record.Bins["SUCCESS"], sum) 66 | } 67 | log.Println("Map/Reduce took", time.Now().Sub(t)) 68 | } 69 | -------------------------------------------------------------------------------- /examples/query-aggregate/udf/average.lua: -------------------------------------------------------------------------------- 1 | function average(s, name) 2 | 3 | local function mapper(out, rec) 4 | out['sum'] = (out['sum'] or 0) + (rec[name] or 0) 5 | out['count'] = (out['count'] or 0) + 1 6 | return out 7 | end 8 | 9 | local function reducer(a, b) 10 | local out = map() 11 | 12 | out['sum'] = a['sum'] + b['sum'] 13 | out['count'] = a['count'] + b['count'] 14 | return out 15 | end 16 | 17 | return s : aggregate(map{sum = 0, count = 0}, mapper) : reduce(reducer) 18 | end 19 | -------------------------------------------------------------------------------- /examples/query-aggregate/udf/sum_single_bin.lua: -------------------------------------------------------------------------------- 1 | local function reducer(val1,val2) 2 | return val1 + val2 3 | end 4 | 5 | function sum_single_bin(stream,name) 6 | local function mapper(rec) 7 | return rec[name] 8 | end 9 | 10 | return stream : map(mapper) : reduce(reducer) 11 | end 12 | -------------------------------------------------------------------------------- /examples/scan_paginate/scan_paginate.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | "time" 23 | 24 | as "github.com/aerospike/aerospike-client-go/v8" 25 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 26 | ) 27 | 28 | func main() { 29 | runExample(shared.Client) 30 | 31 | log.Println("Example finished successfully.") 32 | } 33 | 34 | func runExample(client *as.Client) { 35 | log.Printf("Scan parallel: namespace=" + *shared.Namespace + " set=" + *shared.Set) 36 | recordCount := 0 37 | begin := time.Now() 38 | policy := as.NewScanPolicy() 39 | policy.MaxRecords = 30 40 | 41 | pf := as.NewPartitionFilterAll() 42 | 43 | receivedRecords := 1 44 | for receivedRecords > 0 { 45 | receivedRecords = 0 46 | 47 | log.Println("Scanning Page:", recordCount/int(policy.MaxRecords)) 48 | recordset, err := client.ScanPartitions(policy, pf, *shared.Namespace, *shared.Set) 49 | shared.PanicOnError(err) 50 | 51 | for rec := range recordset.Results() { 52 | if rec.Err != nil { 53 | // if there was an error, handle it if needed 54 | // Scans are retried in Aerospike servers v5+ 55 | log.Println(err) 56 | continue 57 | } 58 | 59 | recordCount++ 60 | receivedRecords++ 61 | } 62 | } 63 | 64 | log.Println("Total records returned: ", recordCount) 65 | log.Println("Elapsed time: ", time.Since(begin), " seconds") 66 | } 67 | -------------------------------------------------------------------------------- /examples/scan_parallel/scan_parallel.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package main 19 | 20 | import ( 21 | "log" 22 | "time" 23 | 24 | as "github.com/aerospike/aerospike-client-go/v8" 25 | shared "github.com/aerospike/aerospike-client-go/v8/examples/shared" 26 | ) 27 | 28 | func main() { 29 | runExample(shared.Client) 30 | 31 | log.Println("Example finished successfully.") 32 | } 33 | 34 | func runExample(client *as.Client) { 35 | log.Printf("Scan parallel: namespace=" + *shared.Namespace + " set=" + *shared.Set) 36 | 37 | recordCount := 0 38 | begin := time.Now() 39 | policy := as.NewScanPolicy() 40 | recordset, err := client.ScanAll(policy, *shared.Namespace, *shared.Set) 41 | shared.PanicOnError(err) 42 | 43 | for rec := range recordset.Results() { 44 | if rec.Err != nil { 45 | // if there was an error, handle it if needed 46 | // Scans are retried in Aerospike servers v5+ 47 | log.Println(err) 48 | continue 49 | } 50 | 51 | recordCount++ 52 | 53 | if (recordCount % 100000) == 0 { 54 | log.Println("Records ", recordCount) 55 | } 56 | } 57 | 58 | end := time.Now() 59 | seconds := float64(end.Sub(begin)) / float64(time.Second) 60 | log.Println("Total records returned: ", recordCount) 61 | log.Println("Elapsed time: ", seconds, " seconds") 62 | performance := shared.Round(float64(recordCount)/float64(seconds), 0.5, 0) 63 | log.Println("Records/second: ", performance) 64 | } 65 | -------------------------------------------------------------------------------- /exists_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee existsCommand implements command interface 22 | var _ command = &existsCommand{} 23 | 24 | type existsCommand struct { 25 | baseReadCommand 26 | 27 | exists bool 28 | } 29 | 30 | func newExistsCommand(cluster *Cluster, policy *BasePolicy, key *Key) (existsCommand, Error) { 31 | brc, err := newBaseReadCommand(cluster, policy, key) 32 | if err != nil { 33 | return existsCommand{}, err 34 | } 35 | 36 | return existsCommand{ 37 | baseReadCommand: brc, 38 | }, nil 39 | } 40 | 41 | func (cmd *existsCommand) writeBuffer(ifc command) Error { 42 | return cmd.setExists(cmd.policy, cmd.key) 43 | } 44 | 45 | func (cmd *existsCommand) parseResult(ifc command, conn *Connection) Error { 46 | rp, err := newRecordParser(&cmd.baseCommand) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | if err := rp.parseFields(cmd.policy.Txn, cmd.key, false); err != nil { 52 | return err 53 | } 54 | 55 | switch rp.resultCode { 56 | case types.OK: 57 | cmd.exists = true 58 | case types.KEY_NOT_FOUND_ERROR: 59 | cmd.exists = false 60 | case types.FILTERED_OUT: 61 | cmd.exists = true 62 | return ErrFilteredOut.err() 63 | default: 64 | return newError(rp.resultCode) 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func (cmd *existsCommand) Exists() bool { 71 | return cmd.exists 72 | } 73 | 74 | func (cmd *existsCommand) Execute() Error { 75 | return cmd.execute(cmd) 76 | } 77 | 78 | func (cmd *existsCommand) commandType() commandType { 79 | return ttExists 80 | } 81 | -------------------------------------------------------------------------------- /field_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // FieldType represents the type of the field in Aerospike Wire Protocol 18 | type FieldType int 19 | 20 | // FieldType constants used in the Aerospike Wire Protocol. 21 | const ( 22 | NAMESPACE FieldType = 0 23 | TABLE FieldType = 1 24 | KEY FieldType = 2 25 | RECORD_VERSION FieldType = 3 26 | DIGEST_RIPE FieldType = 4 27 | MRT_ID FieldType = 5 28 | MRT_DEADLINE FieldType = 6 29 | QUERY_ID FieldType = 7 30 | SOCKET_TIMEOUT FieldType = 9 31 | RECORDS_PER_SECOND FieldType = 10 32 | PID_ARRAY FieldType = 11 33 | DIGEST_ARRAY FieldType = 12 34 | MAX_RECORDS FieldType = 13 35 | BVAL_ARRAY FieldType = 15 36 | INDEX_NAME FieldType = 21 37 | INDEX_RANGE FieldType = 22 38 | INDEX_CONTEXT FieldType = 23 39 | INDEX_TYPE FieldType = 26 40 | UDF_PACKAGE_NAME FieldType = 30 41 | UDF_FUNCTION FieldType = 31 42 | UDF_ARGLIST FieldType = 32 43 | UDF_OP FieldType = 33 44 | QUERY_BINLIST FieldType = 40 45 | BATCH_INDEX FieldType = 41 46 | BATCH_INDEX_WITH_SET FieldType = 42 47 | FILTER_EXP FieldType = 43 48 | ) 49 | -------------------------------------------------------------------------------- /generation_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // GenerationPolicy determines how to handle record writes based on record generation. 18 | type GenerationPolicy int 19 | 20 | const ( 21 | // NONE means: Do not use record generation to restrict writes. 22 | NONE GenerationPolicy = iota 23 | 24 | // EXPECT_GEN_EQUAL means: Update/Delete record if expected generation is equal to server generation. Otherwise, fail. 25 | EXPECT_GEN_EQUAL 26 | 27 | // EXPECT_GEN_GT means: Update/Delete record if expected generation greater than the server generation. Otherwise, fail. 28 | // This is useful for restore after backup. 29 | EXPECT_GEN_GT 30 | ) 31 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aerospike/aerospike-client-go/v8 2 | 3 | go 1.23.0 4 | 5 | require ( 6 | github.com/onsi/ginkgo/v2 v2.22.2 7 | github.com/onsi/gomega v1.36.2 8 | github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad 9 | github.com/yuin/gopher-lua v1.1.1 10 | golang.org/x/sync v0.12.0 11 | ) 12 | 13 | require ( 14 | github.com/go-logr/logr v1.4.2 // indirect 15 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect 16 | github.com/google/go-cmp v0.6.0 // indirect 17 | github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect 18 | github.com/kr/pretty v0.3.1 // indirect 19 | github.com/stretchr/testify v1.10.0 // indirect 20 | golang.org/x/net v0.37.0 // indirect 21 | golang.org/x/sys v0.31.0 // indirect 22 | golang.org/x/text v0.23.0 // indirect 23 | golang.org/x/tools v0.31.0 // indirect 24 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 25 | gopkg.in/yaml.v3 v3.0.1 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /hll_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // HLLPolicy determines the HyperLogLog operation policy. 18 | type HLLPolicy struct { 19 | flags int 20 | } 21 | 22 | // DefaultHLLPolicy uses the default policy when performing HLL operations. 23 | func DefaultHLLPolicy() *HLLPolicy { 24 | return &HLLPolicy{HLLWriteFlagsDefault} 25 | } 26 | 27 | // NewHLLPolicy uses specified HLLWriteFlags when performing HLL operations. 28 | func NewHLLPolicy(flags int) *HLLPolicy { 29 | return &HLLPolicy{flags} 30 | } 31 | -------------------------------------------------------------------------------- /hll_write_flags.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // HLLWriteFlags specifies the HLL write operation flags. 18 | 19 | const ( 20 | // HLLWriteFlagsDefault is Default. Allow create or update. 21 | HLLWriteFlagsDefault = 0 22 | 23 | // HLLWriteFlagsCreateOnly behaves like the following: 24 | // If the bin already exists, the operation will be denied. 25 | // If the bin does not exist, a new bin will be created. 26 | HLLWriteFlagsCreateOnly = 1 27 | 28 | // HLLWriteFlagsUpdateOnly behaves like the following: 29 | // If the bin already exists, the bin will be overwritten. 30 | // If the bin does not exist, the operation will be denied. 31 | HLLWriteFlagsUpdateOnly = 2 32 | 33 | // HLLWriteFlagsNoFail does not raise error if operation is denied. 34 | HLLWriteFlagsNoFail = 4 35 | 36 | // HLLWriteFlagsAllowFold allows the resulting set to be the minimum of provided index bits. 37 | // Also, allow the usage of less precise HLL algorithms when minHash bits 38 | // of all participating sets do not match. 39 | HLLWriteFlagsAllowFold = 8 40 | ) 41 | -------------------------------------------------------------------------------- /host.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "fmt" 19 | "net" 20 | "strconv" 21 | 22 | "github.com/aerospike/aerospike-client-go/v8/types" 23 | ) 24 | 25 | // Host name/port of database server. 26 | type Host struct { 27 | 28 | // Host name or IP address of database server. 29 | Name string 30 | 31 | //TLSName defines the TLS certificate name used for secure connections. 32 | TLSName string 33 | 34 | // Port of database server. 35 | Port int 36 | } 37 | 38 | // NewHost initializes new host instance. 39 | func NewHost(name string, port int) *Host { 40 | return &Host{Name: name, Port: port} 41 | } 42 | 43 | // Implements stringer interface 44 | func (h *Host) String() string { 45 | return net.JoinHostPort(h.Name, strconv.Itoa(h.Port)) 46 | } 47 | 48 | // Implements stringer interface 49 | func (h *Host) equals(other *Host) bool { 50 | return h.Name == other.Name && h.Port == other.Port 51 | } 52 | 53 | // NewHosts initializes new host instances by a passed slice of addresses. 54 | func NewHosts(addresses ...string) ([]*Host, Error) { 55 | aerospikeHosts := make([]*Host, 0, len(addresses)) 56 | for _, address := range addresses { 57 | hostStr, portStr, err := net.SplitHostPort(address) 58 | if err != nil { 59 | return nil, newErrorAndWrap(err, types.PARAMETER_ERROR, fmt.Sprintf("error parsing address %s: %s", address, err)) 60 | } 61 | port, err := strconv.Atoi(portStr) 62 | if err != nil { 63 | return nil, newErrorAndWrap(err, types.PARAMETER_ERROR, fmt.Sprintf("error converting port %s: %s", address, err)) 64 | } 65 | 66 | host := NewHost(hostStr, port) 67 | aerospikeHosts = append(aerospikeHosts, host) 68 | } 69 | 70 | return aerospikeHosts, nil 71 | } 72 | -------------------------------------------------------------------------------- /host_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike_test 16 | 17 | import ( 18 | as "github.com/aerospike/aerospike-client-go/v8" 19 | 20 | gg "github.com/onsi/ginkgo/v2" 21 | gm "github.com/onsi/gomega" 22 | ) 23 | 24 | // ALL tests are isolated by SetName and Key, which are 50 random characters 25 | var _ = gg.Describe("Aerospike", func() { 26 | 27 | gg.Describe("Host", func() { 28 | 29 | gg.It("must handle multiple valid host strings", func() { 30 | // use the same client for all 31 | hosts, err := as.NewHosts("host1:4000", "host2:3000", "127.0.0.1:1200", "[2001:0db8:85a3:0000:0000:8a2e:0370]:7334") 32 | gm.Expect(err).ToNot(gm.HaveOccurred()) 33 | gm.Expect(hosts).To(gm.Equal([]*as.Host{as.NewHost("host1", 4000), as.NewHost("host2", 3000), as.NewHost("127.0.0.1", 1200), as.NewHost("2001:0db8:85a3:0000:0000:8a2e:0370", 7334)})) 34 | }) 35 | 36 | gg.It("must error on invalid host strings", func() { 37 | // use the same client for all 38 | hosts, err := as.NewHosts("host1:4000", "host2://+3000") 39 | gm.Expect(err).To(gm.HaveOccurred()) 40 | gm.Expect(hosts).To(gm.BeNil()) 41 | }) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /index_collection_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "fmt" 19 | ) 20 | 21 | // IndexCollectionType is the secondary index collection type. 22 | type IndexCollectionType int 23 | 24 | const ( 25 | 26 | // ICT_DEFAULT is the Normal scalar index. 27 | ICT_DEFAULT IndexCollectionType = iota 28 | 29 | // ICT_LIST is Index list elements. 30 | ICT_LIST 31 | 32 | // ICT_MAPKEYS is Index map keys. 33 | ICT_MAPKEYS 34 | 35 | // ICT_MAPVALUES is Index map values. 36 | ICT_MAPVALUES 37 | ) 38 | 39 | func (ict IndexCollectionType) String() string { 40 | switch ict { 41 | // Normal scalar index. 42 | case ICT_DEFAULT: 43 | return "ICT_DEFAULT" 44 | // Index list elements. 45 | case ICT_LIST: 46 | return "ICT_LIST" 47 | // Index map keys. 48 | case ICT_MAPKEYS: 49 | return "ICT_MAPKEYS" 50 | // Index map values. 51 | case ICT_MAPVALUES: 52 | return "ICT_MAPVALUES" 53 | } 54 | panic(unreachable) 55 | } 56 | 57 | // ictToString converts IndexCollectionType to string representations 58 | func ictToString(ict IndexCollectionType) string { 59 | switch ict { 60 | 61 | case ICT_LIST: 62 | return "LIST" 63 | 64 | case ICT_MAPKEYS: 65 | return "MAPKEYS" 66 | 67 | case ICT_MAPVALUES: 68 | return "MAPVALUES" 69 | 70 | default: 71 | panic(fmt.Sprintf("Unknown IndexCollectionType value %v", ict)) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /index_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // IndexType the type of the secondary index. 18 | type IndexType string 19 | 20 | const ( 21 | // NUMERIC specifies an index on numeric values. 22 | NUMERIC IndexType = "NUMERIC" 23 | 24 | // STRING specifies an index on string values. 25 | STRING IndexType = "STRING" 26 | 27 | // BLOB specifies a []byte index. Requires server version 7.0+. 28 | BLOB IndexType = "BLOB" 29 | 30 | // GEO2DSPHERE specifies 2-dimensional spherical geospatial index. 31 | GEO2DSPHERE IndexType = "GEO2DSPHERE" 32 | ) 33 | -------------------------------------------------------------------------------- /info_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "time" 19 | ) 20 | 21 | // InfoPolicy contains attributes used for info commands. 22 | type InfoPolicy struct { 23 | 24 | // Info command socket timeout. 25 | // Default is 2 seconds. 26 | Timeout time.Duration 27 | } 28 | 29 | // NewInfoPolicy generates a new InfoPolicy with default values. 30 | func NewInfoPolicy() *InfoPolicy { 31 | return &InfoPolicy{ 32 | Timeout: _DEFAULT_TIMEOUT, 33 | } 34 | } 35 | 36 | func (p *InfoPolicy) deadline() time.Time { 37 | var deadline time.Time 38 | if p != nil && p.Timeout > 0 { 39 | deadline = time.Now().Add(p.Timeout) 40 | } 41 | 42 | return deadline 43 | } 44 | 45 | func (p *InfoPolicy) timeout() time.Duration { 46 | if p != nil && p.Timeout > 0 { 47 | return p.Timeout 48 | } 49 | 50 | return _DEFAULT_TIMEOUT 51 | } 52 | -------------------------------------------------------------------------------- /internal/atomic/array.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic 16 | 17 | import ( 18 | "fmt" 19 | "sync" 20 | ) 21 | 22 | // Array implement a fixed width array with atomic semantics 23 | type Array struct { 24 | items []interface{} 25 | length int 26 | mutex sync.RWMutex 27 | } 28 | 29 | // NewArray generates a new Array instance. 30 | func NewArray(length int) *Array { 31 | return &Array{ 32 | length: length, 33 | items: make([]interface{}, length), 34 | } 35 | } 36 | 37 | // Get atomically retrieves an element from the Array. 38 | // If idx is out of range, it will return nil 39 | func (aa *Array) Get(idx int) interface{} { 40 | // do not lock if not needed 41 | if idx < 0 || idx >= aa.length { 42 | return nil 43 | } 44 | 45 | aa.mutex.RLock() 46 | res := aa.items[idx] 47 | aa.mutex.RUnlock() 48 | return res 49 | } 50 | 51 | // Set atomically sets an element in the Array. 52 | // If idx is out of range, it will return an error 53 | func (aa *Array) Set(idx int, node interface{}) error { 54 | // do not lock if not needed 55 | if idx < 0 || idx >= aa.length { 56 | return fmt.Errorf("index %d is larger than array size (%d)", idx, aa.length) 57 | } 58 | 59 | aa.mutex.Lock() 60 | aa.items[idx] = node 61 | aa.mutex.Unlock() 62 | return nil 63 | } 64 | 65 | // Length returns the array size. 66 | func (aa *Array) Length() int { 67 | aa.mutex.RLock() 68 | res := aa.length 69 | aa.mutex.RUnlock() 70 | 71 | return res 72 | } 73 | -------------------------------------------------------------------------------- /internal/atomic/atomic_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic_test 16 | 17 | import ( 18 | "testing" 19 | 20 | gg "github.com/onsi/ginkgo/v2" 21 | gm "github.com/onsi/gomega" 22 | ) 23 | 24 | func TestAerospike(t *testing.T) { 25 | gm.RegisterFailHandler(gg.Fail) 26 | gg.RunSpecs(t, "Atomic Types Suite") 27 | } 28 | -------------------------------------------------------------------------------- /internal/atomic/bool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic 16 | 17 | import ( 18 | "sync" 19 | ) 20 | 21 | // Bool implements a synchronized boolean value 22 | type Bool struct { 23 | m sync.Mutex 24 | val bool 25 | } 26 | 27 | // NewBool generates a new Boolean instance. 28 | func NewBool(value bool) *Bool { 29 | return &Bool{ 30 | val: value, 31 | } 32 | } 33 | 34 | // String implements the Stringer interface 35 | func (ab *Bool) String() string { 36 | res := ab.Get() 37 | if res { 38 | return "true" 39 | } 40 | return "false" 41 | } 42 | 43 | // GomegaString implements the GomegaStringer interface 44 | // to prevent race conditions in tests 45 | func (ab *Bool) GomegaString() string { 46 | return ab.String() 47 | } 48 | 49 | // Get atomically retrieves the boolean value. 50 | func (ab *Bool) Get() bool { 51 | ab.m.Lock() 52 | res := ab.val 53 | ab.m.Unlock() 54 | return res 55 | } 56 | 57 | // Set atomically sets the boolean value. 58 | func (ab *Bool) Set(newVal bool) { 59 | ab.m.Lock() 60 | ab.val = newVal 61 | ab.m.Unlock() 62 | } 63 | 64 | // Or atomically applies OR operation to the boolean value. 65 | func (ab *Bool) Or(newVal bool) bool { 66 | if !newVal { 67 | return ab.Get() 68 | } 69 | ab.Set(newVal) 70 | return true 71 | } 72 | 73 | // CompareAndToggle atomically sets the boolean value if the current value is equal to updated value. 74 | func (ab *Bool) CompareAndToggle(expect bool) bool { 75 | res := false 76 | ab.m.Lock() 77 | if ab.val == expect { 78 | res = true 79 | ab.val = !ab.val 80 | } 81 | ab.m.Unlock() 82 | return res 83 | } 84 | -------------------------------------------------------------------------------- /internal/atomic/bool_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic_test 16 | 17 | import ( 18 | "runtime" 19 | "sync" 20 | 21 | "github.com/aerospike/aerospike-client-go/v8/internal/atomic" 22 | 23 | gg "github.com/onsi/ginkgo/v2" 24 | gm "github.com/onsi/gomega" 25 | ) 26 | 27 | var _ = gg.Describe("Atomic Bool", func() { 28 | // atomic tests require actual parallelism 29 | runtime.GOMAXPROCS(runtime.NumCPU()) 30 | 31 | var ab *atomic.Bool 32 | 33 | gg.BeforeEach(func() { 34 | ab = atomic.NewBool(true) 35 | }) 36 | 37 | gg.It("must CompareAndToggle correctly", func() { 38 | gm.Expect(ab.CompareAndToggle(true)).To(gm.BeTrue()) 39 | gm.Expect(ab.CompareAndToggle(true)).To(gm.BeFalse()) 40 | }) 41 | 42 | gg.It("must CompareAndToggle correctly", func() { 43 | var count int = 1e5 44 | wg := new(sync.WaitGroup) 45 | wg.Add(count * 4) 46 | for i := 0; i < count; i++ { 47 | go func() { 48 | defer wg.Done() 49 | ab.Set(true) 50 | }() 51 | } 52 | 53 | for i := 0; i < count; i++ { 54 | go func() { 55 | defer wg.Done() 56 | ab.Set(false) 57 | }() 58 | } 59 | 60 | for i := 0; i < count; i++ { 61 | go func() { 62 | defer wg.Done() 63 | ab.Get() 64 | }() 65 | } 66 | 67 | for i := 0; i < count; i++ { 68 | go func(i int) { 69 | defer wg.Done() 70 | ab.CompareAndToggle(i%2 == 0) 71 | }(i) 72 | } 73 | 74 | wg.Wait() 75 | }) 76 | 77 | }) 78 | -------------------------------------------------------------------------------- /internal/atomic/guard.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic 16 | 17 | import "sync" 18 | 19 | // Guard allows synchronized access to a value 20 | type Guard[T any] struct { 21 | val *T 22 | m sync.Mutex 23 | } 24 | 25 | // NewGuard creates a new instance of Guard 26 | func NewGuard[T any](val *T) *Guard[T] { 27 | return &Guard[T]{val: val} 28 | } 29 | 30 | // Do calls the passed closure. 31 | func (g *Guard[T]) Do(f func(*T)) { 32 | g.m.Lock() 33 | defer g.m.Unlock() 34 | f(g.val) 35 | } 36 | 37 | // DoVal calls the passed closure with a dereferenced internal value. 38 | func (g *Guard[T]) DoVal(f func(T)) { 39 | g.m.Lock() 40 | defer g.m.Unlock() 41 | f(*g.val) 42 | } 43 | 44 | // Call the passed closure allowing to replace the content. 45 | func (g *Guard[T]) Update(f func(**T)) { 46 | g.m.Lock() 47 | defer g.m.Unlock() 48 | f(&g.val) 49 | } 50 | 51 | // Calls the passed closure allowing to replace the content. 52 | // It will call the init func if the internal values is nil. 53 | func (g *Guard[T]) InitDo(init func() *T, f func(*T)) { 54 | g.m.Lock() 55 | defer g.m.Unlock() 56 | if g.val == nil { 57 | g.val = init() 58 | } 59 | f(g.val) 60 | } 61 | 62 | // Calls the passed closure allowing to replace the content. 63 | // It will call the init func if the internal values is nil. 64 | // It is used for reference values like slices and maps. 65 | func (g *Guard[T]) InitDoVal(init func() T, f func(T)) { 66 | g.m.Lock() 67 | defer g.m.Unlock() 68 | if g.val == nil { 69 | t := init() 70 | g.val = &t 71 | } 72 | f(*g.val) 73 | } 74 | 75 | // Release returns the internal value and sets it to nil 76 | func (g *Guard[T]) Release() *T { 77 | g.m.Lock() 78 | defer g.m.Unlock() 79 | res := g.val 80 | g.val = nil 81 | return res 82 | } 83 | -------------------------------------------------------------------------------- /internal/atomic/int_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic_test 16 | 17 | import ( 18 | "runtime" 19 | "sync" 20 | 21 | "github.com/aerospike/aerospike-client-go/v8/internal/atomic" 22 | 23 | gg "github.com/onsi/ginkgo/v2" 24 | gm "github.com/onsi/gomega" 25 | ) 26 | 27 | var _ = gg.Describe("Atomic Int", func() { 28 | // atomic tests require actual parallelism 29 | runtime.GOMAXPROCS(runtime.NumCPU()) 30 | 31 | var ai *atomic.Int 32 | wg := new(sync.WaitGroup) 33 | 34 | gg.BeforeEach(func() { 35 | ai = atomic.NewInt(0) 36 | }) 37 | 38 | gg.It("must Offer() more elements than queue's capacity, and still not block", func() { 39 | var count int = 1e6 40 | wg.Add(count) 41 | for i := 0; i < count; i++ { 42 | go func() { 43 | defer wg.Done() 44 | ai.IncrementAndGet() 45 | }() 46 | } 47 | 48 | wg.Wait() 49 | gm.Expect(ai.Get()).To(gm.Equal(count)) 50 | }) 51 | 52 | }) 53 | -------------------------------------------------------------------------------- /internal/atomic/queue.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic 16 | 17 | import "sync" 18 | 19 | // Queue is a non-blocking FIFO queue. 20 | // If the queue is empty, nil is returned. 21 | // if the queue is full, offer will return false 22 | type Queue struct { 23 | head, tail uint32 24 | data []interface{} 25 | size uint32 26 | wrapped bool 27 | mutex sync.Mutex 28 | } 29 | 30 | // NewQueue creates a new queue with initial size. 31 | func NewQueue(size int) *Queue { 32 | if size <= 0 { 33 | panic("Queue size cannot be less than 1") 34 | } 35 | 36 | return &Queue{ 37 | wrapped: false, 38 | data: make([]interface{}, uint32(size)), 39 | size: uint32(size), 40 | } 41 | } 42 | 43 | // Offer adds an item to the queue unless the queue is full. 44 | // In case the queue is full, the item will not be added to the queue 45 | // and false will be returned 46 | func (q *Queue) Offer(obj interface{}) bool { 47 | q.mutex.Lock() 48 | 49 | // make sure queue is not full 50 | if q.tail == q.head && q.wrapped { 51 | q.mutex.Unlock() 52 | return false 53 | } 54 | 55 | if q.head+1 == q.size { 56 | q.wrapped = true 57 | } 58 | 59 | q.head = (q.head + 1) % q.size 60 | q.data[q.head] = obj 61 | q.mutex.Unlock() 62 | return true 63 | } 64 | 65 | // Poll removes and returns an item from the queue. 66 | // If the queue is empty, nil will be returned. 67 | func (q *Queue) Poll() (res interface{}) { 68 | q.mutex.Lock() 69 | 70 | // if queue is not empty 71 | if q.wrapped || (q.tail != q.head) { 72 | if q.tail+1 == q.size { 73 | q.wrapped = false 74 | } 75 | q.tail = (q.tail + 1) % q.size 76 | res = q.data[q.tail] 77 | } 78 | 79 | q.mutex.Unlock() 80 | return res 81 | } 82 | -------------------------------------------------------------------------------- /internal/atomic/queue_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package atomic_test 16 | 17 | import ( 18 | "runtime" 19 | 20 | "github.com/aerospike/aerospike-client-go/v8/internal/atomic" 21 | 22 | gg "github.com/onsi/ginkgo/v2" 23 | gm "github.com/onsi/gomega" 24 | ) 25 | 26 | type testStruct struct{ i int } 27 | 28 | var _ = gg.Describe("Atomic Queue", func() { 29 | // atomic tests require actual parallelism 30 | runtime.GOMAXPROCS(runtime.NumCPU()) 31 | 32 | var qcap int 33 | var q *atomic.Queue 34 | var elem interface{} 35 | 36 | gg.BeforeEach(func() { 37 | qcap = 10 38 | q = atomic.NewQueue(qcap) 39 | }) 40 | 41 | gg.It("must Offer() more elements than queue's capacity, and still not block", func() { 42 | for i := 0; i < 2*qcap; i++ { 43 | q.Offer(&testStruct{}) 44 | } 45 | }) 46 | 47 | gg.It("must Poll() more elements than queue's capacity, and still not block", func() { 48 | for i := 0; i < 2*qcap; i++ { 49 | elem = q.Poll() 50 | } 51 | gm.Expect(elem).To(gm.BeNil()) 52 | }) 53 | 54 | gg.It("must Offer() more elements than queue's capacity, and Poll() as many as capacity", func() { 55 | // test for many iterations 56 | for j := 0; j < 10; j++ { 57 | for i := 0; i < 2*qcap; i++ { 58 | q.Offer(&testStruct{i}) 59 | } 60 | 61 | for i := 0; i < 2*qcap; i++ { 62 | obj := q.Poll() 63 | if i < qcap { 64 | gm.Expect(obj.(*testStruct).i).To(gm.Equal(i)) 65 | } else { 66 | gm.Expect(obj).To(gm.BeNil()) 67 | } 68 | } 69 | } 70 | }) 71 | 72 | }) 73 | -------------------------------------------------------------------------------- /internal/atomic/sync_val.go: -------------------------------------------------------------------------------- 1 | package atomic 2 | 3 | import "sync" 4 | 5 | // SyncVal allows synchronized access to a value 6 | type SyncVal[T any] struct { 7 | val T 8 | lock sync.RWMutex 9 | } 10 | 11 | // NewSyncVal creates a new instance of SyncVal 12 | func NewSyncVal[T any](val T) *SyncVal[T] { 13 | return &SyncVal[T]{val: val} 14 | } 15 | 16 | // Set updates the value of SyncVal with the passed argument 17 | func (sv *SyncVal[T]) Set(val T) { 18 | sv.lock.Lock() 19 | sv.val = val 20 | sv.lock.Unlock() 21 | } 22 | 23 | // Get returns the value inside the SyncVal 24 | func (sv *SyncVal[T]) Get() T { 25 | sv.lock.RLock() 26 | val := sv.val 27 | sv.lock.RUnlock() 28 | return val 29 | } 30 | 31 | // GetSyncedVia returns the value returned by the function f. 32 | func (sv *SyncVal[T]) GetSyncedVia(f func(T) (T, error)) (T, error) { 33 | sv.lock.RLock() 34 | defer sv.lock.RUnlock() 35 | 36 | val, err := f(sv.val) 37 | return val, err 38 | } 39 | 40 | // Update gets a function and passes the value of SyncVal to it. 41 | // If the resulting err is nil, it will update the value of SyncVal. 42 | // It will return the resulting error to the caller. 43 | func (sv *SyncVal[T]) Update(f func(T) (T, error)) error { 44 | sv.lock.Lock() 45 | defer sv.lock.Unlock() 46 | 47 | val, err := f(sv.val) 48 | if err == nil { 49 | sv.val = val 50 | } 51 | return err 52 | } 53 | 54 | // MapSyncValue returns the value returned by the function f. 55 | func MapSyncValue[T any, U any](sv *SyncVal[T], f func(T) (U, error)) (U, error) { 56 | sv.lock.RLock() 57 | defer sv.lock.RUnlock() 58 | 59 | val, err := f(sv.val) 60 | return val, err 61 | } 62 | -------------------------------------------------------------------------------- /internal/atomic/typed_val.go: -------------------------------------------------------------------------------- 1 | package atomic 2 | 3 | import "sync/atomic" 4 | 5 | // TypedVal allows synchronized access to a value 6 | type TypedVal[T any] atomic.Value 7 | 8 | // Set updates the value of TypedVal with the passed argument 9 | func (sv *TypedVal[T]) Set(val T) { 10 | (*atomic.Value)(sv).Store(&val) 11 | } 12 | 13 | // Get returns the value inside the TypedVal 14 | func (sv *TypedVal[T]) Get() T { 15 | res := (*atomic.Value)(sv).Load() 16 | if res != nil { 17 | return *res.(*T) 18 | } 19 | 20 | // return zero value; for pointers, it will be nil 21 | var t T 22 | return t 23 | } 24 | -------------------------------------------------------------------------------- /internal/lua/instance.go: -------------------------------------------------------------------------------- 1 | //go:build !app_engine 2 | // +build !app_engine 3 | 4 | // Copyright 2014-2022 Aerospike, Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package lua 19 | 20 | import ( 21 | luaLib "github.com/aerospike/aerospike-client-go/v8/internal/lua/resources" 22 | "github.com/aerospike/aerospike-client-go/v8/logger" 23 | "github.com/aerospike/aerospike-client-go/v8/types" 24 | lua "github.com/yuin/gopher-lua" 25 | ) 26 | 27 | // SetPath sets the interpreter's current Lua Path 28 | func SetPath(lpath string) { 29 | lua.LuaPath = lpath 30 | } 31 | 32 | // Path returns the interpreter's current Lua Path 33 | func Path() string { 34 | return lua.LuaPath 35 | } 36 | 37 | // LuaPool is the global LState pool 38 | var LuaPool = types.NewPool(64) 39 | 40 | func newInstance(params ...interface{}) interface{} { 41 | L := lua.NewState() 42 | 43 | registerLuaAerospikeType(L) 44 | registerLuaStreamType(L) 45 | registerLuaListType(L) 46 | registerLuaMapType(L) 47 | 48 | if err := L.DoString(luaLib.LibStreamOps); err != nil { 49 | logger.Logger.Error(err.Error()) 50 | return nil 51 | } 52 | 53 | if err := L.DoString(luaLib.LibAerospike); err != nil { 54 | logger.Logger.Error(err.Error()) 55 | return nil 56 | } 57 | 58 | return L 59 | } 60 | 61 | func finalizeInstance(instance interface{}) { 62 | if instance != nil { 63 | instance.(*lua.LState).Close() 64 | } 65 | } 66 | 67 | func init() { 68 | LuaPool.New = newInstance 69 | LuaPool.Finalize = finalizeInstance 70 | } 71 | -------------------------------------------------------------------------------- /internal/lua/lua_aerospike.go: -------------------------------------------------------------------------------- 1 | //go:build !app_engine 2 | // +build !app_engine 3 | 4 | // Copyright 2014-2022 Aerospike, Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package lua 19 | 20 | import ( 21 | "github.com/aerospike/aerospike-client-go/v8/logger" 22 | lua "github.com/yuin/gopher-lua" 23 | ) 24 | 25 | const luaLuaAerospikeTypeName = "LuaAerospike" 26 | 27 | // Registers my luaAerospike type to given L. 28 | func registerLuaAerospikeType(L *lua.LState) { 29 | mt := L.NewTypeMetatable(luaLuaAerospikeTypeName) 30 | 31 | L.SetGlobal("aerospike", mt) 32 | 33 | // static attributes 34 | L.SetField(mt, "log", L.NewFunction(luaAerospikeLog)) 35 | 36 | L.SetMetatable(mt, mt) 37 | } 38 | 39 | func luaAerospikeLog(L *lua.LState) int { 40 | if L.GetTop() < 2 || L.GetTop() > 3 { 41 | L.ArgError(1, "2 arguments are expected for aerospike:log method") 42 | return 0 43 | } 44 | 45 | // account for calling it on a table 46 | paramIdx := 1 47 | if L.GetTop() == 3 { 48 | paramIdx = 2 49 | } 50 | 51 | level := L.CheckInt(paramIdx) 52 | str := L.CheckString(paramIdx + 1) 53 | 54 | switch level { 55 | case 1: 56 | logger.Logger.Warn(str) 57 | case 2: 58 | logger.Logger.Info(str) 59 | case 3, 4: 60 | logger.Logger.Debug(str) 61 | } 62 | 63 | return 0 64 | } 65 | -------------------------------------------------------------------------------- /internal/lua/lua_aerospike_test.go: -------------------------------------------------------------------------------- 1 | //go:build !app_engine 2 | // +build !app_engine 3 | 4 | // Copyright 2014-2022 Aerospike, Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package lua_test 19 | 20 | import ( 21 | lua "github.com/yuin/gopher-lua" 22 | 23 | gg "github.com/onsi/ginkgo/v2" 24 | gm "github.com/onsi/gomega" 25 | 26 | ilua "github.com/aerospike/aerospike-client-go/v8/internal/lua" 27 | ) 28 | 29 | var _ = gg.Describe("Lua Aerospike API Test", func() { 30 | 31 | // code vs result 32 | testMatrix := map[string]interface{}{ 33 | "aerospike.log(1, 'Warn')": nil, 34 | "warn('Warn %d', 1)": nil, 35 | 36 | "aerospike.log(2, 'Info')": nil, 37 | "info('Info %d', 2)": nil, 38 | 39 | "aerospike.log(3, 'Debug')": nil, 40 | "trace('Trace %d', 3)": nil, 41 | 42 | "aerospike.log(4, 'Debug')": nil, 43 | "debug('Debug %d', 4)": nil, 44 | } 45 | 46 | gg.It("must run all code blocks", func() { 47 | instance := ilua.LuaPool.Get().(*lua.LState) 48 | defer instance.Close() 49 | for source := range testMatrix { 50 | err := instance.DoString(source) 51 | gm.Expect(err).NotTo(gm.HaveOccurred()) 52 | } 53 | 54 | }) 55 | 56 | }) 57 | -------------------------------------------------------------------------------- /internal/lua/lua_suite_test.go: -------------------------------------------------------------------------------- 1 | //go:build !app_engine 2 | // +build !app_engine 3 | 4 | // Copyright 2014-2022 Aerospike, Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | package lua_test 19 | 20 | import ( 21 | "testing" 22 | 23 | gg "github.com/onsi/ginkgo/v2" 24 | gm "github.com/onsi/gomega" 25 | ) 26 | 27 | func TestLua(t *testing.T) { 28 | gm.RegisterFailHandler(gg.Fail) 29 | gg.RunSpecs(t, "Lua Libs Test") 30 | } 31 | -------------------------------------------------------------------------------- /internal/seq/seq.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package seq 16 | 17 | import ( 18 | "errors" 19 | "sync" 20 | ) 21 | 22 | var Break = errors.New("Break") 23 | 24 | func Do[T any](seq []T, f func(T) error) { 25 | for i := range seq { 26 | if err := f(seq[i]); err == Break { 27 | break 28 | } 29 | } 30 | } 31 | 32 | func ParDo[T any](seq []T, f func(T)) { 33 | if len(seq) == 0 { 34 | return 35 | } 36 | 37 | wg := new(sync.WaitGroup) 38 | wg.Add(len(seq)) 39 | for i := range seq { 40 | go func(t T) { 41 | defer wg.Done() 42 | f(t) 43 | }(seq[i]) 44 | } 45 | wg.Wait() 46 | } 47 | 48 | func Any[T any](seq []T, f func(T) bool) bool { 49 | for i := range seq { 50 | if f(seq[i]) { 51 | return true 52 | } 53 | } 54 | return false 55 | } 56 | 57 | func All[T any](seq []T, f func(T) bool) bool { 58 | if len(seq) == 0 { 59 | return false 60 | } 61 | 62 | for i := range seq { 63 | if !f(seq[i]) { 64 | return false 65 | } 66 | } 67 | return true 68 | } 69 | 70 | func Clone[T any](seq []T) []T { 71 | if seq == nil { 72 | return nil 73 | } 74 | 75 | if len(seq) == 0 { 76 | return []T{} 77 | } 78 | 79 | res := make([]T, len(seq)) 80 | copy(res, seq) 81 | return res 82 | } 83 | -------------------------------------------------------------------------------- /key_reflect_test.go: -------------------------------------------------------------------------------- 1 | //go:build !as_performance 2 | 3 | // Copyright 2014-2022 Aerospike, Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package aerospike_test 18 | 19 | import ( 20 | gg "github.com/onsi/ginkgo/v2" 21 | ) 22 | 23 | // ALL tests are isolated by SetName and Key, which are 50 random characters 24 | var _ = gg.Describe("Key Test Reflection", func() { 25 | 26 | // gg.Context("Digests should be the same", func() { 27 | 28 | // gg.It("for Arrays", func() { 29 | 30 | // // The following two cases should be in exact order 31 | // key, _ := as.NewKey("namespace", "set", []int{1, 2, 3}) 32 | // gm.Expect(hex.EncodeToString(key.Digest())).To(gm.Equal("a8b63a8208ebebb49d027d51899121fd0d03d2f7")) 33 | 34 | // keyInterfaceArrayOfTheSameValues, _ := as.NewKey("namespace", "set", []interface{}{1, 2, 3}) 35 | // gm.Expect(hex.EncodeToString(keyInterfaceArrayOfTheSameValues.Digest())).To(gm.Equal(hex.EncodeToString(key.Digest()))) 36 | 37 | // }) 38 | 39 | // }) 40 | 41 | }) 42 | -------------------------------------------------------------------------------- /language.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // Language specifies User defined function languages. 18 | type Language string 19 | 20 | const ( 21 | 22 | // LUA embedded programming language. 23 | LUA Language = "LUA" 24 | ) 25 | -------------------------------------------------------------------------------- /metrics_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types/histogram" 19 | ) 20 | 21 | // MetricsPolicy specifies client periodic metrics configuration. 22 | type MetricsPolicy struct { 23 | // Histogram type specifies if the histogram should be [histogram.Linear] or [histogram.Logarithmic]. 24 | // 25 | // Default: [histogram.Logarithmic] 26 | HistogramType histogram.Type 27 | 28 | // LatencyColumns defines the number of elapsed time range buckets in latency histograms. 29 | // 30 | // Default: 24 31 | LatencyColumns int //= 24; 32 | 33 | // Depending on the type of histogram: 34 | // 35 | // For logarithmic histograms, the buckets are: =base^(columns-1) 36 | // 37 | // // LatencyColumns=5 latencyBase=8 38 | // <8µs <64µs <512µs <4096µs >=4096 39 | // 40 | // // LatencyColumns=7 LatencyBase=4 41 | // <4µs <16µs <64µs <256µs <1024µs <4096 >=4096µs 42 | // 43 | // For linear histograms, the buckets are: =base*(column-1) 44 | // 45 | // // LatencyColumns=5 latencyBase=15 46 | // <15µs <30µs <45µs <60µs >=60µs 47 | // 48 | // // LatencyColumns=7 LatencyBase=5 49 | // <5µs <10µs <15µs <20µs <25µs <30µs >=30µs 50 | // 51 | // Default: 2 52 | LatencyBase int //= 2; 53 | } 54 | 55 | func DefaultMetricsPolicy() *MetricsPolicy { 56 | return &MetricsPolicy{ 57 | HistogramType: histogram.Logarithmic, 58 | LatencyColumns: 24, 59 | LatencyBase: 2, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /operate_command_read.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | type operateCommandRead struct { 18 | readCommand 19 | 20 | args operateArgs 21 | } 22 | 23 | func newOperateCommandRead(cluster *Cluster, key *Key, args operateArgs) (operateCommandRead, Error) { 24 | rdCommand, err := newReadCommand(cluster, &args.writePolicy.BasePolicy, key, nil) 25 | if err != nil { 26 | return operateCommandRead{}, err 27 | } 28 | 29 | res := operateCommandRead{ 30 | readCommand: rdCommand, 31 | args: args, 32 | } 33 | 34 | res.isOperation = true 35 | 36 | return res, nil 37 | } 38 | 39 | func (cmd *operateCommandRead) writeBuffer(ifc command) (err Error) { 40 | return cmd.setOperate(cmd.args.writePolicy, cmd.key, &cmd.args) 41 | } 42 | 43 | func (cmd *operateCommandRead) Execute() Error { 44 | return cmd.execute(cmd) 45 | } 46 | 47 | func (cmd *operateCommandRead) commandType() commandType { 48 | return ttOperate 49 | } 50 | -------------------------------------------------------------------------------- /operate_command_write.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "github.com/aerospike/aerospike-client-go/v8/types" 18 | 19 | type operateCommandWrite struct { 20 | baseWriteCommand 21 | 22 | record *Record 23 | args operateArgs 24 | } 25 | 26 | func newOperateCommandWrite(cluster *Cluster, key *Key, args operateArgs) (operateCommandWrite, Error) { 27 | bwc, err := newBaseWriteCommand(cluster, args.writePolicy, key) 28 | if err != nil { 29 | return operateCommandWrite{}, err 30 | } 31 | 32 | return operateCommandWrite{ 33 | baseWriteCommand: bwc, 34 | args: args, 35 | }, nil 36 | } 37 | 38 | func (cmd *operateCommandWrite) writeBuffer(ifc command) (err Error) { 39 | return cmd.setOperate(cmd.policy, cmd.key, &cmd.args) 40 | } 41 | 42 | func (cmd *operateCommandWrite) parseResult(ifc command, conn *Connection) Error { 43 | rp, err := newRecordParser(&cmd.baseCommand) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | if err := rp.parseFields(cmd.policy.Txn, cmd.key, true); err != nil { 49 | return err 50 | } 51 | 52 | switch rp.resultCode { 53 | case types.OK: 54 | var err Error 55 | cmd.record, err = rp.parseRecord(cmd.key, true) 56 | if err != nil { 57 | return err 58 | } 59 | return nil 60 | case types.KEY_NOT_FOUND_ERROR: 61 | return ErrKeyNotFound.err() 62 | case types.FILTERED_OUT: 63 | return ErrFilteredOut.err() 64 | default: 65 | return newError(rp.resultCode) 66 | } 67 | } 68 | 69 | func (cmd *operateCommandWrite) Execute() Error { 70 | return cmd.execute(cmd) 71 | } 72 | 73 | func (cmd *operateCommandWrite) commandType() commandType { 74 | return ttOperate 75 | } 76 | 77 | func (cmd *operateCommandWrite) GetRecord() *Record { 78 | return cmd.record 79 | } 80 | -------------------------------------------------------------------------------- /partition_status.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Portions may be licensed to Aerospike, Inc. under one or more contributor 4 | // license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy of 8 | // the License at http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | // License for the specific language governing permissions and limitations under 14 | // the License. 15 | 16 | package aerospike 17 | 18 | import ( 19 | "fmt" 20 | ) 21 | 22 | // PartitionStatus encapsulates the pagination status in partitions. 23 | type PartitionStatus struct { 24 | // BVal 25 | BVal int64 26 | // Id shows the partition Id. 27 | Id int 28 | // Retry signifies if the partition requires a retry. 29 | Retry bool 30 | // Digest records the digest of the last key digest received from the server 31 | // for this partition. 32 | Digest []byte 33 | 34 | // the following fields are transient 35 | node *Node 36 | sequence int 37 | } 38 | 39 | func newPartitionStatus(id int) *PartitionStatus { 40 | return &PartitionStatus{Id: id, Retry: true} 41 | } 42 | 43 | func (ps *PartitionStatus) String() string { 44 | r := 'F' 45 | if ps.Retry { 46 | r = 'T' 47 | } 48 | return fmt.Sprintf("%04d:%c", ps.Id, r) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/bcrypt/.gitignore: -------------------------------------------------------------------------------- 1 | 6.out 2 | *.6 3 | _obj 4 | _test 5 | _testmain.go 6 | -------------------------------------------------------------------------------- /pkg/bcrypt/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 James Keane . All rights reserved. 2 | Copyright (c) 2006 Damien Miller . 3 | Copyright (c) 2011 ZooWar.com, All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | * Neither the name of weekendlogic nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /pkg/bcrypt/README: -------------------------------------------------------------------------------- 1 | Installation: 2 | goinstall github.com/jameskeane/bcrypt 3 | 4 | Example use: 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "github.com/jameskeane/bcrypt" 10 | ) 11 | 12 | var password = "WyWihatdyd?frub1" 13 | var bad_password = "just a wild guess" 14 | 15 | func main() { 16 | // generate a random salt with default rounds of complexity 17 | salt, _ := bcrypt.Salt() 18 | 19 | // generate a random salt with 10 rounds of complexity 20 | salt, _ = bcrypt.Salt(10) 21 | 22 | // hash and verify a password with random salt 23 | hash, _ := bcrypt.Hash(password) 24 | if bcrypt.Match(password, hash) { 25 | fmt.Println("They match") 26 | } 27 | 28 | // hash and verify a password with a static salt 29 | hash, _ = bcrypt.Hash(password, salt) 30 | if bcrypt.Match(password, hash) { 31 | fmt.Println("They match") 32 | } 33 | 34 | // verify a random password fails to match the hashed password 35 | if !bcrypt.Match(bad_password, hash) { 36 | fmt.Println("They don't match") 37 | } 38 | } 39 | 40 | Todo: 41 | grep 'TODO' * -r 42 | 43 | Notes: 44 | * This library is derived from jBcrypt by Damien Miller 45 | * bcrypt_test.go is from ZooWar.com 46 | 47 | -------------------------------------------------------------------------------- /pkg/ripemd160/ripemd160_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ripemd160 6 | 7 | // Test vectors are from: 8 | // http://homes.esat.kuleuven.be/~bosselae/ripemd160.html 9 | 10 | import ( 11 | "fmt" 12 | "io" 13 | "testing" 14 | ) 15 | 16 | type mdTest struct { 17 | out string 18 | in string 19 | } 20 | 21 | var vectors = [...]mdTest{ 22 | {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""}, 23 | {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"}, 24 | {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"}, 25 | {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"}, 26 | {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"}, 27 | {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"}, 28 | {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}, 29 | {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"}, 30 | } 31 | 32 | func TestVectors(t *testing.T) { 33 | for i := 0; i < len(vectors); i++ { 34 | tv := vectors[i] 35 | md := New() 36 | for j := 0; j < 3; j++ { 37 | if j < 2 { 38 | io.WriteString(md, tv.in) 39 | } else { 40 | io.WriteString(md, tv.in[0:len(tv.in)/2]) 41 | // md.Sum(nil) // removed due to our changes in the code; we use only one Sum() and then reset 42 | io.WriteString(md, tv.in[len(tv.in)/2:]) 43 | } 44 | s := fmt.Sprintf("%x", md.Sum(nil)) 45 | if s != tv.out { 46 | t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out) 47 | } 48 | md.Reset() 49 | } 50 | } 51 | } 52 | 53 | func TestMillionA(t *testing.T) { 54 | md := New() 55 | for i := 0; i < 100000; i++ { 56 | io.WriteString(md, "aaaaaaaaaa") 57 | } 58 | out := "52783243c1697bdbe16d37f97f68f08325dc1528" 59 | s := fmt.Sprintf("%x", md.Sum(nil)) 60 | if s != out { 61 | t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out) 62 | } 63 | md.Reset() 64 | } 65 | -------------------------------------------------------------------------------- /query_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | type queryCommand struct { 18 | baseMultiCommand 19 | 20 | policy *QueryPolicy 21 | writePolicy *WritePolicy 22 | statement *Statement 23 | operations []*Operation 24 | } 25 | 26 | func newQueryCommand(node *Node, policy *QueryPolicy, writePolicy *WritePolicy, statement *Statement, operations []*Operation, recordset *Recordset) *queryCommand { 27 | res := &queryCommand{ 28 | baseMultiCommand: *newStreamingMultiCommand(node, recordset, statement.Namespace, false), 29 | policy: policy, 30 | writePolicy: writePolicy, 31 | statement: statement, 32 | operations: operations, 33 | } 34 | res.rawCDT = policy.RawCDT 35 | 36 | return res 37 | } 38 | 39 | func (cmd *queryCommand) getPolicy(ifc command) Policy { 40 | return cmd.policy 41 | } 42 | 43 | func (cmd *queryCommand) writeBuffer(ifc command) (err Error) { 44 | return cmd.setQuery(cmd.policy, cmd.writePolicy, cmd.statement, cmd.recordset.TaskId(), cmd.operations, cmd.writePolicy != nil, nil) 45 | } 46 | 47 | func (cmd *queryCommand) parseResult(ifc command, conn *Connection) Error { 48 | return cmd.baseMultiCommand.parseResult(ifc, conn) 49 | } 50 | 51 | func (cmd *queryCommand) commandType() commandType { 52 | return ttQuery 53 | } 54 | 55 | // Execute will run the query. 56 | func (cmd *queryCommand) Execute() Error { 57 | err := cmd.execute(cmd) 58 | if err != nil { 59 | cmd.recordset.sendError(err) 60 | } 61 | return err 62 | } 63 | -------------------------------------------------------------------------------- /query_duration.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package aerospike 19 | 20 | // QueryDuration defines the expected query duration. The server treats the query in different ways depending on the expected duration. 21 | // This enum is ignored for aggregation queries, background queries and server versions < 6.0. 22 | type QueryDuration int 23 | 24 | const ( 25 | // LONG specifies that the query is expected to return more than 100 records per node. The server optimizes for a large record set in 26 | // the following ways: 27 | // 28 | // Allow query to be run in multiple threads using the server's query threading configuration. 29 | // Do not relax read consistency for AP namespaces. 30 | // Add the query to the server's query monitor. 31 | // Do not add the overall latency to the server's latency histogram. 32 | // Do not allow server timeouts. 33 | LONG = iota 34 | 35 | // Short specifies that the query is expected to return less than 100 records per node. The server optimizes for a small record set in 36 | // the following ways: 37 | // Always run the query in one thread and ignore the server's query threading configuration. 38 | // Allow query to be inlined directly on the server's service thread. 39 | // Relax read consistency for AP namespaces. 40 | // Do not add the query to the server's query monitor. 41 | // Add the overall latency to the server's latency histogram. 42 | // Allow server timeouts. The default server timeout for a short query is 1 second. 43 | SHORT 44 | 45 | // LONG_RELAX_AP will treat query as a LONG query, but relax read consistency for AP namespaces. 46 | // This value is treated exactly like LONG for server versions < 7.1. 47 | LONG_RELAX_AP 48 | ) 49 | -------------------------------------------------------------------------------- /query_executor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "time" 19 | ) 20 | 21 | func (clnt *Client) queryPartitions(policy *QueryPolicy, tracker *partitionTracker, statement *Statement, recordset *Recordset) { 22 | defer recordset.signalEnd() 23 | 24 | // for exponential backoff 25 | interval := policy.SleepBetweenRetries 26 | 27 | var errs Error 28 | for { 29 | list, err := tracker.assignPartitionsToNodes(clnt.Cluster(), statement.Namespace) 30 | if err != nil { 31 | errs = chainErrors(err, errs) 32 | recordset.sendError(errs) 33 | tracker.partitionError() 34 | return 35 | } 36 | 37 | maxConcurrentNodes := policy.MaxConcurrentNodes 38 | if maxConcurrentNodes <= 0 { 39 | maxConcurrentNodes = len(list) 40 | } 41 | 42 | if recordset.IsActive() { 43 | weg := newWeightedErrGroup(maxConcurrentNodes) 44 | for _, nodePartition := range list { 45 | cmd := newQueryPartitionCommand(policy, tracker, nodePartition, statement, recordset) 46 | weg.execute(cmd) 47 | } 48 | errs = chainErrors(weg.wait(), errs) 49 | } 50 | 51 | done, err := tracker.isClusterComplete(clnt.Cluster(), &policy.BasePolicy) 52 | if !recordset.IsActive() || done || err != nil { 53 | errs = chainErrors(err, errs) 54 | // Query is complete. 55 | if errs != nil { 56 | tracker.partitionError() 57 | recordset.sendError(errs) 58 | } 59 | return 60 | } 61 | 62 | if policy.SleepBetweenRetries > 0 { 63 | // Sleep before trying again. 64 | time.Sleep(interval) 65 | 66 | if policy.SleepMultiplier > 1 { 67 | interval = time.Duration(float64(interval) * policy.SleepMultiplier) 68 | } 69 | } 70 | 71 | recordset.resetTaskID() 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /query_partition_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | type queryPartitionCommand queryCommand 18 | 19 | func newQueryPartitionCommand( 20 | policy *QueryPolicy, 21 | tracker *partitionTracker, 22 | nodePartitions *nodePartitions, 23 | statement *Statement, 24 | recordset *Recordset, 25 | ) *queryPartitionCommand { 26 | cmd := &queryPartitionCommand{ 27 | baseMultiCommand: *newCorrectStreamingMultiCommand(recordset, statement.Namespace), 28 | policy: policy, 29 | writePolicy: nil, 30 | statement: statement, 31 | operations: nil, 32 | } 33 | cmd.rawCDT = policy.RawCDT 34 | cmd.terminationErrorType = statement.terminationError() 35 | cmd.tracker = tracker 36 | cmd.nodePartitions = nodePartitions 37 | cmd.node = nodePartitions.node 38 | 39 | return cmd 40 | } 41 | 42 | func (cmd *queryPartitionCommand) getPolicy(ifc command) Policy { 43 | return cmd.policy 44 | } 45 | 46 | func (cmd *queryPartitionCommand) writeBuffer(ifc command) Error { 47 | return cmd.setQuery(cmd.policy, cmd.writePolicy, cmd.statement, cmd.recordset.TaskId(), cmd.operations, cmd.writePolicy != nil, cmd.nodePartitions) 48 | } 49 | 50 | func (cmd *queryPartitionCommand) shouldRetry(e Error) bool { 51 | return cmd.tracker != nil && cmd.tracker.shouldRetry(cmd.nodePartitions, e) 52 | } 53 | 54 | func (cmd *queryPartitionCommand) commandType() commandType { 55 | return ttQuery 56 | } 57 | 58 | func (cmd *queryPartitionCommand) Execute() Error { 59 | err := cmd.execute(cmd) 60 | if err != nil { 61 | // signal to the executor that no retries should be attempted 62 | // don't send error unless no retries are planned 63 | if !cmd.shouldRetry(err) { 64 | cmd.recordset.sendError(err) 65 | } 66 | } 67 | return err 68 | } 69 | -------------------------------------------------------------------------------- /query_partitiopn_objects_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | type queryPartitionObjectsCommand queryCommand 18 | 19 | func newQueryPartitionObjectsCommand( 20 | policy *QueryPolicy, 21 | tracker *partitionTracker, 22 | nodePartitions *nodePartitions, 23 | statement *Statement, 24 | recordset *Recordset, 25 | ) *queryPartitionObjectsCommand { 26 | cmd := &queryPartitionObjectsCommand{ 27 | baseMultiCommand: *newCorrectStreamingMultiCommand(recordset, statement.Namespace), 28 | policy: policy, 29 | writePolicy: nil, 30 | statement: statement, 31 | operations: nil, 32 | } 33 | cmd.terminationErrorType = statement.terminationError() 34 | cmd.tracker = tracker 35 | cmd.nodePartitions = nodePartitions 36 | cmd.node = nodePartitions.node 37 | 38 | return cmd 39 | } 40 | 41 | func (cmd *queryPartitionObjectsCommand) getPolicy(ifc command) Policy { 42 | return cmd.policy 43 | } 44 | 45 | func (cmd *queryPartitionObjectsCommand) writeBuffer(ifc command) Error { 46 | return cmd.setQuery(cmd.policy, cmd.writePolicy, cmd.statement, cmd.recordset.TaskId(), cmd.operations, cmd.writePolicy != nil, cmd.nodePartitions) 47 | } 48 | 49 | func (cmd *queryPartitionObjectsCommand) shouldRetry(e Error) bool { 50 | return cmd.tracker != nil && cmd.tracker.shouldRetry(cmd.nodePartitions, e) 51 | } 52 | 53 | func (cmd *queryPartitionObjectsCommand) commandType() commandType { 54 | return ttQuery 55 | } 56 | 57 | func (cmd *queryPartitionObjectsCommand) Execute() Error { 58 | err := cmd.execute(cmd) 59 | if err != nil { 60 | // signal to the executor that no retries should be attempted 61 | // don't send error unless no retries are planned 62 | if !cmd.shouldRetry(err) { 63 | cmd.recordset.sendError(err) 64 | } 65 | } 66 | return err 67 | } 68 | -------------------------------------------------------------------------------- /read_header_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | type readHeaderCommand struct { 22 | baseReadCommand 23 | } 24 | 25 | func newReadHeaderCommand(cluster *Cluster, policy *BasePolicy, key *Key) (readHeaderCommand, Error) { 26 | brc, err := newBaseReadCommand(cluster, policy, key) 27 | if err != nil { 28 | return readHeaderCommand{}, err 29 | } 30 | 31 | newReadHeaderCmd := readHeaderCommand{ 32 | baseReadCommand: brc, 33 | } 34 | 35 | return newReadHeaderCmd, nil 36 | } 37 | 38 | func (cmd *readHeaderCommand) writeBuffer(ifc command) Error { 39 | return cmd.setReadHeader(cmd.policy, cmd.key) 40 | } 41 | 42 | func (cmd *readHeaderCommand) parseResult(ifc command, conn *Connection) Error { 43 | rp, err := newRecordParser(&cmd.baseCommand) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | if err := rp.parseFields(cmd.policy.Txn, cmd.key, false); err != nil { 49 | return err 50 | } 51 | 52 | if rp.resultCode == 0 { 53 | cmd.record = newRecord(cmd.node, cmd.key, nil, rp.generation, rp.expiration) 54 | } else { 55 | switch rp.resultCode { 56 | case types.KEY_NOT_FOUND_ERROR: 57 | cmd.record = nil 58 | case types.FILTERED_OUT: 59 | return ErrFilteredOut.err() 60 | default: 61 | return newError(rp.resultCode) 62 | } 63 | } 64 | return nil 65 | } 66 | 67 | func (cmd *readHeaderCommand) GetRecord() *Record { 68 | return cmd.record 69 | } 70 | 71 | func (cmd *readHeaderCommand) Execute() Error { 72 | return cmd.execute(cmd) 73 | } 74 | 75 | func (cmd *readHeaderCommand) commandType() commandType { 76 | return ttGetHeader 77 | } 78 | -------------------------------------------------------------------------------- /read_mode_ap.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package aerospike 19 | 20 | // ReadModeAP is the read policy in AP (availability) mode namespaces. 21 | // It indicates how duplicates should be consulted in a read operation. 22 | // Only makes a difference during migrations and only applicable in AP mode. 23 | type ReadModeAP int 24 | 25 | const ( 26 | // ReadModeAPOne indicates that a single node should be involved in the read operation. 27 | ReadModeAPOne ReadModeAP = iota 28 | 29 | // ReadModeAPAll indicates that all duplicates should be consulted in 30 | // the read operation. 31 | ReadModeAPAll 32 | ) 33 | -------------------------------------------------------------------------------- /read_mode_sc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package aerospike 19 | 20 | // ReadModeSC is the read policy in SC (strong consistency) mode namespaces. 21 | // Determines SC read consistency options. 22 | type ReadModeSC int 23 | 24 | const ( 25 | // ReadModeSCSession ensures this client will only see an increasing sequence of record versions. 26 | // Client only reads from master. This is the default. 27 | ReadModeSCSession ReadModeSC = iota 28 | 29 | // ReadModeSCLinearize ensures all clients will only see an increasing sequence of record versions. 30 | // Client only reads from master. 31 | ReadModeSCLinearize 32 | 33 | // ReadModeSCAllowReplica indicates that the client may read from master or any full (non-migrating) replica. 34 | // Increasing sequence of record versions is not guaranteed. 35 | ReadModeSCAllowReplica 36 | 37 | // ReadModeSCAllowUnavailable indicates that the client may read from master or any full (non-migrating) replica or from unavailable 38 | // partitions. Increasing sequence of record versions is not guaranteed. 39 | ReadModeSCAllowUnavailable 40 | ) 41 | -------------------------------------------------------------------------------- /record.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "fmt" 18 | 19 | // Record is the container struct for database records. 20 | // Records are equivalent to rows. 21 | type Record struct { 22 | // Key is the record's key. 23 | // Might be empty, or may only consist of digest value. 24 | Key *Key 25 | 26 | // Node from which the Record is originating from. 27 | Node *Node 28 | 29 | // Bins is the map of requested name/value bins. 30 | Bins BinMap 31 | 32 | // Generation shows record modification count. 33 | Generation uint32 34 | 35 | // Expiration is TTL (Time-To-Live). 36 | // Number of seconds until record expires. 37 | Expiration uint32 38 | } 39 | 40 | func newRecord(node *Node, key *Key, bins BinMap, generation, expiration uint32) *Record { 41 | r := &Record{ 42 | Node: node, 43 | Key: key, 44 | Bins: bins, 45 | Generation: generation, 46 | Expiration: expiration, 47 | } 48 | 49 | // always assign a map of length zero if Bins is nil 50 | if r.Bins == nil { 51 | r.Bins = make(BinMap) 52 | } 53 | 54 | return r 55 | } 56 | 57 | // String implements the Stringer interface. 58 | // Returns string representation of record. 59 | func (rc *Record) String() string { 60 | return fmt.Sprintf("%s %v", rc.Key, rc.Bins) 61 | } 62 | 63 | // udfError returns the the error string returned by a UDF execute in a batch. 64 | // Returns nil if an error did not occur. 65 | func (rc *Record) udfError() string { 66 | return rc.Bins["FAILURE"].(string) 67 | } 68 | 69 | // udfResult returns the value returned by a UDF execute in a batch. 70 | // The result may be nil. 71 | func (rc *Record) udfResult() BinMap { 72 | return BinMap(rc.Bins["SUCCESS"].(map[string]interface{})) 73 | } 74 | -------------------------------------------------------------------------------- /record_exists_action.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // RecordExistsAction determines how to handle writes when 18 | // the record already exists. 19 | type RecordExistsAction int 20 | 21 | const ( 22 | 23 | // UPDATE means: Create or update record. 24 | // Merge write command bins with existing bins. 25 | UPDATE RecordExistsAction = iota 26 | 27 | // UPDATE_ONLY means: Update record only. Fail if record does not exist. 28 | // Merge write command bins with existing bins. 29 | UPDATE_ONLY 30 | 31 | // REPLACE means: Create or replace record. 32 | // Delete existing bins not referenced by write command bins. 33 | // Supported by Aerospike 2 server versions >= 2.7.5 and 34 | // Aerospike 3 server versions >= 3.1.6 and later. 35 | REPLACE 36 | 37 | // REPLACE_ONLY means: Replace record only. Fail if record does not exist. 38 | // Delete existing bins not referenced by write command bins. 39 | // Supported by Aerospike 2 server versions >= 2.7.5 and 40 | // Aerospike 3 server versions >= 3.1.6 and later. 41 | REPLACE_ONLY 42 | 43 | // CREATE_ONLY means: Create only. Fail if record exists. 44 | CREATE_ONLY 45 | ) 46 | -------------------------------------------------------------------------------- /recordset_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "time" 19 | 20 | "github.com/aerospike/aerospike-client-go/v8/types" 21 | 22 | gg "github.com/onsi/ginkgo/v2" 23 | gm "github.com/onsi/gomega" 24 | ) 25 | 26 | // ALL tests are isolated by SetName and Key, which are 50 random characters 27 | var _ = gg.Describe("Recordset test", func() { 28 | 29 | gg.It("must avoid panic on sendError", func() { 30 | rs := newRecordset(100, 1) 31 | 32 | rs.sendError(newError(types.PARAMETER_ERROR, "Error")) 33 | rs.wgGoroutines.Done() 34 | rs.Close() 35 | rs.sendError(newError(types.PARAMETER_ERROR, "Error")) 36 | 37 | timeout := time.After(time.Second) 38 | select { 39 | case res := <-rs.Results(): 40 | gm.Expect(res).ToNot(gm.BeNil()) 41 | case <-timeout: 42 | panic("wrong result!") 43 | } 44 | }) 45 | 46 | }) 47 | -------------------------------------------------------------------------------- /replica_policy.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2022 Aerospike, Inc. 3 | * 4 | * Portions may be licensed to Aerospike, Inc. under one or more contributor 5 | * license agreements. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 8 | * use this file except in compliance with the License. You may obtain a copy of 9 | * the License at http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations under 15 | * the License. 16 | */ 17 | 18 | package aerospike 19 | 20 | // ReplicaPolicy defines type of node partition targeted by read commands. 21 | type ReplicaPolicy int 22 | 23 | const ( 24 | // MASTER reads from node containing key's master partition. 25 | // This is the default behavior. 26 | MASTER ReplicaPolicy = iota 27 | 28 | // MASTER_PROLES Distributes reads across nodes containing key's master and replicated partitions 29 | // in round-robin fashion. 30 | MASTER_PROLES 31 | 32 | // RANDOM Distribute reads across all nodes in cluster in round-robin fashion. 33 | // This option is useful when the replication factor equals the number 34 | // of nodes in the cluster and the overhead of requesting proles is not desired. 35 | RANDOM 36 | 37 | // SEQUENCE Tries node containing master partition first. 38 | // If connection fails, all commands try nodes containing replicated partitions. 39 | // If socketTimeout is reached, reads also try nodes containing replicated partitions, 40 | // but writes remain on master node. 41 | SEQUENCE 42 | 43 | // PREFER_RACK Tries nodes on the same rack first. 44 | // 45 | // This option requires ClientPolicy.Rackaware to be enabled 46 | // in order to function properly. 47 | PREFER_RACK 48 | ) 49 | -------------------------------------------------------------------------------- /role.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Portions may be licensed to Aerospike, Inc. under one or more contributor 4 | // license agreements. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy of 8 | // the License at http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | // License for the specific language governing permissions and limitations under 14 | // the License. 15 | 16 | package aerospike 17 | 18 | // Role allows granular access to database entities for users. 19 | type Role struct { 20 | // Name is role name 21 | Name string 22 | 23 | // Privilege is the list of assigned privileges 24 | Privileges []Privilege 25 | 26 | // While is the list of allowable IP addresses 27 | Whitelist []string 28 | 29 | // ReadQuota is the maximum reads per second limit for the role 30 | ReadQuota uint32 31 | 32 | // WriteQuota is the maximum writes per second limit for the role 33 | WriteQuota uint32 34 | } 35 | 36 | // Pre-defined user roles. 37 | const ( 38 | // UserAdmin allows to manages users and their roles. 39 | UserAdmin privilegeCode = "user-admin" 40 | 41 | // SysAdmin allows to manage indexes, user defined functions and server configuration. 42 | SysAdmin privilegeCode = "sys-admin" 43 | 44 | // DataAdmin allows to manage indicies and user defined functions. 45 | DataAdmin privilegeCode = "data-admin" 46 | 47 | // UDFAdmin allows to manage user defined functions. 48 | UDFAdmin privilegeCode = "udf-admin" 49 | 50 | // SIndexAdmin allows to manage indicies. 51 | SIndexAdmin privilegeCode = "sindex-admin" 52 | 53 | // ReadWriteUDF allows read, write and UDF transactions with the database. 54 | ReadWriteUDF privilegeCode = "read-write-udf" 55 | 56 | // ReadWrite allows read and write transactions with the database. 57 | ReadWrite privilegeCode = "read-write" 58 | 59 | // Read allows read transactions with the database. 60 | Read privilegeCode = "read" 61 | 62 | // Write allows write transactions with the database. 63 | Write privilegeCode = "write" 64 | 65 | // Truncate allow issuing truncate commands. 66 | Truncate privilegeCode = "truncate" 67 | ) 68 | -------------------------------------------------------------------------------- /scan_executor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "time" 19 | ) 20 | 21 | func (clnt *Client) scanPartitions(policy *ScanPolicy, tracker *partitionTracker, namespace string, setName string, recordset *Recordset, binNames ...string) { 22 | defer recordset.signalEnd() 23 | 24 | // for exponential backoff 25 | interval := policy.SleepBetweenRetries 26 | 27 | var errs Error 28 | for { 29 | list, err := tracker.assignPartitionsToNodes(clnt.Cluster(), namespace) 30 | if err != nil { 31 | errs = chainErrors(err, errs) 32 | recordset.sendError(errs) 33 | tracker.partitionError() 34 | return 35 | } 36 | 37 | maxConcurrentNodes := policy.MaxConcurrentNodes 38 | if maxConcurrentNodes <= 0 { 39 | maxConcurrentNodes = len(list) 40 | } 41 | 42 | if recordset.IsActive() { 43 | weg := newWeightedErrGroup(maxConcurrentNodes) 44 | for _, nodePartition := range list { 45 | cmd := newScanPartitionCommand(policy, tracker, nodePartition, namespace, setName, binNames, recordset) 46 | weg.execute(cmd) 47 | } 48 | errs = chainErrors(weg.wait(), errs) 49 | } 50 | 51 | if done, err := tracker.isClusterComplete(clnt.Cluster(), &policy.BasePolicy); !recordset.IsActive() || done || err != nil { 52 | errs = chainErrors(err, errs) 53 | // Scan is complete. 54 | if errs != nil { 55 | tracker.partitionError() 56 | recordset.sendError(errs) 57 | } 58 | return 59 | } 60 | 61 | if policy.SleepBetweenRetries > 0 { 62 | // Sleep before trying again. 63 | time.Sleep(interval) 64 | 65 | if policy.SleepMultiplier > 1 { 66 | interval = time.Duration(float64(interval) * policy.SleepMultiplier) 67 | } 68 | } 69 | 70 | recordset.resetTaskID() 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /scan_partition_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "github.com/aerospike/aerospike-client-go/v8/types" 18 | 19 | type scanPartitionCommand struct { 20 | baseMultiCommand 21 | 22 | policy *ScanPolicy 23 | namespace string 24 | setName string 25 | binNames []string 26 | } 27 | 28 | func newScanPartitionCommand( 29 | policy *ScanPolicy, 30 | tracker *partitionTracker, 31 | nodePartitions *nodePartitions, 32 | namespace string, 33 | setName string, 34 | binNames []string, 35 | recordset *Recordset, 36 | ) *scanPartitionCommand { 37 | cmd := &scanPartitionCommand{ 38 | baseMultiCommand: *newCorrectStreamingMultiCommand(recordset, namespace), 39 | policy: policy, 40 | namespace: namespace, 41 | setName: setName, 42 | binNames: binNames, 43 | } 44 | cmd.rawCDT = policy.RawCDT 45 | cmd.terminationErrorType = types.SCAN_TERMINATED 46 | cmd.tracker = tracker 47 | cmd.nodePartitions = nodePartitions 48 | cmd.node = nodePartitions.node 49 | 50 | return cmd 51 | } 52 | 53 | func (cmd *scanPartitionCommand) getPolicy(ifc command) Policy { 54 | return cmd.policy 55 | } 56 | 57 | func (cmd *scanPartitionCommand) writeBuffer(ifc command) Error { 58 | return cmd.setScan(cmd.policy, &cmd.namespace, &cmd.setName, cmd.binNames, cmd.recordset.taskID, cmd.nodePartitions) 59 | } 60 | 61 | func (cmd *scanPartitionCommand) shouldRetry(e Error) bool { 62 | return cmd.tracker != nil && cmd.tracker.shouldRetry(cmd.nodePartitions, e) 63 | } 64 | 65 | func (cmd *scanPartitionCommand) commandType() commandType { 66 | return ttScan 67 | } 68 | 69 | func (cmd *scanPartitionCommand) Execute() Error { 70 | err := cmd.execute(cmd) 71 | if err != nil { 72 | // signal to the executor that no retries should be attempted 73 | // don't send error unless no retries are planned 74 | if !cmd.shouldRetry(err) { 75 | cmd.recordset.sendError(err) 76 | } 77 | } 78 | return err 79 | } 80 | -------------------------------------------------------------------------------- /scan_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // ScanPolicy encapsulates parameters used in scan operations. 18 | // 19 | // Inherited Policy fields Policy.Txn are ignored in scan commands. 20 | type ScanPolicy struct { 21 | MultiPolicy 22 | } 23 | 24 | // NewScanPolicy creates a new ScanPolicy instance with default values. 25 | // Set MaxRetries for scans on server versions >= 4.9. All other 26 | // scans are not retried. 27 | // 28 | // The latest servers support retries on individual data partitions. 29 | // This feature is useful when a cluster is migrating and partition(s) 30 | // are missed or incomplete on the first scan attempt. 31 | // 32 | // If the first scan attempt misses 2 of 4096 partitions, then only 33 | // those 2 partitions are retried in the next scan attempt from the 34 | // last key digest received for each respective partition. A higher 35 | // default MaxRetries is used because it's wasteful to invalidate 36 | // all scan results because a single partition was missed. 37 | func NewScanPolicy() *ScanPolicy { 38 | mp := *NewMultiPolicy() 39 | mp.TotalTimeout = 0 40 | 41 | return &ScanPolicy{ 42 | MultiPolicy: mp, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /single_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | Buffer "github.com/aerospike/aerospike-client-go/v8/utils/buffer" 19 | ) 20 | 21 | type singleCommand struct { 22 | baseCommand 23 | 24 | cluster *Cluster 25 | key *Key 26 | partition *Partition 27 | } 28 | 29 | func newSingleCommand(cluster *Cluster, key *Key, partition *Partition) singleCommand { 30 | return singleCommand{ 31 | baseCommand: baseCommand{}, 32 | cluster: cluster, 33 | key: key, 34 | partition: partition, 35 | } 36 | } 37 | 38 | func (cmd *singleCommand) getConnection(policy Policy) (*Connection, Error) { 39 | return cmd.node.getConnectionWithHint(policy.GetBasePolicy().TotalTimeout, policy.GetBasePolicy().SocketTimeout, cmd.key.digest[0]) 40 | } 41 | 42 | func (cmd *singleCommand) putConnection(conn *Connection) { 43 | cmd.node.putConnectionWithHint(conn, cmd.key.digest[0]) 44 | } 45 | 46 | func (cmd *singleCommand) emptySocket(conn *Connection) Error { 47 | // There should not be any more bytes. 48 | // Empty the socket to be safe. 49 | sz := Buffer.BytesToInt64(cmd.dataBuffer, 0) 50 | headerLength := cmd.dataBuffer[8] 51 | receiveSize := int(sz&0xFFFFFFFFFFFF) - int(headerLength) 52 | 53 | // Read remaining message bytes. 54 | if receiveSize > 0 { 55 | if err := cmd.sizeBufferSz(receiveSize, false); err != nil { 56 | return err 57 | } 58 | if _, err := conn.Read(cmd.dataBuffer, receiveSize); err != nil { 59 | return err 60 | } 61 | } 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /task.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "time" 19 | 20 | "github.com/aerospike/aerospike-client-go/v8/internal/atomic" 21 | "github.com/aerospike/aerospike-client-go/v8/types" 22 | ) 23 | 24 | // Task interface defines methods for asynchronous tasks. 25 | type Task interface { 26 | IsDone() (bool, Error) 27 | 28 | onComplete(ifc Task) chan Error 29 | OnComplete() chan Error 30 | } 31 | 32 | // baseTask is used to poll for server task completion. 33 | type baseTask struct { 34 | retries atomic.Int 35 | cluster *Cluster 36 | } 37 | 38 | // newTask initializes task with fields needed to query server nodes. 39 | func newTask(cluster *Cluster) *baseTask { 40 | return &baseTask{ 41 | cluster: cluster, 42 | } 43 | } 44 | 45 | // Wait for asynchronous task to complete using default sleep interval. 46 | func (btsk *baseTask) onComplete(ifc Task) chan Error { 47 | ch := make(chan Error, 1) 48 | 49 | // goroutine will loop every until IsDone() returns true or error 50 | go func() { 51 | // always close the channel on return 52 | defer close(ch) 53 | 54 | var interval = 100 * time.Millisecond 55 | 56 | for { 57 | time.Sleep(interval) 58 | 59 | done, err := ifc.IsDone() 60 | // Every 5 failed retries increase the interval 61 | if btsk.retries.IncrementAndGet()%5 == 0 { 62 | interval *= 2 63 | 64 | if interval > 5*time.Second { 65 | interval = 5 * time.Second 66 | } 67 | } 68 | if err != nil { 69 | if err.Matches(types.TIMEOUT) { 70 | err.markInDoubt(true) 71 | } 72 | ch <- err 73 | return 74 | } else if done { 75 | ch <- nil 76 | return 77 | } 78 | } // for 79 | }() 80 | 81 | return ch 82 | } 83 | -------------------------------------------------------------------------------- /task_drop_index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // DropIndexTask is used to poll for long running create index completion. 18 | type DropIndexTask struct { 19 | *baseTask 20 | 21 | namespace string 22 | indexName string 23 | } 24 | 25 | // NewDropIndexTask initializes a task with fields needed to query server nodes. 26 | func NewDropIndexTask(cluster *Cluster, namespace string, indexName string) *DropIndexTask { 27 | return &DropIndexTask{ 28 | baseTask: newTask(cluster), 29 | namespace: namespace, 30 | indexName: indexName, 31 | } 32 | } 33 | 34 | // IsDone queries all nodes for task completion status. 35 | func (tski *DropIndexTask) IsDone() (bool, Error) { 36 | command := "sindex-exists:ns=" + tski.namespace + ";indexname=" + tski.indexName 37 | nodes := tski.cluster.GetNodes() 38 | complete := false 39 | 40 | for _, node := range nodes { 41 | responseMap, err := node.requestInfoWithRetry(&tski.cluster.infoPolicy, 5, command) 42 | if err != nil { 43 | return false, err 44 | } 45 | 46 | for _, response := range responseMap { 47 | if response == "false" { 48 | complete = true 49 | continue 50 | } 51 | 52 | return false, nil 53 | } 54 | } 55 | return complete, nil 56 | } 57 | 58 | // OnComplete returns a channel that will be closed as soon as the task is finished. 59 | // If an error is encountered during operation, an error will be sent on the channel. 60 | func (tski *DropIndexTask) OnComplete() chan Error { 61 | return tski.onComplete(tski) 62 | } 63 | -------------------------------------------------------------------------------- /task_index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "regexp" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // IndexTask is used to poll for long running create index completion. 24 | type IndexTask struct { 25 | *baseTask 26 | 27 | namespace string 28 | indexName string 29 | } 30 | 31 | // NewIndexTask initializes a task with fields needed to query server nodes. 32 | func NewIndexTask(cluster *Cluster, namespace string, indexName string) *IndexTask { 33 | return &IndexTask{ 34 | baseTask: newTask(cluster), 35 | namespace: namespace, 36 | indexName: indexName, 37 | } 38 | } 39 | 40 | // IsDone queries all nodes for task completion status. 41 | func (tski *IndexTask) IsDone() (bool, Error) { 42 | command := "sindex/" + tski.namespace + "/" + tski.indexName 43 | nodes := tski.cluster.GetNodes() 44 | complete := false 45 | 46 | r := regexp.MustCompile(`\.*load_pct=(\d+)\.*`) 47 | 48 | for _, node := range nodes { 49 | responseMap, err := node.requestInfoWithRetry(&tski.cluster.infoPolicy, 5, command) 50 | if err != nil { 51 | return false, err 52 | } 53 | 54 | for _, response := range responseMap { 55 | find := "load_pct=" 56 | index := strings.Index(response, find) 57 | 58 | if index < 0 { 59 | if tski.retries.Get() > 20 { 60 | complete = true 61 | } 62 | continue 63 | } 64 | 65 | matchRes := r.FindStringSubmatch(response) 66 | // we know it exists and is a valid number 67 | pct, _ := strconv.Atoi(matchRes[1]) 68 | 69 | if pct >= 0 && pct < 100 { 70 | return false, nil 71 | } 72 | complete = true 73 | } 74 | } 75 | return complete, nil 76 | } 77 | 78 | // OnComplete returns a channel that will be closed as soon as the task is finished. 79 | // If an error is encountered during operation, an error will be sent on the channel. 80 | func (tski *IndexTask) OnComplete() chan Error { 81 | return tski.onComplete(tski) 82 | } 83 | -------------------------------------------------------------------------------- /task_register.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "strings" 19 | ) 20 | 21 | // RegisterTask is used to poll for UDF registration completion. 22 | type RegisterTask struct { 23 | *baseTask 24 | 25 | packageName string 26 | } 27 | 28 | // NewRegisterTask initializes a RegisterTask with fields needed to query server nodes. 29 | func NewRegisterTask(cluster *Cluster, packageName string) *RegisterTask { 30 | return &RegisterTask{ 31 | baseTask: newTask(cluster), 32 | packageName: packageName, 33 | } 34 | } 35 | 36 | // IsDone will query all nodes for task completion status. 37 | func (tskr *RegisterTask) IsDone() (bool, Error) { 38 | command := "udf-list" 39 | nodes := tskr.cluster.GetNodes() 40 | done := false 41 | 42 | for _, node := range nodes { 43 | responseMap, err := node.requestInfoWithRetry(&tskr.cluster.infoPolicy, 5, command) 44 | if err != nil { 45 | return false, err 46 | } 47 | 48 | for _, response := range responseMap { 49 | find := "filename=" + tskr.packageName 50 | index := strings.Index(response, find) 51 | 52 | if index < 0 { 53 | return false, nil 54 | } 55 | done = true 56 | } 57 | } 58 | return done, nil 59 | } 60 | 61 | // OnComplete returns a channel that will be closed as soon as the task is finished. 62 | // If an error is encountered during operation, an error will be sent on the channel. 63 | func (tskr *RegisterTask) OnComplete() chan Error { 64 | return tskr.onComplete(tskr) 65 | } 66 | -------------------------------------------------------------------------------- /task_remove.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "strings" 19 | ) 20 | 21 | // RemoveTask is used to poll for UDF registration completion. 22 | type RemoveTask struct { 23 | *baseTask 24 | 25 | packageName string 26 | } 27 | 28 | // NewRemoveTask initializes a RemoveTask with fields needed to query server nodes. 29 | func NewRemoveTask(cluster *Cluster, packageName string) *RemoveTask { 30 | return &RemoveTask{ 31 | baseTask: newTask(cluster), 32 | packageName: packageName, 33 | } 34 | } 35 | 36 | // IsDone will query all nodes for task completion status. 37 | func (tskr *RemoveTask) IsDone() (bool, Error) { 38 | command := "udf-list" 39 | nodes := tskr.cluster.GetNodes() 40 | done := false 41 | 42 | find := "filename=" + tskr.packageName 43 | for _, node := range nodes { 44 | responseMap, err := node.requestInfoWithRetry(&tskr.cluster.infoPolicy, 5, command) 45 | if err != nil { 46 | return false, err 47 | } 48 | 49 | for _, response := range responseMap { 50 | index := strings.Index(response, find) 51 | 52 | if index >= 0 { 53 | return false, nil 54 | } 55 | done = true 56 | } 57 | } 58 | return done, nil 59 | } 60 | 61 | // OnComplete returns a channel that will be closed as soon as the task is finished. 62 | // If an error is encountered during operation, an error will be sent on the channel. 63 | func (tskr *RemoveTask) OnComplete() chan Error { 64 | return tskr.onComplete(tskr) 65 | } 66 | -------------------------------------------------------------------------------- /test/resources/average.lua: -------------------------------------------------------------------------------- 1 | function average(s, name) 2 | 3 | local function mapper(out, rec) 4 | out['sum'] = (out['sum'] or 0) + (rec[name] or 0) 5 | out['count'] = (out['count'] or 0) + 1 6 | return out 7 | end 8 | 9 | local function reducer(a, b) 10 | local out = map() 11 | 12 | out['sum'] = a['sum'] + b['sum'] 13 | out['count'] = a['count'] + b['count'] 14 | return out 15 | end 16 | 17 | return s : aggregate(map{sum = 0, count = 0}, mapper) : reduce(reducer) 18 | end 19 | -------------------------------------------------------------------------------- /test/resources/sum_single_bin.lua: -------------------------------------------------------------------------------- 1 | local function reducer(val1,val2) 2 | return val1 + val2 3 | end 4 | 5 | function sum_single_bin(stream,name) 6 | local function mapper(rec) 7 | return rec[name] 8 | end 9 | 10 | return stream : map(mapper) : reduce(reducer) 11 | end 12 | -------------------------------------------------------------------------------- /tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | // Copyright 2014-2022 Aerospike, Inc. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | // This package imports things required by build scripts, to force `go mod` to see them as dependencies 19 | package aerospike 20 | 21 | import ( 22 | _ "github.com/wadey/gocovmerge" 23 | ) 24 | -------------------------------------------------------------------------------- /tools/asinfo/asinfo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "log" 20 | "os" 21 | "strings" 22 | 23 | as "github.com/aerospike/aerospike-client-go/v8" 24 | ) 25 | 26 | var ( 27 | host = flag.String("h", "127.0.0.1", "host (default 127.0.0.1)") 28 | port = flag.Int("p", 3000, "port (default 3000)") 29 | value = flag.String("v", "", "(fetch single value - default all)") 30 | user = flag.String("U", "", "User.") 31 | password = flag.String("P", "", "Password.") 32 | 33 | clientPolicy *as.ClientPolicy 34 | ) 35 | 36 | func main() { 37 | flag.Parse() 38 | log.SetOutput(os.Stdout) 39 | log.SetFlags(0) 40 | 41 | clientPolicy = as.NewClientPolicy() 42 | if *user != "" { 43 | clientPolicy.User = *user 44 | clientPolicy.Password = *password 45 | } 46 | *value = strings.Trim(*value, " ") 47 | 48 | // connect to the host 49 | conn, err := as.NewConnection(clientPolicy, as.NewHost(*host, *port)) 50 | dieIfError(err) 51 | 52 | infoMap, err := conn.RequestInfo(*value) 53 | dieIfError(err) 54 | 55 | defer conn.Close() 56 | 57 | if len(infoMap) == 0 { 58 | log.Printf("Query successful, no information for -v \"%s\"\n\n", *value) 59 | return 60 | } 61 | 62 | outfmt := "%d : %s\n %s\n" 63 | cnt := 1 64 | for k, v := range infoMap { 65 | log.Printf(outfmt, cnt, k, v) 66 | cnt++ 67 | } 68 | } 69 | 70 | // dieIfError calls each callback in turn before printing the error via log.Fatalln. 71 | func dieIfError(err error, cleanup ...func()) { 72 | if err != nil { 73 | log.Println("Error:") 74 | for _, cb := range cleanup { 75 | cb() 76 | } 77 | log.Fatalln(err.Error()) 78 | } 79 | return 80 | } 81 | -------------------------------------------------------------------------------- /touch_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee touchCommand implements command interface 22 | var _ command = &touchCommand{} 23 | 24 | type touchCommand struct { 25 | baseWriteCommand 26 | } 27 | 28 | func newTouchCommand(cluster *Cluster, policy *WritePolicy, key *Key) (touchCommand, Error) { 29 | bwc, err := newBaseWriteCommand(cluster, policy, key) 30 | if err != nil { 31 | return touchCommand{}, err 32 | } 33 | 34 | newTouchCmd := touchCommand{ 35 | baseWriteCommand: bwc, 36 | } 37 | 38 | return newTouchCmd, nil 39 | } 40 | 41 | func (cmd *touchCommand) writeBuffer(ifc command) Error { 42 | return cmd.setTouch(cmd.policy, cmd.key) 43 | } 44 | 45 | func (cmd *touchCommand) parseResult(ifc command, conn *Connection) Error { 46 | resultCode, err := cmd.parseHeader() 47 | if err != nil { 48 | return newCustomNodeError(cmd.node, err.resultCode()) 49 | } 50 | 51 | switch resultCode { 52 | case types.OK: 53 | return nil 54 | case types.KEY_NOT_FOUND_ERROR: 55 | return ErrKeyNotFound.err() 56 | case types.FILTERED_OUT: 57 | return ErrFilteredOut.err() 58 | default: 59 | return newError(types.ResultCode(resultCode)) 60 | } 61 | } 62 | 63 | func (cmd *touchCommand) isRead() bool { 64 | return false 65 | } 66 | 67 | func (cmd *touchCommand) Execute() Error { 68 | return cmd.execute(cmd) 69 | } 70 | 71 | func (cmd *touchCommand) commandType() commandType { 72 | return ttPut 73 | } 74 | -------------------------------------------------------------------------------- /txn_add_keys_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee txnAddKeysCommand implements command interface 22 | var _ command = &txnAddKeysCommand{} 23 | 24 | type txnAddKeysCommand struct { 25 | baseWriteCommand 26 | 27 | args operateArgs 28 | txn *Txn 29 | } 30 | 31 | func newTxnAddKeysCommand( 32 | cluster *Cluster, 33 | key *Key, 34 | args operateArgs, 35 | txn *Txn, 36 | ) (txnAddKeysCommand, Error) { 37 | bwc, err := newBaseWriteCommand(cluster, args.writePolicy, key) 38 | if err != nil { 39 | return txnAddKeysCommand{}, err 40 | } 41 | 42 | newTxnAddKeysCmd := txnAddKeysCommand{ 43 | baseWriteCommand: bwc, 44 | args: args, 45 | txn: txn, 46 | } 47 | 48 | return newTxnAddKeysCmd, nil 49 | } 50 | 51 | func (cmd *txnAddKeysCommand) writeBuffer(ifc command) Error { 52 | return cmd.setTxnAddKeys(cmd.policy, cmd.key, cmd.args) 53 | } 54 | 55 | func (cmd *txnAddKeysCommand) parseResult(ifc command, conn *Connection) Error { 56 | rp, err := newRecordParser(&cmd.baseCommand) 57 | if err != nil { 58 | return err 59 | } 60 | rp.parseTranDeadline(cmd.txn) 61 | 62 | if rp.resultCode != types.OK { 63 | return newCustomNodeError(cmd.node, rp.resultCode) 64 | } 65 | 66 | return nil 67 | } 68 | 69 | func (cmd *txnAddKeysCommand) Execute() Error { 70 | return cmd.execute(cmd) 71 | } 72 | -------------------------------------------------------------------------------- /txn_close.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee txnCloseCommand implements command interface 22 | var _ command = &txnCloseCommand{} 23 | 24 | type txnCloseCommand struct { 25 | baseWriteCommand 26 | 27 | txn *Txn 28 | } 29 | 30 | func newTxnCloseCommand( 31 | cluster *Cluster, 32 | txn *Txn, 33 | writePolicy *WritePolicy, 34 | key *Key, 35 | ) (txnCloseCommand, Error) { 36 | bwc, err := newBaseWriteCommand(cluster, writePolicy, key) 37 | if err != nil { 38 | return txnCloseCommand{}, err 39 | } 40 | 41 | newTxnCloseCmd := txnCloseCommand{ 42 | baseWriteCommand: bwc, 43 | txn: txn, 44 | } 45 | 46 | return newTxnCloseCmd, nil 47 | } 48 | 49 | func (cmd *txnCloseCommand) writeBuffer(ifc command) Error { 50 | return cmd.setTxnClose(cmd.txn, cmd.key) 51 | } 52 | 53 | func (cmd *txnCloseCommand) parseResult(ifc command, conn *Connection) Error { 54 | resultCode, err := cmd.parseHeader() 55 | if err != nil { 56 | return newCustomNodeError(cmd.node, err.resultCode()) 57 | } 58 | 59 | if resultCode == 0 || resultCode == types.KEY_NOT_FOUND_ERROR { 60 | return nil 61 | } 62 | 63 | return newCustomNodeError(cmd.node, types.ResultCode(resultCode)) 64 | } 65 | 66 | func (cmd *txnCloseCommand) Execute() Error { 67 | return cmd.execute(cmd) 68 | } 69 | 70 | func (cmd *txnCloseCommand) onInDoubt() { 71 | return 72 | } 73 | -------------------------------------------------------------------------------- /txn_error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "github.com/aerospike/aerospike-client-go/v8/types" 18 | 19 | // TxnError implements Error interface for aerospike multi-record transaction specific errors. 20 | type TxnError struct { 21 | AerospikeError 22 | 23 | // Error status of the attempted commit. 24 | CommitError CommitError 25 | 26 | // Verify result for each read key in the Transaction. May be nil if failure occurred before verify. 27 | VerifyRecords []*BatchRecord 28 | 29 | // Roll forward/backward result for each write key in the Transaction. May be nil if failure occurred before 30 | // roll forward/backward. 31 | RollRecords []*BatchRecord 32 | } 33 | 34 | var _ error = &TxnError{} 35 | var _ Error = &TxnError{} 36 | 37 | func NewTxnCommitError(err CommitError, verifyRecords, rollRecords []*BatchRecord, cause Error) Error { 38 | if cause == nil { 39 | res := newError(types.TXN_FAILED, string(err)) 40 | return &TxnError{ 41 | AerospikeError: *(res.(*AerospikeError)), 42 | CommitError: err, 43 | VerifyRecords: verifyRecords, 44 | RollRecords: rollRecords, 45 | } 46 | } 47 | 48 | embed := newError(types.TXN_FAILED, string(err)).wrap(cause) 49 | return &TxnError{ 50 | AerospikeError: *(embed.(*AerospikeError)), 51 | CommitError: err, 52 | VerifyRecords: verifyRecords, 53 | RollRecords: rollRecords, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /txn_mark_roll_forward.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee txnMarkRollForwardCommand implements command interface 22 | var _ command = &txnMarkRollForwardCommand{} 23 | 24 | type txnMarkRollForwardCommand struct { 25 | baseWriteCommand 26 | } 27 | 28 | func newTxnMarkRollForwardCommand( 29 | cluster *Cluster, 30 | writePolicy *WritePolicy, 31 | key *Key, 32 | ) (txnMarkRollForwardCommand, Error) { 33 | bwc, err := newBaseWriteCommand(cluster, writePolicy, key) 34 | if err != nil { 35 | return txnMarkRollForwardCommand{}, err 36 | } 37 | 38 | newMarkRollForwardCmd := txnMarkRollForwardCommand{ 39 | baseWriteCommand: bwc, 40 | } 41 | 42 | return newMarkRollForwardCmd, nil 43 | } 44 | 45 | func (cmd *txnMarkRollForwardCommand) writeBuffer(ifc command) Error { 46 | return cmd.setTxnMarkRollForward(cmd.key) 47 | } 48 | 49 | func (cmd *txnMarkRollForwardCommand) parseResult(ifc command, conn *Connection) Error { 50 | resultCode, err := cmd.parseHeader() 51 | if err != nil { 52 | return newCustomNodeError(cmd.node, err.resultCode()) 53 | } 54 | 55 | if resultCode == 0 || resultCode == types.MRT_COMMITTED { 56 | return nil 57 | } 58 | 59 | return newCustomNodeError(cmd.node, types.ResultCode(resultCode)) 60 | } 61 | 62 | func (cmd *txnMarkRollForwardCommand) Execute() Error { 63 | return cmd.execute(cmd) 64 | } 65 | -------------------------------------------------------------------------------- /txn_roll_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "time" 18 | 19 | // Transaction policy fields used to batch roll forward/backward records on 20 | // commit or abort. Used a placeholder for now as there are no additional fields beyond BatchPolicy. 21 | type TxnRollPolicy struct { 22 | BatchPolicy 23 | } 24 | 25 | // NewTxnRollPolicy creates a new TxnRollPolicy instance with default values. 26 | func NewTxnRollPolicy() *TxnRollPolicy { 27 | mp := *NewBatchPolicy() 28 | mp.ReplicaPolicy = MASTER 29 | mp.MaxRetries = 5 30 | mp.SocketTimeout = 3 * time.Second 31 | mp.TotalTimeout = 10 * time.Second 32 | mp.SleepBetweenRetries = 1 * time.Second 33 | 34 | return &TxnRollPolicy{ 35 | BatchPolicy: mp, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /txn_verify_policy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import "time" 18 | 19 | // Transaction policy fields used to batch verify record versions on commit. 20 | // Used a placeholder for now as there are no additional fields beyond BatchPolicy. 21 | type TxnVerifyPolicy struct { 22 | BatchPolicy 23 | } 24 | 25 | // NewTxnRollPolicy creates a new TxnVerifyPolicy instance with default values. 26 | func NewTxnVerifyPolicy() *TxnVerifyPolicy { 27 | mp := *NewBatchPolicy() 28 | mp.ReadModeSC = ReadModeSCLinearize 29 | mp.ReplicaPolicy = MASTER 30 | mp.MaxRetries = 5 31 | mp.TotalTimeout = 10 * time.Millisecond 32 | mp.SleepBetweenRetries = 1 * time.Millisecond 33 | 34 | return &TxnVerifyPolicy{ 35 | BatchPolicy: mp, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /types/epoc.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "math" 5 | "time" 6 | ) 7 | 8 | const ( 9 | // CITRUSLEAF_EPOCH defines the citrusleaf epoc: Jan 01 2010 00:00:00 GMT 10 | CITRUSLEAF_EPOCH = 1262304000 11 | ) 12 | 13 | // TTL converts an Expiration time from citrusleaf epoc to TTL in seconds. 14 | func TTL(secsFromCitrusLeafEpoc uint32) uint32 { 15 | switch secsFromCitrusLeafEpoc { 16 | // don't convert magic values 17 | case 0: // when set to don't expire, this value is returned 18 | return math.MaxUint32 19 | default: 20 | // Record may not have expired on server, but delay or clock differences may 21 | // cause it to look expired on client. Floor at 1, not 0, to avoid old 22 | // "never expires" interpretation. 23 | now := time.Now().Unix() 24 | expiration := int64(CITRUSLEAF_EPOCH + secsFromCitrusLeafEpoc) 25 | if (expiration < 0 && now >= 0) || expiration > now { 26 | return uint32(expiration - now) 27 | } 28 | return 1 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /types/histogram/bench_histogram_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2024 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package histogram_test 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/aerospike/aerospike-client-go/v8/types/histogram" 21 | ) 22 | 23 | var ( 24 | _median int 25 | _medianu64 uint64 26 | ) 27 | 28 | func Benchmark_Histogram_Linear_Add(b *testing.B) { 29 | h := histogram.New[int](histogram.Linear, 5, 10) 30 | for i := 0; i < b.N; i++ { 31 | h.Add(i) 32 | } 33 | } 34 | 35 | func Benchmark_Histogram_Linear_Median(b *testing.B) { 36 | h := histogram.New[int](histogram.Linear, 50, 101) 37 | for i := 0; i < 10000; i++ { 38 | h.Add(i) 39 | } 40 | 41 | b.ResetTimer() 42 | for i := 0; i < b.N; i++ { 43 | _median = h.Median() 44 | } 45 | } 46 | 47 | func Benchmark_Histogram_Log_Add(b *testing.B) { 48 | h := histogram.NewExponential[int](2, 10) 49 | for i := 0; i < b.N; i++ { 50 | h.Add(i) 51 | } 52 | } 53 | 54 | func Benchmark_Histogram_Log_Median(b *testing.B) { 55 | h := histogram.NewExponential[int](2, 32) 56 | for i := 0; i < 100000; i++ { 57 | h.Add(i) 58 | } 59 | 60 | b.ResetTimer() 61 | for i := 0; i < b.N; i++ { 62 | _median = h.Median() 63 | } 64 | } 65 | 66 | func Benchmark_Histogram_Log2_Add(b *testing.B) { 67 | h := histogram.NewLog2(10) 68 | for i := 0; i < b.N; i++ { 69 | h.Add(uint64(i)) 70 | } 71 | } 72 | 73 | func Benchmark_Histogram_Log2_Median(b *testing.B) { 74 | h := histogram.NewLog2(32) 75 | for i := 0; i < 100000; i++ { 76 | h.Add(uint64(i)) 77 | } 78 | 79 | b.ResetTimer() 80 | for i := 0; i < b.N; i++ { 81 | _medianu64 = h.Median() 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /types/particle_type/particle_type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package particleType 16 | 17 | // Server particle types. Unsupported types are commented out. 18 | const ( 19 | //revive:disable 20 | NULL = 0 21 | INTEGER = 1 22 | FLOAT = 2 23 | STRING = 3 24 | BLOB = 4 25 | DIGEST = 6 26 | PHP_BLOB = 11 // Had to reintroduce to support the old PHP7 client 27 | BOOL = 17 28 | HLL = 18 29 | MAP = 19 30 | LIST = 20 31 | LDT = 21 32 | GEOJSON = 23 33 | //revive:enable 34 | ) 35 | -------------------------------------------------------------------------------- /types/pool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package types 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/internal/atomic" 19 | ) 20 | 21 | // Pool implements a general purpose fixed-size pool. 22 | type Pool struct { 23 | pool *atomic.Queue 24 | 25 | // New will create a new object 26 | New func(params ...interface{}) interface{} 27 | // IsUsable checks if the object polled from the pool is still fresh and usable 28 | IsUsable func(obj interface{}, params ...interface{}) bool 29 | // CanReturn checkes if the object is eligible to go back to the pool 30 | CanReturn func(obj interface{}) bool 31 | // Finalize will be called when an object is not eligible to go back to the pool. 32 | // Usable to close connections, file handles, ... 33 | Finalize func(obj interface{}) 34 | } 35 | 36 | // NewPool creates a new fixed size pool. 37 | func NewPool(poolSize int) *Pool { 38 | return &Pool{ 39 | pool: atomic.NewQueue(poolSize), 40 | } 41 | } 42 | 43 | // Get returns an element from the pool. 44 | // If the pool is empty, or the returned element is not usable, 45 | // nil or the result of the New function will be returned 46 | func (bp *Pool) Get(params ...interface{}) interface{} { 47 | res := bp.pool.Poll() 48 | if res == nil || (bp.IsUsable != nil && !bp.IsUsable(res, params...)) { 49 | // not usable, so finalize 50 | if res != nil && bp.Finalize != nil { 51 | bp.Finalize(res) 52 | } 53 | 54 | if bp.New != nil { 55 | res = bp.New(params...) 56 | } 57 | } 58 | 59 | return res 60 | } 61 | 62 | // Put will add the elem back to the pool, unless the pool is full. 63 | func (bp *Pool) Put(obj interface{}) { 64 | finalize := true 65 | if bp.CanReturn == nil || bp.CanReturn(obj) { 66 | finalize = !bp.pool.Offer(obj) 67 | } 68 | 69 | if finalize && bp.Finalize != nil { 70 | bp.Finalize(obj) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /types/pool/buffer_pool_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2021 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package pool 16 | 17 | import ( 18 | "math/rand" 19 | 20 | gg "github.com/onsi/ginkgo/v2" 21 | gm "github.com/onsi/gomega" 22 | ) 23 | 24 | var _ = gg.Describe("BufferPool Test", func() { 25 | 26 | const ( 27 | Min = 1 << 10 28 | Max = 1 << 16 29 | ) 30 | 31 | gg.Context("Any size Buffer Pool", func() { 32 | bp := NewTieredBufferPool(Min, Max) 33 | check := func(sz int) { 34 | buf := bp.Get(sz) 35 | 36 | gm.Expect(len(buf)).To(gm.BeNumerically(">=", sz)) 37 | if sz <= Max { 38 | if powerOf2(sz) { 39 | gm.Expect(len(buf)).To(gm.BeNumerically("==", 1<<(fastLog2(uint64(sz))))) 40 | gm.Expect(cap(buf)).To(gm.BeNumerically("==", 1<<(fastLog2(uint64(sz))))) 41 | } else { 42 | gm.Expect(len(buf)).To(gm.BeNumerically("==", 1<<(fastLog2(uint64(sz))+1))) 43 | gm.Expect(cap(buf)).To(gm.BeNumerically("==", 1<<(fastLog2(uint64(sz))+1))) 44 | } 45 | } else { 46 | gm.Expect(len(buf)).To(gm.BeNumerically("==", sz)) 47 | } 48 | bp.Put(buf) 49 | } 50 | 51 | gg.It("should return a buffer with correct size", func() { 52 | bp = NewTieredBufferPool(Min, Max) 53 | 54 | for i := 1; i < 24; i++ { 55 | check(1<> 17) ^ (s0 >> 26)) 44 | res := r.src[1] + s0 45 | return res 46 | } 47 | 48 | // Read will fill the argument slice with random bytes. 49 | // Implements the Reader interface. 50 | func (r *Xor128Rand) Read(p []byte) (n int, err error) { 51 | l := len(p) / 8 52 | for i := 0; i < l; i += 8 { 53 | binary.PutUvarint(p[i:], r.Uint64()) 54 | } 55 | return len(p), nil 56 | } 57 | -------------------------------------------------------------------------------- /types/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package types 16 | -------------------------------------------------------------------------------- /types/types_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package types_test 16 | 17 | import ( 18 | "testing" 19 | 20 | gg "github.com/onsi/ginkgo/v2" 21 | gm "github.com/onsi/gomega" 22 | ) 23 | 24 | func TestTypes(t *testing.T) { 25 | gm.RegisterFailHandler(gg.Fail) 26 | gg.RunSpecs(t, "Aerospike Client Library Types Suite") 27 | } 28 | -------------------------------------------------------------------------------- /udf.go: -------------------------------------------------------------------------------- 1 | package aerospike 2 | 3 | // UDF carries information about UDFs on the server 4 | type UDF struct { 5 | // Filename of the UDF 6 | Filename string 7 | // Hash digest of the UDF 8 | Hash string 9 | // Language of UDF 10 | Language Language 11 | } 12 | -------------------------------------------------------------------------------- /user_roles.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Portions may be licensed to Aerospike, Inc. under one or more contributor 4 | // license agreements. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not 7 | // use this file except in compliance with the License. You may obtain a copy of 8 | // the License at http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | // License for the specific language governing permissions and limitations under 14 | // the License. 15 | 16 | package aerospike 17 | 18 | // UserRoles contains information about a user. 19 | type UserRoles struct { 20 | // User name. 21 | User string 22 | 23 | // Roles is a list of assigned roles. 24 | Roles []string 25 | 26 | // ReadInfo is the list of read statistics. List may be nil. 27 | // Current statistics by offset are: 28 | // 29 | // 0: read quota in records per second 30 | // 1: single record read command rate (TPS) 31 | // 2: read scan/query record per second rate (RPS) 32 | // 3: number of limitless read scans/queries 33 | // 34 | // Future server releases may add additional statistics. 35 | ReadInfo []int 36 | 37 | // WriteInfo is the list of write statistics. List may be nil. 38 | // Current statistics by offset are: 39 | // 40 | // 0: write quota in records per second 41 | // 1: single record write command rate (TPS) 42 | // 2: write scan/query record per second rate (RPS) 43 | // 3: number of limitless write scans/queries 44 | // 45 | // Future server releases may add additional statistics. 46 | WriteInfo []int 47 | 48 | // ConnsInUse is the number of currently open connections for the user 49 | ConnsInUse int 50 | } 51 | -------------------------------------------------------------------------------- /value_helpers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | // MapIter allows to define general maps of your own type to be used in the Go client 18 | // without the use of reflection. 19 | // function PackMap should be exactly Like the following (Do not change, just copy/paste and adapt PackXXX methods): 20 | // 21 | // func (cm *CustomMap) PackMap(buf aerospike.BufferEx) (int, error) { 22 | // size := 0 23 | // for k, v := range cm { 24 | // n, err := PackXXX(buf, k) 25 | // size += n 26 | // if err != nil { 27 | // return size, err 28 | // } 29 | // 30 | // n, err = PackXXX(buf, v) 31 | // size += n 32 | // if err != nil { 33 | // return size, err 34 | // } 35 | // } 36 | // return size, nil 37 | // } 38 | type MapIter interface { 39 | PackMap(buf BufferEx) (int, error) 40 | Len() int 41 | } 42 | 43 | // ListIter allows to define general maps of your own type to be used in the Go client 44 | // without the use of reflection. 45 | // function PackList should be exactly Like the following (Do not change, just copy/paste and adapt PackXXX methods): 46 | // 47 | // func (cs *CustomSlice) PackList(buf aerospike.BufferEx) (int, error) { 48 | // size := 0 49 | // for _, elem := range cs { 50 | // n, err := PackXXX(buf, elem) 51 | // size += n 52 | // if err != nil { 53 | // return size, err 54 | // } 55 | // } 56 | // return size, nil 57 | // } 58 | type ListIter interface { 59 | PackList(buf BufferEx) (int, error) 60 | Len() int 61 | } 62 | -------------------------------------------------------------------------------- /value_reflect.go: -------------------------------------------------------------------------------- 1 | //go:build !as_performance 2 | 3 | // Copyright 2014-2022 Aerospike, Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | package aerospike 18 | 19 | import ( 20 | "reflect" 21 | ) 22 | 23 | func init() { 24 | newValueReflect = concreteNewValueReflect 25 | } 26 | 27 | // if the returned value is nil, the caller will panic 28 | func concreteNewValueReflect(v interface{}) Value { 29 | // check for array and map 30 | rv := reflect.ValueOf(v) 31 | switch rv.Kind() { 32 | case reflect.Array, reflect.Slice: 33 | l := rv.Len() 34 | arr := make([]interface{}, l) 35 | for i := 0; i < l; i++ { 36 | arr[i] = rv.Index(i).Interface() 37 | } 38 | 39 | return NewListValue(arr) 40 | case reflect.Map: 41 | l := rv.Len() 42 | amap := make(map[interface{}]interface{}, l) 43 | for _, i := range rv.MapKeys() { 44 | amap[i.Interface()] = rv.MapIndex(i).Interface() 45 | } 46 | 47 | return NewMapValue(amap) 48 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 49 | return NewLongValue(reflect.ValueOf(v).Int()) 50 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: 51 | return NewLongValue(int64(reflect.ValueOf(v).Uint())) 52 | case reflect.String: 53 | return NewStringValue(rv.String()) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /werrgroup.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "context" 19 | "sync" 20 | 21 | "golang.org/x/sync/semaphore" 22 | 23 | "github.com/aerospike/aerospike-client-go/v8/logger" 24 | ) 25 | 26 | type werrGroup struct { 27 | sem *semaphore.Weighted 28 | ctx context.Context 29 | wg sync.WaitGroup 30 | el sync.Mutex 31 | errs Error 32 | 33 | // function to defer; used for recordset signals 34 | f func() 35 | } 36 | 37 | func newWeightedErrGroup(maxConcurrency int) *werrGroup { 38 | if maxConcurrency <= 0 { 39 | maxConcurrency = 1 40 | } 41 | 42 | return &werrGroup{ 43 | sem: semaphore.NewWeighted(int64(maxConcurrency)), 44 | ctx: context.Background(), 45 | } 46 | } 47 | 48 | func (weg *werrGroup) execute(cmd command) { 49 | weg.wg.Add(1) 50 | 51 | if err := weg.sem.Acquire(weg.ctx, 1); err != nil { 52 | logger.Logger.Error("Constraint Semaphore failed: %s", err.Error()) 53 | } 54 | 55 | go func() { 56 | defer weg.sem.Release(1) 57 | defer weg.wg.Done() 58 | if weg.f != nil { 59 | defer weg.f() 60 | } 61 | 62 | if err := cmd.Execute(); err != nil { 63 | weg.el.Lock() 64 | weg.errs = chainErrors(err, weg.errs) 65 | weg.el.Unlock() 66 | } 67 | }() 68 | } 69 | 70 | func (weg *werrGroup) wait() Error { 71 | weg.wg.Wait() 72 | return weg.errs 73 | } 74 | -------------------------------------------------------------------------------- /write_command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014-2022 Aerospike, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package aerospike 16 | 17 | import ( 18 | "github.com/aerospike/aerospike-client-go/v8/types" 19 | ) 20 | 21 | // guarantee writeCommand implements command interface 22 | var _ command = &writeCommand{} 23 | 24 | type writeCommand struct { 25 | baseWriteCommand 26 | 27 | bins []*Bin 28 | binMap BinMap 29 | operation OperationType 30 | } 31 | 32 | func newWriteCommand( 33 | cluster *Cluster, 34 | policy *WritePolicy, 35 | key *Key, 36 | bins []*Bin, 37 | binMap BinMap, 38 | operation OperationType, 39 | ) (writeCommand, Error) { 40 | bwc, err := newBaseWriteCommand(cluster, policy, key) 41 | if err != nil { 42 | return writeCommand{}, err 43 | } 44 | 45 | newWriteCmd := writeCommand{ 46 | baseWriteCommand: bwc, 47 | bins: bins, 48 | binMap: binMap, 49 | operation: operation, 50 | } 51 | 52 | return newWriteCmd, nil 53 | } 54 | 55 | func (cmd *writeCommand) writeBuffer(ifc command) Error { 56 | return cmd.setWrite(cmd.policy, cmd.operation, cmd.key, cmd.bins, cmd.binMap) 57 | } 58 | 59 | func (cmd *writeCommand) parseResult(ifc command, conn *Connection) Error { 60 | resultCode, err := cmd.parseHeader() 61 | if err != nil { 62 | return newCustomNodeError(cmd.node, err.resultCode()) 63 | } 64 | 65 | if resultCode != types.OK { 66 | if resultCode == types.KEY_NOT_FOUND_ERROR { 67 | return ErrKeyNotFound.err() 68 | } else if resultCode == types.FILTERED_OUT { 69 | return ErrFilteredOut.err() 70 | } 71 | 72 | return newCustomNodeError(cmd.node, types.ResultCode(resultCode)) 73 | } 74 | 75 | return nil 76 | } 77 | 78 | func (cmd *writeCommand) Execute() Error { 79 | return cmd.execute(cmd) 80 | } 81 | --------------------------------------------------------------------------------