cql-rb 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -4
- data/lib/cql/client/query_result.rb +4 -1
- data/lib/cql/compression/lz4_compressor.rb +46 -0
- data/lib/cql/protocol/cql_byte_buffer.rb +8 -4
- data/lib/cql/protocol/cql_protocol_handler.rb +41 -15
- data/lib/cql/time_uuid.rb +3 -3
- data/lib/cql/version.rb +1 -1
- data/spec/cql/compression/compression_common.rb +14 -2
- data/spec/cql/compression/lz4_compressor_spec.rb +23 -0
- data/spec/cql/compression/snappy_compressor_spec.rb +1 -1
- data/spec/cql/protocol/cql_byte_buffer_spec.rb +10 -0
- data/spec/cql/time_uuid_spec.rb +6 -0
- data/spec/integration/client_spec.rb +35 -19
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3f3bbe6a70ee126fc4ebcf7a33fcd19812bbc69
|
4
|
+
data.tar.gz: 28c7bf1d6d92bd3ac5fb8e38155a7ea6ee06eef5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd921b73960d9bd46289cfe98d3a18239b09df793b1eed9cf87f7d7e211e0d71716aed118ef1a536149722f0939d8466a24aed27b063e8819325e4286262b300
|
7
|
+
data.tar.gz: 95de3b5aaf74d6c7a072ebe054fd4cd73b92b16a6ecb1d02e629d73b675df04e00d8fec3cd8c646ab47c060a08bd4962c6f4df2c4edae0f5efc1909f07050148
|
data/README.md
CHANGED
@@ -14,9 +14,7 @@ Cassandra 1.2 or later with the native transport protocol turned on and a modern
|
|
14
14
|
|
15
15
|
gem install cql-rb
|
16
16
|
|
17
|
-
if you want to use compression you should also install
|
18
|
-
|
19
|
-
gem install snappy
|
17
|
+
if you want to use compression you should also install [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby). See below for more information about compression.
|
20
18
|
|
21
19
|
# Quick start
|
22
20
|
|
@@ -270,7 +268,7 @@ Consistency is ignored for `USE`, `TRUNCATE`, `CREATE` and `ALTER` statements, a
|
|
270
268
|
|
271
269
|
The CQL protocol supports frame compression, which can give you a performance boost if your requests or responses are big. To enable it you can pass a compressor object when you connect.
|
272
270
|
|
273
|
-
Cassandra currently supports two compression algorithms: Snappy and LZ4.
|
271
|
+
Cassandra currently supports two compression algorithms: Snappy and LZ4. cql-rb supports both, but in order to use them you will have to install the [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby) gems separately. Once it's installed you can enable compression like this:
|
274
272
|
|
275
273
|
```ruby
|
276
274
|
require 'cql/compression/snappy_compressor'
|
@@ -279,6 +277,17 @@ compressor = Cql::Compression::SnappyCompressor.new
|
|
279
277
|
client = Cql::Client.connect(hosts: %w[localhost], compressor: compressor)
|
280
278
|
```
|
281
279
|
|
280
|
+
or
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
require 'cql/compression/lz4_compressor'
|
284
|
+
|
285
|
+
compressor = Cql::Compression::Lz4Compressor.new
|
286
|
+
client = Cql::Client.connect(hosts: %w[localhost], compressor: compressor)
|
287
|
+
```
|
288
|
+
|
289
|
+
Which one should you choose? On paper the LZ4 algorithm is more efficient and the one Cassandra defaults to for SSTable compression. They both achieve roughly the same compression ratio, but LZ4 does it quicker.
|
290
|
+
|
282
291
|
## Logging
|
283
292
|
|
284
293
|
You can pass a standard Ruby logger to the client to get some more information about what is going on:
|
@@ -187,10 +187,13 @@ module Cql
|
|
187
187
|
|
188
188
|
def ensure_materialized
|
189
189
|
unless @rows
|
190
|
-
@lock.
|
190
|
+
@lock.lock
|
191
|
+
begin
|
191
192
|
unless @rows
|
192
193
|
@rows = @lazy_rows.materialize(@raw_metadata)
|
193
194
|
end
|
195
|
+
ensure
|
196
|
+
@lock.unlock
|
194
197
|
end
|
195
198
|
end
|
196
199
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'lz4-ruby'
|
5
|
+
rescue LoadError => e
|
6
|
+
raise LoadError, %[LZ4 support requires the "lz4-ruby" gem: #{e.message}], e.backtrace
|
7
|
+
end
|
8
|
+
|
9
|
+
module Cql
|
10
|
+
module Compression
|
11
|
+
# A compressor that uses the LZ4 compression library.
|
12
|
+
#
|
13
|
+
# @note This compressor requires the [lz4-ruby](http://rubygems.org/gems/lz4-ruby)
|
14
|
+
# gem (v0.3.2 or later required).
|
15
|
+
class Lz4Compressor
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :algorithm
|
18
|
+
|
19
|
+
# @param [Integer] min_size (64) Don't compress frames smaller than
|
20
|
+
# this size (see {#compress?}).
|
21
|
+
def initialize(min_size=64)
|
22
|
+
@algorithm = 'lz4'.freeze
|
23
|
+
@min_size = min_size
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [true, false] will return false for frames smaller than the
|
27
|
+
# `min_size` given to the constructor.
|
28
|
+
def compress?(str)
|
29
|
+
str.bytesize > @min_size
|
30
|
+
end
|
31
|
+
|
32
|
+
def compress(str)
|
33
|
+
[str.bytesize, LZ4::Raw.compress(str.to_s).first].pack(BUFFER_FORMAT)
|
34
|
+
end
|
35
|
+
|
36
|
+
def decompress(str)
|
37
|
+
decompressed_size, compressed_data = str.to_s.unpack(BUFFER_FORMAT)
|
38
|
+
LZ4::Raw.decompress(compressed_data, decompressed_size).first
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
BUFFER_FORMAT = 'Na*'.freeze
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -251,10 +251,14 @@ module Cql
|
|
251
251
|
def append_varint(n)
|
252
252
|
num = n
|
253
253
|
bytes = []
|
254
|
-
|
255
|
-
bytes <<
|
256
|
-
|
257
|
-
|
254
|
+
if num == 0
|
255
|
+
bytes << 0
|
256
|
+
else
|
257
|
+
until num == 0
|
258
|
+
bytes << (num & 0xff)
|
259
|
+
num = num >> 8
|
260
|
+
break if num == -1
|
261
|
+
end
|
258
262
|
end
|
259
263
|
append(bytes.reverse.pack(Formats::BYTES_FORMAT))
|
260
264
|
end
|
@@ -58,13 +58,19 @@ module Cql
|
|
58
58
|
# connection has been set up, or to keep statistics specific to the
|
59
59
|
# connection this protocol handler wraps.
|
60
60
|
def []=(key, value)
|
61
|
-
@lock.
|
61
|
+
@lock.lock
|
62
|
+
@data[key] = value
|
63
|
+
ensure
|
64
|
+
@lock.unlock
|
62
65
|
end
|
63
66
|
|
64
67
|
# @see {#[]=}
|
65
68
|
# @return the value associated with the key
|
66
69
|
def [](key)
|
67
|
-
@lock.
|
70
|
+
@lock.lock
|
71
|
+
@data[key]
|
72
|
+
ensure
|
73
|
+
@lock.unlock
|
68
74
|
end
|
69
75
|
|
70
76
|
# @return [true, false] true if the underlying connection is connected
|
@@ -94,9 +100,10 @@ module Cql
|
|
94
100
|
#
|
95
101
|
# @yieldparam event [Cql::Protocol::EventResponse] an event sent by the server
|
96
102
|
def on_event(&listener)
|
97
|
-
@lock.
|
98
|
-
|
99
|
-
|
103
|
+
@lock.lock
|
104
|
+
@event_listeners += [listener]
|
105
|
+
ensure
|
106
|
+
@lock.unlock
|
100
107
|
end
|
101
108
|
|
102
109
|
# Serializes and send a request over the underlying connection.
|
@@ -119,19 +126,25 @@ module Cql
|
|
119
126
|
return Future.failed(NotConnectedError.new) if closed?
|
120
127
|
promise = RequestPromise.new(request, @frame_encoder)
|
121
128
|
id = nil
|
122
|
-
@lock.
|
129
|
+
@lock.lock
|
130
|
+
begin
|
123
131
|
if (id = next_stream_id)
|
124
132
|
@promises[id] = promise
|
125
133
|
end
|
134
|
+
ensure
|
135
|
+
@lock.unlock
|
126
136
|
end
|
127
137
|
if id
|
128
138
|
@connection.write do |buffer|
|
129
139
|
@frame_encoder.encode_frame(request, id, buffer)
|
130
140
|
end
|
131
141
|
else
|
132
|
-
@lock.
|
142
|
+
@lock.lock
|
143
|
+
begin
|
133
144
|
promise.encode_frame
|
134
145
|
@request_queue_in << promise
|
146
|
+
ensure
|
147
|
+
@lock.unlock
|
135
148
|
end
|
136
149
|
end
|
137
150
|
if timeout
|
@@ -196,9 +209,12 @@ module Cql
|
|
196
209
|
|
197
210
|
def notify_event_listeners(event_response)
|
198
211
|
event_listeners = nil
|
199
|
-
@lock.
|
212
|
+
@lock.lock
|
213
|
+
begin
|
200
214
|
event_listeners = @event_listeners
|
201
215
|
return if event_listeners.empty?
|
216
|
+
ensure
|
217
|
+
@lock.unlock
|
202
218
|
end
|
203
219
|
event_listeners.each do |listener|
|
204
220
|
listener.call(@current_frame.body) rescue nil
|
@@ -206,10 +222,13 @@ module Cql
|
|
206
222
|
end
|
207
223
|
|
208
224
|
def complete_request(id, response)
|
209
|
-
promise =
|
225
|
+
promise = nil
|
226
|
+
@lock.lock
|
227
|
+
begin
|
210
228
|
promise = @promises[id]
|
211
229
|
@promises[id] = nil
|
212
|
-
|
230
|
+
ensure
|
231
|
+
@lock.unlock
|
213
232
|
end
|
214
233
|
if response.is_a?(Protocol::SetKeyspaceResultResponse)
|
215
234
|
@keyspace = response.keyspace
|
@@ -220,16 +239,20 @@ module Cql
|
|
220
239
|
end
|
221
240
|
|
222
241
|
def flush_request_queue
|
223
|
-
@lock.
|
242
|
+
@lock.lock
|
243
|
+
begin
|
224
244
|
if @request_queue_out.empty? && !@request_queue_in.empty?
|
225
245
|
@request_queue_out = @request_queue_in
|
226
246
|
@request_queue_in = []
|
227
247
|
end
|
248
|
+
ensure
|
249
|
+
@lock.unlock
|
228
250
|
end
|
229
251
|
while true
|
230
252
|
id = nil
|
231
253
|
frame = nil
|
232
|
-
@lock.
|
254
|
+
@lock.lock
|
255
|
+
begin
|
233
256
|
if @request_queue_out.any? && (id = next_stream_id)
|
234
257
|
promise = @request_queue_out.shift
|
235
258
|
if promise.timed_out?
|
@@ -239,6 +262,8 @@ module Cql
|
|
239
262
|
@promises[id] = promise
|
240
263
|
end
|
241
264
|
end
|
265
|
+
ensure
|
266
|
+
@lock.unlock
|
242
267
|
end
|
243
268
|
if id
|
244
269
|
@frame_encoder.change_stream_id(id, frame)
|
@@ -271,10 +296,11 @@ module Cql
|
|
271
296
|
end
|
272
297
|
|
273
298
|
def next_stream_id
|
274
|
-
@promises.
|
275
|
-
|
299
|
+
if (stream_id = @promises.index(nil))
|
300
|
+
stream_id
|
301
|
+
else
|
302
|
+
nil
|
276
303
|
end
|
277
|
-
nil
|
278
304
|
end
|
279
305
|
end
|
280
306
|
end
|
data/lib/cql/time_uuid.rb
CHANGED
@@ -18,9 +18,9 @@ module Cql
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def <=>(other)
|
21
|
-
c = self.
|
22
|
-
return c
|
23
|
-
|
21
|
+
c = self.value <=> other.value
|
22
|
+
return c if c == 0
|
23
|
+
self.time_bits <=> other.time_bits
|
24
24
|
end
|
25
25
|
|
26
26
|
protected
|
data/lib/cql/version.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
|
6
|
-
shared_examples 'compressor' do |algorithm|
|
6
|
+
shared_examples 'compressor' do |algorithm, compressed_string|
|
7
7
|
describe '#algorithm' do
|
8
8
|
it %(returns "#{algorithm}") do
|
9
9
|
described_class.new.algorithm.should == algorithm
|
@@ -36,8 +36,20 @@ shared_examples 'compressor' do |algorithm|
|
|
36
36
|
compressed.bytesize.should be < input.bytesize
|
37
37
|
end
|
38
38
|
|
39
|
+
it 'compresses byte buffers' do
|
40
|
+
input = Cql::Protocol::CqlByteBuffer.new('hello' * 100)
|
41
|
+
compressed = compressor.compress(input)
|
42
|
+
compressed.should == compressor.compress(input.to_s)
|
43
|
+
end
|
44
|
+
|
39
45
|
it 'decompresses compressed strings' do
|
40
|
-
input =
|
46
|
+
input = compressed_string
|
47
|
+
decompressed = compressor.decompress(input)
|
48
|
+
decompressed.should == 'hellohellohellohellohello'
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'decompresses byte buffers' do
|
52
|
+
input = Cql::Protocol::CqlByteBuffer.new(compressed_string)
|
41
53
|
decompressed = compressor.decompress(input)
|
42
54
|
decompressed.should == 'hellohellohellohellohello'
|
43
55
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'cql/compression/compression_common'
|
5
|
+
|
6
|
+
|
7
|
+
module Cql
|
8
|
+
module Compression
|
9
|
+
begin
|
10
|
+
require 'cql/compression/lz4_compressor'
|
11
|
+
|
12
|
+
describe Lz4Compressor do
|
13
|
+
include_examples 'compressor', 'lz4', "\x00\x00\x01\xF4[hello\x05\x00Phello"
|
14
|
+
end
|
15
|
+
rescue LoadError => e
|
16
|
+
describe 'Lz4Compressor' do
|
17
|
+
it 'supports LZ4' do
|
18
|
+
pending e.message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -10,7 +10,7 @@ module Cql
|
|
10
10
|
require 'cql/compression/snappy_compressor'
|
11
11
|
|
12
12
|
describe SnappyCompressor do
|
13
|
-
include_examples 'compressor', 'snappy'
|
13
|
+
include_examples 'compressor', 'snappy', "\x19\x10helloN\x05\x00"
|
14
14
|
end
|
15
15
|
rescue LoadError => e
|
16
16
|
describe 'SnappyCompressor' do
|
@@ -810,6 +810,11 @@ module Cql
|
|
810
810
|
end
|
811
811
|
|
812
812
|
describe '#append_varint' do
|
813
|
+
it 'encodes zero' do
|
814
|
+
buffer.append_varint(0)
|
815
|
+
buffer.should eql_bytes("\x00")
|
816
|
+
end
|
817
|
+
|
813
818
|
it 'encodes a variable length integer' do
|
814
819
|
buffer.append_varint(1231312312331283012830129382342342412123)
|
815
820
|
buffer.should eql_bytes("\x03\x9EV \x15\f\x03\x9DK\x18\xCDI\\$?\a[")
|
@@ -843,6 +848,11 @@ module Cql
|
|
843
848
|
buffer.should eql_bytes("\x00\x00\x00\x12\r'\xFDI\xAD\x80f\x11g\xDCfV\xAA")
|
844
849
|
end
|
845
850
|
|
851
|
+
it 'encodes a 0.0 BigDecimal' do
|
852
|
+
buffer.append_decimal(BigDecimal.new('0.0'))
|
853
|
+
buffer.should eql_bytes("\x00\x00\x00\x01\x00")
|
854
|
+
end
|
855
|
+
|
846
856
|
it 'appends to the buffer' do
|
847
857
|
buffer << "\x99"
|
848
858
|
buffer.append_decimal(BigDecimal.new('1042342234234.123423435647768234'))
|
data/spec/cql/time_uuid_spec.rb
CHANGED
@@ -252,29 +252,45 @@ describe 'A CQL client' do
|
|
252
252
|
end
|
253
253
|
end
|
254
254
|
|
255
|
-
|
256
|
-
|
257
|
-
|
255
|
+
shared_examples 'with_compressor' do |compressor_impl|
|
256
|
+
let :client do
|
257
|
+
Cql::Client.connect(connection_options.merge(compressor: compressor))
|
258
|
+
end
|
258
259
|
|
259
|
-
|
260
|
-
|
261
|
-
|
260
|
+
let :compressor do
|
261
|
+
compressor_impl.new(0)
|
262
|
+
end
|
262
263
|
|
263
|
-
|
264
|
-
|
265
|
-
|
264
|
+
it 'compresses requests and decompresses responses' do
|
265
|
+
compressor.stub(:compress).and_call_original
|
266
|
+
compressor.stub(:decompress).and_call_original
|
267
|
+
client.execute('SELECT * FROM system.schema_keyspaces')
|
268
|
+
compressor.should have_received(:compress).at_least(1).times
|
269
|
+
compressor.should have_received(:decompress).at_least(1).times
|
270
|
+
end
|
271
|
+
end
|
266
272
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
273
|
+
shared_examples 'no_compressor' do
|
274
|
+
it 'compresses requests and decompresses responses' do
|
275
|
+
pending 'No compressor available for the current platform'
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
context 'with Snappy compression' do
|
280
|
+
begin
|
281
|
+
require 'cql/compression/snappy_compressor'
|
282
|
+
include_examples 'with_compressor', Cql::Compression::SnappyCompressor
|
274
283
|
rescue LoadError
|
275
|
-
|
276
|
-
|
277
|
-
|
284
|
+
include_examples 'no_compressor'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'with LZ4 compression' do
|
289
|
+
begin
|
290
|
+
require 'cql/compression/lz4_compressor'
|
291
|
+
include_examples 'with_compressor', Cql::Compression::Lz4Compressor
|
292
|
+
rescue LoadError
|
293
|
+
include_examples 'no_compressor'
|
278
294
|
end
|
279
295
|
end
|
280
296
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cql-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Hultberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ione
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/cql/client/result_metadata.rb
|
53
53
|
- lib/cql/client/void_result.rb
|
54
54
|
- lib/cql/compression.rb
|
55
|
+
- lib/cql/compression/lz4_compressor.rb
|
55
56
|
- lib/cql/compression/snappy_compressor.rb
|
56
57
|
- lib/cql/protocol.rb
|
57
58
|
- lib/cql/protocol/cql_byte_buffer.rb
|
@@ -105,6 +106,7 @@ files:
|
|
105
106
|
- spec/cql/client/request_runner_spec.rb
|
106
107
|
- spec/cql/client/void_result_spec.rb
|
107
108
|
- spec/cql/compression/compression_common.rb
|
109
|
+
- spec/cql/compression/lz4_compressor_spec.rb
|
108
110
|
- spec/cql/compression/snappy_compressor_spec.rb
|
109
111
|
- spec/cql/protocol/cql_byte_buffer_spec.rb
|
110
112
|
- spec/cql/protocol/cql_protocol_handler_spec.rb
|
@@ -187,6 +189,7 @@ test_files:
|
|
187
189
|
- spec/cql/client/request_runner_spec.rb
|
188
190
|
- spec/cql/client/void_result_spec.rb
|
189
191
|
- spec/cql/compression/compression_common.rb
|
192
|
+
- spec/cql/compression/lz4_compressor_spec.rb
|
190
193
|
- spec/cql/compression/snappy_compressor_spec.rb
|
191
194
|
- spec/cql/protocol/cql_byte_buffer_spec.rb
|
192
195
|
- spec/cql/protocol/cql_protocol_handler_spec.rb
|