Skip to content

Commit 56add63

Browse files
author
Jan Hecking
authored
Support maxRecords scan policy (#359)
* Support maxRecords scan policy * Fix version number, when option was introduced; update changelog * Skip percent-based sampling tests on server v4.9+ * Add note about scan percent sampling on v4.9
1 parent bdeeb25 commit 56add63

6 files changed

Lines changed: 53 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
* **New Features**
8+
* Added a max records option for sampling with basic scans. Requires server version 4.9 or later. [#359](https://github.com/aerospike/aerospike-client-nodejs/pull/359)
9+
710
* **Updates**
11+
* *BREAKING*: The client no longer supports the percent-based scan sampling for server versions 4.9 or later. Use the new max records scan policy option instead.
812
* Update C client library to [v4.6.14](http://www.aerospike.com/download/client/c/notes.html#4.6.14).
913

1014
## [3.15.0] - 2020-03-24

lib/policies/scan_policy.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,21 @@ class ScanPolicy extends BasePolicy {
7373
* @since v3.14.0
7474
*/
7575
this.recordsPerSecond = props.recordsPerSecond
76+
77+
/**
78+
* Approximate number of records to return to client. This number is
79+
* divided by the number of nodes involved in the scan. The actual number
80+
* of records returned may be less than maxRecords if node record counts
81+
* are small and unbalanced across nodes.
82+
*
83+
* Requires Aerospike Server version >= 4.9.
84+
*
85+
* @type number
86+
* @default 0 (do not limit record count)
87+
*
88+
* @since v3.16.0
89+
*/
90+
this.maxRecords = props.maxRecords
7691
}
7792
}
7893

lib/scan.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,11 @@ function Scan (client, ns, set, options) {
140140
this.priority = options.priority
141141

142142
/**
143-
* Percentage of records in the cluster to scan.
143+
* Percentage of records in the cluster to scan. Valid integer range is 1 to
144+
* 100.
145+
*
146+
* This field is supported on server versions < 4.9. For server versions >=
147+
* 4.9, use {@link ScanPolicy#maxRecords}.
144148
*
145149
* @member {number} Scan#percent
146150
*/

src/main/policy.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,9 @@ int scanpolicy_from_jsobject(as_policy_scan* policy, Local<Object> obj, const Lo
312312
if ((rc = get_optional_uint32_property((uint32_t*) &policy->records_per_second, NULL, obj, "recordsPerSecond", log)) != AS_NODE_PARAM_OK) {
313313
return rc;
314314
}
315+
if ((rc = get_optional_uint32_property((uint32_t*) &policy->max_records, NULL, obj, "maxRecords", log)) != AS_NODE_PARAM_OK) {
316+
return rc;
317+
}
315318
as_v8_detail( log, "Parsing scan policy: success");
316319
return AS_NODE_PARAM_OK;
317320
}

src/main/scan.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ void setup_scan(as_scan* scan, Local<Value> ns, Local<Value> set, Local<Value> m
8888
Local<Value> percent = Nan::Get(options, Nan::New("percent").ToLocalChecked()).ToLocalChecked();
8989
TYPE_CHECK_OPT(percent, IsNumber, "percent must be a number");
9090
if (percent->IsNumber()) {
91-
as_scan_set_percent(scan, (uint8_t) Nan::To<uint32_t>(percent).FromJust());
91+
uint8_t pct = (uint8_t) Nan::To<uint32_t>(percent).FromJust();
92+
as_v8_detail(log, "Setting scan percent to %i", pct);
93+
as_scan_set_percent(scan, pct);
9294
}
9395

9496
Local<Value> priority = Nan::Get(options, Nan::New("priority").ToLocalChecked()).ToLocalChecked();

test/scan.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ context('Scans', function () {
147147
socketTimeout: 1000,
148148
durableDelete: true,
149149
failOnClusterChange: true,
150-
recordsPerSecond: 50
150+
recordsPerSecond: 50,
151+
maxRecords: 5000
151152
})
152153

153154
const stream = scan.foreach(policy)
@@ -190,6 +191,8 @@ context('Scans', function () {
190191
})
191192

192193
context('with percent sampling', function () {
194+
helper.skipUnlessVersion('< 4.9', this)
195+
193196
it('should only scan approx. half of the records', function (done) {
194197
const scan = client.scan(helper.namespace, testSet, {
195198
percent: 50,
@@ -207,6 +210,25 @@ context('Scans', function () {
207210
})
208211
})
209212

213+
context('with max records limit', function () {
214+
helper.skipUnlessVersion('>= 4.9.0', this)
215+
216+
it('returns at most X number of records', function (done) {
217+
const scan = client.scan(helper.namespace, testSet, { nobins: true })
218+
219+
const maxRecords = 33
220+
const stream = scan.foreach({ maxRecords })
221+
let recordsReceived = 0
222+
stream.on('data', () => recordsReceived++)
223+
stream.on('end', () => {
224+
// The actual number returned may be less than maxRecords if node
225+
// record counts are small and unbalanced across nodes.
226+
expect(recordsReceived).to.be.at.most(maxRecords)
227+
done()
228+
})
229+
})
230+
})
231+
210232
context('without set', function () {
211233
it('executes a scan without set', function (done) {
212234
var scan = client.scan(helper.namespace)

0 commit comments

Comments
 (0)