cassandra 0.5.6 → 0.5.6.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.
@@ -0,0 +1,101 @@
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, '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, "CompareWith")
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, "CompareSubcolumnsWith")
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 UUID
25
+ else
26
+ String # UTF8, Ascii, Bytes, anything else
27
+ end
28
+ end
29
+
30
+ def column_family_property(column_family, key)
31
+ @schema[column_family][key]
32
+ rescue NoMethodError
33
+ raise AccessError, "Invalid column family \"#{column_family}\""
34
+ end
35
+
36
+ def multi_column_to_hash!(hash)
37
+ hash.each do |key, column_or_supercolumn|
38
+ hash[key] = (column_or_supercolumn.column.value if column_or_supercolumn.column)
39
+ end
40
+ end
41
+
42
+ def multi_columns_to_hash!(column_family, hash)
43
+ hash.each do |key, columns|
44
+ hash[key] = columns_to_hash(column_family, columns)
45
+ end
46
+ end
47
+
48
+ def multi_sub_columns_to_hash!(column_family, hash)
49
+ hash.each do |key, sub_columns|
50
+ hash[key] = sub_columns_to_hash(column_family, sub_columns)
51
+ end
52
+ end
53
+
54
+ def columns_to_hash(column_family, columns)
55
+ columns_to_hash_for_classes(columns, column_name_class(column_family), sub_column_name_class(column_family))
56
+ end
57
+
58
+ def sub_columns_to_hash(column_family, columns)
59
+ columns_to_hash_for_classes(columns, sub_column_name_class(column_family))
60
+ end
61
+
62
+ def columns_to_hash_for_classes(columns, column_name_class, sub_column_name_class = nil)
63
+ hash = OrderedHash.new
64
+ Array(columns).each do |c|
65
+ c = c.super_column || c.column if c.is_a?(CassandraThrift::ColumnOrSuperColumn)
66
+ hash[column_name_class.new(c.name)] = case c
67
+ when CassandraThrift::SuperColumn
68
+ columns_to_hash_for_classes(c.columns, sub_column_name_class) # Pop the class stack, and recurse
69
+ when CassandraThrift::Column
70
+ c.value
71
+ end
72
+ end
73
+ hash
74
+ end
75
+
76
+ def hash_to_columns(column_family, hash, timestamp)
77
+ hash.map do |column, value|
78
+ CassandraThrift::ColumnOrSuperColumn.new(:column =>
79
+ CassandraThrift::Column.new(
80
+ :name => column_name_class(column_family).new(column).to_s,
81
+ :value => value,
82
+ :timestamp => timestamp))
83
+ end
84
+ end
85
+
86
+ def hash_to_super_columns(column_family, hash, timestamp)
87
+ hash.map do |column, sub_hash|
88
+ sub_columns = sub_hash.map do |sub_column, value|
89
+ CassandraThrift::Column.new(
90
+ :name => sub_column_name_class(column_family).new(sub_column).to_s,
91
+ :value => value,
92
+ :timestamp => timestamp)
93
+ end
94
+ CassandraThrift::ColumnOrSuperColumn.new(:super_column =>
95
+ CassandraThrift::SuperColumn.new(
96
+ :name => column_name_class(column_family).new(column).to_s,
97
+ :columns => sub_columns))
98
+ end
99
+ end
100
+ end
101
+ 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
+ self.to_i == other.to_i
22
+ end
23
+
24
+ def to_s
25
+ @bytes
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
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
+ UUID = Cassandra::UUID
9
+ Long = Cassandra::Long
10
+ OrderedHash = Cassandra::OrderedHash
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+
2
+ class CassandraThrift::Cassandra::Client
3
+ def send_message(*args)
4
+ pp args
5
+ super
6
+ end
7
+ 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.to_a.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).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
@@ -0,0 +1,135 @@
1
+
2
+ class Cassandra
3
+ # Hash is ordered in Ruby 1.9!
4
+ if RUBY_VERSION >= '1.9'
5
+ OrderedHash = ::Hash
6
+ else
7
+ # Copyright (c) 2004-2009 David Heinemeier Hansson
8
+ #
9
+ # Permission is hereby granted, free of charge, to any person obtaining
10
+ # a copy of this software and associated documentation files (the
11
+ # "Software"), to deal in the Software without restriction, including
12
+ # without limitation the rights to use, copy, modify, merge, publish,
13
+ # distribute, sublicense, and/or sell copies of the Software, and to
14
+ # permit persons to whom the Software is furnished to do so, subject to
15
+ # the following conditions:
16
+ #
17
+ # The above copyright notice and this permission notice shall be
18
+ # included in all copies or substantial portions of the Software.
19
+ #
20
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+
28
+ class OrderedHash < Hash #:nodoc: all
29
+ require 'enumerator'
30
+
31
+ def self.[](*array)
32
+ hash = new
33
+ array.each_slice(2) { |key, value| hash[key] = value }
34
+ hash
35
+ end
36
+
37
+ def initialize(*args, &block)
38
+ super
39
+ @keys = []
40
+ end
41
+
42
+ def initialize_copy(other)
43
+ super
44
+ # make a deep copy of keys
45
+ @keys = other.keys
46
+ end
47
+
48
+ def []=(key, value)
49
+ @keys << key if !has_key?(key)
50
+ super
51
+ end
52
+
53
+ def delete(key)
54
+ if has_key? key
55
+ index = @keys.index(key)
56
+ @keys.delete_at index
57
+ end
58
+ super
59
+ end
60
+
61
+ def delete_if
62
+ super
63
+ sync_keys!
64
+ self
65
+ end
66
+
67
+ def reject!
68
+ super
69
+ sync_keys!
70
+ self
71
+ end
72
+
73
+ def reject(&block)
74
+ dup.reject!(&block)
75
+ end
76
+
77
+ def keys
78
+ @keys.dup
79
+ end
80
+
81
+ def values
82
+ @keys.collect { |key| self[key] }
83
+ end
84
+
85
+ def to_hash
86
+ self
87
+ end
88
+
89
+ def each_key
90
+ @keys.each { |key| yield key }
91
+ end
92
+
93
+ def each_value
94
+ @keys.each { |key| yield self[key]}
95
+ end
96
+
97
+ def each
98
+ @keys.each {|key| yield [key, self[key]]}
99
+ end
100
+
101
+ alias_method :each_pair, :each
102
+
103
+ def clear
104
+ super
105
+ @keys.clear
106
+ self
107
+ end
108
+
109
+ def shift
110
+ k = @keys.first
111
+ v = delete(k)
112
+ [k, v]
113
+ end
114
+
115
+ def merge!(other_hash)
116
+ other_hash.each {|k,v| self[k] = v }
117
+ self
118
+ end
119
+
120
+ def merge(other_hash)
121
+ dup.merge!(other_hash)
122
+ end
123
+
124
+ def inspect
125
+ "#<OrderedHash #{super}>"
126
+ end
127
+
128
+ private
129
+
130
+ def sync_keys!
131
+ @keys.delete_if {|k| !has_key?(k)}
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,72 @@
1
+
2
+ class Cassandra
3
+ # Inner methods for actually doing the Thrift calls
4
+ module Protocol #:nodoc:
5
+ private
6
+
7
+ def _mutate(mutation, consistency)
8
+ @client.batch_mutate(@keyspace, mutation, consistency)
9
+ end
10
+
11
+ def _count_columns(column_family, key, super_column, consistency)
12
+ @client.get_count(@keyspace, key,
13
+ CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => super_column),
14
+ consistency
15
+ )
16
+ end
17
+
18
+ def _get_columns(column_family, key, columns, sub_columns, consistency)
19
+ result = if is_super(column_family)
20
+ if sub_columns
21
+ columns_to_hash(column_family, @client.get_slice(@keyspace, key,
22
+ CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => columns),
23
+ CassandraThrift::SlicePredicate.new(:column_names => sub_columns),
24
+ consistency))
25
+ else
26
+ columns_to_hash(column_family, @client.get_slice(@keyspace, key,
27
+ CassandraThrift::ColumnParent.new(:column_family => column_family),
28
+ CassandraThrift::SlicePredicate.new(:column_names => columns),
29
+ consistency))
30
+ end
31
+ else
32
+ columns_to_hash(column_family, @client.get_slice(@keyspace, key,
33
+ CassandraThrift::ColumnParent.new(:column_family => column_family),
34
+ CassandraThrift::SlicePredicate.new(:column_names => columns),
35
+ consistency))
36
+ end
37
+ sub_columns || columns.map { |name| result[name] }
38
+ end
39
+
40
+ def _multiget(column_family, keys, column, sub_column, count, start, finish, reversed, consistency)
41
+ # Single values; count and range parameters have no effect
42
+ if is_super(column_family) and sub_column
43
+ column_path = CassandraThrift::ColumnPath.new(:column_family => column_family, :super_column => column, :column => sub_column)
44
+ multi_column_to_hash!(@client.multiget(@keyspace, keys, column_path, consistency))
45
+ elsif !is_super(column_family) and column
46
+ column_path = CassandraThrift::ColumnPath.new(:column_family => column_family, :column => column)
47
+ multi_column_to_hash!(@client.multiget(@keyspace, keys, column_path, consistency))
48
+
49
+ # Slices
50
+ else
51
+ predicate = CassandraThrift::SlicePredicate.new(:slice_range =>
52
+ CassandraThrift::SliceRange.new(
53
+ :reversed => reversed,
54
+ :count => count,
55
+ :start => start,
56
+ :finish => finish))
57
+
58
+ if is_super(column_family) and column
59
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => column)
60
+ multi_sub_columns_to_hash!(column_family, @client.multiget_slice(@keyspace, keys, column_parent, predicate, consistency))
61
+ else
62
+ column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
63
+ multi_columns_to_hash!(column_family, @client.multiget_slice(@keyspace, keys, column_parent, predicate, consistency))
64
+ end
65
+ end
66
+ end
67
+
68
+ def _get_range(column_family, start, finish, count, consistency)
69
+ @client.get_key_range(@keyspace, column_family, start, finish, count, consistency)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+
2
+ module CassandraThrift #:nodoc: all
3
+ module Cassandra
4
+
5
+ class SafeClient
6
+ def initialize(client, transport, reset = false)
7
+ @client = client
8
+ @transport = transport
9
+ @reset = reset
10
+ end
11
+
12
+ def reset_transport
13
+ @transport.close rescue nil
14
+ @transport.open
15
+ end
16
+
17
+ def method_missing(*args)
18
+ reset_transport if @reset
19
+ @client.send(*args)
20
+ rescue IOError, UnavailableException, Thrift::ProtocolException, Thrift::ApplicationException, Thrift::TransportException
21
+ reset_transport
22
+ @client.send(*args)
23
+ end
24
+ end
25
+ end
26
+ end