cassandra 0.5.6 → 0.5.6.1

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