cassandra-driver 3.0.0.rc.2-java → 3.0.2-java

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -39
  3. data/lib/cassandra.rb +74 -32
  4. data/lib/cassandra/auth.rb +3 -1
  5. data/lib/cassandra/cluster.rb +14 -3
  6. data/lib/cassandra/cluster/client.rb +98 -62
  7. data/lib/cassandra/cluster/connector.rb +7 -9
  8. data/lib/cassandra/cluster/metadata.rb +1 -1
  9. data/lib/cassandra/cluster/options.rb +19 -7
  10. data/lib/cassandra/cluster/schema/cql_type_parser.rb +3 -0
  11. data/lib/cassandra/cluster/schema/fetchers.rb +1 -1
  12. data/lib/cassandra/custom_data.rb +51 -0
  13. data/lib/cassandra/driver.rb +23 -20
  14. data/lib/cassandra/execution/options.rb +1 -1
  15. data/lib/cassandra/index.rb +22 -8
  16. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +19 -1
  17. data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -0
  18. data/lib/cassandra/load_balancing/policies/token_aware.rb +7 -0
  19. data/lib/cassandra/load_balancing/policies/white_list.rb +7 -0
  20. data/lib/cassandra/protocol.rb +7 -0
  21. data/lib/cassandra/protocol/coder.rb +28 -8
  22. data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -4
  23. data/lib/cassandra/protocol/cql_protocol_handler.rb +3 -2
  24. data/lib/cassandra/protocol/requests/batch_request.rb +1 -1
  25. data/lib/cassandra/protocol/requests/execute_request.rb +1 -1
  26. data/lib/cassandra/protocol/requests/query_request.rb +1 -1
  27. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +4 -2
  28. data/lib/cassandra/protocol/v1.rb +2 -1
  29. data/lib/cassandra/protocol/v3.rb +2 -1
  30. data/lib/cassandra/protocol/v4.rb +5 -3
  31. data/lib/cassandra/result.rb +2 -2
  32. data/lib/cassandra/session.rb +10 -15
  33. data/lib/cassandra/statement.rb +5 -0
  34. data/lib/cassandra/statements/batch.rb +6 -0
  35. data/lib/cassandra/statements/bound.rb +5 -0
  36. data/lib/cassandra/statements/prepared.rb +11 -2
  37. data/lib/cassandra/statements/simple.rb +5 -0
  38. data/lib/cassandra/statements/void.rb +5 -0
  39. data/lib/cassandra/table.rb +5 -5
  40. data/lib/cassandra/timestamp_generator.rb +37 -0
  41. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  42. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  43. data/lib/cassandra/tuple.rb +2 -2
  44. data/lib/cassandra/types.rb +2 -2
  45. data/lib/cassandra/util.rb +136 -2
  46. data/lib/cassandra/version.rb +1 -1
  47. data/lib/cassandra_murmur3.jar +0 -0
  48. metadata +8 -4
@@ -92,6 +92,13 @@ module Cassandra
92
92
  "Not enough bytes available to decode a double: #{e.message}", e.backtrace
93
93
  end
94
94
 
95
+ def read_double_le
96
+ read(8).unpack(Formats::DOUBLE_FORMAT_LE).first
97
+ rescue RangeError => e
98
+ raise Errors::DecodingError,
99
+ "Not enough bytes available to decode a double: #{e.message}", e.backtrace
100
+ end
101
+
95
102
  def read_float
96
103
  read(4).unpack(Formats::FLOAT_FORMAT).first
97
104
  rescue RangeError => e
@@ -108,6 +115,13 @@ module Cassandra
108
115
  "Not enough bytes available to decode an int: #{e.message}", e.backtrace
109
116
  end
110
117
 
118
+ def read_unsigned_int_le
119
+ read(4).unpack(Formats::INT_FORMAT_LE).first
120
+ rescue RangeError => e
121
+ raise Errors::DecodingError,
122
+ "Not enough bytes available to decode an int: #{e.message}", e.backtrace
123
+ end
124
+
111
125
  def read_unsigned_short
112
126
  read_short
113
127
  rescue RangeError => e
@@ -115,6 +129,13 @@ module Cassandra
115
129
  "Not enough bytes available to decode a short: #{e.message}", e.backtrace
116
130
  end
117
131
 
132
+ def read_unsigned_short_le
133
+ read(2).unpack(Formats::SHORT_FORMAT_LE).first
134
+ rescue RangeError => e
135
+ raise Errors::DecodingError,
136
+ "Not enough bytes available to decode a short: #{e.message}", e.backtrace
137
+ end
138
+
118
139
  def read_string
119
140
  length = read_unsigned_short
120
141
  string = read(length)
@@ -324,10 +345,6 @@ module Cassandra
324
345
  self
325
346
  end
326
347
 
327
- def append_timestamp(timestamp)
328
- append_long(timestamp.tv_sec * 1000000 + timestamp.tv_usec)
329
- end
330
-
331
348
  def append_long(n)
332
349
  top = n >> 32
333
350
  bottom = n & 0xffffffff
@@ -46,7 +46,8 @@ module Cassandra
46
46
  compressor = nil,
47
47
  heartbeat_interval = 30,
48
48
  idle_timeout = 60,
49
- requests_per_connection = 128)
49
+ requests_per_connection = 128,
50
+ custom_type_handlers = {})
50
51
  @protocol_version = protocol_version
51
52
  @connection = connection
52
53
  @scheduler = scheduler
@@ -60,7 +61,7 @@ module Cassandra
60
61
 
61
62
  if protocol_version > 3
62
63
  @frame_encoder = V4::Encoder.new(@compressor, protocol_version)
63
- @frame_decoder = V4::Decoder.new(self, @compressor)
64
+ @frame_decoder = V4::Decoder.new(self, @compressor, custom_type_handlers)
64
65
  elsif protocol_version > 2
65
66
  @frame_encoder = V3::Encoder.new(@compressor, protocol_version)
66
67
  @frame_decoder = V3::Decoder.new(self, @compressor)
@@ -81,7 +81,7 @@ module Cassandra
81
81
 
82
82
  buffer.append(flags.chr)
83
83
  buffer.append_consistency(@serial_consistency) if @serial_consistency
84
- buffer.append_timestamp(@timestamp) if @timestamp
84
+ buffer.append_long(@timestamp) if @timestamp
85
85
  end
86
86
 
87
87
  buffer
@@ -78,7 +78,7 @@ module Cassandra
78
78
  buffer.append_int(@page_size) if @page_size
79
79
  buffer.append_bytes(@paging_state) if @paging_state
80
80
  buffer.append_consistency(@serial_consistency) if @serial_consistency
81
- buffer.append_timestamp(@timestamp) if protocol_version > 2 && @timestamp
81
+ buffer.append_long(@timestamp) if protocol_version > 2 && @timestamp
82
82
  else
83
83
  encoder.write_parameters(buffer, @values, @metadata)
84
84
  buffer.append_consistency(@consistency)
@@ -71,7 +71,7 @@ module Cassandra
71
71
  buffer.append_int(@page_size) if @page_size
72
72
  buffer.append_bytes(@paging_state) if @paging_state
73
73
  buffer.append_consistency(@serial_consistency) if @serial_consistency
74
- buffer.append_timestamp(@timestamp) if protocol_version > 2 && @timestamp
74
+ buffer.append_long(@timestamp) if protocol_version > 2 && @timestamp
75
75
  end
76
76
  buffer
77
77
  end
@@ -24,17 +24,19 @@ module Cassandra
24
24
  protocol_version,
25
25
  raw_rows,
26
26
  paging_state,
27
- trace_id)
27
+ trace_id,
28
+ custom_type_handlers = nil)
28
29
  super(custom_payload, warnings, nil, nil, paging_state, trace_id)
29
30
  @protocol_version = protocol_version
30
31
  @raw_rows = raw_rows
32
+ @custom_type_handlers = custom_type_handlers
31
33
  end
32
34
 
33
35
  def materialize(metadata)
34
36
  @metadata = metadata
35
37
 
36
38
  @rows = if @protocol_version == 4
37
- Coder.read_values_v4(@raw_rows, @metadata)
39
+ Coder.read_values_v4(@raw_rows, @metadata, @custom_type_handlers)
38
40
  elsif @protocol_version == 3
39
41
  Coder.read_values_v3(@raw_rows, @metadata)
40
42
  else
@@ -241,7 +241,8 @@ module Cassandra
241
241
  protocol_version,
242
242
  remaining_bytes,
243
243
  paging_state,
244
- trace_id)
244
+ trace_id,
245
+ nil)
245
246
  else
246
247
  RowsResultResponse.new(nil,
247
248
  nil,
@@ -275,7 +275,8 @@ module Cassandra
275
275
  protocol_version,
276
276
  remaining_bytes,
277
277
  paging_state,
278
- trace_id)
278
+ trace_id,
279
+ nil)
279
280
  else
280
281
  RowsResultResponse.new(nil,
281
282
  nil,
@@ -59,7 +59,7 @@ module Cassandra
59
59
  end
60
60
 
61
61
  class Decoder
62
- def initialize(handler, compressor = nil)
62
+ def initialize(handler, compressor = nil, custom_type_handlers = {})
63
63
  @handler = handler
64
64
  @compressor = compressor
65
65
  @state = :initial
@@ -68,6 +68,7 @@ module Cassandra
68
68
  @code = nil
69
69
  @length = nil
70
70
  @buffer = CqlByteBuffer.new
71
+ @custom_type_handlers = custom_type_handlers
71
72
  end
72
73
 
73
74
  def <<(data)
@@ -325,11 +326,12 @@ module Cassandra
325
326
  protocol_version,
326
327
  remaining_bytes,
327
328
  paging_state,
328
- trace_id)
329
+ trace_id,
330
+ @custom_type_handlers)
329
331
  else
330
332
  RowsResultResponse.new(custom_payload,
331
333
  warnings,
332
- Coder.read_values_v4(buffer, column_specs),
334
+ Coder.read_values_v4(buffer, column_specs, @custom_type_handlers),
333
335
  column_specs,
334
336
  paging_state,
335
337
  trace_id)
@@ -76,8 +76,8 @@ module Cassandra
76
76
  #
77
77
  # @note `:paging_state` option will be ignored.
78
78
  #
79
- # @return [Cassandra::Future<Cassandra::Result, nil>] `nil` if last
80
- # page
79
+ # @return [Cassandra::Future<Cassandra::Result>] a future that resolves to a new Result if there is a new page,
80
+ # `nil` otherwise.
81
81
  #
82
82
  # @see Cassandra::Session#execute
83
83
  def next_page_async(options = nil)
@@ -89,20 +89,13 @@ module Cassandra
89
89
 
90
90
  case statement
91
91
  when ::String
92
- @client.query(Statements::Simple.new(statement,
93
- options.arguments,
94
- options.type_hints,
95
- options.idempotent?),
96
- options)
97
- when Statements::Simple
98
- @client.query(statement, options)
99
- when Statements::Prepared
100
- @client.execute(statement.bind(options.arguments), options)
101
- when Statements::Bound
102
- @client.execute(statement, options)
103
- when Statements::Batch
104
- Util.assert_not_empty(statement.statements) { 'batch cannot be empty' }
105
- @client.batch(statement, options)
92
+ Statements::Simple.new(statement,
93
+ options.arguments,
94
+ options.type_hints,
95
+ options.idempotent?).accept(@client,
96
+ options)
97
+ when Statement
98
+ statement.accept(@client, options)
106
99
  else
107
100
  @futures.error(::ArgumentError.new("unsupported statement #{statement.inspect}"))
108
101
  end
@@ -238,7 +231,9 @@ module Cassandra
238
231
 
239
232
  # @private
240
233
  def inspect
241
- "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
234
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} " \
235
+ "@keyspace=#{keyspace.inspect}, " \
236
+ "@options=#{@options.inspect}>"
242
237
  end
243
238
  end
244
239
  end
@@ -23,5 +23,10 @@ module Cassandra
23
23
  def idempotent?
24
24
  !!@idempotent
25
25
  end
26
+
27
+ # @private
28
+ def accept(client, options)
29
+ raise NotImplementedError, "#{self.class} must implement :accept method"
30
+ end
26
31
  end
27
32
  end
@@ -113,6 +113,12 @@ module Cassandra
113
113
  self
114
114
  end
115
115
 
116
+ # @private
117
+ def accept(client, options)
118
+ Util.assert_not_empty(statements) { 'batch cannot be empty' }
119
+ client.batch(self, options)
120
+ end
121
+
116
122
  # Determines whether or not the statement is safe to retry on timeout
117
123
  # Batches are idempotent only when all statements in a batch are.
118
124
  # @return [Boolean] whether the statement is safe to retry on timeout
@@ -46,6 +46,11 @@ module Cassandra
46
46
  @idempotent = idempotent
47
47
  end
48
48
 
49
+ # @private
50
+ def accept(client, options)
51
+ client.execute(self, options)
52
+ end
53
+
49
54
  # @return [String] a CLI-friendly bound statement representation
50
55
  def inspect
51
56
  "#<#{self.class.name}:0x#{object_id.to_s(16)} @cql=#{@cql.inspect} " \
@@ -155,6 +155,11 @@ module Cassandra
155
155
  nil)
156
156
  end
157
157
 
158
+ # @private
159
+ def accept(client, options)
160
+ client.execute(bind(options.arguments), options)
161
+ end
162
+
158
163
  # @return [String] a CLI-friendly prepared statement representation
159
164
  def inspect
160
165
  "#<#{self.class.name}:0x#{object_id.to_s(16)} @cql=#{@cql.inspect}>"
@@ -180,7 +185,9 @@ module Cassandra
180
185
  'the partition key and must be present.'
181
186
  end
182
187
 
183
- if @connection_options.protocol_version >= 3
188
+ if @connection_options.protocol_version >= 4
189
+ Protocol::Coder.write_value_v4(buffer, value, type)
190
+ elsif @connection_options.protocol_version >= 3
184
191
  Protocol::Coder.write_value_v3(buffer, value, type)
185
192
  else
186
193
  Protocol::Coder.write_value_v1(buffer, value, type)
@@ -200,7 +207,9 @@ module Cassandra
200
207
  'the partition key and must be present.'
201
208
  end
202
209
 
203
- if @connection_options.protocol_version >= 3
210
+ if @connection_options.protocol_version >= 4
211
+ Protocol::Coder.write_value_v4(buf, value, type)
212
+ elsif @connection_options.protocol_version >= 3
204
213
  Protocol::Coder.write_value_v3(buf, value, type)
205
214
  else
206
215
  Protocol::Coder.write_value_v1(buf, value, type)
@@ -93,6 +93,11 @@ module Cassandra
93
93
  @idempotent = idempotent
94
94
  end
95
95
 
96
+ # @private
97
+ def accept(client, options)
98
+ client.query(self, options)
99
+ end
100
+
96
101
  # @return [String] a CLI-friendly simple statement representation
97
102
  def inspect
98
103
  "#<#{self.class.name}:0x#{object_id.to_s(16)} @cql=#{@cql.inspect} " \
@@ -23,6 +23,11 @@ module Cassandra
23
23
  class Void
24
24
  include Statement
25
25
 
26
+ # @private
27
+ def accept(client, options)
28
+ nil
29
+ end
30
+
26
31
  # Returns nothing
27
32
  # @return [nil] there is no cql for the void statement
28
33
  def cql
@@ -80,14 +80,14 @@ module Cassandra
80
80
  else
81
81
  cql << ",\n"
82
82
  end
83
- cql << " #{column.name} #{type_to_cql(column.type, column.frozen?)}"
83
+ cql << " #{Util.escape_name(column.name)} #{type_to_cql(column.type, column.frozen?)}"
84
84
  cql << ' PRIMARY KEY' if primary_key && column.name == primary_key
85
85
  end
86
86
 
87
87
  unless primary_key
88
88
  cql << ",\n PRIMARY KEY ("
89
89
  if @partition_key.one?
90
- cql << @partition_key.first.name
90
+ cql << Util.escape_name(@partition_key.first.name)
91
91
  else
92
92
  cql << '('
93
93
  first = true
@@ -97,12 +97,12 @@ module Cassandra
97
97
  else
98
98
  cql << ', '
99
99
  end
100
- cql << column.name
100
+ cql << Util.escape_name(column.name)
101
101
  end
102
102
  cql << ')'
103
103
  end
104
104
  @clustering_columns.each do |column|
105
- cql << ", #{column.name}"
105
+ cql << ", #{Util.escape_name(column.name)}"
106
106
  end
107
107
  cql << ')'
108
108
  end
@@ -118,7 +118,7 @@ module Cassandra
118
118
  else
119
119
  cql << ', '
120
120
  end
121
- cql << "#{column.name} #{order.to_s.upcase}"
121
+ cql << "#{Util.escape_name(column.name)} #{order.to_s.upcase}"
122
122
  end
123
123
  cql << ")\n AND "
124
124
  end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2016 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ # A generator is used to create client-timestamps (in the form of long integers) to send with C* requests when
21
+ # the `:client_timestamps` cluster option is set to true.
22
+ #
23
+ # @abstract A timestamp generator given to {Cassandra.cluster} doesn't need to include this module, but needs to
24
+ # implement the same methods. This module exists only for documentation purposes.
25
+ module TimestampGenerator
26
+ # Create a new timestamp, as a 64-bit integer. Calls must return monotonically increasing values.
27
+ #
28
+ # @return [Integer] an integer representing a timestamp in microseconds.
29
+ # @raise [NotImplementedError] if a class including this module does not define this method.
30
+ def next
31
+ raise NotImplementedError, "#{self.class} class must implement the 'next' method"
32
+ end
33
+ end
34
+ end
35
+
36
+ require 'cassandra/timestamp_generator/ticking_on_duplicate'
37
+ require 'cassandra/timestamp_generator/simple'
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2016 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module TimestampGenerator
21
+ # Generate long integer timestamps from current time. This implementation relies on the {::Time} class to return
22
+ # microsecond precision time.
23
+ # @note It is not appropriate for use with JRuby because its {::Time#now} returns millisecond precision time.
24
+ class Simple
25
+ include TimestampGenerator
26
+
27
+ # Create a new timestamp, as a 64-bit integer. This is just a wrapper around Time::now.
28
+ #
29
+ # @return [Integer] an integer representing a timestamp in microseconds.
30
+ def next
31
+ # Use Time.now, which has microsecond precision on MRI (and probably Rubinius) to make an int representing
32
+ # client timestamp in protocol requests.
33
+ timestamp = ::Time.now
34
+ timestamp.tv_sec * 1000000 + timestamp.tv_usec
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2016 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module TimestampGenerator
21
+ # In JRuby, {::Time} has millisecond precision. We require client timestamps to have microsecond precision to
22
+ # minimize clashes in C*. This generator keeps track of the last generated timestamp, and if the current-time
23
+ # is within the same millisecond as the last, it fills the microsecond portion of the new timestamp with the
24
+ # value of an incrementing counter.
25
+ #
26
+ # For example, if the generator triggers twice at time 12345678000 (microsecond granularity, but ms precisions
27
+ # as shown by 0's for the three least-significant digits), it'll return 12345678000 and 12345678001.
28
+ class TickingOnDuplicate
29
+ include MonitorMixin
30
+ include TimestampGenerator
31
+
32
+ # @private
33
+ def initialize
34
+ mon_initialize
35
+ @last = 0
36
+ end
37
+
38
+ # Create a new timestamp, as a 64-bit integer.
39
+ #
40
+ # @return [Integer] an integer representing a timestamp in microseconds.
41
+ def next
42
+ now = ::Time.now
43
+ now_millis = now.tv_sec * 1000 + now.tv_usec / 1000
44
+ synchronize do
45
+ millis = @last / 1000
46
+ counter = @last % 1000
47
+ if millis >= now_millis
48
+ counter += 1
49
+ else
50
+ millis = now_millis
51
+ counter = 0
52
+ end
53
+ @last = millis * 1000 + counter
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end