cassandra-driver 2.1.7-java → 3.0.0.beta.1-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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -53
  3. data/lib/cassandra.rb +22 -3
  4. data/lib/cassandra/aggregate.rb +109 -0
  5. data/lib/cassandra/argument.rb +51 -0
  6. data/lib/cassandra/auth/providers/password.rb +7 -4
  7. data/lib/cassandra/cluster.rb +14 -3
  8. data/lib/cassandra/cluster/client.rb +56 -34
  9. data/lib/cassandra/cluster/connector.rb +6 -6
  10. data/lib/cassandra/cluster/control_connection.rb +204 -251
  11. data/lib/cassandra/cluster/metadata.rb +2 -0
  12. data/lib/cassandra/cluster/schema.rb +131 -209
  13. data/lib/cassandra/cluster/schema/cql_type_parser.rb +104 -0
  14. data/lib/cassandra/cluster/schema/fetchers.rb +1174 -0
  15. data/lib/cassandra/cluster/schema/{type_parser.rb → fqcn_type_parser.rb} +7 -3
  16. data/lib/cassandra/column.rb +2 -2
  17. data/lib/cassandra/driver.rb +27 -9
  18. data/lib/cassandra/errors.rb +179 -25
  19. data/lib/cassandra/execution/info.rb +8 -1
  20. data/lib/cassandra/execution/options.rb +34 -0
  21. data/lib/cassandra/execution/trace.rb +42 -10
  22. data/lib/cassandra/function.rb +150 -0
  23. data/lib/cassandra/future.rb +66 -35
  24. data/lib/cassandra/host.rb +7 -4
  25. data/lib/cassandra/keyspace.rb +112 -13
  26. data/lib/cassandra/load_balancing.rb +1 -1
  27. data/lib/cassandra/protocol.rb +9 -3
  28. data/lib/cassandra/protocol/coder.rb +434 -155
  29. data/lib/cassandra/protocol/cql_byte_buffer.rb +43 -0
  30. data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -1
  31. data/lib/cassandra/protocol/request.rb +4 -0
  32. data/lib/cassandra/protocol/requests/auth_response_request.rb +5 -1
  33. data/lib/cassandra/protocol/requests/batch_request.rb +7 -2
  34. data/lib/cassandra/protocol/requests/credentials_request.rb +5 -1
  35. data/lib/cassandra/protocol/requests/execute_request.rb +16 -10
  36. data/lib/cassandra/protocol/requests/prepare_request.rb +12 -3
  37. data/lib/cassandra/protocol/requests/query_request.rb +20 -11
  38. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +4 -4
  39. data/lib/cassandra/protocol/responses/error_response.rb +14 -14
  40. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +41 -0
  41. data/lib/cassandra/protocol/responses/prepared_result_response.rb +12 -9
  42. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +5 -3
  43. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +43 -0
  44. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +4 -4
  45. data/lib/cassandra/protocol/responses/ready_response.rb +5 -1
  46. data/lib/cassandra/protocol/responses/result_response.rb +3 -3
  47. data/lib/cassandra/protocol/responses/rows_result_response.rb +2 -2
  48. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +25 -24
  49. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +20 -23
  50. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
  51. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +4 -4
  52. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +4 -4
  53. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +45 -0
  54. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +4 -4
  55. data/lib/cassandra/protocol/v1.rb +38 -13
  56. data/lib/cassandra/protocol/v3.rb +34 -29
  57. data/lib/cassandra/protocol/v4.rb +334 -0
  58. data/lib/cassandra/result.rb +10 -9
  59. data/lib/cassandra/retry.rb +17 -3
  60. data/lib/cassandra/retry/policies/default.rb +9 -3
  61. data/lib/cassandra/session.rb +15 -7
  62. data/lib/cassandra/statement.rb +5 -0
  63. data/lib/cassandra/statements/batch.rb +36 -12
  64. data/lib/cassandra/statements/bound.rb +2 -1
  65. data/lib/cassandra/statements/prepared.rb +106 -35
  66. data/lib/cassandra/statements/simple.rb +4 -2
  67. data/lib/cassandra/table.rb +70 -105
  68. data/lib/cassandra/time.rb +98 -0
  69. data/lib/cassandra/time_uuid.rb +1 -1
  70. data/lib/cassandra/tuple.rb +7 -0
  71. data/lib/cassandra/types.rb +472 -272
  72. data/lib/cassandra/udt.rb +10 -0
  73. data/lib/cassandra/util.rb +32 -1
  74. data/lib/cassandra/uuid.rb +6 -1
  75. data/lib/cassandra/uuid/generator.rb +7 -7
  76. data/lib/cassandra/version.rb +1 -1
  77. data/lib/cassandra_murmur3.jar +0 -0
  78. data/lib/datastax/cassandra.rb +5 -2
  79. metadata +27 -17
@@ -30,6 +30,8 @@ module Cassandra
30
30
  @partitioners = schema_partitioners
31
31
  @strategies = replication_strategies
32
32
  @default_strategy = default_replication_strategy
33
+ @token_replicas = ::Hash.new
34
+ @token_ring = ::Array.new
33
35
  end
34
36
 
35
37
  def find_replicas(keyspace, statement)
@@ -22,17 +22,33 @@ module Cassandra
22
22
  class Schema
23
23
  include MonitorMixin
24
24
 
25
- def initialize(schema_type_parser)
26
- @type_parser = schema_type_parser
27
- @keyspaces = ::Hash.new
28
- @listeners = ::Set.new
25
+ def initialize
26
+ @keyspaces = ::Hash.new
27
+ @listeners = ::Set.new
29
28
 
30
29
  mon_initialize
31
30
  end
32
31
 
33
- def create_partition_key(keyspace, table, values)
34
- keyspace = @keyspaces[keyspace]
35
- keyspace && keyspace.create_partition_key(table, values)
32
+ def get_pk_idx(metadata)
33
+ return EMPTY_LIST unless metadata
34
+
35
+ keyspace_name, table_name, _ = metadata.first
36
+ return EMPTY_LIST unless keyspace_name && table_name
37
+
38
+ keyspace = @keyspaces[keyspace_name]
39
+ return EMPTY_LIST unless keyspace
40
+
41
+ table = keyspace.table(table_name)
42
+ return EMPTY_LIST unless table
43
+
44
+ partition_key = table.partition_key
45
+ return EMPTY_LIST unless partition_key && partition_key.size <= metadata.size
46
+
47
+ partition_key.map do |column|
48
+ i = metadata.index {|(_, _, name, _)| name == column.name}
49
+ return EMPTY_LIST if i.nil?
50
+ i
51
+ end
36
52
  end
37
53
 
38
54
  def add_listener(listener)
@@ -51,25 +67,13 @@ module Cassandra
51
67
  self
52
68
  end
53
69
 
54
- def update_keyspaces(host, keyspaces, tables, columns, types)
55
- columns = columns.each_with_object(deephash { [] }) do |row, index|
56
- index[row['keyspace_name']] << row
57
- end
58
-
59
- tables = tables.each_with_object(deephash { [] }) do |row, index|
60
- index[row['keyspace_name']] << row
61
- end
62
-
63
- types = types.each_with_object(deephash { [] }) do |row, index|
64
- index[row['keyspace_name']] << row
65
- end
66
-
70
+ def replace(keyspaces)
67
71
  current_keyspaces = ::Set.new
68
72
 
69
- keyspaces.each do |row|
70
- current_keyspaces << keyspace = row['keyspace_name']
73
+ keyspaces.each do |keyspace|
74
+ current_keyspaces << keyspace.name
71
75
 
72
- update_keyspace(host, row, tables[keyspace], columns[keyspace], types[keyspace])
76
+ replace_keyspace(keyspace)
73
77
  end
74
78
 
75
79
  @keyspaces.each do |name, keyspace|
@@ -79,40 +83,21 @@ module Cassandra
79
83
  self
80
84
  end
81
85
 
82
- def update_keyspace(host, keyspace, tables, columns, types)
83
- keyspace_name = keyspace['keyspace_name']
86
+ def replace_keyspace(keyspace)
87
+ old_keyspace = @keyspaces[keyspace.name]
84
88
 
85
- columns = columns.each_with_object(deephash { ::Hash.new }) do |row, index|
86
- index[row['columnfamily_name']][row['column_name']] = row
87
- end
88
-
89
- tables = tables.each_with_object(Hash.new) do |row, index|
90
- name = row['columnfamily_name']
91
- index[name] = create_table(row, columns[name], host.release_version)
92
- end
93
-
94
- types = types.each_with_object(Hash.new) do |row, index|
95
- name = row['type_name']
96
- index[name] = create_type(row, host.release_version)
97
- end
98
-
99
- replication = Keyspace::Replication.new(keyspace['strategy_class'], ::JSON.load(keyspace['strategy_options']))
100
- keyspace = Keyspace.new(keyspace_name, keyspace['durable_writes'], replication, tables, types)
101
-
102
- return self if keyspace == @keyspaces[keyspace_name]
103
-
104
- created = !@keyspaces.include?(keyspace_name)
89
+ return self if old_keyspace == keyspace
105
90
 
106
91
  synchronize do
107
92
  keyspaces = @keyspaces.dup
108
- keyspaces[keyspace_name] = keyspace
93
+ keyspaces[keyspace.name] = keyspace
109
94
  @keyspaces = keyspaces
110
95
  end
111
96
 
112
- if created
113
- keyspace_created(keyspace)
114
- else
97
+ if old_keyspace
115
98
  keyspace_changed(keyspace)
99
+ else
100
+ keyspace_created(keyspace)
116
101
  end
117
102
 
118
103
  self
@@ -134,20 +119,20 @@ module Cassandra
134
119
  self
135
120
  end
136
121
 
137
- def update_table(host, keyspace_name, table, columns)
138
- keyspace = @keyspaces[keyspace_name]
122
+ def replace_table(table)
123
+ keyspace = @keyspaces[table.keyspace]
139
124
 
140
125
  return self unless keyspace
141
126
 
142
- columns = columns.each_with_object(::Hash.new) do |row, index|
143
- index[row['column_name']] = row
144
- end
145
- table = create_table(table, columns, host.release_version)
127
+ old_table = keyspace.table(table.name)
128
+
129
+ return self if old_table == table
130
+
146
131
  keyspace = keyspace.update_table(table)
147
132
 
148
133
  synchronize do
149
134
  keyspaces = @keyspaces.dup
150
- keyspaces[keyspace_name] = keyspace
135
+ keyspaces[keyspace.name] = keyspace
151
136
  @keyspaces = keyspaces
152
137
  end
153
138
 
@@ -161,6 +146,10 @@ module Cassandra
161
146
 
162
147
  return self unless keyspace
163
148
 
149
+ table = keyspace.table(table_name)
150
+
151
+ return self unless table
152
+
164
153
  keyspace = keyspace.delete_table(table_name)
165
154
 
166
155
  synchronize do
@@ -174,17 +163,20 @@ module Cassandra
174
163
  self
175
164
  end
176
165
 
177
- def update_type(host, keyspace_name, type)
178
- keyspace = @keyspaces[keyspace_name]
166
+ def replace_type(type)
167
+ keyspace = @keyspaces[type.keyspace]
179
168
 
180
169
  return self unless keyspace
181
170
 
182
- type = create_type(type, host.release_version)
171
+ old_type = keyspace.type(type.name)
172
+
173
+ return self if old_type == type
174
+
183
175
  keyspace = keyspace.update_type(type)
184
176
 
185
177
  synchronize do
186
178
  keyspaces = @keyspaces.dup
187
- keyspaces[keyspace_name] = keyspace
179
+ keyspaces[keyspace.name] = keyspace
188
180
  @keyspaces = keyspaces
189
181
  end
190
182
 
@@ -198,6 +190,10 @@ module Cassandra
198
190
 
199
191
  return self unless keyspace
200
192
 
193
+ type = keyspace.type(type_name)
194
+
195
+ return self unless type
196
+
201
197
  keyspace = keyspace.delete_type(type_name)
202
198
 
203
199
  synchronize do
@@ -211,189 +207,113 @@ module Cassandra
211
207
  self
212
208
  end
213
209
 
214
- def has_keyspace?(name)
215
- @keyspaces.include?(name)
216
- end
210
+ def replace_function(function)
211
+ keyspace = @keyspaces[function.keyspace]
217
212
 
218
- def keyspace(name)
219
- @keyspaces[name]
220
- end
221
-
222
- def each_keyspace(&block)
223
- if block_given?
224
- @keyspaces.each_value(&block)
225
- self
226
- else
227
- @keyspaces.values
228
- end
229
- end
230
- alias :keyspaces :each_keyspace
213
+ return self unless keyspace
231
214
 
232
- private
215
+ old_function = keyspace.function(function.name, *function.argument_types)
233
216
 
234
- def create_type(type, version)
235
- keyspace = type['keyspace_name']
236
- name = type['type_name']
237
- fields = ::Array.new
217
+ return self if old_function == function
238
218
 
239
- type['field_names'].zip(type['field_types']) do |(field_name, field_type)|
240
- field_type = @type_parser.parse(field_type).results.first.first
219
+ keyspace = keyspace.update_function(function)
241
220
 
242
- fields << [field_name, field_type]
221
+ synchronize do
222
+ keyspaces = @keyspaces.dup
223
+ keyspaces[keyspace.name] = keyspace
224
+ @keyspaces = keyspaces
243
225
  end
244
226
 
245
- Types.udt(keyspace, name, fields)
227
+ keyspace_changed(keyspace)
228
+
229
+ self
246
230
  end
247
231
 
248
- def create_table(table, columns, version)
249
- keyspace = table['keyspace_name']
250
- name = table['columnfamily_name']
251
- key_validator = @type_parser.parse(table['key_validator'])
252
- comparator = @type_parser.parse(table['comparator'])
253
- column_aliases = ::JSON.load(table['column_aliases'])
232
+ def delete_function(keyspace_name, function_name, function_arg_types)
233
+ keyspace = @keyspaces[keyspace_name]
234
+
235
+ return self unless keyspace
254
236
 
255
- clustering_size = find_clustering_size(comparator, columns.values,
256
- column_aliases, version)
237
+ function = keyspace.function(function_name, *function_arg_types)
257
238
 
258
- is_dense = clustering_size != comparator.results.size - 1
259
- is_compact = is_dense || !comparator.collections
260
- partition_key = []
261
- clustering_columns = []
262
- clustering_order = []
239
+ return self unless function
263
240
 
264
- compaction_strategy = Table::Compaction.new(
265
- table['compaction_strategy_class'],
266
- ::JSON.load(table['compaction_strategy_options'])
267
- )
268
- compression_parameters = ::JSON.load(table['compression_parameters'])
241
+ keyspace = keyspace.delete_function(function_name, function_arg_types)
269
242
 
270
- options = Table::Options.new(table, compaction_strategy, compression_parameters, is_compact, version)
271
- columns = create_columns(key_validator, comparator, column_aliases, is_dense, clustering_size, table, columns, version, partition_key, clustering_columns, clustering_order)
243
+ synchronize do
244
+ keyspaces = @keyspaces.dup
245
+ keyspaces[keyspace_name] = keyspace
246
+ @keyspaces = keyspaces
247
+ end
248
+
249
+ keyspace_changed(keyspace)
272
250
 
273
- Table.new(keyspace, name, partition_key, clustering_columns, columns, options, clustering_order, version)
251
+ self
274
252
  end
275
253
 
276
- def find_clustering_size(comparator, columns, aliases, cassandra_version)
277
- if cassandra_version.start_with?('1')
278
- if comparator.collections
279
- size = comparator.results.size
280
- (!comparator.collections.empty? || aliases.size == size - 1 && comparator.results.last.first == :text) ? size - 1 : size
281
- else
282
- (!aliases.empty? || columns.empty?) ? 1 : 0
283
- end
284
- else
285
- max_index = nil
254
+ def replace_aggregate(aggregate)
255
+ keyspace = @keyspaces[aggregate.keyspace]
256
+
257
+ return self unless keyspace
286
258
 
287
- columns.each do |cl|
288
- if cl['type'].to_s.upcase == 'CLUSTERING_KEY'
289
- index = cl['component_index'] || 0
259
+ old_aggregate = keyspace.aggregate(aggregate.name, *aggregate.argument_types)
290
260
 
291
- if max_index.nil? || index > max_index
292
- max_index = index
293
- end
294
- end
295
- end
261
+ return self if old_aggregate == aggregate
296
262
 
297
- return 0 if max_index.nil?
263
+ keyspace = keyspace.update_aggregate(aggregate)
298
264
 
299
- max_index + 1
265
+ synchronize do
266
+ keyspaces = @keyspaces.dup
267
+ keyspaces[keyspace.name] = keyspace
268
+ @keyspaces = keyspaces
300
269
  end
270
+
271
+ keyspace_changed(keyspace)
272
+
273
+ self
301
274
  end
302
275
 
303
- def create_columns(key_validator, comparator, column_aliases, is_dense, clustering_size, table, columns, cassandra_version, partition_key, clustering_columns, clustering_order)
304
- table_columns = {}
305
- other_columns = []
306
-
307
- if cassandra_version.start_with?('1')
308
- key_aliases = ::JSON.load(table['key_aliases'])
309
-
310
- key_validator.results.each_with_index do |(type, order, is_frozen), i|
311
- key_alias = key_aliases.fetch(i) { i.zero? ? "key" : "key#{i + 1}" }
312
-
313
- partition_key[i] = Column.new(key_alias, type, order, nil, false, is_frozen)
314
- end
315
-
316
- if comparator.results.size > 1
317
- clustering_size.times do |i|
318
- column_alias = column_aliases.fetch(i) { "column#{i + 1}" }
319
- type, order, is_frozen = comparator.results.fetch(i)
320
-
321
- clustering_columns[i] = Column.new(column_alias, type, order, nil, false, is_frozen)
322
- clustering_order[i] = order
323
- end
324
- else
325
- column_alias = column_aliases.first || "column1"
326
- type, order, is_frozen = comparator.results.first
327
-
328
- clustering_columns[0] = Column.new(column_alias, type, order, nil, false, is_frozen)
329
- clustering_order[0] = order
330
- end
331
-
332
- if is_dense
333
- value_alias = table['value_alias']
334
- value_alias = 'value' if value_alias.nil? || value_alias.empty?
335
- type, order, is_frozen = @type_parser.parse(table['default_validator']).results.first
336
- other_columns << Column.new(value_alias, type, order, nil, false, is_frozen)
337
- end
338
-
339
- columns.each do |name, row|
340
- other_columns << create_column(row)
341
- end
342
- else
343
- columns.each do |name, row|
344
- next if row['column_name'].empty?
345
-
346
- column = create_column(row)
347
- type = row['type'].to_s
348
- index = row['component_index'] || 0
349
-
350
- case type.upcase
351
- when 'PARTITION_KEY'
352
- partition_key[index] = column
353
- when 'CLUSTERING_KEY'
354
- clustering_columns[index] = column
355
- clustering_order[index] = column.order
356
- else
357
- other_columns << column
358
- end
359
- end
360
- end
276
+ def delete_aggregate(keyspace_name, aggregate_name, aggregate_arg_types)
277
+ keyspace = @keyspaces[keyspace_name]
361
278
 
362
- partition_key.each do |column|
363
- table_columns[column.name] = column
364
- end
279
+ return self unless keyspace
365
280
 
366
- clustering_columns.each do |column|
367
- table_columns[column.name] = column
368
- end
281
+ aggregate = keyspace.aggregate(aggregate_name, *aggregate_arg_types)
282
+
283
+ return self unless aggregate
369
284
 
370
- other_columns.each do |column|
371
- table_columns[column.name] = column
285
+ keyspace = keyspace.delete_aggregate(aggregate_name, aggregate_arg_types)
286
+
287
+ synchronize do
288
+ keyspaces = @keyspaces.dup
289
+ keyspaces[keyspace_name] = keyspace
290
+ @keyspaces = keyspaces
372
291
  end
373
292
 
374
- table_columns
293
+ keyspace_changed(keyspace)
294
+
295
+ self
296
+ end
297
+
298
+ def has_keyspace?(name)
299
+ @keyspaces.include?(name)
375
300
  end
376
301
 
377
- def create_column(column)
378
- name = column['column_name']
379
- type, order, is_frozen = @type_parser.parse(column['validator']).results.first
380
- is_static = (column['type'] == 'STATIC')
302
+ def keyspace(name)
303
+ @keyspaces[name]
304
+ end
381
305
 
382
- if column['index_type'].nil?
383
- index = nil
384
- elsif column['index_type'].to_s.upcase == 'CUSTOM' || !column['index_options']
385
- index = Column::Index.new(column['index_name'])
306
+ def each_keyspace(&block)
307
+ if block_given?
308
+ @keyspaces.each_value(&block)
309
+ self
386
310
  else
387
- options = ::JSON.load(column['index_options'])
388
- index = Column::Index.new(column['index_name'], options && options['class_name'])
311
+ @keyspaces.values
389
312
  end
390
-
391
- Column.new(name, type, order, index, is_static, is_frozen)
392
313
  end
314
+ alias :keyspaces :each_keyspace
393
315
 
394
- def deephash
395
- ::Hash.new {|hash, key| hash[key] = yield}
396
- end
316
+ private
397
317
 
398
318
  def keyspace_created(keyspace)
399
319
  @listeners.each do |listener|
@@ -416,6 +336,8 @@ module Cassandra
416
336
  end
417
337
  end
418
338
 
339
+ require 'cassandra/cluster/schema/cql_type_parser'
340
+ require 'cassandra/cluster/schema/fetchers'
419
341
  require 'cassandra/cluster/schema/partitioners'
420
342
  require 'cassandra/cluster/schema/replication_strategies'
421
- require 'cassandra/cluster/schema/type_parser'
343
+ require 'cassandra/cluster/schema/fqcn_type_parser'