cassilds 0.9.1

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 (47) hide show
  1. data/CHANGELOG +53 -0
  2. data/LICENSE +202 -0
  3. data/Manifest +45 -0
  4. data/README.rdoc +83 -0
  5. data/Rakefile +9 -0
  6. data/bin/cassandra_helper +16 -0
  7. data/cassandra.gemspec +46 -0
  8. data/conf/cassandra.in.sh +47 -0
  9. data/conf/cassandra.yaml +113 -0
  10. data/conf/log4j.properties +38 -0
  11. data/conf/storage-conf.xml +342 -0
  12. data/lib/cassandra/0.6/cassandra.rb +68 -0
  13. data/lib/cassandra/0.6/columns.rb +35 -0
  14. data/lib/cassandra/0.6/protocol.rb +92 -0
  15. data/lib/cassandra/0.6.rb +7 -0
  16. data/lib/cassandra/0.7/cassandra.rb +272 -0
  17. data/lib/cassandra/0.7/column_family.rb +3 -0
  18. data/lib/cassandra/0.7/columns.rb +67 -0
  19. data/lib/cassandra/0.7/keyspace.rb +3 -0
  20. data/lib/cassandra/0.7/protocol.rb +139 -0
  21. data/lib/cassandra/0.7.rb +7 -0
  22. data/lib/cassandra/array.rb +8 -0
  23. data/lib/cassandra/cassandra.rb +302 -0
  24. data/lib/cassandra/columns.rb +79 -0
  25. data/lib/cassandra/comparable.rb +28 -0
  26. data/lib/cassandra/constants.rb +11 -0
  27. data/lib/cassandra/debug.rb +9 -0
  28. data/lib/cassandra/helpers.rb +40 -0
  29. data/lib/cassandra/long.rb +58 -0
  30. data/lib/cassandra/mock.rb +326 -0
  31. data/lib/cassandra/ordered_hash.rb +200 -0
  32. data/lib/cassandra/time.rb +11 -0
  33. data/lib/cassandra.rb +39 -0
  34. data/test/cassandra_client_test.rb +20 -0
  35. data/test/cassandra_mock_test.rb +73 -0
  36. data/test/cassandra_test.rb +412 -0
  37. data/test/comparable_types_test.rb +45 -0
  38. data/test/eventmachine_test.rb +42 -0
  39. data/test/ordered_hash_test.rb +380 -0
  40. data/test/test_helper.rb +14 -0
  41. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  42. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  43. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  44. data/vendor/0.7/gen-rb/cassandra.rb +1937 -0
  45. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  46. data/vendor/0.7/gen-rb/cassandra_types.rb +679 -0
  47. metadata +176 -0
@@ -0,0 +1,272 @@
1
+ class Cassandra
2
+
3
+ def self.DEFAULT_TRANSPORT_WRAPPER
4
+ Thrift::FramedTransport
5
+ end
6
+
7
+ def login!(username, password)
8
+ @auth_request = CassandraThrift::AuthenticationRequest.new
9
+ @auth_request.credentials = {'username' => username, 'password' => password}
10
+ client.login(@auth_request)
11
+ end
12
+
13
+ def inspect
14
+ "#<Cassandra:#{object_id}, @keyspace=#{keyspace.inspect}, @schema={#{
15
+ Array(schema(false).cf_defs).map {|cfdef| ":#{cfdef.name} => #{cfdef.column_type}"}.join(', ')
16
+ }}, @servers=#{servers.inspect}>"
17
+ end
18
+
19
+ def keyspace=(ks)
20
+ client.set_keyspace(ks)
21
+ @schema = nil; @keyspace = ks
22
+ end
23
+
24
+ def keyspaces
25
+ client.describe_keyspaces.to_a.collect {|ksdef| ksdef.name }
26
+ end
27
+
28
+ def schema(load=true)
29
+ if !load && !@schema
30
+ Cassandra::Keyspace.new
31
+ else
32
+ @schema ||= client.describe_keyspace(@keyspace)
33
+ end
34
+ end
35
+
36
+ def schema_agreement?
37
+ client.describe_schema_versions().length == 1
38
+ end
39
+
40
+ def version
41
+ client.describe_version()
42
+ end
43
+
44
+ def cluster_name
45
+ @cluster_name ||= client.describe_cluster_name()
46
+ end
47
+
48
+ def ring
49
+ client.describe_ring(@keyspace)
50
+ end
51
+
52
+ def partitioner
53
+ client.describe_partitioner()
54
+ end
55
+
56
+ ## Delete
57
+
58
+ # Remove all rows in the column family you request.
59
+ def truncate!(column_family)
60
+ #each_key(column_family) do |key|
61
+ # remove(column_family, key, options)
62
+ #end
63
+ client.truncate(column_family)
64
+ end
65
+
66
+ # Remove all rows in the keyspace.
67
+ def clear_keyspace!
68
+ schema.cf_defs.each { |cfdef| truncate!(cfdef.name) }
69
+ end
70
+
71
+ ### Read
72
+
73
+ def add_column_family(cf_def)
74
+ begin
75
+ res = client.system_add_column_family(cf_def)
76
+ rescue CassandraThrift::TimedOutException => te
77
+ puts "Timed out: #{te.inspect}"
78
+ end
79
+ @schema = nil
80
+ res
81
+ end
82
+
83
+ def drop_column_family(cf_name)
84
+ begin
85
+ res = client.system_drop_column_family(cf_name)
86
+ rescue CassandraThrift::TimedOutException => te
87
+ puts "Timed out: #{te.inspect}"
88
+ end
89
+ @schema = nil
90
+ res
91
+ end
92
+
93
+ def rename_column_family(old_name, new_name)
94
+ begin
95
+ res = client.system_rename_column_family(old_name, new_name)
96
+ rescue CassandraThrift::TimedOutException => te
97
+ puts "Timed out: #{te.inspect}"
98
+ end
99
+ @schema = nil
100
+ res
101
+ end
102
+
103
+ def update_column_family(cf_def)
104
+ begin
105
+ res = client.system_update_column_family(cf_def)
106
+ rescue CassandraThrift::TimedOutException => te
107
+ puts "Timed out: #{te.inspect}"
108
+ end
109
+ @schema = nil
110
+ res
111
+ end
112
+
113
+ def add_keyspace(ks_def)
114
+ begin
115
+ res = client.system_add_keyspace(ks_def)
116
+ rescue CassandraThrift::TimedOutException => toe
117
+ puts "Timed out: #{toe.inspect}"
118
+ rescue Thrift::TransportException => te
119
+ puts "Timed out: #{te.inspect}"
120
+ end
121
+ @keyspaces = nil
122
+ res
123
+ end
124
+
125
+ def drop_keyspace(ks_name)
126
+ begin
127
+ res = client.system_drop_keyspace(ks_name)
128
+ rescue CassandraThrift::TimedOutException => toe
129
+ puts "Timed out: #{toe.inspect}"
130
+ rescue Thrift::TransportException => te
131
+ puts "Timed out: #{te.inspect}"
132
+ end
133
+ keyspace = "system" if ks_name.eql?(@keyspace)
134
+ @keyspaces = nil
135
+ res
136
+ end
137
+
138
+ def rename_keyspace(old_name, new_name)
139
+ begin
140
+ res = client.system_rename_keyspace(old_name, new_name)
141
+ rescue CassandraThrift::TimedOutException => toe
142
+ puts "Timed out: #{toe.inspect}"
143
+ rescue Thrift::TransportException => te
144
+ puts "Timed out: #{te.inspect}"
145
+ end
146
+ keyspace = new_name if old_name.eql?(@keyspace)
147
+ @keyspaces = nil
148
+ res
149
+ end
150
+
151
+ def update_keyspace(ks_def)
152
+ begin
153
+ res = client.system_update_keyspace(ks_def)
154
+ rescue CassandraThrift::TimedOutException => toe
155
+ puts "Timed out: #{toe.inspect}"
156
+ rescue Thrift::TransportException => te
157
+ puts "Timed out: #{te.inspect}"
158
+ end
159
+ @keyspaces = nil
160
+ res
161
+ end
162
+
163
+ # Open a batch operation and yield self. Inserts and deletes will be queued
164
+ # until the block closes, and then sent atomically to the server. Supports
165
+ # the <tt>:consistency</tt> option, which overrides the consistency set in
166
+ # the individual commands.
167
+ def batch(options = {})
168
+ _, _, _, options =
169
+ extract_and_validate_params(schema.cf_defs.first.name, "", [options], WRITE_DEFAULTS)
170
+
171
+ @batch = []
172
+ yield(self)
173
+ compact_mutations!
174
+
175
+ @batch.each do |mutation|
176
+ case mutation.first
177
+ when :remove
178
+ _remove(*mutation[1])
179
+ else
180
+ _mutate(*mutation)
181
+ end
182
+ end
183
+ ensure
184
+ @batch = nil
185
+ end
186
+
187
+ ### 2ary Indexing
188
+
189
+ def create_index(ks_name, cf_name, c_name, v_class)
190
+ cf_def = client.describe_keyspace(ks_name).cf_defs.find{|x| x.name == cf_name}
191
+ if !cf_def.nil? and !cf_def.column_metadata.find{|x| x.name == c_name}
192
+ c_def = CassandraThrift::ColumnDef.new do |cd|
193
+ cd.name = c_name
194
+ cd.validation_class = "org.apache.cassandra.db.marshal."+v_class
195
+ cd.index_type = CassandraThrift::IndexType::KEYS
196
+ end
197
+ cf_def.column_metadata.push(c_def)
198
+ update_column_family(cf_def)
199
+ end
200
+ end
201
+
202
+ def drop_index(ks_name, cf_name, c_name)
203
+ cf_def = client.describe_keyspace(ks_name).cf_defs.find{|x| x.name == cf_name}
204
+ if !cf_def.nil? and cf_def.column_metadata.find{|x| x.name == c_name}
205
+ cf_def.column_metadata.delete_if{|x| x.name == c_name}
206
+ update_column_family(cf_def)
207
+ end
208
+ end
209
+
210
+ def create_idx_expr(c_name, value, op)
211
+ CassandraThrift::IndexExpression.new(
212
+ :column_name => c_name,
213
+ :value => value,
214
+ :op => (case op
215
+ when nil, "EQ", "eq", "=="
216
+ CassandraThrift::IndexOperator::EQ
217
+ when "GTE", "gte", ">="
218
+ CassandraThrift::IndexOperator::GTE
219
+ when "GT", "gt", ">"
220
+ CassandraThrift::IndexOperator::GT
221
+ when "LTE", "lte", "<="
222
+ CassandraThrift::IndexOperator::LTE
223
+ when "LT", "lt", "<"
224
+ CassandraThrift::IndexOperator::LT
225
+ end ))
226
+ end
227
+
228
+ def create_idx_clause(idx_expressions, start = "")
229
+ CassandraThrift::IndexClause.new(
230
+ :start_key => start,
231
+ :expressions => idx_expressions)
232
+ end
233
+
234
+ # TODO: Supercolumn support.
235
+ def get_indexed_slices(column_family, idx_clause, *columns_and_options)
236
+ column_family, columns, _, options =
237
+ extract_and_validate_params(column_family, [], columns_and_options, READ_DEFAULTS)
238
+ _get_indexed_slices(column_family, idx_clause, columns, options[:count], options[:start],
239
+ options[:finish], options[:reversed], options[:consistency])
240
+ end
241
+
242
+ protected
243
+
244
+ def client
245
+ if @client.nil? || @client.current_server.nil?
246
+ reconnect!
247
+ @client.set_keyspace(@keyspace)
248
+ end
249
+ @client
250
+ end
251
+
252
+ def reconnect!
253
+ @servers = all_nodes
254
+ @client = new_client
255
+ end
256
+
257
+ def all_nodes
258
+ if @auto_discover_nodes && !@keyspace.eql?("system")
259
+ temp_client = new_client
260
+ begin
261
+ ips = (temp_client.describe_ring(@keyspace).map {|range| range.endpoints}).flatten.uniq
262
+ port = @servers.first.split(':').last
263
+ ips.map{|ip| "#{ip}:#{port}" }
264
+ ensure
265
+ temp_client.disconnect!
266
+ end
267
+ else
268
+ @servers
269
+ end
270
+ end
271
+
272
+ end
@@ -0,0 +1,3 @@
1
+ class Cassandra
2
+ class ColumnFamily < CassandraThrift::CfDef ; end
3
+ end
@@ -0,0 +1,67 @@
1
+
2
+ class Cassandra
3
+ # A bunch of crap, mostly related to introspecting on column types
4
+ module Columns #:nodoc:
5
+
6
+ def is_super(column_family)
7
+ @is_super[column_family] ||= column_family_property(column_family, 'column_type') == "Super"
8
+ end
9
+
10
+ def column_name_class(column_family)
11
+ @column_name_class[column_family] ||= column_name_class_for_key(column_family, "comparator_type")
12
+ end
13
+
14
+ def sub_column_name_class(column_family)
15
+ @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "subcomparator_type")
16
+ end
17
+
18
+ def column_family_property(column_family, key)
19
+ cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
20
+ unless cfdef
21
+ raise AccessError, "Invalid column family \"#{column_family}\""
22
+ end
23
+ cfdef.send(key)
24
+ end
25
+
26
+ def keyslice_to_hash(column_family, slice_array)
27
+ hash = OrderedHash.new
28
+ slice_array.each { |slice|
29
+ hash[slice.key] = columns_to_hash(column_family, slice.columns)
30
+ }
31
+ hash
32
+ end
33
+
34
+ private
35
+
36
+ def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
37
+ CassandraThrift::Mutation.new(
38
+ :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
39
+ :column => CassandraThrift::Column.new(
40
+ :name => column_name_class(column_family).new(column_name).to_s,
41
+ :value => value,
42
+ :timestamp => timestamp,
43
+ :ttl => ttl
44
+ )
45
+ )
46
+ )
47
+ end
48
+
49
+ def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
50
+ CassandraThrift::Mutation.new(:column_or_supercolumn =>
51
+ CassandraThrift::ColumnOrSuperColumn.new(
52
+ :super_column => CassandraThrift::SuperColumn.new(
53
+ :name => column_name_class(column_family).new(super_column_name).to_s,
54
+ :columns => sub_columns.collect { |sub_column_name, sub_column_value|
55
+ CassandraThrift::Column.new(
56
+ :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
57
+ :value => sub_column_value.to_s,
58
+ :timestamp => timestamp,
59
+ :ttl => ttl
60
+ )
61
+ }
62
+ )
63
+ )
64
+ )
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,3 @@
1
+ class Cassandra
2
+ class Keyspace < CassandraThrift::KsDef ; end
3
+ end
@@ -0,0 +1,139 @@
1
+
2
+ class Cassandra
3
+ # Inner methods for actually doing the Thrift calls
4
+ module Protocol #:nodoc:
5
+ private
6
+
7
+ def _mutate(mutation_map, consistency_level)
8
+ client.batch_mutate(mutation_map, consistency_level)
9
+ end
10
+
11
+ def _remove(key, column_path, timestamp, consistency_level)
12
+ client.remove(key, column_path, timestamp, consistency_level)
13
+ end
14
+
15
+ def _count_columns(column_family, key, super_column, consistency)
16
+ client.get_count(key,
17
+ CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => super_column),
18
+ consistency
19
+ )
20
+ end
21
+
22
+ def _get_columns(column_family, key, columns, sub_columns, consistency)
23
+ result = if is_super(column_family)
24
+ if sub_columns
25
+ columns_to_hash(column_family, client.get_slice(key,
26
+ CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => columns),
27
+ CassandraThrift::SlicePredicate.new(:column_names => Array(sub_columns)),
28
+ consistency))
29
+ else
30
+ columns_to_hash(column_family, client.get_slice(key,
31
+ CassandraThrift::ColumnParent.new(:column_family => column_family),
32
+ CassandraThrift::SlicePredicate.new(:column_names => Array(columns)),
33
+ consistency))
34
+ end
35
+ else
36
+ columns_to_hash(column_family, client.get_slice(key,
37
+ CassandraThrift::ColumnParent.new(:column_family => column_family),
38
+ CassandraThrift::SlicePredicate.new(:column_names => Array(columns)),
39
+ consistency))
40
+ end
41
+ end
42
+
43
+ def _multiget(column_family, keys, column, sub_column, start, finish, count, reversed, consistency)
44
+ # Single values; count and range parameters have no effect
45
+ if is_super(column_family) and sub_column
46
+ predicate = CassandraThrift::SlicePredicate.new(:column_names => Array(column))
47
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => column)
48
+ multi_sub_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
49
+
50
+ elsif !is_super(column_family) and column
51
+ predicate = CassandraThrift::SlicePredicate.new(:column_names => Array(column))
52
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
53
+ multi_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
54
+
55
+ # Slices
56
+ else
57
+ predicate = CassandraThrift::SlicePredicate.new(:slice_range =>
58
+ CassandraThrift::SliceRange.new(
59
+ :reversed => reversed,
60
+ :count => count,
61
+ :start => start,
62
+ :finish => finish))
63
+
64
+ if is_super(column_family) and column
65
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => column)
66
+ multi_sub_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
67
+ else
68
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
69
+ multi_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
70
+ end
71
+ end
72
+ end
73
+
74
+ def _get_range(column_family, start, finish, count, consistency)
75
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
76
+ predicate = CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => '', :count => count*10))
77
+ range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
78
+ client.get_range_slices(column_parent, predicate, range, consistency)
79
+ end
80
+
81
+ def _get_range_hash(column_family, start, finish, count, consistency)
82
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
83
+ predicate = CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
84
+ range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
85
+ result = client.get_range_slices(column_parent, predicate, range, consistency)
86
+ keyslice_to_hash column_family, result
87
+ end
88
+
89
+ def _get_range_columns(column_family, columns, sub_columns, start, finish, count, consistency)
90
+ result = if is_super(column_family)
91
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
92
+ predicate = if sub_columns
93
+ CassandraThrift::SlicePredicate.new(:column_names => Array(sub_columns))
94
+ else
95
+ CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
96
+ end
97
+ range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
98
+ client.get_range_slices(column_parent, predicate, range, consistency)
99
+ else
100
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
101
+ predicate = if columns
102
+ CassandraThrift::SlicePredicate.new(:column_names => Array(columns))
103
+ else
104
+ CassandraThrift::SlicePredicate.new(:slice_range => CassandraThrift::SliceRange.new(:start => '', :finish => ''))
105
+ end
106
+ range = CassandraThrift::KeyRange.new(:start_key => start, :end_key => finish, :count => count)
107
+ client.get_range_slices(column_parent, predicate, range, consistency)
108
+ end
109
+ keyslice_to_hash(column_family, result)
110
+ end
111
+
112
+ def _get_range_keys(column_family, start, finish, count, consistency)
113
+ _get_range(column_family, start, finish, count, consistency).collect{|i| i.key }
114
+ end
115
+
116
+ # TODO: Supercolumn support
117
+ def _get_indexed_slices(column_family, idx_clause, column, count, start, finish, reversed, consistency)
118
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
119
+ if column
120
+ predicate = CassandraThrift::SlicePredicate.new(:column_names => [column])
121
+ else
122
+ predicate = CassandraThrift::SlicePredicate.new(:slice_range =>
123
+ CassandraThrift::SliceRange.new(
124
+ :reversed => reversed,
125
+ :count => count,
126
+ :start => start,
127
+ :finish => finish))
128
+ end
129
+ client.get_indexed_slices(column_parent, idx_clause, predicate, consistency)
130
+ end
131
+
132
+ def each_key(column_family)
133
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family.to_s)
134
+ predicate = CassandraThrift::SlicePredicate.new(:column_names => [])
135
+ range = CassandraThrift::KeyRange.new(:start_key => '', :end_key => '')
136
+ client.get_range_slices(column_parent, predicate, range, 1).each{|i| yield i.key }
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,7 @@
1
+ class Cassandra
2
+ def self.VERSION
3
+ "0.7"
4
+ end
5
+ end
6
+
7
+ require "#{File.expand_path(File.dirname(__FILE__))}/../cassandra"
@@ -0,0 +1,8 @@
1
+
2
+ class Array
3
+ def _flatten_once
4
+ result = []
5
+ each { |el| result.concat(Array(el)) }
6
+ result
7
+ end
8
+ end