cassandra 0.11.0 → 0.11.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.
- data/CHANGELOG +10 -0
- data/LICENSE +0 -0
- data/Manifest +12 -13
- data/README.md +344 -0
- data/Rakefile +52 -8
- data/cassandra.gemspec +5 -5
- data/conf/0.6/cassandra.in.sh +0 -0
- data/conf/0.6/log4j.properties +0 -0
- data/conf/0.6/schema.json +9 -0
- data/conf/0.6/storage-conf.xml +10 -0
- data/conf/0.7/cassandra.in.sh +0 -0
- data/conf/0.7/cassandra.yaml +0 -0
- data/conf/0.7/log4j-server.properties +0 -0
- data/conf/0.7/schema.json +9 -0
- data/conf/0.7/schema.txt +5 -16
- data/conf/0.8/cassandra.in.sh +0 -0
- data/conf/0.8/cassandra.yaml +1 -1
- data/conf/0.8/log4j-server.properties +0 -0
- data/conf/0.8/schema.json +19 -1
- data/conf/0.8/schema.txt +12 -17
- data/lib/cassandra.rb +3 -2
- data/lib/cassandra/0.6.rb +0 -0
- data/lib/cassandra/0.6/cassandra.rb +57 -6
- data/lib/cassandra/0.6/columns.rb +19 -0
- data/lib/cassandra/0.6/protocol.rb +2 -1
- data/lib/cassandra/0.7.rb +0 -0
- data/lib/cassandra/0.7/cassandra.rb +0 -270
- data/lib/cassandra/0.7/columns.rb +1 -81
- data/lib/cassandra/0.7/protocol.rb +0 -112
- data/lib/cassandra/0.8.rb +0 -0
- data/lib/cassandra/0.8/cassandra.rb +5 -267
- data/lib/cassandra/0.8/columns.rb +1 -81
- data/lib/cassandra/0.8/protocol.rb +9 -103
- data/lib/cassandra/array.rb +0 -0
- data/lib/cassandra/cassandra.rb +715 -92
- data/lib/cassandra/{0.7/column_family.rb → column_family.rb} +0 -0
- data/lib/cassandra/columns.rb +63 -6
- data/lib/cassandra/comparable.rb +0 -0
- data/lib/cassandra/constants.rb +0 -0
- data/lib/cassandra/debug.rb +0 -0
- data/lib/cassandra/helpers.rb +0 -0
- data/lib/cassandra/{0.7/keyspace.rb → keyspace.rb} +0 -0
- data/lib/cassandra/long.rb +0 -0
- data/lib/cassandra/mock.rb +45 -8
- data/lib/cassandra/ordered_hash.rb +0 -0
- data/lib/cassandra/protocol.rb +119 -0
- data/lib/cassandra/time.rb +0 -0
- data/test/cassandra_client_test.rb +0 -0
- data/test/cassandra_mock_test.rb +3 -0
- data/test/cassandra_test.rb +202 -20
- data/test/comparable_types_test.rb +0 -0
- data/test/eventmachine_test.rb +0 -0
- data/test/ordered_hash_test.rb +0 -0
- data/test/test_helper.rb +1 -1
- data/vendor/0.6/gen-rb/cassandra.rb +0 -0
- data/vendor/0.6/gen-rb/cassandra_constants.rb +0 -0
- data/vendor/0.6/gen-rb/cassandra_types.rb +0 -0
- data/vendor/0.7/gen-rb/cassandra.rb +0 -0
- data/vendor/0.7/gen-rb/cassandra_constants.rb +0 -0
- data/vendor/0.7/gen-rb/cassandra_types.rb +0 -0
- data/vendor/0.8/gen-rb/cassandra.rb +0 -0
- data/vendor/0.8/gen-rb/cassandra_constants.rb +0 -0
- data/vendor/0.8/gen-rb/cassandra_types.rb +0 -0
- metadata +27 -29
- data/README.rdoc +0 -99
- data/lib/cassandra/0.8/column_family.rb +0 -3
- data/lib/cassandra/0.8/keyspace.rb +0 -3
@@ -1,84 +1,4 @@
|
|
1
|
-
|
2
1
|
class Cassandra
|
3
|
-
# A bunch of crap, mostly related to introspecting on column types
|
4
2
|
module Columns #:nodoc:
|
5
|
-
|
6
|
-
def is_super(column_family)
|
7
|
-
@is_super[column_family] ||= column_family_property(column_family, 'column_type') == "Super"
|
8
|
-
end
|
9
|
-
|
10
|
-
def column_name_class(column_family)
|
11
|
-
@column_name_class[column_family] ||= column_name_class_for_key(column_family, "comparator_type")
|
12
|
-
end
|
13
|
-
|
14
|
-
def sub_column_name_class(column_family)
|
15
|
-
@sub_column_name_class[column_family] ||= column_name_class_for_key(column_family, "subcomparator_type")
|
16
|
-
end
|
17
|
-
|
18
|
-
def column_family_property(column_family, key)
|
19
|
-
cfdef = schema.cf_defs.find {|cfdef| cfdef.name == column_family }
|
20
|
-
unless cfdef
|
21
|
-
raise AccessError, "Invalid column family \"#{column_family}\""
|
22
|
-
end
|
23
|
-
cfdef.send(key)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def _standard_insert_mutation(column_family, column_name, value, timestamp, ttl = nil)
|
29
|
-
CassandraThrift::Mutation.new(
|
30
|
-
:column_or_supercolumn => CassandraThrift::ColumnOrSuperColumn.new(
|
31
|
-
:column => CassandraThrift::Column.new(
|
32
|
-
:name => column_name_class(column_family).new(column_name).to_s,
|
33
|
-
:value => value,
|
34
|
-
:timestamp => timestamp,
|
35
|
-
:ttl => ttl
|
36
|
-
)
|
37
|
-
)
|
38
|
-
)
|
39
|
-
end
|
40
|
-
|
41
|
-
def _super_insert_mutation(column_family, super_column_name, sub_columns, timestamp, ttl = nil)
|
42
|
-
CassandraThrift::Mutation.new(:column_or_supercolumn =>
|
43
|
-
CassandraThrift::ColumnOrSuperColumn.new(
|
44
|
-
:super_column => CassandraThrift::SuperColumn.new(
|
45
|
-
:name => column_name_class(column_family).new(super_column_name).to_s,
|
46
|
-
:columns => sub_columns.collect { |sub_column_name, sub_column_value|
|
47
|
-
CassandraThrift::Column.new(
|
48
|
-
:name => sub_column_name_class(column_family).new(sub_column_name).to_s,
|
49
|
-
:value => sub_column_value.to_s,
|
50
|
-
:timestamp => timestamp,
|
51
|
-
:ttl => ttl
|
52
|
-
)
|
53
|
-
}
|
54
|
-
)
|
55
|
-
)
|
56
|
-
)
|
57
|
-
end
|
58
|
-
|
59
|
-
# General info about a deletion object within a mutation
|
60
|
-
# timestamp - required. If this is the only param, it will cause deletion of the whole key at that TS
|
61
|
-
# supercolumn - opt. If passed, the deletes will only occur within that supercolumn (only subcolumns
|
62
|
-
# will be deleted). Otherwise the normal columns will be deleted.
|
63
|
-
# predicate - opt. Defines how to match the columns to delete. if supercolumn passed, the slice will
|
64
|
-
# be scoped to subcolumns of that supercolumn.
|
65
|
-
|
66
|
-
# Deletes a single column from the containing key/CF (and possibly supercolumn), at a given timestamp.
|
67
|
-
# Although mutations (as opposed to 'remove' calls) support deleting slices and lists of columns in one shot, this is not implemented here.
|
68
|
-
# 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
|
69
|
-
# methods to use delete mutation calls...although that might have performance implications. We'll leave that refactoring for later.
|
70
|
-
def _delete_mutation(cf, column, subcolumn, timestamp, options={})
|
71
|
-
deletion_hash = {:timestamp => timestamp}
|
72
|
-
if is_super(cf)
|
73
|
-
deletion_hash[:super_column] = column if column
|
74
|
-
deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [subcolumn]) if subcolumn
|
75
|
-
else
|
76
|
-
deletion_hash[:predicate] = CassandraThrift::SlicePredicate.new(:column_names => [column]) if column
|
77
|
-
end
|
78
|
-
CassandraThrift::Mutation.new(
|
79
|
-
:deletion => CassandraThrift::Deletion.new(deletion_hash)
|
80
|
-
)
|
81
|
-
end
|
82
|
-
|
83
3
|
end
|
84
|
-
end
|
4
|
+
end
|
@@ -1,117 +1,23 @@
|
|
1
|
+
require "#{File.expand_path(File.dirname(__FILE__))}/../0.7/protocol"
|
1
2
|
|
2
3
|
class Cassandra
|
3
4
|
# Inner methods for actually doing the Thrift calls
|
4
5
|
module Protocol #:nodoc:
|
5
6
|
private
|
6
7
|
|
7
|
-
def
|
8
|
-
client.
|
8
|
+
def _remove_counter(key, column_path, consistency_level)
|
9
|
+
client.remove_counter(key, column_path, consistency_level)
|
9
10
|
end
|
10
11
|
|
11
|
-
def
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def _count_columns(column_family, key, super_column, consistency)
|
16
|
-
client.get_count(key,
|
17
|
-
CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => super_column),
|
18
|
-
CassandraThrift::SlicePredicate.new(:slice_range =>
|
19
|
-
CassandraThrift::SliceRange.new(
|
20
|
-
:start => '',
|
21
|
-
:finish => ''
|
22
|
-
)),
|
23
|
-
consistency
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
def _get_columns(column_family, key, columns, sub_columns, consistency)
|
28
|
-
result = if is_super(column_family)
|
29
|
-
if sub_columns
|
30
|
-
columns_to_hash(column_family, client.get_slice(key,
|
31
|
-
CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => columns),
|
32
|
-
CassandraThrift::SlicePredicate.new(:column_names => sub_columns),
|
33
|
-
consistency))
|
34
|
-
else
|
35
|
-
columns_to_hash(column_family, client.get_slice(key,
|
36
|
-
CassandraThrift::ColumnParent.new(:column_family => column_family),
|
37
|
-
CassandraThrift::SlicePredicate.new(:column_names => columns),
|
38
|
-
consistency))
|
39
|
-
end
|
40
|
-
else
|
41
|
-
columns_to_hash(column_family, client.get_slice(key,
|
42
|
-
CassandraThrift::ColumnParent.new(:column_family => column_family),
|
43
|
-
CassandraThrift::SlicePredicate.new(:column_names => columns),
|
44
|
-
consistency))
|
45
|
-
end
|
46
|
-
|
47
|
-
klass = column_name_class(column_family)
|
48
|
-
(sub_columns || columns).map { |name| result[klass.new(name)] }
|
49
|
-
end
|
50
|
-
|
51
|
-
def _multiget(column_family, keys, column, sub_column, count, start, finish, reversed, consistency)
|
52
|
-
# Single values; count and range parameters have no effect
|
53
|
-
if is_super(column_family) and sub_column
|
54
|
-
predicate = CassandraThrift::SlicePredicate.new(:column_names => [sub_column])
|
12
|
+
def _add(column_family, key, column, sub_column, value, consistency)
|
13
|
+
if is_super(column_family)
|
55
14
|
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => column)
|
56
|
-
|
57
|
-
|
58
|
-
klass = sub_column_name_class(column_family)
|
59
|
-
keys.inject({}){|hash, key| hash[key] = column_hash[key][klass.new(sub_column)]; hash}
|
60
|
-
elsif !is_super(column_family) and column
|
61
|
-
predicate = CassandraThrift::SlicePredicate.new(:column_names => [column])
|
62
|
-
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
|
63
|
-
column_hash = multi_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
|
64
|
-
|
65
|
-
keys.inject({}){|hash, key| hash[key] = column_hash[key][column]; hash}
|
66
|
-
|
67
|
-
# Slices
|
68
|
-
else
|
69
|
-
predicate = CassandraThrift::SlicePredicate.new(:slice_range =>
|
70
|
-
CassandraThrift::SliceRange.new(
|
71
|
-
:reversed => reversed,
|
72
|
-
:count => count,
|
73
|
-
:start => start,
|
74
|
-
:finish => finish))
|
75
|
-
|
76
|
-
if is_super(column_family) and column
|
77
|
-
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family, :super_column => column)
|
78
|
-
multi_sub_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
|
79
|
-
else
|
80
|
-
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
|
81
|
-
multi_columns_to_hash!(column_family, client.multiget_slice(keys, column_parent, predicate, consistency))
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def _get_range(column_family, start_key, finish_key, key_count, columns, start, finish, count, consistency)
|
87
|
-
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
|
88
|
-
predicate = if columns
|
89
|
-
CassandraThrift::SlicePredicate.new(:column_names => columns)
|
90
|
-
else
|
91
|
-
CassandraThrift::SlicePredicate.new(:slice_range =>
|
92
|
-
CassandraThrift::SliceRange.new(
|
93
|
-
:start => start,
|
94
|
-
:finish => finish,
|
95
|
-
:count => count))
|
96
|
-
end
|
97
|
-
range = CassandraThrift::KeyRange.new(:start_key => start_key, :end_key => finish_key, :count => key_count)
|
98
|
-
client.get_range_slices(column_parent, predicate, range, consistency)
|
99
|
-
end
|
100
|
-
|
101
|
-
# TODO: Supercolumn support
|
102
|
-
def _get_indexed_slices(column_family, idx_clause, column, count, start, finish, reversed, consistency)
|
103
|
-
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
|
104
|
-
if column
|
105
|
-
predicate = CassandraThrift::SlicePredicate.new(:column_names => [column])
|
15
|
+
counter_column = CassandraThrift::CounterColumn.new(:name => sub_column, :value => value)
|
106
16
|
else
|
107
|
-
|
108
|
-
|
109
|
-
:reversed => reversed,
|
110
|
-
:count => count,
|
111
|
-
:start => start,
|
112
|
-
:finish => finish))
|
17
|
+
column_parent = CassandraThrift::ColumnParent.new(:column_family => column_family)
|
18
|
+
counter_column = CassandraThrift::CounterColumn.new(:name => column, :value => value)
|
113
19
|
end
|
114
|
-
client.
|
20
|
+
client.add(key, column_parent, counter_column, consistency)
|
115
21
|
end
|
116
22
|
end
|
117
23
|
end
|
data/lib/cassandra/array.rb
CHANGED
File without changes
|
data/lib/cassandra/cassandra.rb
CHANGED
@@ -49,7 +49,7 @@ class Cassandra
|
|
49
49
|
:timestamp => nil,
|
50
50
|
:consistency => Consistency::ONE,
|
51
51
|
:ttl => nil
|
52
|
-
}
|
52
|
+
}
|
53
53
|
|
54
54
|
READ_DEFAULTS = {
|
55
55
|
:count => 100,
|
@@ -57,15 +57,19 @@ class Cassandra
|
|
57
57
|
:finish => nil,
|
58
58
|
:reversed => false,
|
59
59
|
:consistency => Consistency::ONE
|
60
|
-
}
|
61
|
-
|
60
|
+
}
|
61
|
+
|
62
62
|
THRIFT_DEFAULTS = {
|
63
63
|
:transport_wrapper => Thrift::BufferedTransport,
|
64
64
|
:thrift_client_class => ThriftClient
|
65
|
-
}
|
65
|
+
}
|
66
66
|
|
67
67
|
attr_reader :keyspace, :servers, :schema, :thrift_client_options, :thrift_client_class, :auth_request
|
68
68
|
|
69
|
+
def self.DEFAULT_TRANSPORT_WRAPPER
|
70
|
+
Thrift::FramedTransport
|
71
|
+
end
|
72
|
+
|
69
73
|
# Create a new Cassandra instance and open the connection.
|
70
74
|
def initialize(keyspace, servers = "127.0.0.1:9160", thrift_client_options = {})
|
71
75
|
@is_super = {}
|
@@ -79,10 +83,25 @@ class Cassandra
|
|
79
83
|
@servers = Array(servers)
|
80
84
|
end
|
81
85
|
|
86
|
+
##
|
87
|
+
# This method will prevent us from trying to auto-discover all the
|
88
|
+
# server addresses, and only use the list of servers provided on
|
89
|
+
# initialization.
|
90
|
+
|
91
|
+
# This is primarily helpful when the cassandra cluster is communicating
|
92
|
+
# internally on a different ip address than what you are using to connect.
|
93
|
+
# A prime example of this would be when using EC2 to host a cluster.
|
94
|
+
# Typically, the cluster would be communicating over the local ip
|
95
|
+
# addresses issued by Amazon, but any clients connecting from outside EC2
|
96
|
+
# would need to use the public ip.
|
97
|
+
#
|
82
98
|
def disable_node_auto_discovery!
|
83
99
|
@auto_discover_nodes = false
|
84
100
|
end
|
85
101
|
|
102
|
+
##
|
103
|
+
# Disconnect the current client connection.
|
104
|
+
#
|
86
105
|
def disconnect!
|
87
106
|
if @client
|
88
107
|
@client.disconnect!
|
@@ -90,27 +109,320 @@ class Cassandra
|
|
90
109
|
end
|
91
110
|
end
|
92
111
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
112
|
+
##
|
113
|
+
# Issues a login attempt using the username and password specified.
|
114
|
+
#
|
115
|
+
# * username
|
116
|
+
# * password
|
117
|
+
#
|
97
118
|
def login!(username, password)
|
98
119
|
@auth_request = CassandraThrift::AuthenticationRequest.new
|
99
120
|
@auth_request.credentials = {'username' => username, 'password' => password}
|
100
|
-
client.login(@
|
121
|
+
client.login(@auth_request)
|
101
122
|
end
|
102
|
-
|
123
|
+
|
103
124
|
def inspect
|
104
125
|
"#<Cassandra:#{object_id}, @keyspace=#{keyspace.inspect}, @schema={#{
|
105
|
-
schema(false).map {|
|
126
|
+
Array(schema(false).cf_defs).map {|cfdef| ":#{cfdef.name} => #{cfdef.column_type}"}.join(', ')
|
106
127
|
}}, @servers=#{servers.inspect}>"
|
107
128
|
end
|
108
129
|
|
109
|
-
|
130
|
+
##
|
131
|
+
# Set the keyspace to use.
|
132
|
+
#
|
133
|
+
# Please note that this only works on version 0.7.0 and higher.
|
134
|
+
def keyspace=(ks)
|
135
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
136
|
+
|
137
|
+
client.set_keyspace(ks)
|
138
|
+
@schema = nil; @keyspace = ks
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Return an array of the keyspace names available.
|
143
|
+
#
|
144
|
+
# Please note that this only works on version 0.7.0 and higher.
|
145
|
+
def keyspaces
|
146
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
147
|
+
|
148
|
+
client.describe_keyspaces.to_a.collect {|ksdef| ksdef.name }
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Return a Cassandra::Keyspace object loaded with the current
|
153
|
+
# keyspaces schema.
|
154
|
+
#
|
155
|
+
# Please note that this only works on version 0.7.0 and higher.
|
156
|
+
def schema(load=true)
|
157
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
158
|
+
|
159
|
+
if !load && !@schema
|
160
|
+
Cassandra::Keyspace.new
|
161
|
+
else
|
162
|
+
@schema ||= client.describe_keyspace(@keyspace)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# This returns true if all servers are in agreement on the schema.
|
168
|
+
#
|
169
|
+
# Please note that this only works on version 0.7.0 and higher.
|
170
|
+
def schema_agreement?
|
171
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
172
|
+
|
173
|
+
client.describe_schema_versions().length == 1
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# Lists the current cassandra.thrift version.
|
178
|
+
#
|
179
|
+
# Please note that this only works on version 0.7.0 and higher.
|
180
|
+
def version
|
181
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
182
|
+
|
183
|
+
client.describe_version()
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Returns the string name specified for the cluster.
|
188
|
+
#
|
189
|
+
# Please note that this only works on version 0.7.0 and higher.
|
190
|
+
def cluster_name
|
191
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
192
|
+
|
193
|
+
@cluster_name ||= client.describe_cluster_name()
|
194
|
+
end
|
195
|
+
|
196
|
+
##
|
197
|
+
# Returns an array of CassandraThrift::TokenRange objects indicating
|
198
|
+
# which servers make up the current ring. What their start and end
|
199
|
+
# tokens are, and their list of endpoints.
|
200
|
+
#
|
201
|
+
# Please note that this only works on version 0.7.0 and higher.
|
202
|
+
def ring
|
203
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
204
|
+
|
205
|
+
client.describe_ring(@keyspace)
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Returns a string identifying which partitioner is in use by the
|
210
|
+
# current cluster. Typically, this will be RandomPartitioner, but it
|
211
|
+
# could be OrderPreservingPartioner as well.
|
212
|
+
#
|
213
|
+
# Please note that this only works on version 0.7.0 and higher.
|
214
|
+
def partitioner
|
215
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
216
|
+
|
217
|
+
client.describe_partitioner()
|
218
|
+
end
|
219
|
+
|
220
|
+
##
|
221
|
+
# Remove all rows in the column family you request.
|
222
|
+
#
|
223
|
+
# * column_family
|
224
|
+
# * options
|
225
|
+
# * consitency
|
226
|
+
# * timestamp
|
227
|
+
#
|
228
|
+
def truncate!(column_family)
|
229
|
+
client.truncate(column_family.to_s)
|
230
|
+
end
|
231
|
+
alias clear_column_family! truncate!
|
232
|
+
|
233
|
+
##
|
234
|
+
# Remove all column families in the keyspace.
|
235
|
+
#
|
236
|
+
# This method calls Cassandra#truncate! for each column family in the
|
237
|
+
# keyspace.
|
238
|
+
#
|
239
|
+
# Please note that this only works on version 0.7.0 and higher.
|
240
|
+
#
|
241
|
+
def clear_keyspace!
|
242
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
243
|
+
|
244
|
+
schema.cf_defs.each { |cfdef| truncate!(cfdef.name) }
|
245
|
+
end
|
246
|
+
|
247
|
+
##
|
248
|
+
# Creates a new column family from the passed in
|
249
|
+
# Cassandra::ColumnFamily instance, and returns the schema id.
|
250
|
+
#
|
251
|
+
def add_column_family(cf_def)
|
252
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
253
|
+
|
254
|
+
begin
|
255
|
+
res = client.system_add_column_family(cf_def)
|
256
|
+
rescue CassandraThrift::TimedOutException => te
|
257
|
+
puts "Timed out: #{te.inspect}"
|
258
|
+
end
|
259
|
+
@schema = nil
|
260
|
+
res
|
261
|
+
end
|
262
|
+
|
263
|
+
##
|
264
|
+
# Delete the specified column family. Return the new schema id.
|
265
|
+
#
|
266
|
+
# * column_family - The column_family name to drop.
|
267
|
+
#
|
268
|
+
def drop_column_family(column_family)
|
269
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
270
|
+
|
271
|
+
begin
|
272
|
+
res = client.system_drop_column_family(column_family)
|
273
|
+
rescue CassandraThrift::TimedOutException => te
|
274
|
+
puts "Timed out: #{te.inspect}"
|
275
|
+
end
|
276
|
+
@schema = nil
|
277
|
+
res
|
278
|
+
end
|
279
|
+
|
280
|
+
##
|
281
|
+
# Rename a column family. Returns the new schema id.
|
282
|
+
#
|
283
|
+
# * old_name - The current column_family name.
|
284
|
+
# * new_name - The desired column_family name.
|
285
|
+
#
|
286
|
+
def rename_column_family(old_name, new_name)
|
287
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
288
|
+
|
289
|
+
begin
|
290
|
+
res = client.system_rename_column_family(old_name, new_name)
|
291
|
+
rescue CassandraThrift::TimedOutException => te
|
292
|
+
puts "Timed out: #{te.inspect}"
|
293
|
+
end
|
294
|
+
@schema = nil
|
295
|
+
res
|
296
|
+
end
|
297
|
+
|
298
|
+
##
|
299
|
+
# Update the column family based on the passed in definition.
|
300
|
+
#
|
301
|
+
def update_column_family(cf_def)
|
302
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
303
|
+
|
304
|
+
begin
|
305
|
+
res = client.system_update_column_family(cf_def)
|
306
|
+
rescue CassandraThrift::TimedOutException => te
|
307
|
+
puts "Timed out: #{te.inspect}"
|
308
|
+
end
|
309
|
+
@schema = nil
|
310
|
+
res
|
311
|
+
end
|
312
|
+
|
313
|
+
##
|
314
|
+
# Add keyspace using the passed in keyspace definition.
|
315
|
+
#
|
316
|
+
# Returns the new schema id.
|
317
|
+
#
|
318
|
+
def add_keyspace(ks_def)
|
319
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
320
|
+
|
321
|
+
begin
|
322
|
+
res = client.system_add_keyspace(ks_def)
|
323
|
+
rescue CassandraThrift::TimedOutException => toe
|
324
|
+
puts "Timed out: #{toe.inspect}"
|
325
|
+
rescue Thrift::TransportException => te
|
326
|
+
puts "Timed out: #{te.inspect}"
|
327
|
+
end
|
328
|
+
@keyspaces = nil
|
329
|
+
res
|
330
|
+
end
|
331
|
+
|
332
|
+
##
|
333
|
+
# Deletes keyspace using the passed in keyspace name.
|
334
|
+
#
|
335
|
+
# Returns the new schema id.
|
336
|
+
#
|
337
|
+
def drop_keyspace(keyspace)
|
338
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
110
339
|
|
111
|
-
|
112
|
-
|
113
|
-
|
340
|
+
begin
|
341
|
+
res = client.system_drop_keyspace(keyspace)
|
342
|
+
rescue CassandraThrift::TimedOutException => toe
|
343
|
+
puts "Timed out: #{toe.inspect}"
|
344
|
+
rescue Thrift::TransportException => te
|
345
|
+
puts "Timed out: #{te.inspect}"
|
346
|
+
end
|
347
|
+
keyspace = "system" if keyspace.eql?(@keyspace)
|
348
|
+
@keyspaces = nil
|
349
|
+
res
|
350
|
+
end
|
351
|
+
|
352
|
+
##
|
353
|
+
# Renames keyspace.
|
354
|
+
#
|
355
|
+
# * old_name - Current keyspace name.
|
356
|
+
# * new_name - Desired keyspace name.
|
357
|
+
#
|
358
|
+
# Returns the new schema id
|
359
|
+
def rename_keyspace(old_name, new_name)
|
360
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
361
|
+
|
362
|
+
begin
|
363
|
+
res = client.system_rename_keyspace(old_name, new_name)
|
364
|
+
rescue CassandraThrift::TimedOutException => toe
|
365
|
+
puts "Timed out: #{toe.inspect}"
|
366
|
+
rescue Thrift::TransportException => te
|
367
|
+
puts "Timed out: #{te.inspect}"
|
368
|
+
end
|
369
|
+
keyspace = new_name if old_name.eql?(@keyspace)
|
370
|
+
@keyspaces = nil
|
371
|
+
res
|
372
|
+
end
|
373
|
+
|
374
|
+
##
|
375
|
+
# Update the keyspace using the passed in keyspace definition.
|
376
|
+
#
|
377
|
+
def update_keyspace(ks_def)
|
378
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
379
|
+
|
380
|
+
begin
|
381
|
+
res = client.system_update_keyspace(ks_def)
|
382
|
+
rescue CassandraThrift::TimedOutException => toe
|
383
|
+
puts "Timed out: #{toe.inspect}"
|
384
|
+
rescue Thrift::TransportException => te
|
385
|
+
puts "Timed out: #{te.inspect}"
|
386
|
+
end
|
387
|
+
@keyspaces = nil
|
388
|
+
res
|
389
|
+
end
|
390
|
+
##
|
391
|
+
# The initial default consistency is set to ONE, but you can use this method
|
392
|
+
# to override the normal default with your specified value. Use this if you
|
393
|
+
# do not want to specify a write consistency for each insert statement.
|
394
|
+
#
|
395
|
+
def default_write_consistency=(value)
|
396
|
+
WRITE_DEFAULTS[:consistency] = value
|
397
|
+
end
|
398
|
+
|
399
|
+
##
|
400
|
+
# The initial default consistency is set to ONE, but you can use this method
|
401
|
+
# to override the normal default with your specified value. Use this if you
|
402
|
+
# do not want to specify a read consistency for each query.
|
403
|
+
#
|
404
|
+
def default_read_consistency=(value)
|
405
|
+
READ_DEFAULTS[:consistency] = value
|
406
|
+
end
|
407
|
+
|
408
|
+
##
|
409
|
+
# This is the main method used to insert rows into cassandra. If the
|
410
|
+
# column\_family that you are inserting into is a SuperColumnFamily then
|
411
|
+
# the hash passed in should be a nested hash, otherwise it should be a
|
412
|
+
# flat hash.
|
413
|
+
#
|
414
|
+
# This method can also be called while in batch mode. If in batch mode
|
415
|
+
# then we queue up the mutations (an insert in this case) and pass them to
|
416
|
+
# cassandra in a single batch at the end of the block.
|
417
|
+
#
|
418
|
+
# * column\_family - The column\_family that you are inserting into.
|
419
|
+
# * key - The row key to insert.
|
420
|
+
# * hash - The columns or super columns to insert.
|
421
|
+
# * options - Valid options are:
|
422
|
+
# * :timestamp - Uses the current time if none specified.
|
423
|
+
# * :consistency - Uses the default write consistency if none specified.
|
424
|
+
# * :ttl - If specified this is the number of seconds after the insert that this value will be available.
|
425
|
+
#
|
114
426
|
def insert(column_family, key, hash, options = {})
|
115
427
|
column_family, _, _, options = extract_and_validate_params(column_family, key, [options], WRITE_DEFAULTS)
|
116
428
|
|
@@ -133,12 +445,23 @@ class Cassandra
|
|
133
445
|
end
|
134
446
|
|
135
447
|
|
136
|
-
##
|
137
|
-
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
448
|
+
##
|
449
|
+
# This method is used to delete (actually marking them as deleted with a
|
450
|
+
# tombstone) columns or super columns.
|
451
|
+
#
|
452
|
+
# This method can also be used in batch mode. If in batch mode then we
|
453
|
+
# queue up the mutations (a deletion in this case)
|
454
|
+
#
|
455
|
+
# * column\_family - The column\_family that you are inserting into.
|
456
|
+
# * key - The row key to insert.
|
457
|
+
# * columns - Either a single super_column or a list of columns.
|
458
|
+
# * sub_columns - The list of sub\_columns to select.
|
459
|
+
# * options - Valid options are:
|
460
|
+
# * :timestamp - Uses the current time if none specified.
|
461
|
+
# * :consistency - Uses the default write consistency if none specified.
|
462
|
+
#
|
141
463
|
# TODO: we could change this function or add another that support multi-column removal (by list or predicate)
|
464
|
+
#
|
142
465
|
def remove(column_family, key, *columns_and_options)
|
143
466
|
column_family, column, sub_column, options = extract_and_validate_params(column_family, key, columns_and_options, WRITE_DEFAULTS)
|
144
467
|
|
@@ -160,83 +483,197 @@ class Cassandra
|
|
160
483
|
end
|
161
484
|
end
|
162
485
|
|
163
|
-
|
164
|
-
|
165
|
-
#
|
166
|
-
#
|
486
|
+
##
|
487
|
+
# Count the columns for the provided parameters.
|
488
|
+
#
|
489
|
+
# * column_family - The column_family that you are inserting into.
|
490
|
+
# * key - The row key to insert.
|
491
|
+
# * columns - Either a single super_column or a list of columns.
|
492
|
+
# * sub_columns - The list of sub_columns to select.
|
493
|
+
# * options - Valid options are:
|
494
|
+
# * :consistency - Uses the default read consistency if none specified.
|
495
|
+
#
|
167
496
|
def count_columns(column_family, key, *columns_and_options)
|
168
497
|
column_family, super_column, _, options =
|
169
498
|
extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
170
499
|
_count_columns(column_family, key, super_column, options[:consistency])
|
171
500
|
end
|
172
501
|
|
173
|
-
|
174
|
-
#
|
175
|
-
#
|
502
|
+
##
|
503
|
+
# Multi-key version of Cassandra#count_columns. Please note that this
|
504
|
+
# queries the server for each key passed in.
|
505
|
+
#
|
506
|
+
# Supports same parameters as Cassandra#count_columns.
|
507
|
+
#
|
508
|
+
# * column_family - The column_family that you are inserting into.
|
509
|
+
# * key - The row key to insert.
|
510
|
+
# * columns - Either a single super_column or a list of columns.
|
511
|
+
# * sub_columns - The list of sub_columns to select.
|
512
|
+
# * options - Valid options are:
|
513
|
+
# * :consistency - Uses the default read consistency if none specified.
|
514
|
+
#
|
515
|
+
# FIXME: Not real multi; needs server support
|
176
516
|
def multi_count_columns(column_family, keys, *options)
|
177
517
|
OrderedHash[*keys.map { |key| [key, count_columns(column_family, key, *options)] }._flatten_once]
|
178
518
|
end
|
179
519
|
|
180
|
-
|
181
|
-
#
|
182
|
-
#
|
520
|
+
##
|
521
|
+
# Return a hash of column value pairs for the path you request.
|
522
|
+
#
|
523
|
+
# * column_family - The column_family that you are inserting into.
|
524
|
+
# * key - The row key to insert.
|
525
|
+
# * columns - Either a single super_column or a list of columns.
|
526
|
+
# * sub_columns - The list of sub_columns to select.
|
527
|
+
# * options - Valid options are:
|
528
|
+
# * :consistency - Uses the default read consistency if none specified.
|
529
|
+
#
|
183
530
|
def get_columns(column_family, key, *columns_and_options)
|
184
531
|
column_family, columns, sub_columns, options =
|
185
532
|
extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
186
533
|
_get_columns(column_family, key, columns, sub_columns, options[:consistency])
|
187
534
|
end
|
188
535
|
|
189
|
-
|
190
|
-
#
|
536
|
+
##
|
537
|
+
# Multi-key version of Cassandra#get_columns. Please note that this
|
538
|
+
# queries the server for each key passed in.
|
539
|
+
#
|
540
|
+
# Supports same parameters as Cassandra#get_columns
|
541
|
+
#
|
542
|
+
# * column_family - The column_family that you are inserting into.
|
543
|
+
# * key - The row key to insert.
|
544
|
+
# * columns - Either a single super_column or a list of columns.
|
545
|
+
# * sub_columns - The list of sub_columns to select.
|
546
|
+
# * options - Valid options are:
|
547
|
+
# * :consistency - Uses the default read consistency if none specified.
|
548
|
+
#
|
191
549
|
# FIXME Not real multi; needs to use a Column predicate
|
192
550
|
def multi_get_columns(column_family, keys, *options)
|
193
551
|
OrderedHash[*keys.map { |key| [key, get_columns(column_family, key, *options)] }._flatten_once]
|
194
552
|
end
|
195
553
|
|
554
|
+
##
|
196
555
|
# Return a hash (actually, a Cassandra::OrderedHash) or a single value
|
197
556
|
# representing the element at the column_family:key:[column]:[sub_column]
|
198
|
-
# path you request.
|
199
|
-
#
|
557
|
+
# path you request.
|
558
|
+
#
|
559
|
+
# * column_family - The column_family that you are inserting into.
|
560
|
+
# * key - The row key to insert.
|
561
|
+
# * columns - Either a single super_column or a list of columns.
|
562
|
+
# * sub_columns - The list of sub_columns to select.
|
563
|
+
# * options - Valid options are:
|
564
|
+
# * :count - The number of columns requested to be returned.
|
565
|
+
# * :start - The starting value for selecting a range of columns.
|
566
|
+
# * :finish - The final value for selecting a range of columns.
|
567
|
+
# * :reversed - If set to true the results will be returned in
|
568
|
+
# reverse order.
|
569
|
+
# * :consistency - Uses the default read consistency if none specified.
|
570
|
+
#
|
200
571
|
def get(column_family, key, *columns_and_options)
|
201
572
|
multi_get(column_family, [key], *columns_and_options)[key]
|
202
573
|
end
|
203
574
|
|
204
|
-
|
205
|
-
#
|
575
|
+
##
|
576
|
+
# Multi-key version of Cassandra#get.
|
577
|
+
#
|
578
|
+
# This method allows you to select multiple rows with a single query.
|
579
|
+
# If a key that is passed in doesn't exist an empty hash will be
|
580
|
+
# returned.
|
581
|
+
#
|
582
|
+
# Supports the same parameters as Cassandra#get.
|
583
|
+
#
|
584
|
+
# * column_family - The column_family that you are inserting into.
|
585
|
+
# * key - An array of keys to.
|
586
|
+
# * columns - Either a single super_column or a list of columns.
|
587
|
+
# * sub_columns - The list of sub_columns to select.
|
588
|
+
# * options - Valid options are:
|
589
|
+
# * :count - The number of columns requested to be returned.
|
590
|
+
# * :start - The starting value for selecting a range of columns.
|
591
|
+
# * :finish - The final value for selecting a range of columns.
|
592
|
+
# * :reversed - If set to true the results will be returned in reverse order.
|
593
|
+
# * :consistency - Uses the default read consistency if none specified.
|
594
|
+
#
|
206
595
|
def multi_get(column_family, keys, *columns_and_options)
|
207
596
|
column_family, column, sub_column, options =
|
208
597
|
extract_and_validate_params(column_family, keys, columns_and_options, READ_DEFAULTS)
|
209
598
|
|
210
599
|
hash = _multiget(column_family, keys, column, sub_column, options[:count], options[:start], options[:finish], options[:reversed], options[:consistency])
|
600
|
+
|
211
601
|
# Restore order
|
212
602
|
ordered_hash = OrderedHash.new
|
213
603
|
keys.each { |key| ordered_hash[key] = hash[key] || (OrderedHash.new if is_super(column_family) and !sub_column) }
|
214
604
|
ordered_hash
|
215
605
|
end
|
216
606
|
|
607
|
+
##
|
217
608
|
# Return true if the column_family:key:[column]:[sub_column] path you
|
218
|
-
# request exists.
|
609
|
+
# request exists.
|
610
|
+
#
|
611
|
+
# If passed in only a row key it will query for any columns (limiting
|
612
|
+
# to 1) for that row key. If a column is passed in it will query for
|
613
|
+
# that specific column/super column.
|
614
|
+
#
|
615
|
+
# This method will return true or false.
|
616
|
+
#
|
617
|
+
# * column_family - The column_family that you are inserting into.
|
618
|
+
# * key - The row key to insert.
|
619
|
+
# * columns - Either a single super_column or a list of columns.
|
620
|
+
# * sub_columns - The list of sub_columns to select.
|
621
|
+
# * options - Valid options are:
|
622
|
+
# * :consistency - Uses the default read consistency if none specified.
|
623
|
+
#
|
219
624
|
def exists?(column_family, key, *columns_and_options)
|
220
625
|
column_family, column, sub_column, options =
|
221
626
|
extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
222
|
-
if column
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
627
|
+
result = if column
|
628
|
+
_multiget(column_family, [key], column, sub_column, 1, '', '', false, options[:consistency])[key]
|
629
|
+
else
|
630
|
+
_multiget(column_family, [key], nil, nil, 1, '', '', false, options[:consistency])[key]
|
631
|
+
end
|
632
|
+
|
633
|
+
![{}, nil].include?(result)
|
227
634
|
end
|
228
635
|
|
229
|
-
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
# and
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
636
|
+
##
|
637
|
+
# Return an Cassandra::OrderedHash containing the columns specified for the given
|
638
|
+
# range of keys in the column_family you request.
|
639
|
+
#
|
640
|
+
# This method is just a convenience wrapper around Cassandra#get_range_single
|
641
|
+
# and Cassandra#get_range_batch. If :key_size, :batch_size, or a block
|
642
|
+
# is passed in Cassandra#get_range_batch will be called. Otherwise
|
643
|
+
# Cassandra#get_range_single will be used.
|
644
|
+
#
|
645
|
+
# The start_key and finish_key parameters are only useful for iterating of all records
|
646
|
+
# as is done in the Cassandra#each and Cassandra#each_key methods if you are using the
|
647
|
+
# RandomPartitioner.
|
648
|
+
#
|
649
|
+
# If the table is partitioned with OrderPreservingPartitioner you may
|
650
|
+
# use the start_key and finish_key params to select all records with
|
651
|
+
# the same prefix value.
|
652
|
+
#
|
653
|
+
# If a block is passed in we will yield the row key and columns for
|
654
|
+
# each record returned.
|
655
|
+
#
|
656
|
+
# Please note that Cassandra returns a row for each row that has existed in the
|
657
|
+
# system since gc_grace_seconds. This is because deleted row keys are marked as
|
658
|
+
# deleted, but left in the system until the cluster has had resonable time to replicate the deletion.
|
238
659
|
# This function attempts to suppress deleted rows (actually any row returned without
|
239
660
|
# columns is suppressed).
|
661
|
+
#
|
662
|
+
# * column_family - The column_family that you are inserting into.
|
663
|
+
# * key - The row key to insert.
|
664
|
+
# * columns - Either a single super_column or a list of columns.
|
665
|
+
# * sub_columns - The list of sub_columns to select.
|
666
|
+
# * options - Valid options are:
|
667
|
+
# * :start_key - The starting value for selecting a range of keys (only useful with OPP).
|
668
|
+
# * :finish_key - The final value for selecting a range of keys (only useful with OPP).
|
669
|
+
# * :key_count - The total number of keys to return from the query. (see note regarding deleted records)
|
670
|
+
# * :batch_size - The maximum number of keys to return per query. If specified will loop until :key_count is obtained or all records have been returned.
|
671
|
+
# * :count - The number of columns requested to be returned.
|
672
|
+
# * :start - The starting value for selecting a range of columns.
|
673
|
+
# * :finish - The final value for selecting a range of columns.
|
674
|
+
# * :reversed - If set to true the results will be returned in reverse order.
|
675
|
+
# * :consistency - Uses the default read consistency if none specified.
|
676
|
+
#
|
240
677
|
def get_range(column_family, options = {})
|
241
678
|
if block_given? || options[:key_count] || options[:batch_size]
|
242
679
|
get_range_batch(column_family, options)
|
@@ -245,6 +682,12 @@ class Cassandra
|
|
245
682
|
end
|
246
683
|
end
|
247
684
|
|
685
|
+
##
|
686
|
+
# Return an Cassandra::OrderedHash containing the columns specified for the given
|
687
|
+
# range of keys in the column_family you request.
|
688
|
+
#
|
689
|
+
# See Cassandra#get_range for more details.
|
690
|
+
#
|
248
691
|
def get_range_single(column_family, options = {})
|
249
692
|
return_empty_rows = options.delete(:return_empty_rows) || false
|
250
693
|
|
@@ -270,6 +713,15 @@ class Cassandra
|
|
270
713
|
multi_key_slices_to_hash(column_family, results, return_empty_rows)
|
271
714
|
end
|
272
715
|
|
716
|
+
##
|
717
|
+
# Return an Cassandra::OrderedHash containing the columns specified for the given
|
718
|
+
# range of keys in the column_family you request.
|
719
|
+
#
|
720
|
+
# If a block is passed in we will yield the row key and columns for
|
721
|
+
# each record returned.
|
722
|
+
#
|
723
|
+
# See Cassandra#get_range for more details.
|
724
|
+
#
|
273
725
|
def get_range_batch(column_family, options = {})
|
274
726
|
batch_size = options.delete(:batch_size) || 100
|
275
727
|
count = options.delete(:key_count)
|
@@ -299,80 +751,221 @@ class Cassandra
|
|
299
751
|
result
|
300
752
|
end
|
301
753
|
|
302
|
-
|
303
|
-
#
|
304
|
-
#
|
305
|
-
#
|
754
|
+
##
|
755
|
+
# Count all rows in the column_family you request.
|
756
|
+
#
|
757
|
+
# This method just calls Cassandra#get_range_keys and returns the
|
758
|
+
# number of records returned.
|
759
|
+
#
|
760
|
+
# See Cassandra#get_range for options.
|
761
|
+
#
|
306
762
|
def count_range(column_family, options = {})
|
307
763
|
get_range_keys(column_family, options).length
|
308
764
|
end
|
309
765
|
|
310
|
-
|
311
|
-
#
|
312
|
-
#
|
313
|
-
#
|
766
|
+
##
|
767
|
+
# Return an Array containing all of the keys within a given range.
|
768
|
+
#
|
769
|
+
# This method just calls Cassandra#get_range and returns the
|
770
|
+
# row keys for the records returned.
|
771
|
+
#
|
772
|
+
# See Cassandra#get_range for options.
|
773
|
+
#
|
314
774
|
def get_range_keys(column_family, options = {})
|
315
775
|
get_range(column_family,options.merge!(:count => 1)).keys
|
316
776
|
end
|
317
777
|
|
778
|
+
##
|
318
779
|
# Iterate through each key within the given parameters. This function can be
|
319
|
-
# used to iterate over each key in the given column family.
|
320
|
-
#
|
321
|
-
#
|
322
|
-
#
|
323
|
-
#
|
324
|
-
#
|
780
|
+
# used to iterate over each key in the given column family.
|
781
|
+
#
|
782
|
+
# This method just calls Cassandra#get_range and yields each row key.
|
783
|
+
#
|
784
|
+
# See Cassandra#get_range for options.
|
785
|
+
#
|
325
786
|
def each_key(column_family, options = {})
|
326
787
|
get_range_batch(column_family, options) do |key, columns|
|
327
788
|
yield key
|
328
789
|
end
|
329
790
|
end
|
330
791
|
|
331
|
-
|
332
|
-
#
|
333
|
-
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
#
|
337
|
-
#
|
338
|
-
#
|
792
|
+
##
|
793
|
+
# Iterate through each row in the given column family
|
794
|
+
#
|
795
|
+
# This method just calls Cassandra#get_range and yields the key and
|
796
|
+
# columns.
|
797
|
+
#
|
798
|
+
# See Cassandra#get_range for options.
|
799
|
+
#
|
339
800
|
def each(column_family, options = {})
|
340
801
|
get_range_batch(column_family, options) do |key, columns|
|
341
802
|
yield key, columns
|
342
803
|
end
|
343
804
|
end
|
344
805
|
|
806
|
+
##
|
345
807
|
# Open a batch operation and yield self. Inserts and deletes will be queued
|
346
|
-
# until the block closes, and then sent atomically to the server.
|
347
|
-
#
|
808
|
+
# until the block closes, and then sent atomically to the server.
|
809
|
+
#
|
810
|
+
# Supports the :consistency option, which overrides the consistency set in
|
348
811
|
# the individual commands.
|
812
|
+
#
|
349
813
|
def batch(options = {})
|
350
|
-
_, _, _, options =
|
351
|
-
extract_and_validate_params(schema.
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
814
|
+
_, _, _, options =
|
815
|
+
extract_and_validate_params(schema.cf_defs.first.name, "", [options], WRITE_DEFAULTS)
|
816
|
+
|
817
|
+
@batch = []
|
818
|
+
yield(self)
|
819
|
+
compacted_map,seen_clevels = compact_mutations!
|
820
|
+
clevel = if options[:consistency] != nil # Override any clevel from individual mutations if
|
821
|
+
options[:consistency]
|
822
|
+
elsif seen_clevels.length > 1 # Cannot choose which CLevel to use if there are several ones
|
823
|
+
raise "Multiple consistency levels used in the batch, and no override...cannot pick one"
|
824
|
+
else # if no consistency override has been provided but all the clevels in the batch are the same: use that one
|
825
|
+
seen_clevels.first
|
826
|
+
end
|
827
|
+
|
828
|
+
_mutate(compacted_map,clevel)
|
365
829
|
ensure
|
366
830
|
@batch = nil
|
367
831
|
end
|
368
|
-
|
832
|
+
|
833
|
+
##
|
834
|
+
# Create secondary index.
|
835
|
+
#
|
836
|
+
# * keyspace
|
837
|
+
# * column_family
|
838
|
+
# * column_name
|
839
|
+
# * validation_class
|
840
|
+
#
|
841
|
+
def create_index(keyspace, column_family, column_name, validation_class)
|
842
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
843
|
+
|
844
|
+
cf_def = client.describe_keyspace(keyspace).cf_defs.find{|x| x.name == column_family}
|
845
|
+
if !cf_def.nil? and !cf_def.column_metadata.find{|x| x.name == column_name}
|
846
|
+
c_def = CassandraThrift::ColumnDef.new do |cd|
|
847
|
+
cd.name = column_name
|
848
|
+
cd.validation_class = "org.apache.cassandra.db.marshal."+validation_class
|
849
|
+
cd.index_type = CassandraThrift::IndexType::KEYS
|
850
|
+
end
|
851
|
+
cf_def.column_metadata.push(c_def)
|
852
|
+
update_column_family(cf_def)
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
##
|
857
|
+
# Delete secondary index.
|
858
|
+
#
|
859
|
+
# * keyspace
|
860
|
+
# * column_family
|
861
|
+
# * column_name
|
862
|
+
#
|
863
|
+
def drop_index(keyspace, column_family, column_name)
|
864
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
865
|
+
|
866
|
+
cf_def = client.describe_keyspace(keyspace).cf_defs.find{|x| x.name == column_family}
|
867
|
+
if !cf_def.nil? and cf_def.column_metadata.find{|x| x.name == column_name}
|
868
|
+
cf_def.column_metadata.delete_if{|x| x.name == column_name}
|
869
|
+
update_column_family(cf_def)
|
870
|
+
end
|
871
|
+
end
|
872
|
+
|
873
|
+
##
|
874
|
+
# This method is mostly used internally by get_index_slices to create
|
875
|
+
# a CassandraThrift::IndexExpression for the given options.
|
876
|
+
#
|
877
|
+
# * column_name - Column to be compared
|
878
|
+
# * value - Value to compare against
|
879
|
+
# * comparison - Type of comparison to do.
|
880
|
+
#
|
881
|
+
def create_index_expression(column_name, value, comparison)
|
882
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
883
|
+
|
884
|
+
CassandraThrift::IndexExpression.new(
|
885
|
+
:column_name => column_name,
|
886
|
+
:value => value,
|
887
|
+
:op => (case comparison
|
888
|
+
when nil, "EQ", "eq", "=="
|
889
|
+
CassandraThrift::IndexOperator::EQ
|
890
|
+
when "GTE", "gte", ">="
|
891
|
+
CassandraThrift::IndexOperator::GTE
|
892
|
+
when "GT", "gt", ">"
|
893
|
+
CassandraThrift::IndexOperator::GT
|
894
|
+
when "LTE", "lte", "<="
|
895
|
+
CassandraThrift::IndexOperator::LTE
|
896
|
+
when "LT", "lt", "<"
|
897
|
+
CassandraThrift::IndexOperator::LT
|
898
|
+
end ))
|
899
|
+
end
|
900
|
+
alias :create_idx_expr :create_index_expression
|
901
|
+
|
902
|
+
##
|
903
|
+
# This method takes an array if CassandraThrift::IndexExpression
|
904
|
+
# objects and creates a CassandraThrift::IndexClause for use in the
|
905
|
+
# Cassandra#get_index_slices
|
906
|
+
#
|
907
|
+
# * index_expressions - Array of CassandraThrift::IndexExpressions.
|
908
|
+
# * start - The starting row key.
|
909
|
+
# * count - The count of items to be returned
|
910
|
+
#
|
911
|
+
def create_index_clause(index_expressions, start = "", count = 100)
|
912
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
913
|
+
|
914
|
+
CassandraThrift::IndexClause.new(
|
915
|
+
:start_key => start,
|
916
|
+
:expressions => index_expressions,
|
917
|
+
:count => count)
|
918
|
+
end
|
919
|
+
alias :create_idx_clause :create_index_clause
|
920
|
+
|
921
|
+
##
|
922
|
+
# This method is used to query a secondary index with a set of
|
923
|
+
# provided search parameters
|
924
|
+
#
|
925
|
+
# Please note that you can either specify a
|
926
|
+
# CassandraThrift::IndexClause or an array of hashes with the
|
927
|
+
# format as below.
|
928
|
+
#
|
929
|
+
# * column_family - The Column Family this operation will be run on.
|
930
|
+
# * index_clause - This can either be a CassandraThrift::IndexClause or an array of hashes with the following keys:
|
931
|
+
# * :column_name - Column to be compared
|
932
|
+
# * :value - Value to compare against
|
933
|
+
# * :comparison - Type of comparison to do.
|
934
|
+
# * options
|
935
|
+
# * :key_count - Set maximum number of rows to return. (Only works if CassandraThrift::IndexClause is not passed in.)
|
936
|
+
# * :key_start - Set starting row key for search. (Only works if CassandraThrift::IndexClause is not passed in.)
|
937
|
+
# * :consistency
|
938
|
+
#
|
939
|
+
# TODO: Supercolumn support.
|
940
|
+
def get_indexed_slices(column_family, index_clause, *columns_and_options)
|
941
|
+
return false if Cassandra.VERSION.to_f < 0.7
|
942
|
+
|
943
|
+
column_family, columns, _, options =
|
944
|
+
extract_and_validate_params(column_family, [], columns_and_options, READ_DEFAULTS.merge(:key_count => 100, :key_start => ""))
|
945
|
+
|
946
|
+
if index_clause.class != CassandraThrift::IndexClause
|
947
|
+
index_expressions = index_clause.collect do |expression|
|
948
|
+
create_index_expression(expression[:column_name], expression[:value], expression[:comparison])
|
949
|
+
end
|
950
|
+
|
951
|
+
index_clause = create_index_clause(index_expressions, options[:key_start], options[:key_count])
|
952
|
+
end
|
953
|
+
|
954
|
+
key_slices = _get_indexed_slices(column_family, index_clause, columns, options[:count], options[:start],
|
955
|
+
options[:finish], options[:reversed], options[:consistency])
|
956
|
+
|
957
|
+
key_slices.inject({}){|h, key_slice| h[key_slice.key] = key_slice.columns; h}
|
958
|
+
end
|
959
|
+
|
369
960
|
protected
|
370
961
|
|
371
962
|
def calling_method
|
372
963
|
"#{self.class}##{caller[0].split('`').last[0..-3]}"
|
373
964
|
end
|
374
965
|
|
966
|
+
##
|
375
967
|
# Roll up queued mutations, to improve atomicity (and performance).
|
968
|
+
#
|
376
969
|
def compact_mutations!
|
377
970
|
used_clevels = {} # hash that lists the consistency levels seen in the batch array. key is the clevel, value is true
|
378
971
|
by_key = Hash.new{|h,k | h[k] = {}}
|
@@ -404,8 +997,38 @@ class Cassandra
|
|
404
997
|
[by_key, used_clevels.keys]
|
405
998
|
end
|
406
999
|
|
1000
|
+
##
|
1001
|
+
# Creates a new client as specified by Cassandra.thrift_client_options[:thrift_client_class]
|
1002
|
+
#
|
407
1003
|
def new_client
|
408
1004
|
thrift_client_class.new(CassandraThrift::Cassandra::Client, @servers, @thrift_client_options)
|
409
1005
|
end
|
410
|
-
|
1006
|
+
|
1007
|
+
def client
|
1008
|
+
if @client.nil? || @client.current_server.nil?
|
1009
|
+
reconnect!
|
1010
|
+
@client.set_keyspace(@keyspace)
|
1011
|
+
end
|
1012
|
+
@client
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def reconnect!
|
1016
|
+
@servers = all_nodes
|
1017
|
+
@client = new_client
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
def all_nodes
|
1021
|
+
if @auto_discover_nodes && !@keyspace.eql?("system")
|
1022
|
+
temp_client = new_client
|
1023
|
+
begin
|
1024
|
+
ips = (temp_client.describe_ring(@keyspace).map {|range| range.endpoints}).flatten.uniq
|
1025
|
+
port = @servers.first.split(':').last
|
1026
|
+
ips.map{|ip| "#{ip}:#{port}" }
|
1027
|
+
ensure
|
1028
|
+
temp_client.disconnect!
|
1029
|
+
end
|
1030
|
+
else
|
1031
|
+
@servers
|
1032
|
+
end
|
1033
|
+
end
|
411
1034
|
end
|