ilios 1.1.1 → 1.1.2
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +19 -0
- data/Rakefile +5 -5
- data/docker-compose.yml +15 -0
- data/ext/ilios/cluster.c +460 -4
- data/ext/ilios/statement.c +1 -1
- data/lib/ilios/version.rb +1 -1
- data/sig/ilios.rbs +29 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c20c800bf59b7673cdb60ce4dd5086412e3461f4fa75f8f729eef7b2bba3ade
|
|
4
|
+
data.tar.gz: 1edb52689033a9047388c4be27f81ac3c1078fefcd845bc6f03c8d0080983670
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0724d14f13175a62b25aeda0926ea4f9bb6593f64c75cf871bf55426594ec2cf1b4d76fcd61a86a85c686cec49902e37b0f9302bce9933467c688d55dad9c78d
|
|
7
|
+
data.tar.gz: 7c3cd165e571bbdccbf627a2bb50aadfa84a02188fed7ede80a6bb41d7bfb7b75d43c0b31ab92dcf9de882d3dbfd7a5170663708e72023c9c640da9b3bedf14d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 1.1.2
|
|
4
|
+
|
|
5
|
+
- Support username/password authentication with `Cluster#credentials` (#33)
|
|
6
|
+
- Add cluster options: consistency, serial_consistency, num_threads_io, queue_size_io, core_connections_per_host, constant_reconnect, exponential_reconnect, tcp_nodelay, tcp_keepalive, connection_heartbeat_interval, connection_idle_timeout, load_balance_round_robin, load_balance_dc_aware, token_aware_routing, latency_aware_routing and use_schema (#33)
|
|
7
|
+
- Accept Symbol consistency levels (e.g. `:quorum`) in `Cluster#consistency` and `Cluster#serial_consistency` (#33)
|
|
8
|
+
- Fix infinite loop when binding a `list`/`set` whose element appends to the array while it is being converted (#34)
|
|
9
|
+
- Fix infinite loop in `Cluster#hosts` when an element appends to the array while it is being converted (#34)
|
|
10
|
+
|
|
3
11
|
## 1.1.1
|
|
4
12
|
|
|
5
13
|
- Fix out-of-bounds read when binding a `list`/`set` whose element mutates the array while it is being converted (#31)
|
data/README.md
CHANGED
|
@@ -171,6 +171,25 @@ Notes:
|
|
|
171
171
|
- Because a `Symbol` map key is stored as its `String` equivalent, binding a map that contains both (for example `{ k1: 1, 'k1' => 2 }`) ends up as a single key on the server; the entry bound last wins.
|
|
172
172
|
- Binding a `String` containing a NUL character (`\0`) to a `text` (or `ascii` / `varchar`) column raises `ArgumentError` (known limitation).
|
|
173
173
|
|
|
174
|
+
### Authentication and cluster options
|
|
175
|
+
|
|
176
|
+
Username/password authentication (Cassandra's `PasswordAuthenticator`) and
|
|
177
|
+
common cluster options are configured on `Cluster` before `connect`:
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
cluster = Ilios::Cassandra::Cluster.new
|
|
181
|
+
cluster.hosts(['127.0.0.1'])
|
|
182
|
+
cluster.credentials('username', 'password')
|
|
183
|
+
cluster.consistency(:quorum) # or Ilios::Cassandra::Cluster::CONSISTENCY_QUORUM
|
|
184
|
+
cluster.num_threads_io(4)
|
|
185
|
+
cluster.exponential_reconnect(2_000, 60_000)
|
|
186
|
+
cluster.tcp_keepalive(true, 60)
|
|
187
|
+
cluster.load_balance_dc_aware('dc1')
|
|
188
|
+
session = cluster.connect
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
See the RBS signatures in `sig/ilios.rbs` for the full list of options.
|
|
192
|
+
|
|
174
193
|
### Synchronous API
|
|
175
194
|
`Ilios::Cassandra::Session#prepare` and `Ilios::Cassandra::Session#execute` are provided as synchronous API.
|
|
176
195
|
|
data/Rakefile
CHANGED
|
@@ -4,9 +4,6 @@ require 'bundler/gem_tasks'
|
|
|
4
4
|
require 'rake/extensiontask'
|
|
5
5
|
require 'rake/testtask'
|
|
6
6
|
|
|
7
|
-
desc 'Run tests'
|
|
8
|
-
task test: :compile
|
|
9
|
-
|
|
10
7
|
task default: :test
|
|
11
8
|
|
|
12
9
|
Rake::ExtensionTask.new('ilios') do |ext|
|
|
@@ -14,9 +11,10 @@ Rake::ExtensionTask.new('ilios') do |ext|
|
|
|
14
11
|
end
|
|
15
12
|
|
|
16
13
|
test_config = lambda do |t|
|
|
14
|
+
t.deps = [:compile]
|
|
17
15
|
t.pattern = 'test/test_*.rb'
|
|
18
16
|
end
|
|
19
|
-
Rake::TestTask.new(test
|
|
17
|
+
Rake::TestTask.new(:test, &test_config)
|
|
20
18
|
|
|
21
19
|
namespace :rbs do
|
|
22
20
|
desc 'Validate RBS definitions'
|
|
@@ -31,7 +29,9 @@ end
|
|
|
31
29
|
if RUBY_PLATFORM.include?('linux')
|
|
32
30
|
require 'ruby_memcheck'
|
|
33
31
|
|
|
32
|
+
RubyMemcheck.config(binary_name: 'ilios')
|
|
33
|
+
|
|
34
34
|
namespace :test do
|
|
35
|
-
RubyMemcheck::TestTask.new(valgrind
|
|
35
|
+
RubyMemcheck::TestTask.new(:valgrind, &test_config)
|
|
36
36
|
end
|
|
37
37
|
end
|
data/docker-compose.yml
CHANGED
|
@@ -6,17 +6,32 @@ services:
|
|
|
6
6
|
- 9042:9042
|
|
7
7
|
volumes:
|
|
8
8
|
- cassandra-data:/var/lib/cassandra
|
|
9
|
+
cassandra-auth:
|
|
10
|
+
image: cassandra:4
|
|
11
|
+
ports:
|
|
12
|
+
- "9043:9042"
|
|
13
|
+
command: >
|
|
14
|
+
bash -c "sed -i 's/^authenticator:.*/authenticator: PasswordAuthenticator/'
|
|
15
|
+
/etc/cassandra/cassandra.yaml
|
|
16
|
+
&& exec docker-entrypoint.sh cassandra -f"
|
|
17
|
+
volumes:
|
|
18
|
+
- cassandra-auth-data:/var/lib/cassandra
|
|
9
19
|
ilios:
|
|
10
20
|
build:
|
|
11
21
|
context: ./dockerfiles
|
|
12
22
|
dockerfile: ubuntu.dockerfile
|
|
13
23
|
depends_on:
|
|
14
24
|
- cassandra
|
|
25
|
+
- cassandra-auth
|
|
15
26
|
environment:
|
|
16
27
|
CASSANDRA_HOST: cassandra
|
|
28
|
+
CASSANDRA_AUTH_HOST: cassandra-auth
|
|
29
|
+
CASSANDRA_AUTH_PORT: 9042
|
|
17
30
|
command: bash -c 'sleep infinity'
|
|
18
31
|
volumes:
|
|
19
32
|
- "./:/opt/ilios"
|
|
20
33
|
volumes:
|
|
21
34
|
cassandra-data:
|
|
22
35
|
driver: local
|
|
36
|
+
cassandra-auth-data:
|
|
37
|
+
driver: local
|
data/ext/ilios/cluster.c
CHANGED
|
@@ -86,16 +86,18 @@ static VALUE cluster_connect(VALUE self)
|
|
|
86
86
|
static VALUE cluster_hosts(VALUE self, VALUE hosts)
|
|
87
87
|
{
|
|
88
88
|
CassandraCluster *cassandra_cluster;
|
|
89
|
+
long length;
|
|
89
90
|
|
|
90
91
|
GET_CLUSTER(self, cassandra_cluster);
|
|
91
92
|
|
|
92
93
|
Check_Type(hosts, T_ARRAY);
|
|
93
|
-
|
|
94
|
+
length = RARRAY_LEN(hosts);
|
|
95
|
+
if (length == 0) {
|
|
94
96
|
rb_raise(rb_eArgError, "No host exists.");
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
for (
|
|
98
|
-
VALUE host =
|
|
99
|
+
for (long i = 0; i < length && i < RARRAY_LEN(hosts); i++) {
|
|
100
|
+
VALUE host = rb_ary_entry(hosts, i);
|
|
99
101
|
cass_cluster_set_contact_points(cassandra_cluster->cluster, StringValueCStr(host));
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -141,7 +143,7 @@ static VALUE cluster_keyspace(VALUE self, VALUE keyspace)
|
|
|
141
143
|
* Sets the protocol version. The driver will automatically downgrade to the lowest supported protocol version.
|
|
142
144
|
* Default is +PROTOCOL_VERSION_V4+.
|
|
143
145
|
*
|
|
144
|
-
* @param
|
|
146
|
+
* @param version [Integer] A protocol version.
|
|
145
147
|
* @return [Cassandra::Cluster] self.
|
|
146
148
|
*/
|
|
147
149
|
static VALUE cluster_protocol_version(VALUE self, VALUE version)
|
|
@@ -226,6 +228,427 @@ static VALUE cluster_constant_speculative_execution_policy(VALUE self, VALUE con
|
|
|
226
228
|
return self;
|
|
227
229
|
}
|
|
228
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Sets credentials for plain text authentication.
|
|
233
|
+
*
|
|
234
|
+
* @param username [String] A username.
|
|
235
|
+
* @param password [String] A password.
|
|
236
|
+
* @return [Cassandra::Cluster] self.
|
|
237
|
+
*/
|
|
238
|
+
static VALUE cluster_credentials(VALUE self, VALUE username, VALUE password)
|
|
239
|
+
{
|
|
240
|
+
CassandraCluster *cassandra_cluster;
|
|
241
|
+
|
|
242
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
243
|
+
// The driver copies both strings into its own memory
|
|
244
|
+
// (cluster_config.cpp: cass_cluster_set_credentials_n), so the Ruby
|
|
245
|
+
// strings do not need to be retained.
|
|
246
|
+
cass_cluster_set_credentials(cassandra_cluster->cluster, StringValueCStr(username), StringValueCStr(password));
|
|
247
|
+
|
|
248
|
+
return self;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
static void cluster_check_error(CassError error, const char *name)
|
|
252
|
+
{
|
|
253
|
+
if (error != CASS_OK) {
|
|
254
|
+
rb_raise(rb_eArgError, "Invalid %s: %s", name, cass_error_desc(error));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Casting a negative value to unsigned wraps it into a huge number, so check
|
|
259
|
+
// the range on the signed value NUM2LONG/NUM2LL already produced. Converting a
|
|
260
|
+
// second time would run to_int again, which may return a different value.
|
|
261
|
+
static unsigned cluster_value_to_uint(VALUE value, const char *name)
|
|
262
|
+
{
|
|
263
|
+
long v = NUM2LONG(value);
|
|
264
|
+
|
|
265
|
+
if (v < 0 || v > UINT_MAX) {
|
|
266
|
+
rb_raise(rb_eRangeError, "Invalid %s: %ld", name, v);
|
|
267
|
+
}
|
|
268
|
+
return (unsigned)v;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static cass_uint64_t cluster_value_to_uint64(VALUE value, const char *name)
|
|
272
|
+
{
|
|
273
|
+
long long v = NUM2LL(value);
|
|
274
|
+
|
|
275
|
+
if (v < 0) {
|
|
276
|
+
rb_raise(rb_eRangeError, "Invalid %s: %lld", name, v);
|
|
277
|
+
}
|
|
278
|
+
return (cass_uint64_t)v;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// The driver only rejects CASS_CONSISTENCY_UNKNOWN at set time; any other
|
|
282
|
+
// out-of-range value is accepted and later fails every query with an
|
|
283
|
+
// opaque protocol error, so validate the range here.
|
|
284
|
+
static void cluster_check_consistency(long value, const char *name)
|
|
285
|
+
{
|
|
286
|
+
if (value < CASS_CONSISTENCY_ANY || value > CASS_CONSISTENCY_LOCAL_ONE) {
|
|
287
|
+
rb_raise(rb_eArgError, "Invalid %s: %ld", name, value);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static struct {
|
|
292
|
+
const char *name;
|
|
293
|
+
CassConsistency consistency;
|
|
294
|
+
ID id;
|
|
295
|
+
} cluster_consistency_symbols[] = {
|
|
296
|
+
{ "any", CASS_CONSISTENCY_ANY, 0 },
|
|
297
|
+
{ "one", CASS_CONSISTENCY_ONE, 0 },
|
|
298
|
+
{ "two", CASS_CONSISTENCY_TWO, 0 },
|
|
299
|
+
{ "three", CASS_CONSISTENCY_THREE, 0 },
|
|
300
|
+
{ "quorum", CASS_CONSISTENCY_QUORUM, 0 },
|
|
301
|
+
{ "all", CASS_CONSISTENCY_ALL, 0 },
|
|
302
|
+
{ "local_quorum", CASS_CONSISTENCY_LOCAL_QUORUM, 0 },
|
|
303
|
+
{ "each_quorum", CASS_CONSISTENCY_EACH_QUORUM, 0 },
|
|
304
|
+
{ "serial", CASS_CONSISTENCY_SERIAL, 0 },
|
|
305
|
+
{ "local_serial", CASS_CONSISTENCY_LOCAL_SERIAL, 0 },
|
|
306
|
+
{ "local_one", CASS_CONSISTENCY_LOCAL_ONE, 0 },
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
// Accepts either an Integer consistency constant or a Symbol such as
|
|
310
|
+
// +:quorum+/+:local_serial+ naming one of the CONSISTENCY_* constants.
|
|
311
|
+
static CassConsistency cluster_value_to_consistency(VALUE value, const char *name)
|
|
312
|
+
{
|
|
313
|
+
long v;
|
|
314
|
+
|
|
315
|
+
if (SYMBOL_P(value)) {
|
|
316
|
+
// rb_sym2id would intern an unknown Symbol and leave it uncollectable, so
|
|
317
|
+
// repeated invalid values grow memory with no way to reclaim it.
|
|
318
|
+
VALUE name_value = value;
|
|
319
|
+
ID id = rb_check_id(&name_value);
|
|
320
|
+
|
|
321
|
+
for (size_t i = 0; id && i < sizeof(cluster_consistency_symbols) / sizeof(cluster_consistency_symbols[0]); i++) {
|
|
322
|
+
if (id == cluster_consistency_symbols[i].id) {
|
|
323
|
+
return cluster_consistency_symbols[i].consistency;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
rb_raise(rb_eArgError, "Invalid %s: %"PRIsVALUE"", name, value);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
v = NUM2LONG(value);
|
|
330
|
+
cluster_check_consistency(v, name);
|
|
331
|
+
return (CassConsistency)v;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Sets the default consistency level of the statement.
|
|
336
|
+
* Default is +CONSISTENCY_LOCAL_ONE+.
|
|
337
|
+
*
|
|
338
|
+
* @param consistency [Integer, Symbol] A consistency level.
|
|
339
|
+
* Symbols such as +:quorum+ or +:local_serial+ are also accepted.
|
|
340
|
+
* @return [Cassandra::Cluster] self.
|
|
341
|
+
* @raise [ArgumentError] If an invalid consistency level was given.
|
|
342
|
+
* @raise [RangeError] If the value does not fit in a C long.
|
|
343
|
+
*/
|
|
344
|
+
static VALUE cluster_consistency(VALUE self, VALUE consistency)
|
|
345
|
+
{
|
|
346
|
+
CassandraCluster *cassandra_cluster;
|
|
347
|
+
CassConsistency consistency_value = cluster_value_to_consistency(consistency, "consistency");
|
|
348
|
+
|
|
349
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
350
|
+
cluster_check_error(cass_cluster_set_consistency(cassandra_cluster->cluster, consistency_value), "consistency");
|
|
351
|
+
|
|
352
|
+
return self;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Sets the default serial consistency level of the statement.
|
|
357
|
+
* Default is +CONSISTENCY_ANY+.
|
|
358
|
+
*
|
|
359
|
+
* @param consistency [Integer, Symbol] A serial consistency level. Only
|
|
360
|
+
* +CONSISTENCY_SERIAL+/+CONSISTENCY_LOCAL_SERIAL+ (or +:serial+/+:local_serial+)
|
|
361
|
+
* are accepted.
|
|
362
|
+
* @return [Cassandra::Cluster] self.
|
|
363
|
+
* @raise [ArgumentError] If an invalid consistency level was given, or if it is
|
|
364
|
+
* not +CONSISTENCY_SERIAL+ or +CONSISTENCY_LOCAL_SERIAL+.
|
|
365
|
+
* @raise [RangeError] If the value does not fit in a C long.
|
|
366
|
+
*/
|
|
367
|
+
static VALUE cluster_serial_consistency(VALUE self, VALUE consistency)
|
|
368
|
+
{
|
|
369
|
+
CassandraCluster *cassandra_cluster;
|
|
370
|
+
CassConsistency consistency_value = cluster_value_to_consistency(consistency, "serial_consistency");
|
|
371
|
+
|
|
372
|
+
// Cassandra only accepts SERIAL/LOCAL_SERIAL as a serial consistency
|
|
373
|
+
// level (used for lightweight transactions); any other value passes
|
|
374
|
+
// the generic range check above but is later rejected by the server
|
|
375
|
+
// at query time with an opaque error, so validate it here.
|
|
376
|
+
if (consistency_value != CASS_CONSISTENCY_SERIAL && consistency_value != CASS_CONSISTENCY_LOCAL_SERIAL) {
|
|
377
|
+
rb_raise(rb_eArgError, "Invalid serial_consistency: %"PRIsVALUE"", consistency);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
381
|
+
cluster_check_error(cass_cluster_set_serial_consistency(cassandra_cluster->cluster, consistency_value), "serial_consistency");
|
|
382
|
+
|
|
383
|
+
return self;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Sets the number of IO threads that will handle query requests.
|
|
388
|
+
* Default is +1+.
|
|
389
|
+
*
|
|
390
|
+
* @param num_threads [Integer] A number of IO threads.
|
|
391
|
+
* @return [Cassandra::Cluster] self.
|
|
392
|
+
* @raise [ArgumentError] If zero was given.
|
|
393
|
+
* @raise [RangeError] If a negative value was given.
|
|
394
|
+
*/
|
|
395
|
+
static VALUE cluster_num_threads_io(VALUE self, VALUE num_threads)
|
|
396
|
+
{
|
|
397
|
+
CassandraCluster *cassandra_cluster;
|
|
398
|
+
|
|
399
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
400
|
+
cluster_check_error(cass_cluster_set_num_threads_io(cassandra_cluster->cluster, cluster_value_to_uint(num_threads, "num_threads_io")), "num_threads_io");
|
|
401
|
+
|
|
402
|
+
return self;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Sets the size of the fixed size queue that stores pending requests.
|
|
407
|
+
* Default is +8192+.
|
|
408
|
+
*
|
|
409
|
+
* @param queue_size [Integer] A queue size.
|
|
410
|
+
* @return [Cassandra::Cluster] self.
|
|
411
|
+
* @raise [ArgumentError] If zero was given.
|
|
412
|
+
* @raise [RangeError] If a negative value was given.
|
|
413
|
+
*/
|
|
414
|
+
static VALUE cluster_queue_size_io(VALUE self, VALUE queue_size)
|
|
415
|
+
{
|
|
416
|
+
CassandraCluster *cassandra_cluster;
|
|
417
|
+
|
|
418
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
419
|
+
cluster_check_error(cass_cluster_set_queue_size_io(cassandra_cluster->cluster, cluster_value_to_uint(queue_size, "queue_size_io")), "queue_size_io");
|
|
420
|
+
|
|
421
|
+
return self;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Sets the number of connections made to each server in each IO thread.
|
|
426
|
+
* Default is +1+.
|
|
427
|
+
*
|
|
428
|
+
* @param num_connections [Integer] A number of connections.
|
|
429
|
+
* @return [Cassandra::Cluster] self.
|
|
430
|
+
* @raise [ArgumentError] If zero was given.
|
|
431
|
+
* @raise [RangeError] If a negative value was given.
|
|
432
|
+
*/
|
|
433
|
+
static VALUE cluster_core_connections_per_host(VALUE self, VALUE num_connections)
|
|
434
|
+
{
|
|
435
|
+
CassandraCluster *cassandra_cluster;
|
|
436
|
+
|
|
437
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
438
|
+
cluster_check_error(cass_cluster_set_core_connections_per_host(cassandra_cluster->cluster, cluster_value_to_uint(num_connections, "core_connections_per_host")), "core_connections_per_host");
|
|
439
|
+
|
|
440
|
+
return self;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Configures the cluster to use a reconnection policy that waits a constant
|
|
445
|
+
* time between each reconnection attempt.
|
|
446
|
+
* The exponential policy is used unless this method is called.
|
|
447
|
+
*
|
|
448
|
+
* @param delay_ms [Integer] A delay in milliseconds.
|
|
449
|
+
* @return [Cassandra::Cluster] self.
|
|
450
|
+
* @raise [RangeError] If a negative value was given.
|
|
451
|
+
*/
|
|
452
|
+
static VALUE cluster_constant_reconnect(VALUE self, VALUE delay_ms)
|
|
453
|
+
{
|
|
454
|
+
CassandraCluster *cassandra_cluster;
|
|
455
|
+
|
|
456
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
457
|
+
cass_cluster_set_constant_reconnect(cassandra_cluster->cluster, cluster_value_to_uint64(delay_ms, "constant_reconnect"));
|
|
458
|
+
|
|
459
|
+
return self;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Configures the cluster to use a reconnection policy that waits
|
|
464
|
+
* exponentially longer between each reconnection attempt; however
|
|
465
|
+
* will maintain a constant delay once the maximum delay is reached.
|
|
466
|
+
* This is the default policy, with a base delay of +2000+ milliseconds and
|
|
467
|
+
* a maximum delay of +60000+ milliseconds.
|
|
468
|
+
*
|
|
469
|
+
* @param base_delay_ms [Integer] A base delay in milliseconds.
|
|
470
|
+
* @param max_delay_ms [Integer] A maximum delay in milliseconds.
|
|
471
|
+
* @return [Cassandra::Cluster] self.
|
|
472
|
+
* @raise [ArgumentError] If the base delay is 1 or less, the maximum delay is 1 or less,
|
|
473
|
+
* or the maximum delay is less than the base delay.
|
|
474
|
+
* @raise [RangeError] If a negative value was given.
|
|
475
|
+
*/
|
|
476
|
+
static VALUE cluster_exponential_reconnect(VALUE self, VALUE base_delay_ms, VALUE max_delay_ms)
|
|
477
|
+
{
|
|
478
|
+
CassandraCluster *cassandra_cluster;
|
|
479
|
+
|
|
480
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
481
|
+
cluster_check_error(cass_cluster_set_exponential_reconnect(cassandra_cluster->cluster, cluster_value_to_uint64(base_delay_ms, "exponential_reconnect base_delay_ms"), cluster_value_to_uint64(max_delay_ms, "exponential_reconnect max_delay_ms")), "exponential_reconnect");
|
|
482
|
+
|
|
483
|
+
return self;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Enables/Disables Nagle's algorithm on the connections.
|
|
488
|
+
* Default is +true+ (disables Nagle's algorithm).
|
|
489
|
+
*
|
|
490
|
+
* @param enabled [Boolean] Whether to disable Nagle's algorithm.
|
|
491
|
+
* @return [Cassandra::Cluster] self.
|
|
492
|
+
*/
|
|
493
|
+
static VALUE cluster_tcp_nodelay(VALUE self, VALUE enabled)
|
|
494
|
+
{
|
|
495
|
+
CassandraCluster *cassandra_cluster;
|
|
496
|
+
|
|
497
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
498
|
+
cass_cluster_set_tcp_nodelay(cassandra_cluster->cluster, RTEST(enabled) ? cass_true : cass_false);
|
|
499
|
+
|
|
500
|
+
return self;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Enables/Disables TCP keep-alive.
|
|
505
|
+
* Default is +false+ (disabled).
|
|
506
|
+
*
|
|
507
|
+
* @param enabled [Boolean] Whether to enable TCP keep-alive.
|
|
508
|
+
* @param delay_secs [Integer] The initial delay in seconds. Ignored when disabled.
|
|
509
|
+
* @return [Cassandra::Cluster] self.
|
|
510
|
+
* @raise [RangeError] If a negative value was given.
|
|
511
|
+
*/
|
|
512
|
+
static VALUE cluster_tcp_keepalive(VALUE self, VALUE enabled, VALUE delay_secs)
|
|
513
|
+
{
|
|
514
|
+
CassandraCluster *cassandra_cluster;
|
|
515
|
+
|
|
516
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
517
|
+
cass_cluster_set_tcp_keepalive(cassandra_cluster->cluster, RTEST(enabled) ? cass_true : cass_false, cluster_value_to_uint(delay_secs, "tcp_keepalive delay_secs"));
|
|
518
|
+
|
|
519
|
+
return self;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Sets the amount of time between heartbeat messages and controls the amount
|
|
524
|
+
* of time the connection must be idle before sending heartbeat messages.
|
|
525
|
+
* This is useful for preventing intermediate network devices from dropping connections.
|
|
526
|
+
* Default is +30+ seconds.
|
|
527
|
+
*
|
|
528
|
+
* @param interval_secs [Integer] An interval in seconds. +0+ disables heartbeat messages.
|
|
529
|
+
* @return [Cassandra::Cluster] self.
|
|
530
|
+
* @raise [RangeError] If a negative value was given.
|
|
531
|
+
*/
|
|
532
|
+
static VALUE cluster_connection_heartbeat_interval(VALUE self, VALUE interval_secs)
|
|
533
|
+
{
|
|
534
|
+
CassandraCluster *cassandra_cluster;
|
|
535
|
+
|
|
536
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
537
|
+
cass_cluster_set_connection_heartbeat_interval(cassandra_cluster->cluster, cluster_value_to_uint(interval_secs, "connection_heartbeat_interval"));
|
|
538
|
+
|
|
539
|
+
return self;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Sets the amount of time a connection is allowed to be without a successful
|
|
544
|
+
* heartbeat response before being terminated and scheduled for reconnection.
|
|
545
|
+
* Default is +60+ seconds.
|
|
546
|
+
*
|
|
547
|
+
* @param timeout_secs [Integer] A timeout in seconds.
|
|
548
|
+
* @return [Cassandra::Cluster] self.
|
|
549
|
+
* @raise [RangeError] If a negative value was given.
|
|
550
|
+
*/
|
|
551
|
+
static VALUE cluster_connection_idle_timeout(VALUE self, VALUE timeout_secs)
|
|
552
|
+
{
|
|
553
|
+
CassandraCluster *cassandra_cluster;
|
|
554
|
+
|
|
555
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
556
|
+
cass_cluster_set_connection_idle_timeout(cassandra_cluster->cluster, cluster_value_to_uint(timeout_secs, "connection_idle_timeout"));
|
|
557
|
+
|
|
558
|
+
return self;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Configures the cluster to use round-robin load balancing.
|
|
563
|
+
* The driver discovers all nodes in a cluster and cycles through them per request.
|
|
564
|
+
*
|
|
565
|
+
* @return [Cassandra::Cluster] self.
|
|
566
|
+
*/
|
|
567
|
+
static VALUE cluster_load_balance_round_robin(VALUE self)
|
|
568
|
+
{
|
|
569
|
+
CassandraCluster *cassandra_cluster;
|
|
570
|
+
|
|
571
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
572
|
+
cass_cluster_set_load_balance_round_robin(cassandra_cluster->cluster);
|
|
573
|
+
|
|
574
|
+
return self;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Configures the cluster to use DC-aware load balancing.
|
|
579
|
+
* For each query, all live nodes in a primary 'local' DC are tried first,
|
|
580
|
+
* followed by any node from other DCs.
|
|
581
|
+
*
|
|
582
|
+
* @param local_dc [String] The primary data center to try first.
|
|
583
|
+
* @return [Cassandra::Cluster] self.
|
|
584
|
+
* @raise [ArgumentError] If an invalid data center name was given.
|
|
585
|
+
*/
|
|
586
|
+
static VALUE cluster_load_balance_dc_aware(VALUE self, VALUE local_dc)
|
|
587
|
+
{
|
|
588
|
+
CassandraCluster *cassandra_cluster;
|
|
589
|
+
|
|
590
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
591
|
+
// The 3rd and 4th parameters (used_hosts_per_remote_dc and
|
|
592
|
+
// allow_remote_dcs_for_local_cl) are deprecated in driver 2.16, so they
|
|
593
|
+
// are fixed to 0/cass_false and not exposed to Ruby.
|
|
594
|
+
cluster_check_error(cass_cluster_set_load_balance_dc_aware(cassandra_cluster->cluster, StringValueCStr(local_dc), 0, cass_false), "load_balance_dc_aware");
|
|
595
|
+
|
|
596
|
+
return self;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Configures the cluster to use token-aware request routing or not.
|
|
601
|
+
* Default is +true+ (enabled).
|
|
602
|
+
*
|
|
603
|
+
* @param enabled [Boolean] Whether to enable token-aware routing.
|
|
604
|
+
* @return [Cassandra::Cluster] self.
|
|
605
|
+
*/
|
|
606
|
+
static VALUE cluster_token_aware_routing(VALUE self, VALUE enabled)
|
|
607
|
+
{
|
|
608
|
+
CassandraCluster *cassandra_cluster;
|
|
609
|
+
|
|
610
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
611
|
+
cass_cluster_set_token_aware_routing(cassandra_cluster->cluster, RTEST(enabled) ? cass_true : cass_false);
|
|
612
|
+
|
|
613
|
+
return self;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Configures the cluster to use latency-aware request routing or not.
|
|
618
|
+
* Default is +false+ (disabled).
|
|
619
|
+
*
|
|
620
|
+
* @param enabled [Boolean] Whether to enable latency-aware routing.
|
|
621
|
+
* @return [Cassandra::Cluster] self.
|
|
622
|
+
*/
|
|
623
|
+
static VALUE cluster_latency_aware_routing(VALUE self, VALUE enabled)
|
|
624
|
+
{
|
|
625
|
+
CassandraCluster *cassandra_cluster;
|
|
626
|
+
|
|
627
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
628
|
+
cass_cluster_set_latency_aware_routing(cassandra_cluster->cluster, RTEST(enabled) ? cass_true : cass_false);
|
|
629
|
+
|
|
630
|
+
return self;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Enables/Disables retrieving and updating schema metadata. Disabling this
|
|
635
|
+
* can be useful to improve startup performance, but it means that
|
|
636
|
+
* 'Session#schema_metadata'-like features will not work.
|
|
637
|
+
* Default is +true+ (enabled).
|
|
638
|
+
*
|
|
639
|
+
* @param enabled [Boolean] Whether to keep schema metadata synchronized.
|
|
640
|
+
* @return [Cassandra::Cluster] self.
|
|
641
|
+
*/
|
|
642
|
+
static VALUE cluster_use_schema(VALUE self, VALUE enabled)
|
|
643
|
+
{
|
|
644
|
+
CassandraCluster *cassandra_cluster;
|
|
645
|
+
|
|
646
|
+
GET_CLUSTER(self, cassandra_cluster);
|
|
647
|
+
cass_cluster_set_use_schema(cassandra_cluster->cluster, RTEST(enabled) ? cass_true : cass_false);
|
|
648
|
+
|
|
649
|
+
return self;
|
|
650
|
+
}
|
|
651
|
+
|
|
229
652
|
static void cluster_mark(void *ptr)
|
|
230
653
|
{
|
|
231
654
|
CassandraCluster *cassandra_cluster = (CassandraCluster *)ptr;
|
|
@@ -256,6 +679,10 @@ static void cluster_compact(void *ptr)
|
|
|
256
679
|
|
|
257
680
|
void Init_cluster(void)
|
|
258
681
|
{
|
|
682
|
+
for (size_t i = 0; i < sizeof(cluster_consistency_symbols) / sizeof(cluster_consistency_symbols[0]); i++) {
|
|
683
|
+
cluster_consistency_symbols[i].id = rb_intern(cluster_consistency_symbols[i].name);
|
|
684
|
+
}
|
|
685
|
+
|
|
259
686
|
rb_define_alloc_func(cCluster, cluster_allocator);
|
|
260
687
|
rb_define_method(cCluster, "initialize", cluster_initialize, 0);
|
|
261
688
|
rb_define_method(cCluster, "connect", cluster_connect, 0);
|
|
@@ -267,6 +694,23 @@ void Init_cluster(void)
|
|
|
267
694
|
rb_define_method(cCluster, "request_timeout", cluster_request_timeout, 1);
|
|
268
695
|
rb_define_method(cCluster, "resolve_timeout", cluster_resolve_timeout, 1);
|
|
269
696
|
rb_define_method(cCluster, "constant_speculative_execution_policy", cluster_constant_speculative_execution_policy, 2);
|
|
697
|
+
rb_define_method(cCluster, "credentials", cluster_credentials, 2);
|
|
698
|
+
rb_define_method(cCluster, "consistency", cluster_consistency, 1);
|
|
699
|
+
rb_define_method(cCluster, "serial_consistency", cluster_serial_consistency, 1);
|
|
700
|
+
rb_define_method(cCluster, "num_threads_io", cluster_num_threads_io, 1);
|
|
701
|
+
rb_define_method(cCluster, "queue_size_io", cluster_queue_size_io, 1);
|
|
702
|
+
rb_define_method(cCluster, "core_connections_per_host", cluster_core_connections_per_host, 1);
|
|
703
|
+
rb_define_method(cCluster, "constant_reconnect", cluster_constant_reconnect, 1);
|
|
704
|
+
rb_define_method(cCluster, "exponential_reconnect", cluster_exponential_reconnect, 2);
|
|
705
|
+
rb_define_method(cCluster, "tcp_nodelay", cluster_tcp_nodelay, 1);
|
|
706
|
+
rb_define_method(cCluster, "tcp_keepalive", cluster_tcp_keepalive, 2);
|
|
707
|
+
rb_define_method(cCluster, "connection_heartbeat_interval", cluster_connection_heartbeat_interval, 1);
|
|
708
|
+
rb_define_method(cCluster, "connection_idle_timeout", cluster_connection_idle_timeout, 1);
|
|
709
|
+
rb_define_method(cCluster, "load_balance_round_robin", cluster_load_balance_round_robin, 0);
|
|
710
|
+
rb_define_method(cCluster, "load_balance_dc_aware", cluster_load_balance_dc_aware, 1);
|
|
711
|
+
rb_define_method(cCluster, "token_aware_routing", cluster_token_aware_routing, 1);
|
|
712
|
+
rb_define_method(cCluster, "latency_aware_routing", cluster_latency_aware_routing, 1);
|
|
713
|
+
rb_define_method(cCluster, "use_schema", cluster_use_schema, 1);
|
|
270
714
|
|
|
271
715
|
rb_define_const(cCluster, "PROTOCOL_VERSION_V1", INT2NUM(CASS_PROTOCOL_VERSION_V1));
|
|
272
716
|
rb_define_const(cCluster, "PROTOCOL_VERSION_V2", INT2NUM(CASS_PROTOCOL_VERSION_V2));
|
|
@@ -275,4 +719,16 @@ void Init_cluster(void)
|
|
|
275
719
|
rb_define_const(cCluster, "PROTOCOL_VERSION_V5", INT2NUM(CASS_PROTOCOL_VERSION_V5));
|
|
276
720
|
rb_define_const(cCluster, "PROTOCOL_VERSION_DSEV1", INT2NUM(CASS_PROTOCOL_VERSION_DSEV1));
|
|
277
721
|
rb_define_const(cCluster, "PROTOCOL_VERSION_DSEV2", INT2NUM(CASS_PROTOCOL_VERSION_DSEV2));
|
|
722
|
+
|
|
723
|
+
rb_define_const(cCluster, "CONSISTENCY_ANY", INT2NUM(CASS_CONSISTENCY_ANY));
|
|
724
|
+
rb_define_const(cCluster, "CONSISTENCY_ONE", INT2NUM(CASS_CONSISTENCY_ONE));
|
|
725
|
+
rb_define_const(cCluster, "CONSISTENCY_TWO", INT2NUM(CASS_CONSISTENCY_TWO));
|
|
726
|
+
rb_define_const(cCluster, "CONSISTENCY_THREE", INT2NUM(CASS_CONSISTENCY_THREE));
|
|
727
|
+
rb_define_const(cCluster, "CONSISTENCY_QUORUM", INT2NUM(CASS_CONSISTENCY_QUORUM));
|
|
728
|
+
rb_define_const(cCluster, "CONSISTENCY_ALL", INT2NUM(CASS_CONSISTENCY_ALL));
|
|
729
|
+
rb_define_const(cCluster, "CONSISTENCY_LOCAL_QUORUM", INT2NUM(CASS_CONSISTENCY_LOCAL_QUORUM));
|
|
730
|
+
rb_define_const(cCluster, "CONSISTENCY_EACH_QUORUM", INT2NUM(CASS_CONSISTENCY_EACH_QUORUM));
|
|
731
|
+
rb_define_const(cCluster, "CONSISTENCY_SERIAL", INT2NUM(CASS_CONSISTENCY_SERIAL));
|
|
732
|
+
rb_define_const(cCluster, "CONSISTENCY_LOCAL_SERIAL", INT2NUM(CASS_CONSISTENCY_LOCAL_SERIAL));
|
|
733
|
+
rb_define_const(cCluster, "CONSISTENCY_LOCAL_ONE", INT2NUM(CASS_CONSISTENCY_LOCAL_ONE));
|
|
278
734
|
}
|
data/ext/ilios/statement.c
CHANGED
|
@@ -428,7 +428,7 @@ static VALUE statement_snapshot_value(const CassDataType *data_type, VALUE value
|
|
|
428
428
|
|
|
429
429
|
length = RARRAY_LEN(array);
|
|
430
430
|
snapshot = rb_ary_new_capa(length);
|
|
431
|
-
for (long i = 0; i < RARRAY_LEN(array); i++) {
|
|
431
|
+
for (long i = 0; i < length && i < RARRAY_LEN(array); i++) {
|
|
432
432
|
rb_ary_push(snapshot, statement_snapshot_value(element_type, rb_ary_entry(array, i)));
|
|
433
433
|
}
|
|
434
434
|
return rb_ary_freeze(snapshot);
|
data/lib/ilios/version.rb
CHANGED
data/sig/ilios.rbs
CHANGED
|
@@ -21,6 +21,18 @@ module Ilios
|
|
|
21
21
|
PROTOCOL_VERSION_DSEV1: Integer
|
|
22
22
|
PROTOCOL_VERSION_DSEV2: Integer
|
|
23
23
|
|
|
24
|
+
CONSISTENCY_ANY: Integer
|
|
25
|
+
CONSISTENCY_ONE: Integer
|
|
26
|
+
CONSISTENCY_TWO: Integer
|
|
27
|
+
CONSISTENCY_THREE: Integer
|
|
28
|
+
CONSISTENCY_QUORUM: Integer
|
|
29
|
+
CONSISTENCY_ALL: Integer
|
|
30
|
+
CONSISTENCY_LOCAL_QUORUM: Integer
|
|
31
|
+
CONSISTENCY_EACH_QUORUM: Integer
|
|
32
|
+
CONSISTENCY_SERIAL: Integer
|
|
33
|
+
CONSISTENCY_LOCAL_SERIAL: Integer
|
|
34
|
+
CONSISTENCY_LOCAL_ONE: Integer
|
|
35
|
+
|
|
24
36
|
def connect: () -> Ilios::Cassandra::Session
|
|
25
37
|
def hosts: (Array[String]) -> self
|
|
26
38
|
def port: (Integer) -> self
|
|
@@ -30,6 +42,23 @@ module Ilios
|
|
|
30
42
|
def request_timeout: (Integer) -> self
|
|
31
43
|
def resolve_timeout: (Integer) -> self
|
|
32
44
|
def constant_speculative_execution_policy: (Integer, Integer) -> self
|
|
45
|
+
def credentials: (String, String) -> self
|
|
46
|
+
def consistency: (Integer | Symbol) -> self
|
|
47
|
+
def serial_consistency: (Integer | Symbol) -> self
|
|
48
|
+
def num_threads_io: (Integer) -> self
|
|
49
|
+
def queue_size_io: (Integer) -> self
|
|
50
|
+
def core_connections_per_host: (Integer) -> self
|
|
51
|
+
def constant_reconnect: (Integer) -> self
|
|
52
|
+
def exponential_reconnect: (Integer, Integer) -> self
|
|
53
|
+
def tcp_nodelay: (bool) -> self
|
|
54
|
+
def tcp_keepalive: (bool, Integer) -> self
|
|
55
|
+
def connection_heartbeat_interval: (Integer) -> self
|
|
56
|
+
def connection_idle_timeout: (Integer) -> self
|
|
57
|
+
def load_balance_round_robin: () -> self
|
|
58
|
+
def load_balance_dc_aware: (String) -> self
|
|
59
|
+
def token_aware_routing: (bool) -> self
|
|
60
|
+
def latency_aware_routing: (bool) -> self
|
|
61
|
+
def use_schema: (bool) -> self
|
|
33
62
|
end
|
|
34
63
|
|
|
35
64
|
class Session
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ilios
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Watson
|
|
@@ -58,7 +58,7 @@ metadata:
|
|
|
58
58
|
homepage_uri: https://github.com/Watson1978/ilios
|
|
59
59
|
source_code_uri: https://github.com/Watson1978/ilios
|
|
60
60
|
bug_tracker_uri: https://github.com/Watson1978/ilios/issues
|
|
61
|
-
documentation_uri: https://www.rubydoc.info/gems/ilios/1.1.
|
|
61
|
+
documentation_uri: https://www.rubydoc.info/gems/ilios/1.1.2
|
|
62
62
|
rubygems_mfa_required: 'true'
|
|
63
63
|
rdoc_options: []
|
|
64
64
|
require_paths:
|