sessionm-cassandra 1.0.0

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 (96) hide show
  1. data/CHANGELOG +135 -0
  2. data/Gemfile +8 -0
  3. data/LICENSE +202 -0
  4. data/Manifest +94 -0
  5. data/README.md +373 -0
  6. data/Rakefile +195 -0
  7. data/bin/cassandra_helper +16 -0
  8. data/conf/0.6/cassandra.in.sh +47 -0
  9. data/conf/0.6/log4j.properties +38 -0
  10. data/conf/0.6/schema.json +57 -0
  11. data/conf/0.6/storage-conf.xml +352 -0
  12. data/conf/0.7/cassandra.in.sh +46 -0
  13. data/conf/0.7/cassandra.yaml +336 -0
  14. data/conf/0.7/log4j-server.properties +41 -0
  15. data/conf/0.7/schema.json +57 -0
  16. data/conf/0.7/schema.txt +45 -0
  17. data/conf/0.8/cassandra.in.sh +41 -0
  18. data/conf/0.8/cassandra.yaml +61 -0
  19. data/conf/0.8/log4j-server.properties +40 -0
  20. data/conf/0.8/schema.json +72 -0
  21. data/conf/0.8/schema.txt +57 -0
  22. data/conf/1.0/cassandra.in.sh +41 -0
  23. data/conf/1.0/cassandra.yaml +415 -0
  24. data/conf/1.0/log4j-server.properties +40 -0
  25. data/conf/1.0/schema.json +72 -0
  26. data/conf/1.0/schema.txt +57 -0
  27. data/conf/1.1/cassandra.in.sh +41 -0
  28. data/conf/1.1/cassandra.yaml +567 -0
  29. data/conf/1.1/log4j-server.properties +44 -0
  30. data/conf/1.1/schema.json +72 -0
  31. data/conf/1.1/schema.txt +57 -0
  32. data/ext/cassandra_native.c +34 -0
  33. data/ext/extconf.rb +9 -0
  34. data/lib/cassandra/0.6/cassandra.rb +113 -0
  35. data/lib/cassandra/0.6/columns.rb +78 -0
  36. data/lib/cassandra/0.6/protocol.rb +91 -0
  37. data/lib/cassandra/0.6.rb +7 -0
  38. data/lib/cassandra/0.7/cassandra.rb +2 -0
  39. data/lib/cassandra/0.7/columns.rb +4 -0
  40. data/lib/cassandra/0.7/protocol.rb +5 -0
  41. data/lib/cassandra/0.7.rb +7 -0
  42. data/lib/cassandra/0.8/cassandra.rb +51 -0
  43. data/lib/cassandra/0.8/columns.rb +28 -0
  44. data/lib/cassandra/0.8/protocol.rb +10 -0
  45. data/lib/cassandra/0.8.rb +7 -0
  46. data/lib/cassandra/1.0/cassandra.rb +1 -0
  47. data/lib/cassandra/1.0/columns.rb +1 -0
  48. data/lib/cassandra/1.0/protocol.rb +1 -0
  49. data/lib/cassandra/1.0.rb +7 -0
  50. data/lib/cassandra/1.1/cassandra.rb +1 -0
  51. data/lib/cassandra/1.1/columns.rb +1 -0
  52. data/lib/cassandra/1.1/protocol.rb +1 -0
  53. data/lib/cassandra/1.1.rb +7 -0
  54. data/lib/cassandra/array.rb +8 -0
  55. data/lib/cassandra/batch.rb +41 -0
  56. data/lib/cassandra/cassandra.rb +1088 -0
  57. data/lib/cassandra/column_family.rb +3 -0
  58. data/lib/cassandra/columns.rb +172 -0
  59. data/lib/cassandra/comparable.rb +28 -0
  60. data/lib/cassandra/composite.rb +140 -0
  61. data/lib/cassandra/constants.rb +11 -0
  62. data/lib/cassandra/debug.rb +9 -0
  63. data/lib/cassandra/dynamic_composite.rb +96 -0
  64. data/lib/cassandra/helpers.rb +41 -0
  65. data/lib/cassandra/keyspace.rb +3 -0
  66. data/lib/cassandra/long.rb +58 -0
  67. data/lib/cassandra/mock.rb +525 -0
  68. data/lib/cassandra/ordered_hash.rb +192 -0
  69. data/lib/cassandra/protocol.rb +137 -0
  70. data/lib/cassandra/time.rb +11 -0
  71. data/lib/cassandra.rb +41 -0
  72. data/sessionm-cassandra.gemspec +47 -0
  73. data/test/cassandra_client_test.rb +20 -0
  74. data/test/cassandra_mock_test.rb +128 -0
  75. data/test/cassandra_test.rb +1353 -0
  76. data/test/comparable_types_test.rb +45 -0
  77. data/test/composite_type_test.rb +64 -0
  78. data/test/eventmachine_test.rb +42 -0
  79. data/test/ordered_hash_test.rb +386 -0
  80. data/test/test_helper.rb +19 -0
  81. data/vendor/0.6/gen-rb/cassandra.rb +1481 -0
  82. data/vendor/0.6/gen-rb/cassandra_constants.rb +12 -0
  83. data/vendor/0.6/gen-rb/cassandra_types.rb +482 -0
  84. data/vendor/0.7/gen-rb/cassandra.rb +1936 -0
  85. data/vendor/0.7/gen-rb/cassandra_constants.rb +12 -0
  86. data/vendor/0.7/gen-rb/cassandra_types.rb +681 -0
  87. data/vendor/0.8/gen-rb/cassandra.rb +2215 -0
  88. data/vendor/0.8/gen-rb/cassandra_constants.rb +12 -0
  89. data/vendor/0.8/gen-rb/cassandra_types.rb +824 -0
  90. data/vendor/1.0/gen-rb/cassandra.rb +2215 -0
  91. data/vendor/1.0/gen-rb/cassandra_constants.rb +12 -0
  92. data/vendor/1.0/gen-rb/cassandra_types.rb +857 -0
  93. data/vendor/1.1/gen-rb/cassandra.rb +2571 -0
  94. data/vendor/1.1/gen-rb/cassandra_constants.rb +12 -0
  95. data/vendor/1.1/gen-rb/cassandra_types.rb +928 -0
  96. metadata +287 -0
@@ -0,0 +1,3 @@
1
+ class Cassandra
2
+ class ColumnFamily < CassandraThrift::CfDef ; end
3
+ end
@@ -0,0 +1,172 @@
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_maker(column_family)
20
+ @column_name_maker[column_family] ||=
21
+ begin
22
+ klass = column_name_class(column_family)
23
+ if klass == Composite
24
+ lambda {|name| klass.new_from_packed(name) }
25
+ else
26
+ lambda {|name| klass.new(name) }
27
+ end
28
+ end
29
+ end
30
+
31
+ def sub_column_name_maker(column_family)
32
+ @sub_column_name_maker[column_family] ||=
33
+ begin
34
+ klass = sub_column_name_class(column_family)
35
+ if klass == Composite
36
+ lambda {|name| klass.new_from_packed(name) }
37
+ else
38
+ lambda {|name| klass.new(name) }
39
+ end
40
+ end
41
+ end
42
+
43
+ def column_name_class_for_key(column_family, comparator_key)
44
+ property = column_family_property(column_family, comparator_key)
45
+ property =~ /[^(]*\.(.*?)$/
46
+ case $1
47
+ when "LongType" then Long
48
+ when "LexicalUUIDType", "TimeUUIDType" then SimpleUUID::UUID
49
+ when /^DynamicCompositeType\(/ then DynamicComposite
50
+ when /^CompositeType\(/ then Composite
51
+ else
52
+ String # UTF8, Ascii, Bytes, anything else
53
+ end
54
+ end
55
+
56
+ def column_family_property(column_family, key)
57
+ cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
58
+ unless cfdef
59
+ raise AccessError, "Invalid column family \"#{column_family}\""
60
+ end
61
+ cfdef.send(key)
62
+ end
63
+
64
+ def multi_key_slices_to_hash(column_family, array, return_empty_rows = false)
65
+ ret = OrderedHash.new
66
+ array.each do |value|
67
+ next if return_empty_rows == false && value.columns.length == 0
68
+ ret[value.key] = columns_to_hash(column_family, value.columns)
69
+ end
70
+ ret
71
+ end
72
+
73
+ def multi_column_to_hash!(hash)
74
+ hash.each do |key, column_or_supercolumn|
75
+ hash[key] = (column_or_supercolumn.column.value if column_or_supercolumn.column)
76
+ end
77
+ end
78
+
79
+ def multi_columns_to_hash!(column_family, hash)
80
+ hash.each do |key, columns|
81
+ hash[key] = columns_to_hash(column_family, columns)
82
+ end
83
+ end
84
+
85
+ def multi_sub_columns_to_hash!(column_family, hash)
86
+ hash.each do |key, sub_columns|
87
+ hash[key] = sub_columns_to_hash(column_family, sub_columns)
88
+ end
89
+ end
90
+
91
+ def columns_to_hash(column_family, columns)
92
+ columns_to_hash_for_classes(columns, column_name_maker(column_family), sub_column_name_maker(column_family))
93
+ end
94
+
95
+ def sub_columns_to_hash(column_family, columns)
96
+ columns_to_hash_for_classes(columns, sub_column_name_maker(column_family))
97
+ end
98
+
99
+ def columns_to_hash_for_classes(columns, column_name_maker, sub_column_name_maker = nil)
100
+ hash = OrderedHash.new
101
+ Array(columns).each do |c|
102
+ c = c.super_column || c.column || c.counter_column || c.counter_super_column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
103
+ case c
104
+ when CassandraThrift::SuperColumn
105
+ hash.[]=(column_name_maker.call(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_maker)) # Pop the class stack, and recurse
106
+ when CassandraThrift::Column
107
+ hash.[]=(column_name_maker.call(c.name), c.value, c.timestamp)
108
+ when CassandraThrift::CounterColumn
109
+ hash.[]=(column_name_maker.call(c.name), c.value, 0)
110
+ when CassandraThrift::CounterSuperColumn
111
+ hash.[]=(column_name_maker.call(c.name), columns_to_hash_for_classes(c.columns, sub_column_name_maker)) # Pop the class stack, and recurse
112
+ end
113
+ end
114
+ hash
115
+ end
116
+
117
+ def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
118
+ CassandraThrift::Mutation.new(
119
+ :column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
120
+ :column => CassandraThrift::Column.new(
121
+ :name => column_name_class(column_family).new(column_name).to_s,
122
+ :value => value,
123
+ :timestamp => timestamp,
124
+ :ttl => ttl
125
+ )
126
+ )
127
+ )
128
+ end
129
+
130
+ def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
131
+ CassandraThrift::Mutation.new(:column_or_supercolumn =>
132
+ CassandraThrift::ColumnOrSuperColumn.new(
133
+ :super_column => CassandraThrift::SuperColumn.new(
134
+ :name => column_name_class(column_family).new(super_column_name).to_s,
135
+ :columns => sub_columns.collect { |sub_column_name, sub_column_value|
136
+ CassandraThrift::Column.new(
137
+ :name => sub_column_name_class(column_family).new(sub_column_name).to_s,
138
+ :value => sub_column_value.to_s,
139
+ :timestamp => timestamp,
140
+ :ttl => ttl
141
+ )
142
+ }
143
+ )
144
+ )
145
+ )
146
+ end
147
+
148
+ # General info about a deletion object within a mutation
149
+ # timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
150
+ # supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
151
+ # will be deleted). Otherwise the normal columns will be deleted.
152
+ # predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
153
+ # be scoped to subcolumns of that supercolumn.
154
+
155
+ # Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
156
+ # Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
157
+ # 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
158
+ # methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
159
+ def _delete_mutation(cf, column, subcolumn, timestamp, options={})
160
+ deletion_hash = {:timestamp => timestamp}
161
+ if is_super(cf)
162
+ deletion_hash[:super_column] = column if column
163
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
164
+ else
165
+ deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
166
+ end
167
+ CassandraThrift::Mutation.new(
168
+ :deletion => CassandraThrift::Deletion.new(deletion_hash)
169
+ )
170
+ end
171
+ end
172
+ 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,140 @@
1
+ class Cassandra
2
+ class Composite
3
+ include ::Comparable
4
+ attr_reader :parts
5
+ attr_reader :column_slice
6
+
7
+ def initialize(*parts)
8
+ return if parts.empty?
9
+
10
+ options = {}
11
+ if parts.last.is_a?(Hash)
12
+ options = parts.pop
13
+ end
14
+ @column_slice = options[:slice]
15
+ raise ArgumentError if @column_slice != nil && ![:before, :after].include?(@column_slice)
16
+
17
+ if parts.length == 1 && parts[0].instance_of?(self.class)
18
+ @column_slice = parts[0].column_slice
19
+ @parts = parts[0].parts
20
+ elsif parts.length == 1 && parts[0].instance_of?(String) && @column_slice.nil? && try_packed_composite(parts[0])
21
+ @hash = parts[0].hash
22
+ else
23
+ @parts = parts
24
+ end
25
+ end
26
+
27
+ def self.new_from_packed(packed)
28
+ obj = new
29
+ obj.fast_unpack(packed)
30
+ return obj
31
+ end
32
+
33
+ def [](*args)
34
+ return @parts[*args]
35
+ end
36
+
37
+ def pack
38
+ packed = @parts.map do |part|
39
+ [part.length].pack('n') + part + "\x00"
40
+ end
41
+ if @column_slice
42
+ part = @parts[-1]
43
+ packed[-1] = [part.length].pack('n') + part + slice_end_of_component
44
+ end
45
+ return packed.join('')
46
+ end
47
+
48
+ def to_s
49
+ return pack
50
+ end
51
+
52
+ def <=>(other)
53
+ if !other.instance_of?(self.class)
54
+ return @parts.first <=> other
55
+ end
56
+ eoc = slice_end_of_component.unpack('c')[0]
57
+ other_eoc = other.slice_end_of_component.unpack('c')[0]
58
+ @parts.zip(other.parts).each do |a, b|
59
+ next if a == b
60
+ if a.nil? && b.nil?
61
+ return eoc <=> other_eoc
62
+ end
63
+
64
+ if a.nil?
65
+ return @column_slice == :after ? 1 : -1
66
+ end
67
+ if b.nil?
68
+ return other.column_slice == :after ? -1 : 1
69
+ end
70
+ return -1 if a < b
71
+ return 1 if a > b
72
+ end
73
+ return 0
74
+ end
75
+
76
+ def inspect
77
+ return "#<#{self.class}:#{@column_slice} #{@parts.inspect}>"
78
+ end
79
+
80
+ def slice_end_of_component
81
+ return "\x01" if @column_slice == :after
82
+ return "\xFF" if @column_slice == :before
83
+ return "\x00"
84
+ end
85
+
86
+ def fast_unpack(packed_string)
87
+ @hash = packed_string.hash
88
+
89
+ @parts = []
90
+ end_of_component = packed_string.slice(packed_string.length-1, 1)
91
+ while packed_string.length > 0
92
+ length = packed_string.unpack('n')[0]
93
+ @parts << packed_string.slice(2, length)
94
+
95
+ packed_string.slice!(0, length+3)
96
+ end
97
+
98
+ @column_slice = :after if end_of_component == "\x01"
99
+ @column_slice = :before if end_of_component == "\xFF"
100
+ end
101
+
102
+ private
103
+ def try_packed_composite(packed_string)
104
+ parts = []
105
+ end_of_component = nil
106
+ while packed_string.length > 0
107
+ length = packed_string.slice(0, 2).unpack('n')[0]
108
+ return false if length.nil? || length + 3 > packed_string.length
109
+
110
+ parts << packed_string.slice(2, length)
111
+ end_of_component = packed_string.slice(2 + length, 1)
112
+ if length + 3 != packed_string.length
113
+ return false if end_of_component != "\x00"
114
+ end
115
+
116
+ packed_string = packed_string.slice(3 + length, packed_string.length)
117
+ end
118
+
119
+ @column_slice = :after if end_of_component == "\x01"
120
+ @column_slice = :before if end_of_component == "\xFF"
121
+ @parts = parts
122
+
123
+ return true
124
+ end
125
+
126
+ def hash
127
+ return @hash ||= pack.hash
128
+ end
129
+
130
+ def eql?(other)
131
+ return to_s == other.to_s
132
+ end
133
+ end
134
+ end
135
+
136
+ begin
137
+ require "cassandra_native"
138
+ rescue LoadError
139
+ puts "Unable to load cassandra_native extension. Defaulting to pure Ruby libraries."
140
+ 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,96 @@
1
+ class Cassandra
2
+ class DynamicComposite < Composite
3
+ attr_accessor :types
4
+
5
+ def initialize(*parts)
6
+ return if parts.empty?
7
+
8
+ options = {}
9
+ if parts.last.is_a?(Hash)
10
+ options = parts.pop
11
+ end
12
+ @column_slice = options[:slice]
13
+ raise ArgumentError if @column_slice != nil && ![:before, :after].include?(@column_slice)
14
+
15
+ if parts.length == 1 && parts[0].instance_of?(self.class)
16
+ @column_slice = parts[0].column_slice
17
+ @parts = parts[0].parts
18
+ @types = parts[0].types
19
+ elsif parts.length == 1 && parts[0].instance_of?(String) && @column_slice.nil? && try_packed_composite(parts[0])
20
+ @hash = parts[0].hash
21
+ else
22
+ @types, @parts = parts.transpose
23
+ end
24
+ end
25
+
26
+ def pack
27
+ packed_parts = @parts.map do |part|
28
+ [part.length].pack('n') + part + "\x00"
29
+ end
30
+
31
+ if @column_slice
32
+ part = @parts[-1]
33
+ packed_parts[-1] = [part.length].pack('n') + part + slice_end_of_component
34
+ end
35
+
36
+ packed_types = @types.map do |type|
37
+ if type.length == 1
38
+ [0x8000 | type[0].ord].pack('n')
39
+ else
40
+ [type.length].pack('n') + type
41
+ end
42
+ end
43
+
44
+ return packed_types.zip(packed_parts).flatten.join('')
45
+ end
46
+
47
+ def fast_unpack(packed_string)
48
+ result = try_packed_composite(packed_string)
49
+ raise ArgumentError.new("Invalid DynamicComposite column") if !result
50
+ @hash = packed_string.hash
51
+ end
52
+
53
+ private
54
+ def try_packed_composite(packed_string)
55
+ types = []
56
+ parts = []
57
+ end_of_component = nil
58
+ offset = 0
59
+
60
+ read_bytes = proc do |length|
61
+ return false if offset + length > packed_string.length
62
+ out = packed_string.slice(offset, length)
63
+ offset += length
64
+ out
65
+ end
66
+
67
+ while offset < packed_string.length
68
+ header = read_bytes.call(2).unpack('n')[0]
69
+ is_alias = header & 0x8000 != 0
70
+ if is_alias
71
+ alias_char = (header & 0xFF).chr
72
+ types << alias_char
73
+ else
74
+ length = header
75
+ return false if length.nil? || length + offset > packed_string.length
76
+ type = read_bytes.call(length)
77
+ types << type
78
+ end
79
+ length = read_bytes.call(2).unpack('n')[0]
80
+ return false if length.nil? || length + offset > packed_string.length
81
+ parts << read_bytes.call(length)
82
+ end_of_component = read_bytes.call(1)
83
+ if offset < packed_string.length
84
+ return false if end_of_component != "\x00"
85
+ end
86
+ end
87
+ @column_slice = :after if end_of_component == "\x01"
88
+ @column_slice = :before if end_of_component == "\xFF"
89
+ @types = types
90
+ @parts = parts
91
+ @hash = packed_string.hash
92
+
93
+ return true
94
+ end
95
+ end
96
+ end