cassandra-driver 0.1.0.alpha1 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/.yardopts +4 -0
  2. data/README.md +117 -0
  3. data/lib/cassandra.rb +320 -0
  4. data/lib/cassandra/auth.rb +97 -0
  5. data/lib/cassandra/auth/providers.rb +16 -0
  6. data/lib/cassandra/auth/providers/password.rb +73 -0
  7. data/lib/cassandra/client.rb +144 -0
  8. data/lib/cassandra/client/batch.rb +212 -0
  9. data/lib/cassandra/client/client.rb +591 -0
  10. data/lib/cassandra/client/column_metadata.rb +54 -0
  11. data/lib/cassandra/client/connection_manager.rb +72 -0
  12. data/lib/cassandra/client/connector.rb +272 -0
  13. data/lib/cassandra/client/execute_options_decoder.rb +59 -0
  14. data/lib/cassandra/client/null_logger.rb +37 -0
  15. data/lib/cassandra/client/peer_discovery.rb +50 -0
  16. data/lib/cassandra/client/prepared_statement.rb +314 -0
  17. data/lib/cassandra/client/query_result.rb +230 -0
  18. data/lib/cassandra/client/request_runner.rb +71 -0
  19. data/lib/cassandra/client/result_metadata.rb +48 -0
  20. data/lib/cassandra/client/void_result.rb +78 -0
  21. data/lib/cassandra/cluster.rb +191 -0
  22. data/lib/cassandra/cluster/client.rb +767 -0
  23. data/lib/cassandra/cluster/connector.rb +231 -0
  24. data/lib/cassandra/cluster/control_connection.rb +420 -0
  25. data/lib/cassandra/cluster/options.rb +40 -0
  26. data/lib/cassandra/cluster/registry.rb +181 -0
  27. data/lib/cassandra/cluster/schema.rb +321 -0
  28. data/lib/cassandra/cluster/schema/type_parser.rb +138 -0
  29. data/lib/cassandra/column.rb +92 -0
  30. data/lib/cassandra/compression.rb +66 -0
  31. data/lib/cassandra/compression/compressors/lz4.rb +72 -0
  32. data/lib/cassandra/compression/compressors/snappy.rb +66 -0
  33. data/lib/cassandra/driver.rb +86 -0
  34. data/lib/cassandra/errors.rb +79 -0
  35. data/lib/cassandra/execution/info.rb +51 -0
  36. data/lib/cassandra/execution/options.rb +77 -0
  37. data/lib/cassandra/execution/trace.rb +152 -0
  38. data/lib/cassandra/future.rb +675 -0
  39. data/lib/cassandra/host.rb +75 -0
  40. data/lib/cassandra/keyspace.rb +120 -0
  41. data/lib/cassandra/listener.rb +87 -0
  42. data/lib/cassandra/load_balancing.rb +112 -0
  43. data/lib/cassandra/load_balancing/policies.rb +18 -0
  44. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +149 -0
  45. data/lib/cassandra/load_balancing/policies/round_robin.rb +95 -0
  46. data/lib/cassandra/load_balancing/policies/white_list.rb +90 -0
  47. data/lib/cassandra/protocol.rb +93 -0
  48. data/lib/cassandra/protocol/cql_byte_buffer.rb +307 -0
  49. data/lib/cassandra/protocol/cql_protocol_handler.rb +323 -0
  50. data/lib/cassandra/protocol/frame_decoder.rb +128 -0
  51. data/lib/cassandra/protocol/frame_encoder.rb +48 -0
  52. data/lib/cassandra/protocol/request.rb +38 -0
  53. data/lib/cassandra/protocol/requests/auth_response_request.rb +47 -0
  54. data/lib/cassandra/protocol/requests/batch_request.rb +76 -0
  55. data/lib/cassandra/protocol/requests/credentials_request.rb +47 -0
  56. data/lib/cassandra/protocol/requests/execute_request.rb +103 -0
  57. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  58. data/lib/cassandra/protocol/requests/prepare_request.rb +50 -0
  59. data/lib/cassandra/protocol/requests/query_request.rb +153 -0
  60. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  61. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  62. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  63. data/lib/cassandra/protocol/response.rb +38 -0
  64. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +41 -0
  65. data/lib/cassandra/protocol/responses/auth_success_response.rb +41 -0
  66. data/lib/cassandra/protocol/responses/authenticate_response.rb +41 -0
  67. data/lib/cassandra/protocol/responses/detailed_error_response.rb +60 -0
  68. data/lib/cassandra/protocol/responses/error_response.rb +50 -0
  69. data/lib/cassandra/protocol/responses/event_response.rb +39 -0
  70. data/lib/cassandra/protocol/responses/prepared_result_response.rb +64 -0
  71. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +43 -0
  72. data/lib/cassandra/protocol/responses/ready_response.rb +44 -0
  73. data/lib/cassandra/protocol/responses/result_response.rb +48 -0
  74. data/lib/cassandra/protocol/responses/rows_result_response.rb +139 -0
  75. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +60 -0
  76. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +57 -0
  77. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +42 -0
  78. data/lib/cassandra/protocol/responses/status_change_event_response.rb +44 -0
  79. data/lib/cassandra/protocol/responses/supported_response.rb +41 -0
  80. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +34 -0
  81. data/lib/cassandra/protocol/responses/void_result_response.rb +39 -0
  82. data/lib/cassandra/protocol/type_converter.rb +384 -0
  83. data/lib/cassandra/reconnection.rb +49 -0
  84. data/lib/cassandra/reconnection/policies.rb +20 -0
  85. data/lib/cassandra/reconnection/policies/constant.rb +48 -0
  86. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  87. data/lib/cassandra/result.rb +215 -0
  88. data/lib/cassandra/retry.rb +142 -0
  89. data/lib/cassandra/retry/policies.rb +21 -0
  90. data/lib/cassandra/retry/policies/default.rb +47 -0
  91. data/lib/cassandra/retry/policies/downgrading_consistency.rb +71 -0
  92. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  93. data/lib/cassandra/session.rb +195 -0
  94. data/lib/cassandra/statement.rb +22 -0
  95. data/lib/cassandra/statements.rb +23 -0
  96. data/lib/cassandra/statements/batch.rb +95 -0
  97. data/lib/cassandra/statements/bound.rb +46 -0
  98. data/lib/cassandra/statements/prepared.rb +59 -0
  99. data/lib/cassandra/statements/simple.rb +58 -0
  100. data/lib/cassandra/statements/void.rb +33 -0
  101. data/lib/cassandra/table.rb +254 -0
  102. data/lib/cassandra/time_uuid.rb +141 -0
  103. data/lib/cassandra/util.rb +169 -0
  104. data/lib/cassandra/uuid.rb +104 -0
  105. data/lib/cassandra/version.rb +17 -1
  106. metadata +134 -8
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 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
+ class Cluster
21
+ # @private
22
+ class Options
23
+ attr_reader :credentials, :auth_provider, :compressor, :port,
24
+ :connection_timeout, :connections_per_local_node, :connections_per_remote_node
25
+ attr_accessor :protocol_version
26
+
27
+ def initialize(protocol_version, credentials, auth_provider, compressor, port, connection_timeout, connections_per_local_node, connections_per_remote_node)
28
+ @protocol_version = protocol_version
29
+ @credentials = credentials
30
+ @auth_provider = auth_provider
31
+ @compressor = compressor
32
+ @port = port
33
+ @connection_timeout = connection_timeout
34
+
35
+ @connections_per_local_node = connections_per_local_node
36
+ @connections_per_remote_node = connections_per_remote_node
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,181 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 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
+ class Cluster
21
+ # @private
22
+ class Registry
23
+ include MonitorMixin
24
+
25
+ LISTENER_METHODS = [:host_found, :host_lost, :host_up, :host_down].freeze
26
+
27
+ def initialize(logger)
28
+ @logger = logger
29
+ @hosts = ::Hash.new
30
+ @listeners = ::Set.new
31
+
32
+ mon_initialize
33
+ end
34
+
35
+ def add_listener(listener)
36
+ synchronize { @listeners = @listeners.dup.add(listener) }
37
+
38
+ self
39
+ end
40
+
41
+ def remove_listener(listener)
42
+ synchronize { @listeners = @listeners.dup.delete(listener) }
43
+
44
+ self
45
+ end
46
+
47
+ def each_host(&block)
48
+ @hosts.values.each(&block)
49
+ end
50
+ alias :hosts :each_host
51
+
52
+ def host(address)
53
+ @hosts[address.to_s]
54
+ end
55
+
56
+ def has_host?(address)
57
+ @hosts.has_key?(address.to_s)
58
+ end
59
+
60
+ def host_found(address, data = {})
61
+ ip = address.to_s
62
+ host = @hosts[ip]
63
+
64
+ if host
65
+ if host.id == data['host_id'] &&
66
+ host.release_version == data['release_version'] &&
67
+ host.rack == data['rack'] &&
68
+ host.datacenter == data['data_center']
69
+
70
+ return self
71
+ else
72
+ notify_lost(host)
73
+
74
+ host = create_host(address, data)
75
+
76
+ notify_found(host)
77
+ end
78
+ else
79
+ host = create_host(address, data)
80
+
81
+ notify_found(host)
82
+ end
83
+
84
+ synchronize { @hosts = @hosts.merge(ip => host) }
85
+
86
+ self
87
+ end
88
+
89
+ def host_down(address)
90
+ ip = address.to_s
91
+ host = @hosts[ip]
92
+
93
+ return self unless host && !host.down?
94
+
95
+ host = toggle_down(host)
96
+
97
+ synchronize { @hosts = @hosts.merge(ip => host) }
98
+
99
+ self
100
+ end
101
+
102
+ def host_up(address)
103
+ ip = address.to_s
104
+ host = @hosts[ip]
105
+
106
+ return self unless host && !host.up?
107
+
108
+ host = toggle_up(host)
109
+
110
+ synchronize { @hosts = @hosts.merge(ip => host) }
111
+
112
+ self
113
+ end
114
+
115
+ def host_lost(address)
116
+ ip = address.to_s
117
+ host = nil
118
+
119
+ return self unless @hosts.has_key?(ip)
120
+
121
+ synchronize do
122
+ hosts = @hosts.dup
123
+ host = hosts.delete(ip)
124
+ @hosts = hosts
125
+ end
126
+
127
+ notify_lost(host)
128
+
129
+ self
130
+ end
131
+
132
+ private
133
+
134
+ def create_host(ip, data)
135
+ Host.new(ip, data['host_id'], data['rack'], data['data_center'], data['release_version'], :up)
136
+ end
137
+
138
+ def toggle_up(host)
139
+ host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :up)
140
+ @logger.debug("Host #{host.ip} is up")
141
+ @listeners.each do |listener|
142
+ listener.host_up(host) rescue nil
143
+ end
144
+ host
145
+ end
146
+
147
+ def toggle_down(host)
148
+ host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :down)
149
+ @logger.debug("Host #{host.ip} is down")
150
+ @listeners.each do |listener|
151
+ listener.host_down(host) rescue nil
152
+ end
153
+ host
154
+ end
155
+
156
+ def notify_lost(host)
157
+ if host.up?
158
+ @logger.debug("Host #{host.ip} is down and lost")
159
+ host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, :down)
160
+ @listeners.each do |listener|
161
+ listener.host_down(host) rescue nil
162
+ listener.host_lost(host) rescue nil
163
+ end
164
+ else
165
+ @logger.debug("Host #{host.ip} is lost")
166
+ @listeners.each do |listener|
167
+ listener.host_lost(host) rescue nil
168
+ end
169
+ end
170
+ end
171
+
172
+ def notify_found(host)
173
+ @logger.debug("Host #{host.ip} is found and up")
174
+ @listeners.each do |listener|
175
+ listener.host_found(host) rescue nil
176
+ listener.host_up(host) rescue nil
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,321 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 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
+ class Cluster
21
+ # @private
22
+ class Schema
23
+ include MonitorMixin
24
+
25
+ def initialize(schema_type_parser)
26
+ @type_parser = schema_type_parser
27
+ @keyspaces = ::Hash.new
28
+ @listeners = ::Set.new
29
+
30
+ mon_initialize
31
+ end
32
+
33
+ def add_listener(listener)
34
+ synchronize do
35
+ @listeners = @listeners.dup.add(listener)
36
+ end
37
+
38
+ self
39
+ end
40
+
41
+ def remove_listener(listener)
42
+ synchronize do
43
+ @listeners = @listeners.dup.delete(listener)
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ def update_keyspaces(host, keyspaces, tables, columns)
50
+ columns = columns.each_with_object(deephash { [] }) do |row, index|
51
+ index[row['keyspace_name']] << row
52
+ end
53
+
54
+ tables = tables.each_with_object(deephash { [] }) do |row, index|
55
+ index[row['keyspace_name']] << row
56
+ end
57
+
58
+ current_keyspaces = ::Set.new
59
+
60
+ keyspaces.each do |row|
61
+ current_keyspaces << keyspace = row['keyspace_name']
62
+
63
+ update_keyspace(host, row, tables[keyspace], columns[keyspace])
64
+ end
65
+
66
+ @keyspaces.each do |name, keyspace|
67
+ delete_keyspace(name) unless current_keyspaces.include?(name)
68
+ end
69
+
70
+ self
71
+ end
72
+
73
+ def update_keyspace(host, keyspace, tables, columns)
74
+ keyspace_name = keyspace['keyspace_name']
75
+
76
+ columns = columns.each_with_object(deephash { ::Hash.new }) do |row, index|
77
+ index[row['columnfamily_name']][row['column_name']] = row
78
+ end
79
+
80
+ tables = tables.each_with_object(Hash.new) do |row, index|
81
+ name = row['columnfamily_name']
82
+ index[name] = create_table(row, columns[name], host.release_version)
83
+ end
84
+
85
+ replication = Keyspace::Replication.new(keyspace['strategy_class'], ::JSON.load(keyspace['strategy_options']))
86
+ keyspace = Keyspace.new(keyspace_name, keyspace['durable_writes'], replication, tables)
87
+
88
+ return self if keyspace == @keyspaces[keyspace_name]
89
+
90
+ created = !@keyspaces.include?(keyspace_name)
91
+
92
+ synchronize do
93
+ @keyspaces = @keyspaces.merge(keyspace_name => keyspace)
94
+ end
95
+
96
+ if created
97
+ keyspace_created(keyspace)
98
+ else
99
+ keyspace_changed(keyspace)
100
+ end
101
+
102
+ self
103
+ end
104
+
105
+ def delete_keyspace(keyspace_name)
106
+ keyspace = @keyspaces[keyspace_name]
107
+
108
+ return self unless keyspace
109
+
110
+ synchronize do
111
+ keyspaces = @keyspaces.dup
112
+ keyspaces.delete(keyspace_name)
113
+ @keyspaces = keyspaces
114
+ end
115
+
116
+ keyspace_dropped(keyspace)
117
+
118
+ self
119
+ end
120
+
121
+ def udpate_table(host, keyspace_name, table, columns)
122
+ keyspace = @keyspaces[keyspace_name]
123
+
124
+ return self unless keyspace
125
+
126
+ table = create_table(table, columns, host.release_version)
127
+ keyspace = keyspace.update_table(table)
128
+
129
+ synchronize do
130
+ @keyspaces = @keyspaces.merge(keyspace_name => keyspace)
131
+ end
132
+
133
+ keyspace_updated(keyspace)
134
+
135
+ self
136
+ end
137
+
138
+ def has_keyspace?(name)
139
+ @keyspaces.include?(name)
140
+ end
141
+
142
+ def keyspace(name)
143
+ @keyspaces[name]
144
+ end
145
+
146
+ def each_keyspace(&block)
147
+ @keyspaces.values.each(&block)
148
+ end
149
+ alias :keyspaces :each_keyspace
150
+
151
+ private
152
+
153
+ def create_table(table, columns, version)
154
+ keyspace = table['keyspace_name']
155
+ name = table['columnfamily_name']
156
+ key_validator = @type_parser.parse(table['key_validator'])
157
+ comparator = @type_parser.parse(table['comparator'])
158
+ column_aliases = ::JSON.load(table['column_aliases'])
159
+
160
+ clustering_size = find_clustering_size(comparator, columns.values,
161
+ column_aliases, version)
162
+
163
+ is_dense = clustering_size != comparator.results.size - 1
164
+ is_compact = is_dense || !comparator.collections
165
+ partition_key = []
166
+ clustering_columns = []
167
+ clustering_order = []
168
+
169
+ compaction_strategy = Table::Compaction.new(
170
+ table['compaction_strategy_class'],
171
+ ::JSON.load(table['compaction_strategy_options'])
172
+ )
173
+ compression_parameters = ::JSON.load(table['compression_parameters'])
174
+
175
+ options = Table::Options.new(table, compaction_strategy, compression_parameters, is_compact, version)
176
+ columns = create_columns(key_validator, comparator, column_aliases, is_dense, clustering_size, table, columns, version, partition_key, clustering_columns, clustering_order)
177
+
178
+ Table.new(keyspace, name, partition_key, clustering_columns, columns, options, clustering_order)
179
+ end
180
+
181
+ def find_clustering_size(comparator, columns, aliases, cassandra_version)
182
+ if cassandra_version.start_with?('1')
183
+ if comparator.collections
184
+ size = comparator.results.size
185
+ (!comparator.collections.empty? || aliases.size == size - 1 && comparator.results.last.first == :text) ? size - 1 : size
186
+ else
187
+ (!aliases.empty? || columns.empty?) ? 1 : 0
188
+ end
189
+ else
190
+ max_index = nil
191
+
192
+ columns.each do |cl|
193
+ if cl['type'].upcase == 'CLUSTERING_KEY'
194
+ index = cl['component_index'] || 0
195
+
196
+ if max_index.nil? || index > max_index
197
+ max_index = index
198
+ end
199
+ end
200
+ end
201
+
202
+ return 0 if max_index.nil?
203
+
204
+ max_index + 1
205
+ end
206
+ end
207
+
208
+ def create_columns(key_validator, comparator, column_aliases, is_dense, clustering_size, table, columns, cassandra_version, partition_key, clustering_columns, clustering_order)
209
+ table_columns = {}
210
+ other_columns = []
211
+
212
+ if cassandra_version.start_with?('1')
213
+ key_aliases = ::JSON.load(table['key_aliases'])
214
+
215
+ key_validator.results.each_with_index do |(type, order), i|
216
+ key_alias = key_aliases.fetch(i) { i.zero? ? "key" : "key#{i + 1}" }
217
+
218
+ partition_key[i] = Column.new(key_alias, type, order)
219
+ end
220
+
221
+ if comparator.results.size > 1
222
+ clustering_size.times do |i|
223
+ column_alias = column_aliases.fetch(i) { "column#{i + 1}" }
224
+ type, order = comparator.results.fetch(i)
225
+
226
+ clustering_columns[i] = Column.new(column_alias, type, order)
227
+ clustering_order[i] = order
228
+ end
229
+ else
230
+ column_alias = column_aliases.first || "column1"
231
+ type, order = comparator.results.first
232
+
233
+ clustering_columns[0] = Column.new(column_alias, type, order)
234
+ clustering_order[0] = order
235
+ end
236
+
237
+ if is_dense
238
+ value_alias = table['value_alias'] || 'value'
239
+ type, order = @type_parser.parse(table['default_validator']).results.first
240
+ other_columns << Column.new(value_alias, type, order)
241
+ end
242
+
243
+ columns.each do |name, row|
244
+ other_columns << create_column(row)
245
+ end
246
+ else
247
+ columns.each do |name, row|
248
+ column = create_column(row)
249
+ type = row['type']
250
+ index = row['component_index'] || 0
251
+
252
+ case type.upcase
253
+ when 'PARTITION_KEY'
254
+ partition_key[index] = column
255
+ when 'CLUSTERING_KEY'
256
+ clustering_columns[index] = column
257
+ clustering_order[index] = column.order
258
+ else
259
+ other_columns << column
260
+ end
261
+ end
262
+ end
263
+
264
+ partition_key.each do |column|
265
+ table_columns[column.name] = column
266
+ end
267
+
268
+ clustering_columns.each do |column|
269
+ table_columns[column.name] = column
270
+ end
271
+
272
+ other_columns.each do |column|
273
+ table_columns[column.name] = column
274
+ end
275
+
276
+ table_columns
277
+ end
278
+
279
+ def create_column(column)
280
+ name = column['column_name']
281
+ type, order = @type_parser.parse(column['validator']).results.first
282
+ is_static = (column['type'] == 'STATIC')
283
+
284
+ if column['index_type'].nil?
285
+ index = nil
286
+ elsif column['index_type'].upcase == 'CUSTOM' || !column['index_options']
287
+ index = Column::Index.new(column['index_name'])
288
+ else
289
+ options = ::JSON.load(column['index_options'])
290
+ index = Column::Index.new(column['index_name'], options['class_name'])
291
+ end
292
+
293
+ Column.new(name, type, order, index, is_static)
294
+ end
295
+
296
+ def deephash
297
+ ::Hash.new {|hash, key| hash[key] = yield}
298
+ end
299
+
300
+ def keyspace_created(keyspace)
301
+ @listeners.each do |listener|
302
+ listener.keyspace_created(keyspace) rescue nil
303
+ end
304
+ end
305
+
306
+ def keyspace_changed(keyspace)
307
+ @listeners.each do |listener|
308
+ listener.keyspace_changed(keyspace) rescue nil
309
+ end
310
+ end
311
+
312
+ def keyspace_dropped(keyspace)
313
+ @listeners.each do |listener|
314
+ listener.keyspace_dropped(keyspace) rescue nil
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ require 'cassandra/cluster/schema/type_parser'