cassandra 0.5.4 → 0.5.5
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.tar.gz.sig +0 -0
- data/CHANGELOG +2 -0
- data/Manifest +1 -0
- data/README +1 -1
- data/Rakefile +32 -21
- data/cassandra.gemspec +4 -4
- data/conf/storage-conf.xml +6 -0
- data/lib/cassandra.rb +1 -0
- data/lib/cassandra/cassandra.rb +95 -102
- data/lib/cassandra/columns.rb +9 -8
- data/lib/cassandra/debug.rb +7 -0
- data/lib/cassandra/long.rb +24 -10
- data/lib/cassandra/protocol.rb +2 -14
- data/lib/cassandra/uuid.rb +28 -28
- data/test/cassandra_test.rb +47 -29
- data/test/comparable_types_test.rb +1 -0
- data/vendor/gen-rb/cassandra.rb +17 -87
- data/vendor/gen-rb/cassandra_types.rb +18 -32
- metadata +4 -2
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
data/README
CHANGED
@@ -27,7 +27,7 @@ Cassandra itself is a rapidly moving target. In order to get a working server, u
|
|
27
27
|
|
28
28
|
cassandra_helper cassandra
|
29
29
|
|
30
|
-
A server will be installed in <tt>$HOME/cassandra/
|
30
|
+
A server will be installed in <tt>$HOME/cassandra/server</tt>, and started in debug mode.
|
31
31
|
|
32
32
|
== Usage
|
33
33
|
|
data/Rakefile
CHANGED
@@ -16,26 +16,28 @@ unless ENV['FROM_BIN_CASSANDRA_HELPER']
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
REVISION = "
|
19
|
+
REVISION = "c4992f48ce9c26ce4fd028240447b4cbe85ecf26"
|
20
20
|
|
21
21
|
PATCHES = [
|
22
|
-
"http://issues.apache.org/jira/secure/attachment/
|
22
|
+
"http://issues.apache.org/jira/secure/attachment/12417533/388.patch",
|
23
|
+
"http://issues.apache.org/jira/secure/attachment/12417682/CASSANDRA-336-code.diff",
|
24
|
+
"http://issues.apache.org/jira/secure/attachment/12417683/CASSANDRA-336-thrift.diff"]
|
23
25
|
|
24
|
-
CASSANDRA_HOME = "#{ENV['HOME']}/cassandra/
|
26
|
+
CASSANDRA_HOME = "#{ENV['HOME']}/cassandra/server"
|
25
27
|
|
26
28
|
CASSANDRA_TEST = "#{ENV['HOME']}/cassandra/test"
|
27
29
|
|
30
|
+
directory CASSANDRA_TEST
|
31
|
+
|
28
32
|
desc "Start Cassandra"
|
29
|
-
task :cassandra => [:
|
33
|
+
task :cassandra => [:build, CASSANDRA_TEST] do
|
30
34
|
# Construct environment
|
31
35
|
env = ""
|
32
36
|
if !ENV["CASSANDRA_INCLUDE"]
|
33
37
|
env << "CASSANDRA_INCLUDE=#{Dir.pwd}/conf/cassandra.in.sh "
|
34
38
|
env << "CASSANDRA_HOME=#{CASSANDRA_HOME} "
|
35
|
-
env << "CASSANDRA_CONF=#{File.expand_path(File.dirname(__FILE__))}/conf"
|
36
|
-
end
|
37
|
-
# Create data dir
|
38
|
-
Dir.mkdir(CASSANDRA_TEST) if !File.exist?(CASSANDRA_TEST)
|
39
|
+
env << "CASSANDRA_CONF=#{File.expand_path(File.dirname(__FILE__))}/conf"
|
40
|
+
end
|
39
41
|
# Start server
|
40
42
|
Dir.chdir(CASSANDRA_TEST) do
|
41
43
|
exec("env #{env} #{CASSANDRA_HOME}/bin/cassandra -f")
|
@@ -53,29 +55,35 @@ task :java do
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
desc "
|
57
|
-
task :
|
58
|
-
# Check git version
|
58
|
+
desc "Check Git version"
|
59
|
+
task :git do
|
59
60
|
unless `git --version 2>&1` =~ /git version 1.6/
|
60
61
|
puts "You need to install git 1.6."
|
61
62
|
exit(1)
|
62
63
|
end
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "Checkout Cassandra from git"
|
67
|
+
task :checkout => [:java, :git] do
|
63
68
|
# Like a git submodule, but all in one more obvious place
|
64
69
|
unless File.exist?(CASSANDRA_HOME)
|
70
|
+
puts "Checking Cassandra out from git"
|
65
71
|
cmd = "git clone git://git.apache.org/cassandra.git #{CASSANDRA_HOME}"
|
66
72
|
if !system(cmd)
|
67
73
|
put "Checkout failed. Try:\n #{cmd}"
|
68
74
|
exit(1)
|
69
75
|
end
|
70
|
-
|
71
|
-
end
|
76
|
+
end
|
72
77
|
end
|
73
78
|
|
74
79
|
desc "Apply patches to Cassandra checkout; use RESET=1 to force"
|
75
|
-
task :patch do
|
76
|
-
|
77
|
-
|
78
|
-
|
80
|
+
task :patch => [:checkout] do
|
81
|
+
# Verify checkout revision and patchset
|
82
|
+
Dir.chdir(CASSANDRA_HOME) do
|
83
|
+
current_checkout = `git show HEAD~#{PATCHES.size} | head -n1`
|
84
|
+
if !current_checkout.include?(REVISION)
|
85
|
+
puts "Updating Cassandra and applying patches"
|
86
|
+
system("rm -rf #{CASSANDRA_TEST}/data")
|
79
87
|
system("ant clean && git fetch && git reset #{REVISION} --hard")
|
80
88
|
# Delete untracked files, so that the patchs can apply again
|
81
89
|
Array(`git status`[/Untracked files:(.*)$/m, 1].to_s.split("\n")[3..-1]).each do |file|
|
@@ -83,7 +91,7 @@ task :patch do
|
|
83
91
|
end
|
84
92
|
# Patch, with a handy commit for each one
|
85
93
|
PATCHES.each do |url|
|
86
|
-
raise "#{url} failed" unless system("
|
94
|
+
raise "#{url} failed" unless system("curl #{url} | patch -p1")
|
87
95
|
system("git commit -a -m 'Applied patch: #{url.inspect}'")
|
88
96
|
end
|
89
97
|
end
|
@@ -91,8 +99,9 @@ task :patch do
|
|
91
99
|
end
|
92
100
|
|
93
101
|
desc "Rebuild Cassandra"
|
94
|
-
task :build do
|
102
|
+
task :build => [:patch] do
|
95
103
|
unless File.exist?("#{CASSANDRA_HOME}/build")
|
104
|
+
puts "Building Cassandra"
|
96
105
|
cmd = "cd #{CASSANDRA_HOME} && ant"
|
97
106
|
if !system(cmd)
|
98
107
|
puts "Could not build Casssandra. Try:\n #{cmd}"
|
@@ -103,25 +112,27 @@ end
|
|
103
112
|
|
104
113
|
desc "Clean Cassandra build"
|
105
114
|
task :clean do
|
115
|
+
puts "Cleaning Cassandra"
|
106
116
|
if File.exist?(CASSANDRA_HOME)
|
107
117
|
Dir.chdir(CASSANDRA_HOME) do
|
108
118
|
system("ant clean")
|
109
119
|
end
|
110
|
-
end
|
120
|
+
end
|
111
121
|
end
|
112
122
|
|
113
123
|
namespace :data do
|
114
124
|
desc "Reset test data"
|
115
125
|
task :reset do
|
126
|
+
puts "Resetting test data"
|
116
127
|
system("rm -rf #{CASSANDRA_TEST}/data")
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
120
131
|
# desc "Regenerate thrift bindings for Cassandra" # Dev only
|
121
132
|
task :thrift do
|
133
|
+
puts "Generating Thrift bindings"
|
122
134
|
system(
|
123
135
|
"cd vendor &&
|
124
136
|
rm -rf gen-rb &&
|
125
137
|
thrift -gen rb #{CASSANDRA_HOME}/interface/cassandra.thrift")
|
126
138
|
end
|
127
|
-
|
data/cassandra.gemspec
CHANGED
@@ -2,18 +2,18 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{cassandra}
|
5
|
-
s.version = "0.5.
|
5
|
+
s.version = "0.5.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0.8") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Evan Weaver"]
|
9
9
|
s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
|
10
|
-
s.date = %q{2009-08-
|
10
|
+
s.date = %q{2009-08-27}
|
11
11
|
s.default_executable = %q{cassandra_helper}
|
12
12
|
s.description = %q{A Ruby client for the Cassandra distributed database.}
|
13
13
|
s.email = %q{}
|
14
14
|
s.executables = ["cassandra_helper"]
|
15
|
-
s.extra_rdoc_files = ["bin/cassandra_helper", "CHANGELOG", "lib/cassandra/array.rb", "lib/cassandra/cassandra.rb", "lib/cassandra/columns.rb", "lib/cassandra/comparable.rb", "lib/cassandra/constants.rb", "lib/cassandra/long.rb", "lib/cassandra/ordered_hash.rb", "lib/cassandra/protocol.rb", "lib/cassandra/safe_client.rb", "lib/cassandra/time.rb", "lib/cassandra/uuid.rb", "lib/cassandra.rb", "LICENSE", "README"]
|
16
|
-
s.files = ["bin/cassandra_helper", "CHANGELOG", "conf/cassandra.in.sh", "conf/log4j.properties", "conf/storage-conf.xml", "lib/cassandra/array.rb", "lib/cassandra/cassandra.rb", "lib/cassandra/columns.rb", "lib/cassandra/comparable.rb", "lib/cassandra/constants.rb", "lib/cassandra/long.rb", "lib/cassandra/ordered_hash.rb", "lib/cassandra/protocol.rb", "lib/cassandra/safe_client.rb", "lib/cassandra/time.rb", "lib/cassandra/uuid.rb", "lib/cassandra.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/cassandra_test.rb", "test/comparable_types_test.rb", "test/test_helper.rb", "vendor/gen-rb/cassandra.rb", "vendor/gen-rb/cassandra_constants.rb", "vendor/gen-rb/cassandra_types.rb", "cassandra.gemspec"]
|
15
|
+
s.extra_rdoc_files = ["bin/cassandra_helper", "CHANGELOG", "lib/cassandra/array.rb", "lib/cassandra/cassandra.rb", "lib/cassandra/columns.rb", "lib/cassandra/comparable.rb", "lib/cassandra/constants.rb", "lib/cassandra/debug.rb", "lib/cassandra/long.rb", "lib/cassandra/ordered_hash.rb", "lib/cassandra/protocol.rb", "lib/cassandra/safe_client.rb", "lib/cassandra/time.rb", "lib/cassandra/uuid.rb", "lib/cassandra.rb", "LICENSE", "README"]
|
16
|
+
s.files = ["bin/cassandra_helper", "CHANGELOG", "conf/cassandra.in.sh", "conf/log4j.properties", "conf/storage-conf.xml", "lib/cassandra/array.rb", "lib/cassandra/cassandra.rb", "lib/cassandra/columns.rb", "lib/cassandra/comparable.rb", "lib/cassandra/constants.rb", "lib/cassandra/debug.rb", "lib/cassandra/long.rb", "lib/cassandra/ordered_hash.rb", "lib/cassandra/protocol.rb", "lib/cassandra/safe_client.rb", "lib/cassandra/time.rb", "lib/cassandra/uuid.rb", "lib/cassandra.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/cassandra_test.rb", "test/comparable_types_test.rb", "test/test_helper.rb", "vendor/gen-rb/cassandra.rb", "vendor/gen-rb/cassandra_constants.rb", "vendor/gen-rb/cassandra_types.rb", "cassandra.gemspec"]
|
17
17
|
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/cassandra/}
|
18
18
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cassandra", "--main", "README"]
|
19
19
|
s.require_paths = ["lib"]
|
data/conf/storage-conf.xml
CHANGED
@@ -45,6 +45,12 @@
|
|
45
45
|
<ColumnFamily CompareWith="TimeUUIDType" Name="Blogs"/>
|
46
46
|
<ColumnFamily CompareWith="TimeUUIDType" Name="Comments"/>
|
47
47
|
</Keyspace>
|
48
|
+
|
49
|
+
<Keyspace Name="MultiblogLong">
|
50
|
+
<KeysCachedFraction>0.01</KeysCachedFraction>
|
51
|
+
<ColumnFamily CompareWith="LongType" Name="Blogs"/>
|
52
|
+
<ColumnFamily CompareWith="LongType" Name="Comments"/>
|
53
|
+
</Keyspace>
|
48
54
|
</Keyspaces>
|
49
55
|
|
50
56
|
<!-- Partitioner: any IPartitioner may be used, including your own
|
data/lib/cassandra.rb
CHANGED
data/lib/cassandra/cassandra.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
Create a new Cassandra client instance. Accepts a keyspace name, and optional host and port.
|
4
4
|
|
5
5
|
client = Cassandra.new('twitter', '127.0.0.1', 9160)
|
6
|
-
|
6
|
+
|
7
7
|
You can then make calls to the server via the <tt>client</tt> instance.
|
8
|
-
|
8
|
+
|
9
9
|
client.insert(:UserRelationships, "5", {"user_timeline" => {UUID.new => "1"}})
|
10
10
|
client.get(:UserRelationships, "5", "user_timeline")
|
11
|
-
|
11
|
+
|
12
12
|
For read methods, valid option parameters are:
|
13
13
|
|
14
14
|
<tt>:count</tt>:: How many results to return. Defaults to 100.
|
@@ -18,9 +18,9 @@ For read methods, valid option parameters are:
|
|
18
18
|
<tt>:consistency</tt>:: The consistency level of the request. Defaults to <tt>Cassandra::Consistency::ONE</tt> (one node must respond). Other valid options are <tt>Cassandra::Consistency::ZERO</tt>, <tt>Cassandra::Consistency::QUORUM</tt>, and <tt>Cassandra::Consistency::ALL</tt>.
|
19
19
|
|
20
20
|
Note that some read options have no relevance in some contexts.
|
21
|
-
|
21
|
+
|
22
22
|
For write methods, valid option parameters are:
|
23
|
-
|
23
|
+
|
24
24
|
<tt>:timestamp </tt>:: The transaction timestamp. Defaults to the current time in milliseconds. This is used for conflict resolution by the server; you normally never need to change it.
|
25
25
|
<tt>:consistency</tt>:: See above.
|
26
26
|
|
@@ -38,18 +38,18 @@ class Cassandra
|
|
38
38
|
end
|
39
39
|
|
40
40
|
MAX_INT = 2**31 - 1
|
41
|
-
|
42
|
-
WRITE_DEFAULTS = {
|
41
|
+
|
42
|
+
WRITE_DEFAULTS = {
|
43
43
|
:count => MAX_INT,
|
44
44
|
:timestamp => nil,
|
45
|
-
:consistency => Consistency::ONE
|
45
|
+
:consistency => Consistency::ONE
|
46
46
|
}.freeze
|
47
47
|
|
48
48
|
READ_DEFAULTS = {
|
49
|
-
:count => 100,
|
50
|
-
:start => nil,
|
51
|
-
:finish => nil,
|
52
|
-
:reversed => false,
|
49
|
+
:count => 100,
|
50
|
+
:start => nil,
|
51
|
+
:finish => nil,
|
52
|
+
:reversed => false,
|
53
53
|
:consistency => Consistency::ONE
|
54
54
|
}.freeze
|
55
55
|
|
@@ -91,46 +91,49 @@ class Cassandra
|
|
91
91
|
# a nested hash for a super column family. Supports the <tt>:consistency</tt>
|
92
92
|
# and <tt>:timestamp</tt> options.
|
93
93
|
def insert(column_family, key, hash, options = {})
|
94
|
-
column_family, _, _, options =
|
94
|
+
column_family, _, _, options =
|
95
|
+
validate_params(column_family, key, [options], WRITE_DEFAULTS)
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
:cfmap => {column_family =>
|
105
|
-
hash_to_columns(column_family, hash, options[:timestamp] || Time.stamp)})
|
106
|
-
end
|
107
|
-
|
108
|
-
args = [mutation, options[:consistency]]
|
109
|
-
@batch ? @batch << args : _insert(*args)
|
97
|
+
args = [column_family, hash, options[:timestamp] || Time.stamp]
|
98
|
+
columns = is_super(column_family) ? hash_to_super_columns(*args) : hash_to_columns(*args)
|
99
|
+
mutation = CassandraThrift::BatchMutation.new(
|
100
|
+
:key => key,
|
101
|
+
:cfmap => {column_family => columns},
|
102
|
+
:column_paths => [])
|
103
|
+
|
104
|
+
@batch ? @batch << mutation : _mutate([mutation], options[:consistency])
|
110
105
|
end
|
111
106
|
|
112
107
|
## Delete
|
113
108
|
|
114
|
-
#
|
109
|
+
# _mutate the element at the column_family:key:[column]:[sub_column]
|
115
110
|
# path you request. Supports the <tt>:consistency</tt> and <tt>:timestamp</tt>
|
116
111
|
# options.
|
117
112
|
def remove(column_family, key, *columns_and_options)
|
118
|
-
column_family, column, sub_column, options =
|
119
|
-
|
120
|
-
|
113
|
+
column_family, column, sub_column, options =
|
114
|
+
validate_params(column_family, key, columns_and_options, WRITE_DEFAULTS)
|
115
|
+
|
116
|
+
args = {:column_family => column_family, :timestamp => options[:timestamp] || Time.stamp}
|
117
|
+
columns = is_super(column_family) ? {:super_column => column, :column => sub_column} : {:column => column}
|
118
|
+
mutation = CassandraThrift::BatchMutation.new(
|
119
|
+
:key => key,
|
120
|
+
:cfmap => {},
|
121
|
+
:column_paths => [CassandraThrift::ColumnPath.new(args.merge(columns))])
|
122
|
+
|
123
|
+
@batch ? @batch << mutation : _mutate([mutation], options[:consistency])
|
121
124
|
end
|
122
125
|
|
123
|
-
# Remove all rows in the column family you request. Supports options
|
126
|
+
# Remove all rows in the column family you request. Supports options
|
124
127
|
# <tt>:consistency</tt> and <tt>:timestamp</tt>.
|
125
|
-
# FIXME May not currently delete all records without multiple calls. Waiting
|
128
|
+
# FIXME May not currently delete all records without multiple calls. Waiting
|
126
129
|
# for ranged remove support in Cassandra.
|
127
130
|
def clear_column_family!(column_family, options = {})
|
128
131
|
get_range(column_family).each { |key| remove(column_family, key, options) }
|
129
132
|
end
|
130
133
|
|
131
|
-
# Remove all rows in the keyspace. Supports options <tt>:consistency</tt> and
|
134
|
+
# Remove all rows in the keyspace. Supports options <tt>:consistency</tt> and
|
132
135
|
# <tt>:timestamp</tt>.
|
133
|
-
# FIXME May not currently delete all records without multiple calls. Waiting
|
136
|
+
# FIXME May not currently delete all records without multiple calls. Waiting
|
134
137
|
# for ranged remove support in Cassandra.
|
135
138
|
def clear_keyspace!(options = {})
|
136
139
|
@schema.keys.each { |column_family| clear_column_family!(column_family, options) }
|
@@ -139,10 +142,11 @@ class Cassandra
|
|
139
142
|
### Read
|
140
143
|
|
141
144
|
# Count the elements at the column_family:key:[super_column] path you
|
142
|
-
# request. Supports options <tt>:count</tt>, <tt>:start</tt>, <tt>:finish</tt>,
|
145
|
+
# request. Supports options <tt>:count</tt>, <tt>:start</tt>, <tt>:finish</tt>,
|
143
146
|
# <tt>:reversed</tt>, and <tt>:consistency</tt>.
|
144
147
|
def count_columns(column_family, key, *columns_and_options)
|
145
|
-
column_family, super_column, _, options =
|
148
|
+
column_family, super_column, _, options =
|
149
|
+
validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
146
150
|
_count_columns(column_family, key, super_column, options[:consistency])
|
147
151
|
end
|
148
152
|
|
@@ -153,14 +157,15 @@ class Cassandra
|
|
153
157
|
end
|
154
158
|
|
155
159
|
# Return a list of single values for the elements at the
|
156
|
-
# column_family:key:column[s]:[sub_columns] path you request. Supports the
|
160
|
+
# column_family:key:column[s]:[sub_columns] path you request. Supports the
|
157
161
|
# <tt>:consistency</tt> option.
|
158
162
|
def get_columns(column_family, key, *columns_and_options)
|
159
|
-
column_family, columns, sub_columns, options =
|
163
|
+
column_family, columns, sub_columns, options =
|
164
|
+
validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
160
165
|
_get_columns(column_family, key, columns, sub_columns, options[:consistency])
|
161
166
|
end
|
162
167
|
|
163
|
-
# Multi-key version of Cassandra#get_columns. Supports the <tt>:consistency</tt>
|
168
|
+
# Multi-key version of Cassandra#get_columns. Supports the <tt>:consistency</tt>
|
164
169
|
# option.
|
165
170
|
def multi_get_columns(column_family, keys, *options)
|
166
171
|
OrderedHash[*keys.map { |key| [key, get_columns(column_family, key, *options)] }._flatten_once]
|
@@ -168,16 +173,17 @@ class Cassandra
|
|
168
173
|
|
169
174
|
# Return a hash (actually, a Cassandra::OrderedHash) or a single value
|
170
175
|
# representing the element at the column_family:key:[column]:[sub_column]
|
171
|
-
# path you request. Supports options <tt>:count</tt>, <tt>:start</tt>,
|
176
|
+
# path you request. Supports options <tt>:count</tt>, <tt>:start</tt>,
|
172
177
|
# <tt>:finish</tt>, <tt>:reversed</tt>, and <tt>:consistency</tt>.
|
173
178
|
def get(column_family, key, *columns_and_options)
|
174
|
-
column_family, column, sub_column, options =
|
179
|
+
column_family, column, sub_column, options =
|
180
|
+
validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
175
181
|
_get(column_family, key, column, sub_column, options[:count], options[:start], options[:finish], options[:reversed], options[:consistency])
|
176
182
|
rescue CassandraThrift::NotFoundException
|
177
183
|
is_super(column_family) && !sub_column ? OrderedHash.new : nil
|
178
184
|
end
|
179
185
|
|
180
|
-
# Multi-key version of Cassandra#get. Supports options <tt>:count</tt>,
|
186
|
+
# Multi-key version of Cassandra#get. Supports options <tt>:count</tt>,
|
181
187
|
# <tt>:start</tt>, <tt>:finish</tt>, <tt>:reversed</tt>, and <tt>:consistency</tt>.
|
182
188
|
def multi_get(column_family, keys, *options)
|
183
189
|
OrderedHash[*keys.map { |key| [key, get(column_family, key, *options)] }._flatten_once]
|
@@ -186,23 +192,25 @@ class Cassandra
|
|
186
192
|
# Return true if the column_family:key:[column]:[sub_column] path you
|
187
193
|
# request exists. Supports the <tt>:consistency</tt> option.
|
188
194
|
def exists?(column_family, key, *columns_and_options)
|
189
|
-
column_family, column, sub_column, options =
|
195
|
+
column_family, column, sub_column, options =
|
196
|
+
validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
|
190
197
|
_get(column_family, key, column, sub_column, 1, nil, nil, nil, options[:consistency])
|
191
198
|
true
|
192
199
|
rescue CassandraThrift::NotFoundException
|
193
200
|
end
|
194
201
|
|
195
202
|
# Return a list of keys in the column_family you request. Requires the
|
196
|
-
# table to be partitioned with OrderPreservingHash. Supports the
|
197
|
-
# <tt>:count</tt>, <tt>:start</tt>, <tt>:finish</tt>, and <tt>:consistency</tt>
|
203
|
+
# table to be partitioned with OrderPreservingHash. Supports the
|
204
|
+
# <tt>:count</tt>, <tt>:start</tt>, <tt>:finish</tt>, and <tt>:consistency</tt>
|
198
205
|
# options.
|
199
206
|
def get_range(column_family, options = {})
|
200
|
-
column_family, _, _, options =
|
207
|
+
column_family, _, _, options =
|
208
|
+
validate_params(column_family, "", [options], READ_DEFAULTS)
|
201
209
|
_get_range(column_family, options[:start], options[:finish], options[:count], options[:consistency])
|
202
210
|
end
|
203
211
|
|
204
212
|
# Count all rows in the column_family you request. Requires the table
|
205
|
-
# to be partitioned with OrderPreservingHash. Supports the <tt>:start</tt>,
|
213
|
+
# to be partitioned with OrderPreservingHash. Supports the <tt>:start</tt>,
|
206
214
|
# <tt>:finish</tt>, and <tt>:consistency</tt> options.
|
207
215
|
# FIXME will count only MAX_INT records
|
208
216
|
def count_range(column_family, options = {})
|
@@ -210,33 +218,42 @@ class Cassandra
|
|
210
218
|
end
|
211
219
|
|
212
220
|
# Open a batch operation and yield. Inserts and deletes will be queued until
|
213
|
-
# the block closes, and then sent atomically to the server.
|
214
|
-
#
|
215
|
-
|
221
|
+
# the block closes, and then sent atomically to the server. Supports the
|
222
|
+
# <tt>:consistency</tt> option, which overrides the consistency set in
|
223
|
+
# the individual commands.
|
224
|
+
def batch(options = {})
|
225
|
+
_, _, _, options =
|
226
|
+
validate_params(@schema.keys.first, "", [options], WRITE_DEFAULTS)
|
227
|
+
|
216
228
|
@batch = []
|
217
229
|
yield
|
218
|
-
compact_mutations
|
219
|
-
|
230
|
+
compact_mutations!
|
231
|
+
_mutate(@batch, options[:consistency])
|
220
232
|
@batch = nil
|
221
233
|
end
|
222
|
-
|
234
|
+
|
223
235
|
private
|
224
|
-
|
236
|
+
|
225
237
|
# Extract and validate options.
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
238
|
+
# FIXME Should be done as a decorator
|
239
|
+
def validate_params(column_family, key, args, options)
|
240
|
+
if !key.is_a?(String)
|
241
|
+
raise ArgumentError, "Key #{key.inspect} must be a String for #{calling_method}"
|
242
|
+
elsif args.last.is_a?(Hash)
|
243
|
+
extras = args.last.keys - options.keys
|
244
|
+
raise ArgumentError, "Invalid options #{extras.inspect[1..-2]} for #{calling_method}" if extras.any?
|
232
245
|
options = options.merge(args.pop)
|
233
|
-
end
|
246
|
+
end
|
234
247
|
|
235
248
|
column_family, column, sub_column = column_family.to_s, args[0], args[1]
|
236
|
-
assert_column_name_classes(column_family, column, sub_column)
|
249
|
+
assert_column_name_classes(column_family, column, sub_column)
|
237
250
|
[column_family, map_to_s(column), map_to_s(sub_column), options]
|
238
251
|
end
|
239
252
|
|
253
|
+
def calling_method
|
254
|
+
"#{self.class}##{caller[0].split('`').last[0..-3]}"
|
255
|
+
end
|
256
|
+
|
240
257
|
# Convert stuff to strings.
|
241
258
|
def map_to_s(el)
|
242
259
|
case el
|
@@ -247,52 +264,28 @@ class Cassandra
|
|
247
264
|
raise Comparable::TypeError, "Can't map #{el.inspect}"
|
248
265
|
end
|
249
266
|
end
|
250
|
-
|
251
|
-
# Roll up queued mutations
|
252
|
-
def compact_mutations
|
253
|
-
compact_batch = []
|
267
|
+
|
268
|
+
# Roll up queued mutations, to improve atomicity.
|
269
|
+
def compact_mutations!
|
254
270
|
mutations = {}
|
255
271
|
|
256
|
-
|
272
|
+
# Nested hash merge
|
257
273
|
@batch.each do |m|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
mutations = {}
|
263
|
-
# Insert delete operation
|
264
|
-
compact_batch << m
|
265
|
-
else # BatchMutation, BatchMutationSuper
|
266
|
-
# Do a nested hash merge
|
267
|
-
if mutation_class = mutations[m.class]
|
268
|
-
if mutation = mutation_class[m.key]
|
269
|
-
if columns = mutation.cfmap[m.cfmap.keys.first]
|
270
|
-
columns.concat(m.cfmap.values.first)
|
271
|
-
else
|
272
|
-
mutation.cfmap.merge!(m.cfmap)
|
273
|
-
end
|
274
|
-
else
|
275
|
-
mutation_class[m.key] = m
|
276
|
-
end
|
274
|
+
if mutation = mutations[m.key]
|
275
|
+
# Inserts
|
276
|
+
if columns = mutation.cfmap[m.cfmap.keys.first]
|
277
|
+
columns.concat(m.cfmap.values.first)
|
277
278
|
else
|
278
|
-
|
279
|
+
mutation.cfmap.merge!(m.cfmap)
|
279
280
|
end
|
281
|
+
# Deletes
|
282
|
+
mutation.column_paths.concat(m.column_paths)
|
283
|
+
else
|
284
|
+
mutations[m.key] = m
|
280
285
|
end
|
281
286
|
end
|
282
287
|
|
283
|
-
|
288
|
+
# FIXME Return atomic thrift thingy
|
289
|
+
@batch = mutations.values
|
284
290
|
end
|
285
|
-
|
286
|
-
# Send all the queued mutations to the server.
|
287
|
-
def dispatch_mutations
|
288
|
-
@batch.compact!
|
289
|
-
@batch.each do |args|
|
290
|
-
case args.first
|
291
|
-
when CassandraThrift::BatchMutationSuper, CassandraThrift::BatchMutation
|
292
|
-
_insert(*args)
|
293
|
-
else
|
294
|
-
_remove(*args)
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
291
|
end
|
data/lib/cassandra/columns.rb
CHANGED
@@ -63,23 +63,24 @@ class Cassandra
|
|
63
63
|
end
|
64
64
|
hash
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def hash_to_columns(column_family, hash, timestamp)
|
68
68
|
assert_column_name_classes(column_family, hash.keys)
|
69
|
-
hash_to_columns_without_assertion(column_family, hash, timestamp)
|
70
|
-
end
|
71
|
-
|
72
|
-
def hash_to_columns_without_assertion(column_family, hash, timestamp)
|
73
69
|
hash.map do |column, value|
|
74
|
-
CassandraThrift::
|
70
|
+
CassandraThrift::ColumnOrSuperColumn.new(:column =>
|
71
|
+
CassandraThrift::Column.new(:name => column.to_s, :value => value, :timestamp => timestamp))
|
75
72
|
end
|
76
|
-
end
|
73
|
+
end
|
77
74
|
|
78
75
|
def hash_to_super_columns(column_family, hash, timestamp)
|
79
76
|
assert_column_name_classes(column_family, hash.keys)
|
80
77
|
hash.map do |column, sub_hash|
|
81
78
|
assert_column_name_classes(column_family, nil, sub_hash.keys)
|
82
|
-
|
79
|
+
sub_columns = sub_hash.map do |sub_column, value|
|
80
|
+
CassandraThrift::Column.new(:name => sub_column.to_s, :value => value, :timestamp => timestamp)
|
81
|
+
end
|
82
|
+
CassandraThrift::ColumnOrSuperColumn.new(:super_column =>
|
83
|
+
CassandraThrift::SuperColumn.new(:name => column.to_s, :columns => sub_columns))
|
83
84
|
end
|
84
85
|
end
|
85
86
|
end
|
data/lib/cassandra/long.rb
CHANGED
@@ -2,18 +2,26 @@
|
|
2
2
|
class Cassandra
|
3
3
|
# A temporally-ordered Long class for use in Cassandra column names
|
4
4
|
class Long < Comparable
|
5
|
-
|
6
|
-
def initialize(bytes = nil)
|
5
|
+
|
6
|
+
def initialize(bytes = nil)
|
7
7
|
case bytes
|
8
8
|
when String
|
9
|
-
|
10
|
-
|
9
|
+
case bytes.size
|
10
|
+
when 8 # Raw byte array
|
11
|
+
@bytes = bytes
|
12
|
+
when 18 # Human-readable UUID-like representation; inverse of #to_guid
|
13
|
+
elements = bytes.split("-")
|
14
|
+
raise TypeError, "Malformed UUID-like representation" if elements.size != 3
|
15
|
+
@bytes = elements.join.to_a.pack('H32')
|
16
|
+
else
|
17
|
+
raise TypeError, "8 bytes required for byte array, or 18 characters required for UUID-like representation"
|
18
|
+
end
|
11
19
|
when Integer
|
12
20
|
raise TypeError, "Integer must be between 0 and 2**64" if bytes < 0 or bytes > 2**64
|
13
21
|
@bytes = [bytes >> 32, bytes % 2**32].pack("NN")
|
14
|
-
when NilClass
|
22
|
+
when NilClass, Time
|
15
23
|
# Time.stamp is 52 bytes, so we have 12 bytes of entropy left over
|
16
|
-
int = (Time.stamp << 12) + rand(2**12)
|
24
|
+
int = ((bytes || Time).stamp << 12) + rand(2**12)
|
17
25
|
@bytes = [int >> 32, int % 2**32].pack("NN")
|
18
26
|
else
|
19
27
|
raise TypeError, "Can't convert from #{bytes.class}"
|
@@ -23,11 +31,15 @@ class Cassandra
|
|
23
31
|
def to_i
|
24
32
|
@to_i ||= begin
|
25
33
|
ints = @bytes.unpack("NN")
|
26
|
-
(ints[0] << 32) +
|
34
|
+
(ints[0] << 32) +
|
27
35
|
ints[1]
|
28
36
|
end
|
29
|
-
end
|
37
|
+
end
|
30
38
|
|
39
|
+
def to_guid
|
40
|
+
"%08x-%04x-%04x" % @bytes.unpack("Nnn")
|
41
|
+
end
|
42
|
+
|
31
43
|
def inspect
|
32
44
|
"<Cassandra::Long##{object_id} time: #{
|
33
45
|
Time.at((to_i >> 12) / 1_000_000).inspect
|
@@ -35,7 +47,9 @@ class Cassandra
|
|
35
47
|
(to_i >> 12) % 1_000_000
|
36
48
|
}, jitter: #{
|
37
49
|
to_i % 2**12
|
50
|
+
}, guid: #{
|
51
|
+
to_guid
|
38
52
|
}>"
|
39
|
-
end
|
40
|
-
end
|
53
|
+
end
|
54
|
+
end
|
41
55
|
end
|
data/lib/cassandra/protocol.rb
CHANGED
@@ -4,20 +4,8 @@ class Cassandra
|
|
4
4
|
module Protocol #:nodoc:
|
5
5
|
private
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
when CassandraThrift::BatchMutationSuper then @client.batch_insert_super_column(@keyspace, mutation, consistency)
|
10
|
-
when CassandraThrift::BatchMutation then @client.batch_insert(@keyspace, mutation, consistency)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def _remove(column_family, key, column, sub_column, consistency, timestamp)
|
15
|
-
column_path_or_parent = if is_super(column_family)
|
16
|
-
CassandraThrift::ColumnPath.new(:column_family => column_family, :super_column => column, :column => sub_column)
|
17
|
-
else
|
18
|
-
CassandraThrift::ColumnPath.new(:column_family => column_family, :column => column)
|
19
|
-
end
|
20
|
-
@client.remove(@keyspace, key, column_path_or_parent, timestamp, consistency)
|
7
|
+
def _mutate(mutation, consistency)
|
8
|
+
@client.batch_mutate(@keyspace, mutation, consistency)
|
21
9
|
end
|
22
10
|
|
23
11
|
def _count_columns(column_family, key, super_column, consistency)
|
data/lib/cassandra/uuid.rb
CHANGED
@@ -8,45 +8,45 @@ class Cassandra
|
|
8
8
|
end
|
9
9
|
|
10
10
|
GREGORIAN_EPOCH_OFFSET = 0x01B2_1DD2_1381_4000 # Oct 15, 1582
|
11
|
-
|
11
|
+
|
12
12
|
VARIANT = 0b1000_0000_0000_0000
|
13
13
|
|
14
14
|
def initialize(bytes = nil)
|
15
15
|
case bytes
|
16
16
|
when String
|
17
17
|
case bytes.size
|
18
|
-
when 16
|
19
|
-
@bytes = bytes
|
20
|
-
when 36
|
18
|
+
when 16 # Raw byte array
|
19
|
+
@bytes = bytes
|
20
|
+
when 36 # Human-readable UUID representation; inverse of #to_guid
|
21
21
|
elements = bytes.split("-")
|
22
22
|
raise TypeError, "Malformed UUID representation" if elements.size != 5
|
23
|
-
@bytes = elements.join.to_a.pack('H32')
|
23
|
+
@bytes = elements.join.to_a.pack('H32')
|
24
24
|
else
|
25
25
|
raise TypeError, "16 bytes required for byte array, or 36 characters required for UUID representation"
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
when Integer
|
29
29
|
raise TypeError, "Integer must be between 0 and 2**128" if bytes < 0 or bytes > 2**128
|
30
30
|
@bytes = [
|
31
|
-
(bytes >> 96) & 0xFFFF_FFFF,
|
32
|
-
(bytes >> 64) & 0xFFFF_FFFF,
|
33
|
-
(bytes >> 32) & 0xFFFF_FFFF,
|
31
|
+
(bytes >> 96) & 0xFFFF_FFFF,
|
32
|
+
(bytes >> 64) & 0xFFFF_FFFF,
|
33
|
+
(bytes >> 32) & 0xFFFF_FFFF,
|
34
34
|
bytes & 0xFFFF_FFFF
|
35
35
|
].pack("NNNN")
|
36
|
-
|
36
|
+
|
37
37
|
when NilClass, Time
|
38
38
|
time = (bytes || Time).stamp * 10 + GREGORIAN_EPOCH_OFFSET
|
39
39
|
# See http://github.com/spectra/ruby-uuid/
|
40
40
|
@bytes = [
|
41
|
-
time & 0xFFFF_FFFF,
|
42
|
-
time >> 32,
|
43
|
-
((time >> 48) & 0x0FFF) | 0x1000,
|
44
|
-
# Top 3 bytes reserved
|
41
|
+
time & 0xFFFF_FFFF,
|
42
|
+
time >> 32,
|
43
|
+
((time >> 48) & 0x0FFF) | 0x1000,
|
44
|
+
# Top 3 bytes reserved
|
45
45
|
rand(2**13) | VARIANT,
|
46
46
|
rand(2**16),
|
47
47
|
rand(2**32)
|
48
48
|
].pack("NnnnnN")
|
49
|
-
|
49
|
+
|
50
50
|
else
|
51
51
|
raise TypeError, "Can't convert from #{bytes.class}"
|
52
52
|
end
|
@@ -54,9 +54,9 @@ class Cassandra
|
|
54
54
|
|
55
55
|
def to_i
|
56
56
|
ints = @bytes.unpack("NNNN")
|
57
|
-
(ints[0] << 96) +
|
58
|
-
(ints[1] << 64) +
|
59
|
-
(ints[2] << 32) +
|
57
|
+
(ints[0] << 96) +
|
58
|
+
(ints[1] << 64) +
|
59
|
+
(ints[2] << 32) +
|
60
60
|
ints[3]
|
61
61
|
end
|
62
62
|
|
@@ -65,7 +65,7 @@ class Cassandra
|
|
65
65
|
version = (time_high & 0xF000).to_s(16)[0].chr.to_i
|
66
66
|
version > 0 and version < 6 ? version : -1
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def variant
|
70
70
|
@bytes.unpack('QnnN')[1] >> 13
|
71
71
|
end
|
@@ -76,19 +76,19 @@ class Cassandra
|
|
76
76
|
elements[-1] = '%02x%02x%02x%02x%02x%02x' % node
|
77
77
|
"%08x-%04x-%04x-%02x%02x-%s" % elements
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
def seconds
|
81
81
|
total_usecs / 1_000_000
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
def usecs
|
85
|
-
total_usecs % 1_000_000
|
85
|
+
total_usecs % 1_000_000
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
def <=>(other)
|
89
89
|
total_usecs <=> other.send(:total_usecs)
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
def inspect(long = false)
|
93
93
|
"<Cassandra::UUID##{object_id} time: #{
|
94
94
|
Time.at(seconds).inspect
|
@@ -97,13 +97,13 @@ class Cassandra
|
|
97
97
|
} jitter: #{
|
98
98
|
@bytes.unpack('QQ')[1]
|
99
99
|
}" + (long ? ", version: #{version}, variant: #{variant}, guid: #{to_guid}>" : ">")
|
100
|
-
end
|
101
|
-
|
100
|
+
end
|
101
|
+
|
102
102
|
private
|
103
|
-
|
103
|
+
|
104
104
|
def total_usecs
|
105
105
|
elements = @bytes.unpack("NnnQ")
|
106
|
-
(elements[0] + (elements[1] << 32) + ((elements[2] & 0x0FFF) << 48) - GREGORIAN_EPOCH_OFFSET) / 10
|
106
|
+
(elements[0] + (elements[1] << 32) + ((elements[2] & 0x0FFF) << 48) - GREGORIAN_EPOCH_OFFSET) / 10
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
data/test/cassandra_test.rb
CHANGED
@@ -6,9 +6,15 @@ class CassandraTest < Test::Unit::TestCase
|
|
6
6
|
def setup
|
7
7
|
@twitter = Cassandra.new('Twitter', '127.0.0.1')
|
8
8
|
@twitter.clear_keyspace!
|
9
|
+
|
9
10
|
@blogs = Cassandra.new('Multiblog', '127.0.0.1')
|
10
11
|
@blogs.clear_keyspace!
|
11
|
-
|
12
|
+
|
13
|
+
@blogs_long = Cassandra.new('MultiblogLong', '127.0.0.1')
|
14
|
+
@blogs_long.clear_keyspace!
|
15
|
+
|
16
|
+
@uuids = (0..6).map {|i| UUID.new(Time.at(2**(24+i))) }
|
17
|
+
@longs = (0..6).map {|i| Long.new(Time.at(2**(24+i))) }
|
12
18
|
end
|
13
19
|
|
14
20
|
def test_inspect
|
@@ -19,21 +25,21 @@ class CassandraTest < Test::Unit::TestCase
|
|
19
25
|
end
|
20
26
|
|
21
27
|
def test_connection_reopens
|
22
|
-
assert_raises(
|
23
|
-
@twitter.
|
28
|
+
assert_raises(Thrift::ProtocolException) do
|
29
|
+
@twitter.send("_mutate", [], -5)
|
24
30
|
end
|
25
31
|
assert_nothing_raised do
|
26
32
|
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
27
33
|
end
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
36
|
+
def test_get_key
|
31
37
|
@twitter.insert(:Users, key, {'body' => 'v', 'user' => 'v'})
|
32
38
|
assert_equal({'body' => 'v', 'user' => 'v'}, @twitter.get(:Users, key))
|
33
39
|
assert_equal({}, @twitter.get(:Users, 'bogus'))
|
34
40
|
end
|
35
41
|
|
36
|
-
def
|
42
|
+
def test_get_key_preserving_order
|
37
43
|
# In-order hash is preserved
|
38
44
|
hash = OrderedHash['a', '', 'b', '', 'c', '', 'd', '',]
|
39
45
|
@twitter.insert(:Users, key, hash)
|
@@ -48,17 +54,38 @@ class CassandraTest < Test::Unit::TestCase
|
|
48
54
|
assert_not_equal(hash.keys, @twitter.get(:Users, key).keys)
|
49
55
|
end
|
50
56
|
|
51
|
-
def
|
52
|
-
@blogs.insert(:Blogs, key,
|
53
|
-
|
57
|
+
def test_get_first_time_uuid_column
|
58
|
+
@blogs.insert(:Blogs, key,
|
59
|
+
{@uuids[0] => 'I like this cat', @uuids[1] => 'Buttons is cuter', @uuids[2] => 'I disagree'})
|
60
|
+
|
61
|
+
assert_equal({@uuids[0] => 'I like this cat'}, @blogs.get(:Blogs, key, :count => 1))
|
62
|
+
assert_equal({@uuids[2] => 'I disagree'}, @blogs.get(:Blogs, key, :count => 1, :reversed => true))
|
54
63
|
assert_equal({}, @blogs.get(:Blogs, 'bogus'))
|
55
64
|
end
|
56
65
|
|
66
|
+
def test_get_first_long_column
|
67
|
+
@blogs_long.insert(:Blogs, key,
|
68
|
+
{@longs[0] => 'I like this cat', @longs[1] => 'Buttons is cuter', @longs[2] => 'I disagree'})
|
69
|
+
|
70
|
+
assert_equal({@longs[0] => 'I like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
|
71
|
+
assert_equal({@longs[2] => 'I disagree'}, @blogs_long.get(:Blogs, key, :count => 1, :reversed => true))
|
72
|
+
assert_equal({}, @blogs_long.get(:Blogs, 'bogus'))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_long_remove_bug
|
76
|
+
@blogs_long.insert(:Blogs, key, {@longs[0] => 'I like this cat'})
|
77
|
+
@blogs_long.remove(:Blogs, key)
|
78
|
+
assert_equal({}, @blogs_long.get(:Blogs, key, :count => 1))
|
79
|
+
|
80
|
+
@blogs_long.insert(:Blogs, key, {@longs[0] => 'I like this cat'})
|
81
|
+
assert_equal({@longs[0] => 'I like this cat'}, @blogs_long.get(:Blogs, key, :count => 1))
|
82
|
+
end
|
83
|
+
|
57
84
|
def test_get_with_count
|
58
85
|
@twitter.insert(:Statuses, key, {'1' => 'v', '2' => 'v', '3' => 'v'})
|
59
86
|
assert_equal 1, @twitter.get(:Statuses, key, :count => 1).size
|
60
87
|
assert_equal 2, @twitter.get(:Statuses, key, :count => 2).size
|
61
|
-
end
|
88
|
+
end
|
62
89
|
|
63
90
|
def test_get_value
|
64
91
|
@twitter.insert(:Statuses, key, {'body' => 'v'})
|
@@ -68,7 +95,7 @@ class CassandraTest < Test::Unit::TestCase
|
|
68
95
|
assert @twitter.exists?(:Statuses, key, 'body')
|
69
96
|
assert_nil @twitter.exists?(:Statuses, 'bogus', 'body')
|
70
97
|
end
|
71
|
-
|
98
|
+
|
72
99
|
def test_get_super_key
|
73
100
|
columns = {'user_timelines' => {@uuids[4] => '4', @uuids[5] => '5'}}
|
74
101
|
@twitter.insert(:StatusRelationships, key, columns)
|
@@ -87,25 +114,25 @@ class CassandraTest < Test::Unit::TestCase
|
|
87
114
|
end
|
88
115
|
|
89
116
|
def test_get_super_sub_keys_with_count
|
90
|
-
@twitter.insert(:StatusRelationships, key,
|
117
|
+
@twitter.insert(:StatusRelationships, key,
|
91
118
|
{'user_timelines' => {@uuids[1] => 'v1', @uuids[2] => 'v2', @uuids[3] => 'v3'}})
|
92
|
-
assert_equal({@uuids[1] => 'v1'},
|
119
|
+
assert_equal({@uuids[1] => 'v1'},
|
93
120
|
@twitter.get(:StatusRelationships, key, "user_timelines", :count => 1))
|
94
|
-
assert_equal({@uuids[3] => 'v3'},
|
121
|
+
assert_equal({@uuids[3] => 'v3'},
|
95
122
|
@twitter.get(:StatusRelationships, key, "user_timelines", :count => 1, :reversed => true))
|
96
123
|
end
|
97
124
|
|
98
|
-
def test_get_super_sub_keys_with_ranges
|
99
|
-
@twitter.insert(:StatusRelationships, key,
|
125
|
+
def test_get_super_sub_keys_with_ranges
|
126
|
+
@twitter.insert(:StatusRelationships, key,
|
100
127
|
{'user_timelines' => {
|
101
|
-
@uuids[1] => 'v1',
|
102
|
-
@uuids[2] => 'v2',
|
128
|
+
@uuids[1] => 'v1',
|
129
|
+
@uuids[2] => 'v2',
|
103
130
|
@uuids[3] => 'v3',
|
104
|
-
@uuids[4] => 'v4',
|
131
|
+
@uuids[4] => 'v4',
|
105
132
|
@uuids[5] => 'v5'}})
|
106
133
|
|
107
134
|
keys = @twitter.get(:StatusRelationships, key, "user_timelines").keys
|
108
|
-
assert_equal keys.sort, keys
|
135
|
+
assert_equal keys.sort, keys
|
109
136
|
assert_equal({@uuids[1] => 'v1'}, @twitter.get(:StatusRelationships, key, "user_timelines", :finish => @uuids[2], :count => 1))
|
110
137
|
assert_equal({@uuids[2] => 'v2'}, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :count => 1))
|
111
138
|
assert_equal 4, @twitter.get(:StatusRelationships, key, "user_timelines", :start => @uuids[2], :finish => @uuids[5]).size
|
@@ -222,15 +249,6 @@ class CassandraTest < Test::Unit::TestCase
|
|
222
249
|
@twitter.multi_get_columns(:Users, [key + '2', 'bogus', key + '1'], ['body', 'user']))
|
223
250
|
end
|
224
251
|
|
225
|
-
# Not supported
|
226
|
-
# def test_get_columns_super_sub
|
227
|
-
# @twitter.insert(:StatusRelationships, key, {
|
228
|
-
# 'user_timelines' => {@uuids[1] => 'v1'},
|
229
|
-
# 'mentions_timelines' => {@uuids[2] => 'v2'}})
|
230
|
-
# assert_equal ['v1', 'v2'],
|
231
|
-
# @twitter.get_columns(:StatusRelationships, key, 'user_timelines', ['1', key])
|
232
|
-
# end
|
233
|
-
|
234
252
|
def test_count_keys
|
235
253
|
@twitter.insert(:Statuses, key + "1", {'body' => '1'})
|
236
254
|
@twitter.insert(:Statuses, key + "2", {'body' => '2'})
|
@@ -266,7 +284,7 @@ class CassandraTest < Test::Unit::TestCase
|
|
266
284
|
@twitter.multi_count_columns(:Users, [key + '2', 'bogus', key + '1']))
|
267
285
|
end
|
268
286
|
|
269
|
-
def
|
287
|
+
def test_batch_mutate
|
270
288
|
@twitter.insert(:Users, key + '1', {'body' => 'v1', 'user' => 'v1'})
|
271
289
|
|
272
290
|
@twitter.batch do
|
data/vendor/gen-rb/cassandra.rb
CHANGED
@@ -78,17 +78,17 @@ require 'cassandra_types'
|
|
78
78
|
return
|
79
79
|
end
|
80
80
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
81
|
+
def batch_mutate(keyspace, batch_mutations, consistency_level)
|
82
|
+
send_batch_mutate(keyspace, batch_mutations, consistency_level)
|
83
|
+
recv_batch_mutate()
|
84
84
|
end
|
85
85
|
|
86
|
-
def
|
87
|
-
send_message('
|
86
|
+
def send_batch_mutate(keyspace, batch_mutations, consistency_level)
|
87
|
+
send_message('batch_mutate', Batch_mutate_args, :keyspace => keyspace, :batch_mutations => batch_mutations, :consistency_level => consistency_level)
|
88
88
|
end
|
89
89
|
|
90
|
-
def
|
91
|
-
result = receive_message(
|
90
|
+
def recv_batch_mutate()
|
91
|
+
result = receive_message(Batch_mutate_result)
|
92
92
|
raise result.ire unless result.ire.nil?
|
93
93
|
raise result.ue unless result.ue.nil?
|
94
94
|
return
|
@@ -110,22 +110,6 @@ require 'cassandra_types'
|
|
110
110
|
return
|
111
111
|
end
|
112
112
|
|
113
|
-
def batch_insert_super_column(keyspace, batch_mutation_super, consistency_level)
|
114
|
-
send_batch_insert_super_column(keyspace, batch_mutation_super, consistency_level)
|
115
|
-
recv_batch_insert_super_column()
|
116
|
-
end
|
117
|
-
|
118
|
-
def send_batch_insert_super_column(keyspace, batch_mutation_super, consistency_level)
|
119
|
-
send_message('batch_insert_super_column', Batch_insert_super_column_args, :keyspace => keyspace, :batch_mutation_super => batch_mutation_super, :consistency_level => consistency_level)
|
120
|
-
end
|
121
|
-
|
122
|
-
def recv_batch_insert_super_column()
|
123
|
-
result = receive_message(Batch_insert_super_column_result)
|
124
|
-
raise result.ire unless result.ire.nil?
|
125
|
-
raise result.ue unless result.ue.nil?
|
126
|
-
return
|
127
|
-
end
|
128
|
-
|
129
113
|
def get_key_range(keyspace, column_family, start, finish, count)
|
130
114
|
send_get_key_range(keyspace, column_family, start, finish, count)
|
131
115
|
return recv_get_key_range()
|
@@ -243,17 +227,17 @@ require 'cassandra_types'
|
|
243
227
|
write_result(result, oprot, 'insert', seqid)
|
244
228
|
end
|
245
229
|
|
246
|
-
def
|
247
|
-
args = read_args(iprot,
|
248
|
-
result =
|
230
|
+
def process_batch_mutate(seqid, iprot, oprot)
|
231
|
+
args = read_args(iprot, Batch_mutate_args)
|
232
|
+
result = Batch_mutate_result.new()
|
249
233
|
begin
|
250
|
-
@handler.
|
234
|
+
@handler.batch_mutate(args.keyspace, args.batch_mutations, args.consistency_level)
|
251
235
|
rescue CassandraThrift::InvalidRequestException => ire
|
252
236
|
result.ire = ire
|
253
237
|
rescue CassandraThrift::UnavailableException => ue
|
254
238
|
result.ue = ue
|
255
239
|
end
|
256
|
-
write_result(result, oprot, '
|
240
|
+
write_result(result, oprot, 'batch_mutate', seqid)
|
257
241
|
end
|
258
242
|
|
259
243
|
def process_remove(seqid, iprot, oprot)
|
@@ -269,19 +253,6 @@ require 'cassandra_types'
|
|
269
253
|
write_result(result, oprot, 'remove', seqid)
|
270
254
|
end
|
271
255
|
|
272
|
-
def process_batch_insert_super_column(seqid, iprot, oprot)
|
273
|
-
args = read_args(iprot, Batch_insert_super_column_args)
|
274
|
-
result = Batch_insert_super_column_result.new()
|
275
|
-
begin
|
276
|
-
@handler.batch_insert_super_column(args.keyspace, args.batch_mutation_super, args.consistency_level)
|
277
|
-
rescue CassandraThrift::InvalidRequestException => ire
|
278
|
-
result.ire = ire
|
279
|
-
rescue CassandraThrift::UnavailableException => ue
|
280
|
-
result.ue = ue
|
281
|
-
end
|
282
|
-
write_result(result, oprot, 'batch_insert_super_column', seqid)
|
283
|
-
end
|
284
|
-
|
285
256
|
def process_get_key_range(seqid, iprot, oprot)
|
286
257
|
args = read_args(iprot, Get_key_range_args)
|
287
258
|
result = Get_key_range_result.new()
|
@@ -504,16 +475,16 @@ require 'cassandra_types'
|
|
504
475
|
|
505
476
|
end
|
506
477
|
|
507
|
-
class
|
478
|
+
class Batch_mutate_args
|
508
479
|
include ::Thrift::Struct
|
509
480
|
KEYSPACE = 1
|
510
|
-
|
481
|
+
BATCH_MUTATIONS = 2
|
511
482
|
CONSISTENCY_LEVEL = 3
|
512
483
|
|
513
|
-
::Thrift::Struct.field_accessor self, :keyspace, :
|
484
|
+
::Thrift::Struct.field_accessor self, :keyspace, :batch_mutations, :consistency_level
|
514
485
|
FIELDS = {
|
515
486
|
KEYSPACE => {:type => ::Thrift::Types::STRING, :name => 'keyspace'},
|
516
|
-
|
487
|
+
BATCH_MUTATIONS => {:type => ::Thrift::Types::LIST, :name => 'batch_mutations', :element => {:type => ::Thrift::Types::STRUCT, :class => CassandraThrift::BatchMutation}},
|
517
488
|
CONSISTENCY_LEVEL => {:type => ::Thrift::Types::I32, :name => 'consistency_level', :default => 0, :enum_class => CassandraThrift::ConsistencyLevel}
|
518
489
|
}
|
519
490
|
|
@@ -527,7 +498,7 @@ require 'cassandra_types'
|
|
527
498
|
|
528
499
|
end
|
529
500
|
|
530
|
-
class
|
501
|
+
class Batch_mutate_result
|
531
502
|
include ::Thrift::Struct
|
532
503
|
IRE = 1
|
533
504
|
UE = 2
|
@@ -590,47 +561,6 @@ require 'cassandra_types'
|
|
590
561
|
|
591
562
|
end
|
592
563
|
|
593
|
-
class Batch_insert_super_column_args
|
594
|
-
include ::Thrift::Struct
|
595
|
-
KEYSPACE = 1
|
596
|
-
BATCH_MUTATION_SUPER = 2
|
597
|
-
CONSISTENCY_LEVEL = 3
|
598
|
-
|
599
|
-
::Thrift::Struct.field_accessor self, :keyspace, :batch_mutation_super, :consistency_level
|
600
|
-
FIELDS = {
|
601
|
-
KEYSPACE => {:type => ::Thrift::Types::STRING, :name => 'keyspace'},
|
602
|
-
BATCH_MUTATION_SUPER => {:type => ::Thrift::Types::STRUCT, :name => 'batch_mutation_super', :class => CassandraThrift::BatchMutationSuper},
|
603
|
-
CONSISTENCY_LEVEL => {:type => ::Thrift::Types::I32, :name => 'consistency_level', :default => 0, :enum_class => CassandraThrift::ConsistencyLevel}
|
604
|
-
}
|
605
|
-
|
606
|
-
def struct_fields; FIELDS; end
|
607
|
-
|
608
|
-
def validate
|
609
|
-
unless @consistency_level.nil? || CassandraThrift::ConsistencyLevel::VALID_VALUES.include?(@consistency_level)
|
610
|
-
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field consistency_level!')
|
611
|
-
end
|
612
|
-
end
|
613
|
-
|
614
|
-
end
|
615
|
-
|
616
|
-
class Batch_insert_super_column_result
|
617
|
-
include ::Thrift::Struct
|
618
|
-
IRE = 1
|
619
|
-
UE = 2
|
620
|
-
|
621
|
-
::Thrift::Struct.field_accessor self, :ire, :ue
|
622
|
-
FIELDS = {
|
623
|
-
IRE => {:type => ::Thrift::Types::STRUCT, :name => 'ire', :class => CassandraThrift::InvalidRequestException},
|
624
|
-
UE => {:type => ::Thrift::Types::STRUCT, :name => 'ue', :class => CassandraThrift::UnavailableException}
|
625
|
-
}
|
626
|
-
|
627
|
-
def struct_fields; FIELDS; end
|
628
|
-
|
629
|
-
def validate
|
630
|
-
end
|
631
|
-
|
632
|
-
end
|
633
|
-
|
634
564
|
class Get_key_range_args
|
635
565
|
include ::Thrift::Struct
|
636
566
|
KEYSPACE = 1
|
@@ -35,24 +35,6 @@ module CassandraThrift
|
|
35
35
|
|
36
36
|
end
|
37
37
|
|
38
|
-
class BatchMutation
|
39
|
-
include ::Thrift::Struct
|
40
|
-
KEY = 1
|
41
|
-
CFMAP = 2
|
42
|
-
|
43
|
-
::Thrift::Struct.field_accessor self, :key, :cfmap
|
44
|
-
FIELDS = {
|
45
|
-
KEY => {:type => ::Thrift::Types::STRING, :name => 'key'},
|
46
|
-
CFMAP => {:type => ::Thrift::Types::MAP, :name => 'cfmap', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::LIST, :element => {:type => ::Thrift::Types::STRUCT, :class => CassandraThrift::Column}}}
|
47
|
-
}
|
48
|
-
|
49
|
-
def struct_fields; FIELDS; end
|
50
|
-
|
51
|
-
def validate
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
38
|
class SuperColumn
|
57
39
|
include ::Thrift::Struct
|
58
40
|
NAME = 1
|
@@ -71,15 +53,15 @@ module CassandraThrift
|
|
71
53
|
|
72
54
|
end
|
73
55
|
|
74
|
-
class
|
56
|
+
class ColumnOrSuperColumn
|
75
57
|
include ::Thrift::Struct
|
76
|
-
|
77
|
-
|
58
|
+
COLUMN = 1
|
59
|
+
SUPER_COLUMN = 2
|
78
60
|
|
79
|
-
::Thrift::Struct.field_accessor self, :
|
61
|
+
::Thrift::Struct.field_accessor self, :column, :super_column
|
80
62
|
FIELDS = {
|
81
|
-
|
82
|
-
|
63
|
+
COLUMN => {:type => ::Thrift::Types::STRUCT, :name => 'column', :class => CassandraThrift::Column, :optional => true},
|
64
|
+
SUPER_COLUMN => {:type => ::Thrift::Types::STRUCT, :name => 'super_column', :class => CassandraThrift::SuperColumn, :optional => true}
|
83
65
|
}
|
84
66
|
|
85
67
|
def struct_fields; FIELDS; end
|
@@ -163,12 +145,14 @@ module CassandraThrift
|
|
163
145
|
COLUMN_FAMILY = 3
|
164
146
|
SUPER_COLUMN = 4
|
165
147
|
COLUMN = 5
|
148
|
+
TIMESTAMP = 6
|
166
149
|
|
167
|
-
::Thrift::Struct.field_accessor self, :column_family, :super_column, :column
|
150
|
+
::Thrift::Struct.field_accessor self, :column_family, :super_column, :column, :timestamp
|
168
151
|
FIELDS = {
|
169
152
|
COLUMN_FAMILY => {:type => ::Thrift::Types::STRING, :name => 'column_family'},
|
170
153
|
SUPER_COLUMN => {:type => ::Thrift::Types::STRING, :name => 'super_column', :optional => true},
|
171
|
-
COLUMN => {:type => ::Thrift::Types::STRING, :name => 'column', :optional => true}
|
154
|
+
COLUMN => {:type => ::Thrift::Types::STRING, :name => 'column', :optional => true},
|
155
|
+
TIMESTAMP => {:type => ::Thrift::Types::I64, :name => 'timestamp', :optional => true}
|
172
156
|
}
|
173
157
|
|
174
158
|
def struct_fields; FIELDS; end
|
@@ -218,15 +202,17 @@ module CassandraThrift
|
|
218
202
|
|
219
203
|
end
|
220
204
|
|
221
|
-
class
|
205
|
+
class BatchMutation
|
222
206
|
include ::Thrift::Struct
|
223
|
-
|
224
|
-
|
207
|
+
KEY = 1
|
208
|
+
CFMAP = 2
|
209
|
+
COLUMN_PATHS = 3
|
225
210
|
|
226
|
-
::Thrift::Struct.field_accessor self, :
|
211
|
+
::Thrift::Struct.field_accessor self, :key, :cfmap, :column_paths
|
227
212
|
FIELDS = {
|
228
|
-
|
229
|
-
|
213
|
+
KEY => {:type => ::Thrift::Types::STRING, :name => 'key'},
|
214
|
+
CFMAP => {:type => ::Thrift::Types::MAP, :name => 'cfmap', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::LIST, :element => {:type => ::Thrift::Types::STRUCT, :class => CassandraThrift::ColumnOrSuperColumn}}},
|
215
|
+
COLUMN_PATHS => {:type => ::Thrift::Types::LIST, :name => 'column_paths', :element => {:type => ::Thrift::Types::STRUCT, :class => CassandraThrift::ColumnPath}}
|
230
216
|
}
|
231
217
|
|
232
218
|
def struct_fields; FIELDS; end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cassandra
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Weaver
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
yZ0=
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2009-08-
|
33
|
+
date: 2009-08-27 00:00:00 -07:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
@@ -67,6 +67,7 @@ extra_rdoc_files:
|
|
67
67
|
- lib/cassandra/columns.rb
|
68
68
|
- lib/cassandra/comparable.rb
|
69
69
|
- lib/cassandra/constants.rb
|
70
|
+
- lib/cassandra/debug.rb
|
70
71
|
- lib/cassandra/long.rb
|
71
72
|
- lib/cassandra/ordered_hash.rb
|
72
73
|
- lib/cassandra/protocol.rb
|
@@ -87,6 +88,7 @@ files:
|
|
87
88
|
- lib/cassandra/columns.rb
|
88
89
|
- lib/cassandra/comparable.rb
|
89
90
|
- lib/cassandra/constants.rb
|
91
|
+
- lib/cassandra/debug.rb
|
90
92
|
- lib/cassandra/long.rb
|
91
93
|
- lib/cassandra/ordered_hash.rb
|
92
94
|
- lib/cassandra/protocol.rb
|
metadata.gz.sig
CHANGED
Binary file
|