aerospike 5.11.0 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +31 -35
  2. package/binding.gyp +2 -1
  3. package/lib/binding/node-v108-darwin-arm64/aerospike.node +0 -0
  4. package/lib/binding/node-v108-darwin-x64/aerospike.node +0 -0
  5. package/lib/binding/node-v108-win32-x64/aerospike-core-client/aerospik.95E228AA.tlog/CustomBuild.command.1.tlog +3 -0
  6. package/lib/binding/node-v108-win32-x64/aerospike-core-client/aerospik.95E228AA.tlog/CustomBuild.read.1.tlog +1 -0
  7. package/lib/binding/node-v108-win32-x64/aerospike-core-client/aerospik.95E228AA.tlog/CustomBuild.write.1.tlog +3 -0
  8. package/lib/binding/node-v108-win32-x64/aerospike-core-client/aerospik.95E228AA.tlog/aerospike-core-client.lastbuildstate +2 -0
  9. package/lib/binding/node-v108-win32-x64/aerospike-core-client/aerospik.95E228AA.tlog/unsuccessfulbuild +0 -0
  10. package/lib/binding/node-v108-win32-x64/aerospike.dll +0 -0
  11. package/lib/binding/node-v108-win32-x64/aerospike.node +0 -0
  12. package/lib/binding/node-v108-win32-x64/event_core.dll +0 -0
  13. package/lib/binding/node-v108-win32-x64/getopt.dll +0 -0
  14. package/lib/binding/node-v108-win32-x64/libeay32.dll +0 -0
  15. package/lib/binding/node-v108-win32-x64/pthreadVC2.dll +0 -0
  16. package/lib/binding/node-v108-win32-x64/ssleay32.dll +0 -0
  17. package/lib/binding/node-v108-win32-x64/zlib.dll +0 -0
  18. package/lib/binding/node-v115-darwin-arm64/aerospike.node +0 -0
  19. package/lib/binding/node-v115-darwin-x64/aerospike.node +0 -0
  20. package/lib/binding/node-v115-win32-x64/aerospike.dll +0 -0
  21. package/lib/binding/node-v115-win32-x64/aerospike.node +0 -0
  22. package/lib/binding/node-v115-win32-x64/event_core.dll +0 -0
  23. package/lib/binding/node-v115-win32-x64/getopt.dll +0 -0
  24. package/lib/binding/node-v115-win32-x64/libeay32.dll +0 -0
  25. package/lib/binding/node-v115-win32-x64/pthreadVC2.dll +0 -0
  26. package/lib/binding/node-v115-win32-x64/ssleay32.dll +0 -0
  27. package/lib/binding/node-v115-win32-x64/zlib.dll +0 -0
  28. package/lib/binding/node-v120-darwin-arm64/aerospike.node +0 -0
  29. package/lib/binding/node-v120-darwin-x64/aerospike.node +0 -0
  30. package/lib/binding/node-v120-win32-x64/aerospike.dll +0 -0
  31. package/lib/binding/node-v120-win32-x64/aerospike.node +0 -0
  32. package/lib/binding/node-v120-win32-x64/event_core.dll +0 -0
  33. package/lib/binding/node-v120-win32-x64/getopt.dll +0 -0
  34. package/lib/binding/node-v120-win32-x64/libeay32.dll +0 -0
  35. package/lib/binding/node-v120-win32-x64/pthreadVC2.dll +0 -0
  36. package/lib/binding/node-v120-win32-x64/ssleay32.dll +0 -0
  37. package/lib/binding/node-v120-win32-x64/zlib.dll +0 -0
  38. package/lib/binding/openssl@1/node-v108-linux-arm64/aerospike.node +0 -0
  39. package/lib/binding/openssl@1/node-v108-linux-x64/aerospike.node +0 -0
  40. package/lib/binding/openssl@1/node-v115-linux-arm64/aerospike.node +0 -0
  41. package/lib/binding/openssl@1/node-v115-linux-x64/aerospike.node +0 -0
  42. package/lib/binding/openssl@1/node-v120-linux-arm64/aerospike.node +0 -0
  43. package/lib/binding/openssl@1/node-v120-linux-x64/aerospike.node +0 -0
  44. package/lib/binding/openssl@3/node-v108-linux-arm64/aerospike.node +0 -0
  45. package/lib/binding/openssl@3/node-v108-linux-x64/aerospike.node +0 -0
  46. package/lib/binding/openssl@3/node-v115-linux-arm64/aerospike.node +0 -0
  47. package/lib/binding/openssl@3/node-v115-linux-x64/aerospike.node +0 -0
  48. package/lib/binding/openssl@3/node-v120-linux-arm64/aerospike.node +0 -0
  49. package/lib/binding/openssl@3/node-v120-linux-x64/aerospike.node +0 -0
  50. package/lib/policies/batch_policy.js +16 -0
  51. package/lib/policies/batch_read_policy.js +15 -0
  52. package/lib/policies/operate_policy.js +15 -0
  53. package/lib/policies/query_policy.js +10 -0
  54. package/lib/policies/read_policy.js +15 -0
  55. package/lib/policy.js +30 -0
  56. package/package.json +7 -7
  57. package/src/include/enums.h +1 -0
  58. package/src/main/aerospike.cc +1 -0
  59. package/src/main/bit_operations.cc +1 -1
  60. package/src/main/enums/query_duration.cc +38 -0
  61. package/src/main/policy.cc +25 -1
  62. package/test/batch_read.js +179 -0
  63. package/test/get.js +87 -0
  64. package/test/operate.js +85 -0
  65. package/test/query.js +39 -0
  66. package/typings/index.d.ts +6 -0
package/README.md CHANGED
@@ -78,8 +78,11 @@ const config = {
78
78
 
79
79
  const key = new Aerospike.Key('test', 'demo', 'demo')
80
80
 
81
- Aerospike.connect(config)
82
- .then(client => {
81
+ ;(async function () {
82
+ let client
83
+ try {
84
+ client = await Aerospike.connect(config)
85
+
83
86
  const bins = {
84
87
  i: 123,
85
88
  s: 'hello',
@@ -97,39 +100,32 @@ Aerospike.connect(config)
97
100
  totalTimeout : 0
98
101
  })
99
102
 
100
- return client.put(key, bins, meta, policy)
101
- .then(() => {
102
- const ops = [
103
- Aerospike.operations.incr('i', 1),
104
- Aerospike.operations.read('i'),
105
- Aerospike.lists.append('l', 'z'),
106
- Aerospike.maps.removeByKey('m', 'bar')
107
- ]
108
-
109
- return client.operate(key, ops)
110
- })
111
- .then(result => {
112
- console.log(result.bins) // => { i: 124, l: 4, m: null }
113
-
114
- return client.get(key)
115
- })
116
- .then(record => {
117
- console.log(record.bins) // => { i: 124,
118
- // s: 'hello',
119
- // b: <Buffer 77 6f 72 6c 64>,
120
- // d: 3.1415,
121
- // g: '{"type":"Point","coordinates":[103.913,1.308]}',
122
- // l: [ 1, 'a', { x: 'y' }, 'z' ],
123
- // m: { foo: 4 } }
124
- })
125
- .then(() => client.close())
126
- })
127
- .catch(error => {
128
- console.error('Error: %s [%i]', error.message, error.code)
129
- if (error.client) {
130
- error.client.close()
131
- }
132
- })
103
+
104
+ await client.put(key, bins, meta, policy)
105
+ const ops = [
106
+ Aerospike.operations.incr('i', 1),
107
+ Aerospike.operations.read('i'),
108
+ Aerospike.lists.append('l', 'z'),
109
+ Aerospike.maps.removeByKey('m', 'bar')
110
+ ]
111
+
112
+ await client.operate(key, ops)
113
+ let record = await client.get(key)
114
+
115
+ console.log(record.bins) // => { i: 124,
116
+ // s: 'hello',
117
+ // b: <Buffer 77 6f 72 6c 64>,
118
+ // d: 3.1415,
119
+ // g: '{"type":"Point","coordinates":[103.913,1.308]}',
120
+ // l: [ 1, 'a', { x: 'y' }, 'z' ],
121
+ // m: { foo: 4 } }
122
+ } catch (error) {
123
+ console.error('Error:', error)
124
+ process.exit(1)
125
+ } finally {
126
+ if (client) client.close()
127
+ }
128
+ })()
133
129
  ```
134
130
  ## Prerequisites
135
131
 
package/binding.gyp CHANGED
@@ -144,13 +144,14 @@
144
144
  'src/main/enums/config_enum.cc',
145
145
  'src/main/enums/exp_enum.cc',
146
146
  'src/main/enums/batch_type.cc',
147
+ 'src/main/enums/query_duration.cc',
147
148
  'src/main/enums/privilege_code.cc',
148
149
  'src/main/enums/exp_read_flags.cc',
149
150
  'src/main/enums/exp_write_flags.cc',
150
151
  'src/main/stats.cc',
151
152
  'src/main/util/conversions.cc',
152
153
  'src/main/util/conversions_batch.cc',
153
- 'src/main/util/log.cc'
154
+ 'src/main/util/log.cc',
154
155
  ],
155
156
  'configurations': {
156
157
  'Release': {
@@ -0,0 +1,3 @@
1
+ ^C:\USERS\ADMINISTRATOR\DOCUMENTS\AEROSPIKE-CLIENT-NODEJS\BINDING.GYP
2
+ call call "pwsh" "../scripts/build-c-client.ps1" "-Configuration" "Release" "-NodeLibFile" "C:/Users/Administrator/AppData/Local/node-gyp/Cache/18.20.2/x64/node.lib"
3
+ if %errorlevel% neq 0 exit /b %errorlevel%
@@ -0,0 +1 @@
1
+ ^C:\USERS\ADMINISTRATOR\DOCUMENTS\AEROSPIKE-CLIENT-NODEJS\BINDING.GYP
@@ -0,0 +1,3 @@
1
+ ^C:\USERS\ADMINISTRATOR\DOCUMENTS\AEROSPIKE-CLIENT-NODEJS\BINDING.GYP
2
+ C:\USERS\ADMINISTRATOR\DOCUMENTS\AEROSPIKE-CLIENT-NODEJS\AEROSPIKE-CLIENT-C-OUTPUT\INCLUDE\AEROSPIKE\AEROSPIKE.H
3
+ C:\USERS\ADMINISTRATOR\DOCUMENTS\AEROSPIKE-CLIENT-NODEJS\AEROSPIKE-CLIENT-C-OUTPUT\LIB\AEROSPIKE.LIB
@@ -0,0 +1,2 @@
1
+ PlatformToolSet=v143:VCToolArchitecture=Native64Bit:VCToolsVersion=14.39.33519:TargetPlatformVersion=10.0.22621.0:
2
+ Release|x64|C:\Users\Administrator\Documents\aerospike-client-nodejs\build\|
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -58,6 +58,22 @@ class BatchPolicy extends BasePolicy {
58
58
  * @see {@link module:aerospike/policy.readModeSC} for supported policy values.
59
59
  */
60
60
  this.readModeSC = props.readModeSC
61
+
62
+ /**
63
+ * Determine how record TTL (time to live) is affected on reads. When enabled, the server can
64
+ * efficiently operate as a read-based LRU cache where the least recently used records are expired.
65
+ * The value is expressed as a percentage of the TTL sent on the most recent write such that a read
66
+ * within this interval of the record’s end of life will generate a touch.
67
+ *
68
+ * For example, if the most recent write had a TTL of 10 hours and read_touch_ttl_percent is set to
69
+ * 80, the next read within 8 hours of the record's end of life (equivalent to 2 hours after the most
70
+ * recent write) will result in a touch, resetting the TTL to another 10 hours.
71
+ * *
72
+ * @type number
73
+ * @default 0
74
+ */
75
+ this.readTouchTtlPercent = props.readTouchTtlPercent
76
+
61
77
  /**
62
78
  * Determine if batch commands to each server are run in parallel threads.
63
79
  *
@@ -52,6 +52,21 @@ class BatchReadPolicy {
52
52
  * @see {@link module:aerospike/policy.readModeSC} for supported policy values.
53
53
  */
54
54
  this.readModeSC = props.readModeSC
55
+
56
+ /**
57
+ * Determine how record TTL (time to live) is affected on reads. When enabled, the server can
58
+ * efficiently operate as a read-based LRU cache where the least recently used records are expired.
59
+ * The value is expressed as a percentage of the TTL sent on the most recent write such that a read
60
+ * within this interval of the record’s end of life will generate a touch.
61
+ *
62
+ * For example, if the most recent write had a TTL of 10 hours and read_touch_ttl_percent is set to
63
+ * 80, the next read within 8 hours of the record's end of life (equivalent to 2 hours after the most
64
+ * recent write) will result in a touch, resetting the TTL to another 10 hours.
65
+ * *
66
+ * @type number
67
+ * @default 0
68
+ */
69
+ this.readTouchTtlPercent = props.readTouchTtlPercent
55
70
  }
56
71
  }
57
72
 
@@ -113,6 +113,21 @@ class OperatePolicy extends BasePolicy {
113
113
  * @see {@link module:aerospike/policy.readModeSC} for supported policy values.
114
114
  */
115
115
  this.readModeSC = props.readModeSC
116
+
117
+ /**
118
+ * Determine how record TTL (time to live) is affected on reads. When enabled, the server can
119
+ * efficiently operate as a read-based LRU cache where the least recently used records are expired.
120
+ * The value is expressed as a percentage of the TTL sent on the most recent write such that a read
121
+ * within this interval of the record’s end of life will generate a touch.
122
+ *
123
+ * For example, if the most recent write had a TTL of 10 hours and read_touch_ttl_percent is set to
124
+ * 80, the next read within 8 hours of the record's end of life (equivalent to 2 hours after the most
125
+ * recent write) will result in a touch, resetting the TTL to another 10 hours.
126
+ * *
127
+ * @type number
128
+ * @default 0
129
+ */
130
+ this.readTouchTtlPercent = props.readTouchTtlPercent
116
131
  }
117
132
  }
118
133
 
@@ -95,6 +95,16 @@ class QueryPolicy extends BasePolicy {
95
95
  * @override
96
96
  */
97
97
  this.totalTimeout = props.totalTimeout
98
+
99
+ /**
100
+ * Expected query duration. The server treats the query in different ways depending on the expected duration.
101
+ * This field is ignored for aggregation queries, background queries and server versions &lt; 6.0.
102
+ *
103
+ * @see {@link module:aerospike/policy.queryDuration} for supported policy values.
104
+ * @type {@link module:aerospike/policy.queryDuration}
105
+ * @default {@link module:aerospike/policy.queryDuration.LONG}
106
+ */
107
+ this.expectedDuration = props.expectedDuration
98
108
  }
99
109
  }
100
110
 
@@ -68,6 +68,21 @@ class ReadPolicy extends BasePolicy {
68
68
  */
69
69
  this.readModeSC = props.readModeSC
70
70
 
71
+ /**
72
+ * Determine how record TTL (time to live) is affected on reads. When enabled, the server can
73
+ * efficiently operate as a read-based LRU cache where the least recently used records are expired.
74
+ * The value is expressed as a percentage of the TTL sent on the most recent write such that a read
75
+ * within this interval of the record’s end of life will generate a touch.
76
+ *
77
+ * For example, if the most recent write had a TTL of 10 hours and read_touch_ttl_percent is set to
78
+ * 80, the next read within 8 hours of the record's end of life (equivalent to 2 hours after the most
79
+ * recent write) will result in a touch, resetting the TTL to another 10 hours.
80
+ * *
81
+ * @type number
82
+ * @default 0
83
+ */
84
+ this.readTouchTtlPercent = props.readTouchTtlPercent
85
+
71
86
  /**
72
87
  * Should CDT data types (Lists / Maps) be deserialized to JS data types
73
88
  * (Arrays / Objects) or returned as raw bytes (Buffer).
package/lib/policy.js CHANGED
@@ -296,6 +296,36 @@ exports.readModeSC = as.policy.readModeSC
296
296
  */
297
297
  exports.commitLevel = as.policy.commitLevel
298
298
 
299
+ /**
300
+ * @summary Expected query duration. The server treats the query in different ways depending on the expected duration.
301
+ * This enum is ignored for aggregation (UDF) queries, background queries and server versions &lt; 6.0.
302
+ *
303
+ * @enum {number}
304
+ *
305
+ * @property {number} LONG - The query is expected to return more than 100 records per node. The server optimizes for a
306
+ * large record set in the following ways:
307
+ * <ul>
308
+ * <li>Allow query to be run in multiple threads using the server's query threading configuration.</li>
309
+ * <li>Do not relax read consistency for AP namespaces.</li>
310
+ * <li>Add the query to the server's query monitor.</li>
311
+ * <li>Do not add the overall latency to the server's latency histogram.</li>
312
+ * <li>Do not allow server timeouts.</li>
313
+ * </ul>
314
+ * @property {number} SHORT - The query is expected to return less than 100 records per node. The server optimizes for a
315
+ * small record set in the following ways:
316
+ * <ul>
317
+ * <li>Always run the query in one thread and ignore the server's query threading configuration.</li>
318
+ * <li>Allow query to be inlined directly on the server's service thread.</li>
319
+ * <li>Relax read consistency for AP namespaces.</li>
320
+ * <li>Do not add the query to the server's query monitor.</li>
321
+ * <li>Add the overall latency to the server's latency histogram.</li>
322
+ * <li>Allow server timeouts. The default server timeout for a short query is 1 second.</li>
323
+ * </ul>
324
+ * @property {number} LONG_RELAX_AP - Treat query as a LONG query, but relax read consistency for AP namespaces.
325
+ * This value is treated exactly like LONG for server versions &lt; 7.1.
326
+ */
327
+ exports.queryDuration = as.queryDuration
328
+
299
329
  /**
300
330
  * A base class extended to client policies.
301
331
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aerospike",
3
- "version": "5.11.0",
3
+ "version": "5.12.0",
4
4
  "description": "Aerospike Client Library",
5
5
  "keywords": [
6
6
  "aerospike",
@@ -59,24 +59,24 @@
59
59
  "@mapbox/node-pre-gyp": "^1.0.11",
60
60
  "bindings": "^1.5.0",
61
61
  "minimatch": "^3.1.2",
62
- "nan": "^2.18.0",
63
- "node-gyp": "^10.0.1",
62
+ "nan": "^2.19.0",
63
+ "node-gyp": "^10.1.0",
64
64
  "npm-run-all": "^4.1.5"
65
65
  },
66
66
  "devDependencies": {
67
- "@types/node": "^20.11.18",
68
- "chai": "^4.3.7",
67
+ "@types/node": "^20.12.7",
68
+ "chai": "^4.4.1",
69
69
  "choma": "^1.2.1",
70
70
  "codecov": "^3.8.3",
71
71
  "deep-eql": "^4.1.3",
72
72
  "husky": "^9.0.11",
73
- "mocha": "^10.3.0",
73
+ "mocha": "^10.4.0",
74
74
  "mocha-clean": "^1.0.0",
75
75
  "nyc": "^15.1.0",
76
76
  "p-throttle": "^3.1.0",
77
77
  "semver": "^7.6.0",
78
78
  "standard": "^17.1.0",
79
- "tmp": "^0.2.1",
79
+ "tmp": "^0.2.3",
80
80
  "yargs": "^17.7.2"
81
81
  },
82
82
  "standard": {
@@ -41,6 +41,7 @@ v8::Local<v8::Object> retry_policy_values();
41
41
  v8::Local<v8::Object> status();
42
42
  v8::Local<v8::Object> ttl_enum_values();
43
43
  v8::Local<v8::Object> batchTypes();
44
+ v8::Local<v8::Object> queryDuration();
44
45
  v8::Local<v8::Object> privilegeCode();
45
46
  v8::Local<v8::Object> expReadFlags();
46
47
  v8::Local<v8::Object> expWriteFlags();
@@ -156,6 +156,7 @@ NAN_MODULE_INIT(Aerospike)
156
156
  export("ttl", ttl_enum_values());
157
157
  export("auth", auth_mode_enum_values());
158
158
  export("batchTypes", batchTypes());
159
+ export("queryDuration", queryDuration());
159
160
  export("privilegeCode", privilegeCode());
160
161
  export("expReadFlags", expReadFlags());
161
162
  export("expWriteFlags", expWriteFlags());
@@ -254,7 +254,7 @@ bool add_bit_rshift_op(as_operations *ops, char *bin, as_bit_policy *policy,
254
254
 
255
255
  typedef bool (*AsBitMath)(as_operations *ops, const char *bin, as_cdt_ctx *ctx,
256
256
  as_bit_policy *policy, int bit_offset,
257
- uint32_t bit_size, int64_t value, bool sign,
257
+ uint32_t bit_size, uint64_t value, bool sign,
258
258
  as_bit_overflow_action action);
259
259
 
260
260
  bool add_bit_math_op(as_operations *ops, AsBitMath math_op, char *bin,
@@ -0,0 +1,38 @@
1
+ /*******************************************************************************
2
+ * Copyright 2023 Aerospike, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * 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,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ ******************************************************************************/
16
+
17
+ #include <node.h>
18
+ #include <nan.h>
19
+
20
+ extern "C" {
21
+ #include <aerospike/as_policy.h>
22
+ }
23
+
24
+ using namespace v8;
25
+
26
+ #define set(__obj, __name, __value) \
27
+ Nan::Set(__obj, Nan::New(__name).ToLocalChecked(), Nan::New(__value))
28
+
29
+ Local<Object> queryDuration()
30
+ {
31
+ Nan::EscapableHandleScope scope;
32
+ Local<Object> obj = Nan::New<Object>();
33
+ set(obj, "LONG", AS_QUERY_DURATION_LONG);
34
+ set(obj, "SHORT", AS_QUERY_DURATION_SHORT);
35
+ set(obj, "LONG_RELAX_AP", AS_QUERY_DURATION_LONG_RELAX_AP);
36
+
37
+ return scope.Escape(obj);
38
+ }
@@ -130,6 +130,11 @@ int readpolicy_from_jsobject(as_policy_read *policy, Local<Object> obj,
130
130
  AS_NODE_PARAM_OK) {
131
131
  return rc;
132
132
  }
133
+ if ((rc = get_optional_int_property((int *)&policy->read_touch_ttl_percent,
134
+ NULL, obj, "readTouchTtlPercent", log)) !=
135
+ AS_NODE_PARAM_OK) {
136
+ return rc;
137
+ }
133
138
  if ((rc = get_optional_bool_property(&policy->deserialize, NULL, obj,
134
139
  "deserialize", log)) !=
135
140
  AS_NODE_PARAM_OK) {
@@ -249,6 +254,11 @@ int operatepolicy_from_jsobject(as_policy_operate *policy, Local<Object> obj,
249
254
  AS_NODE_PARAM_OK) {
250
255
  return rc;
251
256
  }
257
+ if ((rc = get_optional_int_property((int *)&policy->read_touch_ttl_percent,
258
+ NULL, obj, "readTouchTtlPercent", log)) !=
259
+ AS_NODE_PARAM_OK) {
260
+ return rc;
261
+ }
252
262
  if ((rc = get_optional_uint32_property((uint32_t *)&policy->commit_level,
253
263
  NULL, obj, "commitLevel", log)) !=
254
264
  AS_NODE_PARAM_OK) {
@@ -342,6 +352,11 @@ int batchpolicy_from_jsobject(as_policy_batch *policy, Local<Object> obj,
342
352
  AS_NODE_PARAM_OK) {
343
353
  return rc;
344
354
  }
355
+ if ((rc = get_optional_int_property((int *)&policy->read_touch_ttl_percent,
356
+ NULL, obj, "readTouchTtlPercent", log)) !=
357
+ AS_NODE_PARAM_OK) {
358
+ return rc;
359
+ }
345
360
  if ((rc = get_optional_bool_property(&policy->concurrent, NULL, obj,
346
361
  "concurrent", log)) !=
347
362
  AS_NODE_PARAM_OK) {
@@ -405,7 +420,11 @@ int batchread_policy_from_jsobject(as_policy_batch_read *policy,
405
420
  AS_NODE_PARAM_OK) {
406
421
  return rc;
407
422
  }
408
-
423
+ if ((rc = get_optional_int_property((int *)&policy->read_touch_ttl_percent,
424
+ NULL, obj, "readTouchTtlPercent", log)) !=
425
+ AS_NODE_PARAM_OK) {
426
+ return rc;
427
+ }
409
428
  return rc;
410
429
  }
411
430
 
@@ -581,6 +600,11 @@ int querypolicy_from_jsobject(as_policy_query *policy, Local<Object> obj,
581
600
  AS_NODE_PARAM_OK) {
582
601
  return rc;
583
602
  }
603
+ if ((rc = get_optional_uint32_property((uint32_t *)&policy->expected_duration, NULL, obj,
604
+ "expectedDuration", log)) !=
605
+ AS_NODE_PARAM_OK) {
606
+ return rc;
607
+ }
584
608
  if ((rc = get_optional_bool_property(&policy->fail_on_cluster_change, NULL, obj, "failOnClusterChange", log)) != AS_NODE_PARAM_OK) {
585
609
  return rc;
586
610
  }
@@ -181,6 +181,185 @@ describe('client.batchRead()', function () {
181
181
  })
182
182
  })
183
183
  })
184
+
185
+ context('readTouchTtlPercent policy', function () {
186
+ let batch = [{
187
+ key: new Aerospike.Key('test', 'demo', 'batchReadTtl1'),
188
+ readAllBins: true
189
+ }]
190
+ this.timeout(4000)
191
+
192
+ context('BatchPolicy policy', function () {
193
+ helper.skipUnlessVersion('>= 7.1.0', this)
194
+
195
+ it('100% touches record', async function () {
196
+ const policy = new Aerospike.BatchReadPolicy({
197
+ readTouchTtlPercent: 100
198
+ })
199
+
200
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
201
+ await new Promise(resolve => setTimeout(resolve, 3000))
202
+
203
+ const batchResult = await client.batchRead(batch, policy)
204
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
205
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
206
+
207
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
208
+ expect(record.bins).to.eql({ i: 2 })
209
+ expect(record.ttl).to.be.within(9, 10)
210
+
211
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
212
+ })
213
+
214
+ it('71% touches record', async function () {
215
+ const policy = new Aerospike.BatchReadPolicy({
216
+ readTouchTtlPercent: 71
217
+ })
218
+
219
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
220
+ await new Promise(resolve => setTimeout(resolve, 3000))
221
+
222
+ const batchResult = await client.batchRead(batch, policy)
223
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
224
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
225
+
226
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
227
+ expect(record.bins).to.eql({ i: 2 })
228
+ expect(record.ttl).to.be.within(9, 10)
229
+
230
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
231
+ })
232
+
233
+ it('60% doesnt touch record', async function () {
234
+ const policy = new Aerospike.BatchReadPolicy({
235
+ readTouchTtlPercent: 60
236
+ })
237
+
238
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
239
+ await new Promise(resolve => setTimeout(resolve, 3000))
240
+
241
+ const batchResult = await client.batchRead(batch, policy)
242
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
243
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
244
+
245
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
246
+ expect(record.bins).to.eql({ i: 2 })
247
+ expect(record.ttl).to.be.within(7, 8)
248
+
249
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
250
+ })
251
+
252
+ it('0% doesnt touch record', async function () {
253
+ const policy = new Aerospike.BatchReadPolicy({
254
+ readTouchTtlPercent: 0
255
+ })
256
+
257
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
258
+ await new Promise(resolve => setTimeout(resolve, 3000))
259
+
260
+ const batchResult = await client.batchRead(batch, policy)
261
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
262
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
263
+
264
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
265
+ expect(record.bins).to.eql({ i: 2 })
266
+ expect(record.ttl).to.be.within(7, 8)
267
+
268
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
269
+ })
270
+ })
271
+
272
+ context('BatchReadPolicy policy', function () {
273
+ helper.skipUnlessVersion('>= 7.1.0', this)
274
+ it('100% touches record', async function () {
275
+ batch = [{
276
+ key: new Aerospike.Key('test', 'demo', 'batchReadTtl1'),
277
+ readAllBins: true,
278
+ policy: new Aerospike.BatchPolicy({
279
+ readTouchTtlPercent: 100
280
+ })
281
+ }]
282
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
283
+ await new Promise(resolve => setTimeout(resolve, 3000))
284
+
285
+ const batchResult = await client.batchRead(batch)
286
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
287
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
288
+
289
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
290
+ expect(record.bins).to.eql({ i: 2 })
291
+ expect(record.ttl).to.be.within(9, 10)
292
+
293
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
294
+ })
295
+
296
+ it('71% touches record', async function () {
297
+ batch = [{
298
+ key: new Aerospike.Key('test', 'demo', 'batchReadTtl1'),
299
+ readAllBins: true,
300
+ policy: new Aerospike.BatchPolicy({
301
+ readTouchTtlPercent: 71
302
+ })
303
+ }]
304
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
305
+ await new Promise(resolve => setTimeout(resolve, 3000))
306
+
307
+ const batchResult = await client.batchRead(batch)
308
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
309
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
310
+
311
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
312
+ expect(record.bins).to.eql({ i: 2 })
313
+ expect(record.ttl).to.be.within(9, 10)
314
+
315
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
316
+ })
317
+
318
+ it('60% doesnt touch record', async function () {
319
+ batch = [{
320
+ key: new Aerospike.Key('test', 'demo', 'batchReadTtl1'),
321
+ readAllBins: true,
322
+ policy: new Aerospike.BatchPolicy({
323
+ readTouchTtlPercent: 60
324
+ })
325
+ }]
326
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
327
+ await new Promise(resolve => setTimeout(resolve, 3000))
328
+
329
+ const batchResult = await client.batchRead(batch)
330
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
331
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
332
+
333
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
334
+ expect(record.bins).to.eql({ i: 2 })
335
+ expect(record.ttl).to.be.within(7, 8)
336
+
337
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
338
+ })
339
+
340
+ it('0% doesnt touch record', async function () {
341
+ batch = [{
342
+ key: new Aerospike.Key('test', 'demo', 'batchReadTtl1'),
343
+ readAllBins: true,
344
+ policy: new Aerospike.BatchPolicy({
345
+ readTouchTtlPercent: 0
346
+ })
347
+ }]
348
+ await client.put(new Aerospike.Key('test', 'demo', 'batchReadTtl1'), { i: 2 }, { ttl: 10 })
349
+ await new Promise(resolve => setTimeout(resolve, 3000))
350
+
351
+ const batchResult = await client.batchRead(batch)
352
+ expect(batchResult[0].record.bins).to.eql({ i: 2 })
353
+ expect(batchResult[0].record.ttl).to.be.within(7, 8)
354
+
355
+ const record = await client.get(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
356
+ expect(record.bins).to.eql({ i: 2 })
357
+ expect(record.ttl).to.be.within(7, 8)
358
+
359
+ await client.remove(new Aerospike.Key('test', 'demo', 'batchReadTtl1'))
360
+ })
361
+ })
362
+ })
184
363
  })
185
364
 
186
365
  it('returns a Promise that resolves to the batch results', function () {
package/test/get.js CHANGED
@@ -82,6 +82,93 @@ describe('client.get()', function () {
82
82
  })
83
83
  })
84
84
  })
85
+
86
+ context('readTouchTtlPercent policy', function () {
87
+ helper.skipUnlessVersion('>= 7.1.0', this)
88
+
89
+ this.timeout(4000)
90
+ it('100% touches record', async function () {
91
+ const key = keygen.integer(helper.namespace, helper.set)()
92
+ const policy = new Aerospike.ReadPolicy({
93
+ readTouchTtlPercent: 100
94
+ })
95
+
96
+ await client.put(key, { i: 2 }, { ttl: 10 })
97
+ await new Promise(resolve => setTimeout(resolve, 3000))
98
+ let record = await client.get(key, policy)
99
+
100
+ expect(record.bins).to.eql({ i: 2 })
101
+ expect(record.ttl).to.be.within(7, 8)
102
+
103
+ record = await client.get(key, policy)
104
+
105
+ expect(record.bins).to.eql({ i: 2 })
106
+ expect(record.ttl).to.be.within(9, 10)
107
+
108
+ await client.remove(key)
109
+ })
110
+
111
+ it('71% touches record', async function () {
112
+ const key = keygen.integer(helper.namespace, helper.set)()
113
+ const policy = new Aerospike.ReadPolicy({
114
+ readTouchTtlPercent: 71
115
+ })
116
+
117
+ await client.put(key, { i: 2 }, { ttl: 10 })
118
+ await new Promise(resolve => setTimeout(resolve, 3000))
119
+ let record = await client.get(key, policy)
120
+
121
+ expect(record.bins).to.eql({ i: 2 })
122
+ expect(record.ttl).to.be.within(7, 8)
123
+
124
+ record = await client.get(key, policy)
125
+
126
+ expect(record.bins).to.eql({ i: 2 })
127
+ expect(record.ttl).to.be.within(9, 10)
128
+
129
+ await client.remove(key)
130
+ })
131
+
132
+ it('60% never touches record', async function () {
133
+ const key = keygen.integer(helper.namespace, helper.set)()
134
+ const policy = new Aerospike.ReadPolicy({
135
+ readTouchTtlPercent: 60
136
+ })
137
+ await client.put(key, { i: 2 }, { ttl: 10 })
138
+ await new Promise(resolve => setTimeout(resolve, 3000))
139
+
140
+ let record = await client.get(key, policy)
141
+
142
+ expect(record.bins).to.eql({ i: 2 })
143
+ expect(record.ttl).to.be.within(7, 8)
144
+
145
+ record = await client.get(key, policy)
146
+
147
+ expect(record.bins).to.eql({ i: 2 })
148
+ expect(record.ttl).to.be.within(7, 8)
149
+ await client.remove(key)
150
+ })
151
+
152
+ it('0% never touches record', async function () {
153
+ const key = keygen.integer(helper.namespace, helper.set)()
154
+ const policy = new Aerospike.ReadPolicy({
155
+ readTouchTtlPercent: 0
156
+ })
157
+ await client.put(key, { i: 2 }, { ttl: 10 })
158
+ await new Promise(resolve => setTimeout(resolve, 3000))
159
+
160
+ let record = await client.get(key, policy)
161
+
162
+ expect(record.bins).to.eql({ i: 2 })
163
+ expect(record.ttl).to.be.within(7, 8)
164
+
165
+ record = await client.get(key, policy)
166
+
167
+ expect(record.bins).to.eql({ i: 2 })
168
+ expect(record.ttl).to.be.within(7, 8)
169
+ await client.remove(key)
170
+ })
171
+ })
85
172
  })
86
173
 
87
174
  it('should return the TTL for a never expiring record as Aerospike.ttl.NEVER_EXPIRE', function (done) {
package/test/operate.js CHANGED
@@ -281,6 +281,91 @@ context('Operations', function () {
281
281
  })
282
282
  })
283
283
 
284
+ context('readTouchTtlPercent policy', function () {
285
+ helper.skipUnlessVersion('>= 7.1.0', this)
286
+
287
+ this.timeout(4000)
288
+ it('100% touches record', async function () {
289
+ const ops = [op.read('i')]
290
+ const policy = new Aerospike.OperatePolicy({
291
+ readTouchTtlPercent: 100
292
+ })
293
+
294
+ await client.put(new Aerospike.Key('test', 'demo', 'operateTtl1'), { i: 2 }, { ttl: 10 })
295
+ await new Promise(resolve => setTimeout(resolve, 3000))
296
+
297
+ let record = await client.operate(new Aerospike.Key('test', 'demo', 'operateTtl1'), ops, null, policy)
298
+ expect(record.bins).to.eql({ i: 2 })
299
+ expect(record.ttl).to.be.within(7, 8)
300
+
301
+ record = await client.get(new Aerospike.Key('test', 'demo', 'operateTtl1'), policy)
302
+ expect(record.bins).to.eql({ i: 2 })
303
+ expect(record.ttl).to.be.within(9, 10)
304
+
305
+ await client.remove(new Aerospike.Key('test', 'demo', 'operateTtl1'))
306
+ })
307
+
308
+ it('71% touches record', async function () {
309
+ const ops = [op.read('i')]
310
+ const policy = new Aerospike.OperatePolicy({
311
+ readTouchTtlPercent: 71
312
+ })
313
+
314
+ await client.put(new Aerospike.Key('test', 'demo', 'operateTtl1'), { i: 2 }, { ttl: 10 })
315
+ await new Promise(resolve => setTimeout(resolve, 3000))
316
+
317
+ let record = await client.operate(new Aerospike.Key('test', 'demo', 'operateTtl1'), ops, null, policy)
318
+ expect(record.bins).to.eql({ i: 2 })
319
+ expect(record.ttl).to.be.within(7, 8)
320
+
321
+ record = await client.get(new Aerospike.Key('test', 'demo', 'operateTtl1'), policy)
322
+ expect(record.bins).to.eql({ i: 2 })
323
+ expect(record.ttl).to.be.within(9, 10)
324
+
325
+ await client.remove(new Aerospike.Key('test', 'demo', 'operateTtl1'))
326
+ })
327
+
328
+ it('60% does not touch record', async function () {
329
+ const ops = [op.read('i')]
330
+ const policy = new Aerospike.OperatePolicy({
331
+ readTouchTtlPercent: 60
332
+ })
333
+
334
+ await client.put(new Aerospike.Key('test', 'demo', 'operateTtl1'), { i: 2 }, { ttl: 10 })
335
+ await new Promise(resolve => setTimeout(resolve, 3000))
336
+
337
+ let record = await client.operate(new Aerospike.Key('test', 'demo', 'operateTtl1'), ops, null, policy)
338
+ expect(record.bins).to.eql({ i: 2 })
339
+ expect(record.ttl).to.be.within(7, 8)
340
+
341
+ record = await client.get(new Aerospike.Key('test', 'demo', 'operateTtl1'), policy)
342
+ expect(record.bins).to.eql({ i: 2 })
343
+ expect(record.ttl).to.be.within(7, 8)
344
+
345
+ await client.remove(new Aerospike.Key('test', 'demo', 'operateTtl1'))
346
+ })
347
+
348
+ it('0% does not touch record', async function () {
349
+ const ops = [op.read('i')]
350
+ const policy = new Aerospike.OperatePolicy({
351
+ readTouchTtlPercent: 0
352
+ })
353
+
354
+ await client.put(new Aerospike.Key('test', 'demo', 'operateTtl1'), { i: 2 }, { ttl: 10 })
355
+ await new Promise(resolve => setTimeout(resolve, 3000))
356
+
357
+ let record = await client.operate(new Aerospike.Key('test', 'demo', 'operateTtl1'), ops, null, policy)
358
+ expect(record.bins).to.eql({ i: 2 })
359
+ expect(record.ttl).to.be.within(7, 8)
360
+
361
+ record = await client.get(new Aerospike.Key('test', 'demo', 'operateTtl1'), policy)
362
+ expect(record.bins).to.eql({ i: 2 })
363
+ expect(record.ttl).to.be.within(7, 8)
364
+
365
+ await client.remove(new Aerospike.Key('test', 'demo', 'operateTtl1'))
366
+ })
367
+ })
368
+
284
369
  context('gen policy', function () {
285
370
  context('policy.gen.EQ', function () {
286
371
  const policy = new Aerospike.OperatePolicy({
package/test/query.js CHANGED
@@ -273,6 +273,45 @@ describe('Queries', function () {
273
273
  done()
274
274
  })
275
275
  })
276
+ context('expectedDuration', function () {
277
+ helper.skipUnlessVersion('>= 7.1.0', this)
278
+
279
+ it('Should run a regular primary index query with expectedDuration=LONG', function (done) {
280
+ const query = client.query(helper.namespace, testSet)
281
+ const stream = query.foreach({ expectedDuration: Aerospike.policy.queryDuration.LONG })
282
+ const results = []
283
+ stream.on('error', error => { throw error })
284
+ stream.on('data', record => results.push(record.bins))
285
+ stream.on('end', () => {
286
+ expect(results.length).to.be.above(samples.length)
287
+ done()
288
+ })
289
+ })
290
+
291
+ it('Should run a regular primary index query with expectedDuration=SHORT', function (done) {
292
+ const query = client.query(helper.namespace, testSet)
293
+ const stream = query.foreach({ expectedDuration: Aerospike.policy.queryDuration.SHORT })
294
+ const results = []
295
+ stream.on('error', error => { throw error })
296
+ stream.on('data', record => results.push(record.bins))
297
+ stream.on('end', () => {
298
+ expect(results.length).to.be.above(samples.length)
299
+ done()
300
+ })
301
+ })
302
+
303
+ it('Should run a regular primary index query with expectedDuration=LONG_RELAX_AP', function (done) {
304
+ const query = client.query(helper.namespace, testSet)
305
+ const stream = query.foreach({ expectedDuration: Aerospike.policy.queryDuration.LONG_RELAX_AP })
306
+ const results = []
307
+ stream.on('error', error => { throw error })
308
+ stream.on('data', record => results.push(record.bins))
309
+ stream.on('end', () => {
310
+ expect(results.length).to.be.above(samples.length)
311
+ done()
312
+ })
313
+ })
314
+ })
276
315
 
277
316
  it('Should run a paginated primary index query', async function () {
278
317
  let recordTotal = 0
@@ -1504,6 +1504,7 @@ declare module 'policies/query_policy' {
1504
1504
  deserialize: boolean;
1505
1505
  failOnClusterChange: boolean;
1506
1506
  infoTimeout: number;
1507
+ expectedDuration: number;
1507
1508
  }
1508
1509
  import BasePolicy = require("policies/base_policy");
1509
1510
 
@@ -1653,6 +1654,11 @@ declare module 'query' {
1653
1654
  import RecordStream = require("record_stream");
1654
1655
 
1655
1656
  }
1657
+ declare module 'query_duration' {
1658
+ export const LONG: any;
1659
+ export const SHORT: any;
1660
+ export const LONG_RELAX_AP: any;
1661
+ }
1656
1662
  declare module 'record' {
1657
1663
  export = Record;
1658
1664
  class Record {