mcmire-cassandra 0.12.2

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 (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