mcmire-cassandra 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG +108 -0
  2. data/LICENSE +202 -0
  3. data/Manifest +63 -0
  4. data/README.md +352 -0
  5. data/Rakefile +169 -0
  6. data/bin/cassandra_helper +16 -0
  7. data/conf/0.6/cassandra.in.sh +47 -0
  8. data/conf/0.6/log4j.properties +38 -0
  9. data/conf/0.6/schema.json +57 -0
  10. data/conf/0.6/storage-conf.xml +352 -0
  11. data/conf/0.7/cassandra.in.sh +46 -0
  12. data/conf/0.7/cassandra.yaml +336 -0
  13. data/conf/0.7/log4j-server.properties +41 -0
  14. data/conf/0.7/schema.json +57 -0
  15. data/conf/0.7/schema.txt +45 -0
  16. data/conf/0.8/cassandra.in.sh +41 -0
  17. data/conf/0.8/cassandra.yaml +61 -0
  18. data/conf/0.8/log4j-server.properties +40 -0
  19. data/conf/0.8/schema.json +66 -0
  20. data/conf/0.8/schema.txt +51 -0
  21. data/lib/cassandra/0.6/cassandra.rb +113 -0
  22. data/lib/cassandra/0.6/columns.rb +78 -0
  23. data/lib/cassandra/0.6/protocol.rb +90 -0
  24. data/lib/cassandra/0.6.rb +7 -0
  25. data/lib/cassandra/0.7/cassandra.rb +2 -0
  26. data/lib/cassandra/0.7/columns.rb +4 -0
  27. data/lib/cassandra/0.7/protocol.rb +5 -0
  28. data/lib/cassandra/0.7.rb +7 -0
  29. data/lib/cassandra/0.8/cassandra.rb +10 -0
  30. data/lib/cassandra/0.8/columns.rb +4 -0
  31. data/lib/cassandra/0.8/protocol.rb +21 -0
  32. data/lib/cassandra/0.8.rb +7 -0
  33. data/lib/cassandra/array.rb +8 -0
  34. data/lib/cassandra/cassandra.rb +1070 -0
  35. data/lib/cassandra/column_family.rb +3 -0
  36. data/lib/cassandra/columns.rb +144 -0
  37. data/lib/cassandra/comparable.rb +28 -0
  38. data/lib/cassandra/constants.rb +11 -0
  39. data/lib/cassandra/debug.rb +9 -0
  40. data/lib/cassandra/helpers.rb +41 -0
  41. data/lib/cassandra/keyspace.rb +3 -0
  42. data/lib/cassandra/long.rb +58 -0
  43. data/lib/cassandra/mock.rb +511 -0
  44. data/lib/cassandra/ordered_hash.rb +192 -0
  45. data/lib/cassandra/protocol.rb +120 -0
  46. data/lib/cassandra/time.rb +11 -0
  47. data/lib/cassandra.rb +38 -0
  48. data/mcmire-cassandra.gemspec +43 -0
  49. data/test/cassandra_client_test.rb +20 -0
  50. data/test/cassandra_mock_test.rb +116 -0
  51. data/test/cassandra_test.rb +863 -0
  52. data/test/comparable_types_test.rb +45 -0
  53. data/test/eventmachine_test.rb +42 -0
  54. data/test/ordered_hash_test.rb +386 -0
  55. data/test/test_helper.rb +15 -0
  56. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  57. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  58. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  59. data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
  60. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  61. data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
  62. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  63. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  64. data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
  65. metadata +200 -0
@@ -0,0 +1,3 @@
1
+ class Cassandra
2
+ class ColumnFamily < CassandraThrift::CfDef ; end
3
+ end
@@ -0,0 +1,144 @@
1
+
2
+ class Cassandra
3
+ # A bunch of crap, mostly related to introspecting on column types
4
+ module Columns #:nodoc:
5
+ private
6
+
7
+ def is_super(column_family)
8
+ @is_super[column_family] ||= column_family_property(column_family, 'column_type') == "Super"
9
+ end
10
+
11
+ def column_name_class(column_family)
12
+ @column_name_class[column_family] ||= column_name_class_for_key(column_family, "comparator_type")
13
+ end
14
+
15
+ def sub_column_name_class(column_family)
16
+ @sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "subcomparator_type")
17
+ end
18
+
19
+ def column_name_class_for_key(column_family, comparator_key)
20
+ property = column_family_property(column_family, comparator_key)
21
+ property =~ /.*\.(.*?)$/
22
+ case $1
23
+ when "LongType" then Long
24
+ when "LexicalUUIDType", "TimeUUIDType" then SimpleUUID::UUID
25
+ else
26
+ String # UTF8, Ascii, Bytes, anything else
27
+ end
28
+ end
29
+
30
+ def column_family_property(column_family, key)
31
+ cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
32
+ unless cfdef
33
+ raise AccessError, "Invalid column family \"#{column_family}\""
34
+ end
35
+ cfdef.send(key)
36
+ end
37
+
38
+ def multi_key_slices_to_hash(column_family, array, return_empty_rows = false)
39
+ ret = OrderedHash.new
40
+ array.each do |value|
41
+ next if return_empty_rows == false && value.columns.length == 0
42
+ ret[value.key] = columns_to_hash(column_family, value.columns)
43
+ end
44
+ ret
45
+ end
46
+
47
+ def multi_column_to_hash!(hash)
48
+ hash.each do |key, column_or_supercolumn|
49
+ hash[key] = (column_or_supercolumn.column.value if column_or_supercolumn.column)
50
+ end
51
+ end
52
+
53
+ def multi_columns_to_hash!(column_family, hash)
54
+ hash.each do |key, columns|
55
+ hash[key] = columns_to_hash(column_family, columns)
56
+ end
57
+ end
58
+
59
+ def multi_sub_columns_to_hash!(column_family, hash)
60
+ hash.each do |key, sub_columns|
61
+ hash[key] = sub_columns_to_hash(column_family, sub_columns)
62
+ end
63
+ end
64
+
65
+ def columns_to_hash(column_family, columns)
66
+ columns_to_hash_for_classes(columns, column_name_class(column_family), sub_column_name_class(column_family))
67
+ end
68
+
69
+ def sub_columns_to_hash(column_family, columns)
70
+ columns_to_hash_for_classes(columns, sub_column_name_class(column_family))
71
+ end
72
+
73
+ def columns_to_hash_for_classes(columns, column_name_class, sub_column_name_class = nil)
74
+ hash = OrderedHash.new
75
+ Array(columns).each do |c|
76
+ c = c.super_column || c.column || c.counter_column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
77
+ case c
78
+ when CassandraThrift::SuperColumn
79
+ hash.[]=(column_name_class.new(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_class)) # Pop the class stack, and recurse
80
+ when CassandraThrift::Column
81
+ hash.[]=(column_name_class.new(c.name), c.value, c.timestamp)
82
+ when CassandraThrift::CounterColumn
83
+ hash.[]=(column_name_class.new(c.name), c.value, 0)
84
+ end
85
+ end
86
+ hash
87
+ end
88
+
89
+ def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
90
+ CassandraThrift::Mutation.new(
91
+ :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
92
+ :column => CassandraThrift::Column.new(
93
+ :name => column_name_class(column_family).new(column_name).to_s,
94
+ :value => value,
95
+ :timestamp => timestamp,
96
+ :ttl => ttl
97
+ )
98
+ )
99
+ )
100
+ end
101
+
102
+ def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
103
+ CassandraThrift::Mutation.new(:column_or_supercolumn =>
104
+ CassandraThrift::ColumnOrSuperColumn.new(
105
+ :super_column => CassandraThrift::SuperColumn.new(
106
+ :name => column_name_class(column_family).new(super_column_name).to_s,
107
+ :columns => sub_columns.collect { |sub_column_name, sub_column_value|
108
+ CassandraThrift::Column.new(
109
+ :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
110
+ :value => sub_column_value.to_s,
111
+ :timestamp => timestamp,
112
+ :ttl => ttl
113
+ )
114
+ }
115
+ )
116
+ )
117
+ )
118
+ end
119
+
120
+ # General info about a deletion object within a mutation
121
+ # timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
122
+ # supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
123
+ # will be deleted). Otherwise the normal columns will be deleted.
124
+ # predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
125
+ # be scoped to subcolumns of that supercolumn.
126
+
127
+ # Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
128
+ # Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
129
+ # The main reason being that the batch function takes removes, but removes don't have that capability...so we'd need to change the remove
130
+ # methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
131
+ def _delete_mutation(cf, column, subcolumn, timestamp, options={})
132
+ deletion_hash = {:timestamp => timestamp}
133
+ if is_super(cf)
134
+ deletion_hash[:super_column] = column if column
135
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
136
+ else
137
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
138
+ end
139
+ CassandraThrift::Mutation.new(
140
+ :deletion => CassandraThrift::Deletion.new(deletion_hash)
141
+ )
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,28 @@
1
+
2
+ class Cassandra
3
+ # Abstract base class for comparable numeric column name types
4
+ class Comparable
5
+ class TypeError < ::TypeError #:nodoc:
6
+ end
7
+
8
+ def <=>(other)
9
+ self.to_i <=> other.to_i
10
+ end
11
+
12
+ def hash
13
+ @bytes.hash
14
+ end
15
+
16
+ def eql?(other)
17
+ other.is_a?(Comparable) and @bytes == other.to_s
18
+ end
19
+
20
+ def ==(other)
21
+ other.respond_to?(:to_i) && self.to_i == other.to_i
22
+ end
23
+
24
+ def to_s
25
+ @bytes
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+
2
+ class Cassandra
3
+ # A helper module you can include in your own class. Makes it easier
4
+ # to work with Cassandra subclasses.
5
+ module Constants
6
+ include Cassandra::Consistency
7
+
8
+ Long = Cassandra::Long
9
+ OrderedHash = Cassandra::OrderedHash
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+
2
+ require 'pp'
3
+
4
+ class CassandraThrift::Cassandra::Client
5
+ def send_message(*args)
6
+ pp args
7
+ super
8
+ end
9
+ end
@@ -0,0 +1,41 @@
1
+ class Cassandra
2
+ module Helpers
3
+ def extract_and_validate_params(column_family, keys, args, options)
4
+ options = options.dup
5
+ column_family = column_family.to_s
6
+ # Keys
7
+ [keys].flatten.each do |key|
8
+ raise ArgumentError, "Key #{key.inspect} must be a String for #{caller[2].inspect}." unless key.is_a?(String)
9
+ end
10
+
11
+ # Options
12
+ if args.last.is_a?(Hash)
13
+ extras = args.last.keys - options.keys
14
+ raise ArgumentError, "Invalid options #{extras.inspect[1..-2]} for #{caller[1]}" if extras.any?
15
+ options.merge!(args.pop)
16
+ end
17
+
18
+ # Ranges
19
+ column, sub_column = args[0], args[1]
20
+ raise ArgumentError, "Invalid arguments: subcolumns specified for a non-supercolumn family" if sub_column && !is_super(column_family)
21
+ klass, sub_klass = column_name_class(column_family), sub_column_name_class(column_family)
22
+ range_class = column ? sub_klass : klass
23
+
24
+ [:start, :finish].each do |opt|
25
+ options[opt] = options[opt] ? range_class.new(options[opt]).to_s : ''
26
+ end
27
+
28
+ [column_family, s_map(column, klass), s_map(sub_column, sub_klass), options]
29
+ end
30
+
31
+ # Convert stuff to strings.
32
+ def s_map(el, klass)
33
+ case el
34
+ when Array then el.map { |i| s_map(i, klass) }
35
+ when NilClass then nil
36
+ else
37
+ klass.new(el).to_s
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ class Cassandra
2
+ class Keyspace < CassandraThrift::KsDef ; end
3
+ end
@@ -0,0 +1,58 @@
1
+
2
+ class Cassandra
3
+ # A temporally-ordered Long class for use in Cassandra column names
4
+ class Long < Comparable
5
+
6
+ # FIXME Should unify with or subclass Cassandra::UUID
7
+ def initialize(bytes = nil)
8
+ case bytes
9
+ when self.class # Long
10
+ @bytes = bytes.to_s
11
+ when String
12
+ case bytes.size
13
+ when 8 # Raw byte array
14
+ @bytes = bytes
15
+ when 18 # Human-readable UUID-like representation; inverse of #to_guid
16
+ elements = bytes.split("-")
17
+ raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (malformed UUID-like representation)" if elements.size != 3
18
+ @bytes = [elements.join].pack('H32')
19
+ else
20
+ raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (invalid bytecount)"
21
+ end
22
+ when Integer
23
+ raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (integer out of range)" if bytes < 0 or bytes > 2**64
24
+ @bytes = [bytes >> 32, bytes % 2**32].pack("NN")
25
+ when NilClass, Time
26
+ # Time.stamp is 52 bytes, so we have 12 bytes of entropy left over
27
+ int = ((bytes || Time).stamp << 12) + rand(2**12)
28
+ @bytes = [int >> 32, int % 2**32].pack("NN")
29
+ else
30
+ raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (unknown source class)"
31
+ end
32
+ end
33
+
34
+ def to_i
35
+ @to_i ||= begin
36
+ ints = @bytes.unpack("NN")
37
+ (ints[0] << 32) +
38
+ ints[1]
39
+ end
40
+ end
41
+
42
+ def to_guid
43
+ "%08x-%04x-%04x" % @bytes.unpack("Nnn")
44
+ end
45
+
46
+ def inspect
47
+ "<Cassandra::Long##{object_id} time: #{
48
+ Time.at((to_i >> 12) / 1_000_000).utc.inspect
49
+ }, usecs: #{
50
+ (to_i >> 12) % 1_000_000
51
+ }, jitter: #{
52
+ to_i % 2**12
53
+ }, guid: #{
54
+ to_guid
55
+ }>"
56
+ end
57
+ end
58
+ end