cassilds 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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