cassandra 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +2 -0
- data/Manifest +2 -2
- data/README.mkd +72 -0
- data/Rakefile +2 -3
- data/cassandra.gemspec +9 -6
- data/conf/storage-conf.xml +1 -0
- data/lib/cassandra.rb +1 -2
- data/lib/cassandra/cassandra.rb +1 -2
- data/lib/cassandra/columns.rb +1 -1
- data/lib/cassandra/ordered_hash.rb +39 -33
- data/test/cassandra_test.rb +5 -1
- data/test/comparable_types_test.rb +16 -26
- data/test/ordered_hash_test.rb +201 -0
- data/test/test_helper.rb +1 -1
- metadata +17 -7
- metadata.gz.sig +0 -0
- data/README +0 -64
- data/lib/cassandra/uuid.rb +0 -115
data.tar.gz.sig
CHANGED
Binary file
|
data/CHANGELOG
CHANGED
data/Manifest
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
LICENSE
|
3
3
|
Manifest
|
4
|
-
README
|
4
|
+
README.mkd
|
5
5
|
Rakefile
|
6
6
|
bin/cassandra_helper
|
7
7
|
conf/cassandra.in.sh
|
@@ -18,9 +18,9 @@ lib/cassandra/long.rb
|
|
18
18
|
lib/cassandra/ordered_hash.rb
|
19
19
|
lib/cassandra/protocol.rb
|
20
20
|
lib/cassandra/time.rb
|
21
|
-
lib/cassandra/uuid.rb
|
22
21
|
test/cassandra_test.rb
|
23
22
|
test/comparable_types_test.rb
|
23
|
+
test/ordered_hash_test.rb
|
24
24
|
test/test_helper.rb
|
25
25
|
vendor/gen-rb/cassandra.rb
|
26
26
|
vendor/gen-rb/cassandra_constants.rb
|
data/README.mkd
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# cassandra
|
2
|
+
|
3
|
+
A Ruby client for the Cassandra distributed database.
|
4
|
+
|
5
|
+
## License
|
6
|
+
|
7
|
+
Copyright 2009 Twitter, Inc. See included LICENSE file. Portions copyright 2004-2009 David Heinemeier Hansson, and used with permission.
|
8
|
+
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* clean encapsulation of the Thrift API
|
12
|
+
* compatible UUID and Long classes, for GUID generation
|
13
|
+
* Ruby 1.9 compatibility
|
14
|
+
|
15
|
+
The Github source repository is [here](http://github.com/fauna/cassandra/). Patches and contributions are very welcome.
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
You need Ruby 1.8 or 1.9. If you have those, just run:
|
20
|
+
|
21
|
+
sudo gem install cassandra
|
22
|
+
|
23
|
+
Cassandra itself is a rapidly moving target. In order to get a working server, use the `bin/cassandra_helper` script:
|
24
|
+
|
25
|
+
cassandra_helper cassandra
|
26
|
+
|
27
|
+
A server will be installed in `$HOME/cassandra/server`, and started in debug mode.
|
28
|
+
|
29
|
+
WARNING: Don't use the test folder for your data, as it will get overwritten when you update the gem.
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
Now, start IRb and require the library:
|
34
|
+
|
35
|
+
require 'cassandra'
|
36
|
+
|
37
|
+
Connect to a server and keyspace:
|
38
|
+
|
39
|
+
client = Cassandra.new('Twitter', '127.0.0.1:9160')
|
40
|
+
|
41
|
+
Insert into a column family. You can insert a `Cassandra::OrderedHash`, or a regular Hash, if order doesn't matter:
|
42
|
+
|
43
|
+
client.insert(:Users, "5", {'screen_name' => "buttonscat"})
|
44
|
+
|
45
|
+
Insert into a super column family:
|
46
|
+
|
47
|
+
client.insert(:UserRelationships, "5", {"user_timeline" => {UUID.new => "1"}})
|
48
|
+
|
49
|
+
Query a super column:
|
50
|
+
|
51
|
+
timeline = client.get(:UserRelationships, "5", "user_timeline")
|
52
|
+
|
53
|
+
The returned result will always be a Cassandra::OrderedHash.
|
54
|
+
|
55
|
+
See Cassandra for more methods.
|
56
|
+
|
57
|
+
## Configuration
|
58
|
+
|
59
|
+
By default, cassandra is setup to listen on localhost. If you want to move your clients to another host, you're going to need to change which interface it binds to in the storage-conf.xml. You should also change the seed address.
|
60
|
+
|
61
|
+
## Node Auto-Discovery
|
62
|
+
|
63
|
+
The list of hosts you pass to the client is only used to auto-discover all the nodes in your cluster. You don't need to give the client a list of all of your nodes.
|
64
|
+
|
65
|
+
## Further reading
|
66
|
+
|
67
|
+
* [Up and Running With Cassandra](http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra)
|
68
|
+
|
69
|
+
## Reporting problems
|
70
|
+
|
71
|
+
The Github issue tracker is [here](http://github.com/fauna/cassandra/issues). If you have problems with this library or Cassandra itself, please use the [cassandra-user mailing list](http://mail-archives.apache.org/mod_mbox/incubator-cassandra-user/).
|
72
|
+
|
data/Rakefile
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
unless ENV['FROM_BIN_CASSANDRA_HELPER']
|
3
2
|
require 'rubygems'
|
4
3
|
require 'echoe'
|
@@ -8,7 +7,7 @@ unless ENV['FROM_BIN_CASSANDRA_HELPER']
|
|
8
7
|
p.project = "fauna"
|
9
8
|
p.summary = "A Ruby client for the Cassandra distributed database."
|
10
9
|
p.rubygems_version = ">= 0.8"
|
11
|
-
p.dependencies = ['thrift_client', 'json', 'rake']
|
10
|
+
p.dependencies = ['thrift_client', 'json', 'rake', ['simple_uuid', '>= 0.0.2']]
|
12
11
|
p.ignore_pattern = /^(data|vendor\/cassandra|cassandra|vendor\/thrift)/
|
13
12
|
p.rdoc_pattern = /^(lib|bin|tasks|ext)|^README|^CHANGELOG|^TODO|^LICENSE|^COPYING$/
|
14
13
|
p.url = "http://blog.evanweaver.com/files/doc/fauna/cassandra/"
|
@@ -16,7 +15,7 @@ unless ENV['FROM_BIN_CASSANDRA_HELPER']
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
REVISION = "
|
18
|
+
REVISION = "450cfa10f0b82d9d5af9ffda182a5097afee402b"
|
20
19
|
|
21
20
|
PATCHES = []
|
22
21
|
|
data/cassandra.gemspec
CHANGED
@@ -2,26 +2,26 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{cassandra}
|
5
|
-
s.version = "0.7.
|
5
|
+
s.version = "0.7.2"
|
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/ryan/.gemkeys/gem-public_cert.pem"]
|
10
|
-
s.date = %q{2010-01-
|
10
|
+
s.date = %q{2010-01-25}
|
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 = ["CHANGELOG", "LICENSE", "README", "bin/cassandra_helper", "lib/cassandra.rb", "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/time.rb"
|
16
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README", "Rakefile", "bin/cassandra_helper", "conf/cassandra.in.sh", "conf/log4j.properties", "conf/storage-conf.xml", "lib/cassandra.rb", "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/time.rb", "
|
15
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.mkd", "bin/cassandra_helper", "lib/cassandra.rb", "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/time.rb"]
|
16
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.mkd", "Rakefile", "bin/cassandra_helper", "conf/cassandra.in.sh", "conf/log4j.properties", "conf/storage-conf.xml", "lib/cassandra.rb", "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/time.rb", "test/cassandra_test.rb", "test/comparable_types_test.rb", "test/ordered_hash_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
|
-
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cassandra", "--main", "README"]
|
18
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cassandra", "--main", "README.mkd"]
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
s.rubyforge_project = %q{fauna}
|
21
21
|
s.rubygems_version = %q{1.3.5}
|
22
22
|
s.signing_key = %q{/Users/ryan/.gemkeys/gem-private_key.pem}
|
23
23
|
s.summary = %q{A Ruby client for the Cassandra distributed database.}
|
24
|
-
s.test_files = ["test/cassandra_test.rb", "test/comparable_types_test.rb", "test/test_helper.rb"]
|
24
|
+
s.test_files = ["test/cassandra_test.rb", "test/comparable_types_test.rb", "test/ordered_hash_test.rb", "test/test_helper.rb"]
|
25
25
|
|
26
26
|
if s.respond_to? :specification_version then
|
27
27
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -31,14 +31,17 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_runtime_dependency(%q<thrift_client>, [">= 0"])
|
32
32
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
33
33
|
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
34
|
+
s.add_runtime_dependency(%q<simple_uuid>, [">= 0.0.2"])
|
34
35
|
else
|
35
36
|
s.add_dependency(%q<thrift_client>, [">= 0"])
|
36
37
|
s.add_dependency(%q<json>, [">= 0"])
|
37
38
|
s.add_dependency(%q<rake>, [">= 0"])
|
39
|
+
s.add_dependency(%q<simple_uuid>, [">= 0.0.2"])
|
38
40
|
end
|
39
41
|
else
|
40
42
|
s.add_dependency(%q<thrift_client>, [">= 0"])
|
41
43
|
s.add_dependency(%q<json>, [">= 0"])
|
42
44
|
s.add_dependency(%q<rake>, [">= 0"])
|
45
|
+
s.add_dependency(%q<simple_uuid>, [">= 0.0.2"])
|
43
46
|
end
|
44
47
|
end
|
data/conf/storage-conf.xml
CHANGED
@@ -38,6 +38,7 @@
|
|
38
38
|
<ColumnFamily CompareWith="UTF8Type" Name="Statuses" />
|
39
39
|
<ColumnFamily CompareWith="UTF8Type" Name="StatusAudits" />
|
40
40
|
<ColumnFamily CompareWith="UTF8Type" CompareSubcolumnsWith="TimeUUIDType" ColumnType="Super" Name="StatusRelationships" />
|
41
|
+
<ColumnFamily CompareWith="UTF8Type" ColumnType="Super" Name="Index" />
|
41
42
|
</Keyspace>
|
42
43
|
|
43
44
|
<Keyspace Name="Multiblog">
|
data/lib/cassandra.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'thrift_client'
|
3
3
|
require 'json'
|
4
|
-
|
4
|
+
require 'simple_uuid'
|
5
5
|
here = File.expand_path(File.dirname(__FILE__))
|
6
6
|
|
7
7
|
$LOAD_PATH << "#{here}/../vendor/gen-rb"
|
@@ -11,7 +11,6 @@ $LOAD_PATH << "#{here}"
|
|
11
11
|
require 'cassandra/array'
|
12
12
|
require 'cassandra/time'
|
13
13
|
require 'cassandra/comparable'
|
14
|
-
require 'cassandra/uuid'
|
15
14
|
require 'cassandra/long'
|
16
15
|
require 'cassandra/ordered_hash'
|
17
16
|
require 'cassandra/columns'
|
data/lib/cassandra/cassandra.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
=begin rdoc
|
3
3
|
Create a new Cassandra client instance. Accepts a keyspace name, and optional host and port.
|
4
4
|
|
5
|
-
client = Cassandra.new('twitter', '127.0.0.1'
|
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
|
|
@@ -68,7 +68,6 @@ class Cassandra
|
|
68
68
|
@servers = Array(servers)
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
71
|
def client
|
73
72
|
return @client if defined?(@client)
|
74
73
|
client!
|
data/lib/cassandra/columns.rb
CHANGED
@@ -83,7 +83,7 @@ class Cassandra
|
|
83
83
|
:columns => sub_columns.collect { |sub_column_name, sub_column_value|
|
84
84
|
CassandraThrift::Column.new(
|
85
85
|
:name => sub_column_name_class(column_family).new(sub_column_name).to_s,
|
86
|
-
:value => sub_column_value,
|
86
|
+
:value => sub_column_value.to_s,
|
87
87
|
:timestamp => timestamp
|
88
88
|
)
|
89
89
|
}
|
@@ -1,44 +1,39 @@
|
|
1
|
-
|
1
|
+
# OrderedHash is namespaced to prevent conflicts with other implementations
|
2
2
|
class Cassandra
|
3
3
|
# Hash is ordered in Ruby 1.9!
|
4
4
|
if RUBY_VERSION >= '1.9'
|
5
5
|
OrderedHash = ::Hash
|
6
|
-
else
|
7
|
-
|
8
|
-
#
|
9
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
10
|
-
# a copy of this software and associated documentation files (the
|
11
|
-
# "Software"), to deal in the Software without restriction, including
|
12
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
13
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
14
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
15
|
-
# the following conditions:
|
16
|
-
#
|
17
|
-
# The above copyright notice and this permission notice shall be
|
18
|
-
# included in all copies or substantial portions of the Software.
|
19
|
-
#
|
20
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
24
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
25
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
-
|
28
|
-
class OrderedHash < Hash #:nodoc: all
|
29
|
-
require 'enumerator'
|
30
|
-
|
31
|
-
def self.[](*array)
|
32
|
-
hash = new
|
33
|
-
array.each_slice(2) { |key, value| hash[key] = value }
|
34
|
-
hash
|
35
|
-
end
|
36
|
-
|
6
|
+
else
|
7
|
+
class OrderedHash < Hash #:nodoc:
|
37
8
|
def initialize(*args, &block)
|
38
9
|
super
|
39
10
|
@keys = []
|
40
11
|
end
|
41
12
|
|
13
|
+
def self.[](*args)
|
14
|
+
ordered_hash = new
|
15
|
+
|
16
|
+
if (args.length == 1 && args.first.is_a?(Array))
|
17
|
+
args.first.each do |key_value_pair|
|
18
|
+
next unless (key_value_pair.is_a?(Array))
|
19
|
+
ordered_hash[key_value_pair[0]] = key_value_pair[1]
|
20
|
+
end
|
21
|
+
|
22
|
+
return ordered_hash
|
23
|
+
end
|
24
|
+
|
25
|
+
unless (args.size % 2 == 0)
|
26
|
+
raise ArgumentError.new("odd number of arguments for Hash")
|
27
|
+
end
|
28
|
+
|
29
|
+
args.each_with_index do |val, ind|
|
30
|
+
next if (ind % 2 != 0)
|
31
|
+
ordered_hash[val] = args[ind + 1]
|
32
|
+
end
|
33
|
+
|
34
|
+
ordered_hash
|
35
|
+
end
|
36
|
+
|
42
37
|
def initialize_copy(other)
|
43
38
|
super
|
44
39
|
# make a deep copy of keys
|
@@ -86,6 +81,10 @@ class Cassandra
|
|
86
81
|
self
|
87
82
|
end
|
88
83
|
|
84
|
+
def to_a
|
85
|
+
@keys.map { |key| [ key, self[key] ] }
|
86
|
+
end
|
87
|
+
|
89
88
|
def each_key
|
90
89
|
@keys.each { |key| yield key }
|
91
90
|
end
|
@@ -121,6 +120,13 @@ class Cassandra
|
|
121
120
|
dup.merge!(other_hash)
|
122
121
|
end
|
123
122
|
|
123
|
+
# When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
|
124
|
+
def replace(other)
|
125
|
+
super
|
126
|
+
@keys = other.keys
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
124
130
|
def inspect
|
125
131
|
"#<OrderedHash #{super}>"
|
126
132
|
end
|
@@ -132,4 +138,4 @@ class Cassandra
|
|
132
138
|
end
|
133
139
|
end
|
134
140
|
end
|
135
|
-
end
|
141
|
+
end
|
data/test/cassandra_test.rb
CHANGED
@@ -4,7 +4,7 @@ class CassandraTest < Test::Unit::TestCase
|
|
4
4
|
include Cassandra::Constants
|
5
5
|
|
6
6
|
def setup
|
7
|
-
@twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2)
|
7
|
+
@twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :exception_classes => [])
|
8
8
|
@twitter.clear_keyspace!
|
9
9
|
|
10
10
|
@blogs = Cassandra.new('Multiblog')
|
@@ -322,6 +322,10 @@ class CassandraTest < Test::Unit::TestCase
|
|
322
322
|
end
|
323
323
|
end
|
324
324
|
|
325
|
+
def test_nil_sub_column_value
|
326
|
+
@twitter.insert(:Index, 'asdf', {"thing" => {'jkl' => nil} })
|
327
|
+
end
|
328
|
+
|
325
329
|
private
|
326
330
|
|
327
331
|
def key
|
@@ -8,44 +8,34 @@ class ComparableTypesTest < Test::Unit::TestCase
|
|
8
8
|
10.times { ary << Long.new }
|
9
9
|
assert_equal ary.sort, ary
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def test_long_equality
|
13
13
|
long = Long.new
|
14
|
-
assert_equal long, Long.new(long)
|
15
|
-
assert_equal long, Long.new(long.to_s)
|
16
|
-
assert_equal long, Long.new(long.to_i)
|
17
|
-
assert_equal long, Long.new(long.to_guid)
|
14
|
+
assert_equal long, Long.new(long)
|
15
|
+
assert_equal long, Long.new(long.to_s)
|
16
|
+
assert_equal long, Long.new(long.to_i)
|
17
|
+
assert_equal long, Long.new(long.to_guid)
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def test_long_error
|
21
21
|
assert_raises(Cassandra::Comparable::TypeError) do
|
22
22
|
Long.new("bogus")
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
5.times { ary << UUID.new(Time.at(rand(2**31))) }
|
29
|
-
assert_equal ary.map { |_| _.seconds }.sort, ary.sort.map { |_| _.seconds }
|
30
|
-
assert_not_equal ary.sort, ary.sort_by {|_| _.to_guid }
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_uuid_equality
|
34
|
-
uuid = UUID.new
|
35
|
-
assert_equal uuid, UUID.new(uuid)
|
36
|
-
assert_equal uuid, UUID.new(uuid.to_s)
|
37
|
-
assert_equal uuid, UUID.new(uuid.to_i)
|
38
|
-
assert_equal uuid, UUID.new(uuid.to_guid)
|
26
|
+
def test_types_behave_well
|
27
|
+
assert !(Long.new() == false)
|
39
28
|
end
|
40
|
-
|
41
|
-
def
|
29
|
+
|
30
|
+
def test_casting_unknown_class
|
42
31
|
assert_raises(Cassandra::Comparable::TypeError) do
|
43
|
-
|
32
|
+
Cassandra::Long.new({})
|
44
33
|
end
|
45
34
|
end
|
46
|
-
|
47
|
-
def
|
48
|
-
|
49
|
-
|
35
|
+
|
36
|
+
def test_long_inspect
|
37
|
+
obj = Long.new("\000\000\000\000\000\000\000\000")
|
38
|
+
assert_equal "<Cassandra::Long##{obj.object_id} time: Wed Dec 31 16:00:00 -0800 1969, usecs: 0, jitter: 0, guid: 00000000-0000-0000>", obj.inspect
|
50
39
|
end
|
40
|
+
|
51
41
|
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
|
3
|
+
class OrderedHashTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@keys = %w( blue green red pink orange )
|
6
|
+
@values = %w( 000099 009900 aa0000 cc0066 cc6633 )
|
7
|
+
@hash = Hash.new
|
8
|
+
@ordered_hash = Cassandra::OrderedHash.new
|
9
|
+
|
10
|
+
@keys.each_with_index do |key, index|
|
11
|
+
@hash[key] = @values[index]
|
12
|
+
@ordered_hash[key] = @values[index]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_order
|
17
|
+
assert_equal @keys, @ordered_hash.keys
|
18
|
+
assert_equal @values, @ordered_hash.values
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_access
|
22
|
+
assert @hash.all? { |k, v| @ordered_hash[k] == v }
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_assignment
|
26
|
+
key, value = 'purple', '5422a8'
|
27
|
+
|
28
|
+
@ordered_hash[key] = value
|
29
|
+
assert_equal @keys.length + 1, @ordered_hash.length
|
30
|
+
assert_equal key, @ordered_hash.keys.last
|
31
|
+
assert_equal value, @ordered_hash.values.last
|
32
|
+
assert_equal value, @ordered_hash[key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_delete
|
36
|
+
key, value = 'white', 'ffffff'
|
37
|
+
bad_key = 'black'
|
38
|
+
|
39
|
+
@ordered_hash[key] = value
|
40
|
+
assert_equal @keys.length + 1, @ordered_hash.length
|
41
|
+
assert_equal @ordered_hash.keys.length, @ordered_hash.length
|
42
|
+
|
43
|
+
assert_equal value, @ordered_hash.delete(key)
|
44
|
+
assert_equal @keys.length, @ordered_hash.length
|
45
|
+
assert_equal @ordered_hash.keys.length, @ordered_hash.length
|
46
|
+
|
47
|
+
assert_nil @ordered_hash.delete(bad_key)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_to_hash
|
51
|
+
assert_same @ordered_hash, @ordered_hash.to_hash
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_to_a
|
55
|
+
assert_equal @keys.zip(@values), @ordered_hash.to_a
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_has_key
|
59
|
+
assert_equal true, @ordered_hash.has_key?('blue')
|
60
|
+
assert_equal true, @ordered_hash.key?('blue')
|
61
|
+
assert_equal true, @ordered_hash.include?('blue')
|
62
|
+
assert_equal true, @ordered_hash.member?('blue')
|
63
|
+
|
64
|
+
assert_equal false, @ordered_hash.has_key?('indigo')
|
65
|
+
assert_equal false, @ordered_hash.key?('indigo')
|
66
|
+
assert_equal false, @ordered_hash.include?('indigo')
|
67
|
+
assert_equal false, @ordered_hash.member?('indigo')
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_has_value
|
71
|
+
assert_equal true, @ordered_hash.has_value?('000099')
|
72
|
+
assert_equal true, @ordered_hash.value?('000099')
|
73
|
+
assert_equal false, @ordered_hash.has_value?('ABCABC')
|
74
|
+
assert_equal false, @ordered_hash.value?('ABCABC')
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_each_key
|
78
|
+
keys = []
|
79
|
+
@ordered_hash.each_key { |k| keys << k }
|
80
|
+
assert_equal @keys, keys
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_each_value
|
84
|
+
values = []
|
85
|
+
@ordered_hash.each_value { |v| values << v }
|
86
|
+
assert_equal @values, values
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_each
|
90
|
+
values = []
|
91
|
+
@ordered_hash.each {|key, value| values << value}
|
92
|
+
assert_equal @values, values
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_each_with_index
|
96
|
+
@ordered_hash.each_with_index { |pair, index| assert_equal [@keys[index], @values[index]], pair}
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_each_pair
|
100
|
+
values = []
|
101
|
+
keys = []
|
102
|
+
@ordered_hash.each_pair do |key, value|
|
103
|
+
keys << key
|
104
|
+
values << value
|
105
|
+
end
|
106
|
+
assert_equal @values, values
|
107
|
+
assert_equal @keys, keys
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_delete_if
|
111
|
+
copy = @ordered_hash.dup
|
112
|
+
copy.delete('pink')
|
113
|
+
assert_equal copy, @ordered_hash.delete_if { |k, _| k == 'pink' }
|
114
|
+
assert !@ordered_hash.keys.include?('pink')
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_reject!
|
118
|
+
(copy = @ordered_hash.dup).delete('pink')
|
119
|
+
@ordered_hash.reject! { |k, _| k == 'pink' }
|
120
|
+
assert_equal copy, @ordered_hash
|
121
|
+
assert !@ordered_hash.keys.include?('pink')
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_reject
|
125
|
+
copy = @ordered_hash.dup
|
126
|
+
new_ordered_hash = @ordered_hash.reject { |k, _| k == 'pink' }
|
127
|
+
assert_equal copy, @ordered_hash
|
128
|
+
assert !new_ordered_hash.keys.include?('pink')
|
129
|
+
assert @ordered_hash.keys.include?('pink')
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_clear
|
133
|
+
@ordered_hash.clear
|
134
|
+
assert_equal [], @ordered_hash.keys
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_merge
|
138
|
+
other_hash = Cassandra::OrderedHash.new
|
139
|
+
other_hash['purple'] = '800080'
|
140
|
+
other_hash['violet'] = 'ee82ee'
|
141
|
+
merged = @ordered_hash.merge other_hash
|
142
|
+
assert_equal merged.length, @ordered_hash.length + other_hash.length
|
143
|
+
assert_equal @keys + ['purple', 'violet'], merged.keys
|
144
|
+
|
145
|
+
@ordered_hash.merge! other_hash
|
146
|
+
assert_equal @ordered_hash, merged
|
147
|
+
assert_equal @ordered_hash.keys, merged.keys
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_shift
|
151
|
+
pair = @ordered_hash.shift
|
152
|
+
assert_equal [@keys.first, @values.first], pair
|
153
|
+
assert !@ordered_hash.keys.include?(pair.first)
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_keys
|
157
|
+
original = @ordered_hash.keys.dup
|
158
|
+
@ordered_hash.keys.pop
|
159
|
+
assert_equal original, @ordered_hash.keys
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_inspect
|
163
|
+
assert @ordered_hash.inspect.include?(@hash.inspect)
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_alternate_initialization_with_splat
|
167
|
+
alternate = Cassandra::OrderedHash[1,2,3,4]
|
168
|
+
assert_kind_of Cassandra::OrderedHash, alternate
|
169
|
+
assert_equal [1, 3], alternate.keys
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_alternate_initialization_with_array
|
173
|
+
alternate = Cassandra::OrderedHash[ [
|
174
|
+
[1, 2],
|
175
|
+
[3, 4],
|
176
|
+
"bad key value pair",
|
177
|
+
[ 'missing value' ]
|
178
|
+
]]
|
179
|
+
|
180
|
+
assert_kind_of Cassandra::OrderedHash, alternate
|
181
|
+
assert_equal [1, 3, 'missing value'], alternate.keys
|
182
|
+
assert_equal [2, 4, nil ], alternate.values
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_alternate_initialization_raises_exception_on_odd_length_args
|
186
|
+
begin
|
187
|
+
alternate = Cassandra::OrderedHash[1,2,3,4,5]
|
188
|
+
flunk "Hash::[] should have raised an exception on initialization " +
|
189
|
+
"with an odd number of parameters"
|
190
|
+
rescue
|
191
|
+
assert_equal "odd number of arguments for Hash", $!.message
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_replace_updates_keys
|
196
|
+
@other_ordered_hash = Cassandra::OrderedHash[:black, '000000', :white, '000000']
|
197
|
+
original = @ordered_hash.replace(@other_ordered_hash)
|
198
|
+
assert_same original, @ordered_hash
|
199
|
+
assert_equal @other_ordered_hash.keys, @ordered_hash.keys
|
200
|
+
end
|
201
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require "#{File.expand_path(File.dirname(__FILE__))}/../lib/cassandra"
|
|
4
4
|
begin; require 'ruby-debug'; rescue LoadError; end
|
5
5
|
|
6
6
|
begin
|
7
|
-
@test_client = Cassandra.new('Twitter')
|
7
|
+
@test_client = Cassandra.new('Twitter', 'localhost:9160', {:exception_classes => []})
|
8
8
|
rescue Thrift::TransportException => e
|
9
9
|
#FIXME Make server automatically start if not running
|
10
10
|
if e.message =~ /Could not connect/
|
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.7.
|
4
|
+
version: 0.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Weaver
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
zyKMYVRO0z/58g==
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2010-01-
|
33
|
+
date: 2010-01-25 00:00:00 -08:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
@@ -63,6 +63,16 @@ dependencies:
|
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: "0"
|
65
65
|
version:
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: simple_uuid
|
68
|
+
type: :runtime
|
69
|
+
version_requirement:
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 0.0.2
|
75
|
+
version:
|
66
76
|
description: A Ruby client for the Cassandra distributed database.
|
67
77
|
email: ""
|
68
78
|
executables:
|
@@ -72,7 +82,7 @@ extensions: []
|
|
72
82
|
extra_rdoc_files:
|
73
83
|
- CHANGELOG
|
74
84
|
- LICENSE
|
75
|
-
- README
|
85
|
+
- README.mkd
|
76
86
|
- bin/cassandra_helper
|
77
87
|
- lib/cassandra.rb
|
78
88
|
- lib/cassandra/array.rb
|
@@ -85,12 +95,11 @@ extra_rdoc_files:
|
|
85
95
|
- lib/cassandra/ordered_hash.rb
|
86
96
|
- lib/cassandra/protocol.rb
|
87
97
|
- lib/cassandra/time.rb
|
88
|
-
- lib/cassandra/uuid.rb
|
89
98
|
files:
|
90
99
|
- CHANGELOG
|
91
100
|
- LICENSE
|
92
101
|
- Manifest
|
93
|
-
- README
|
102
|
+
- README.mkd
|
94
103
|
- Rakefile
|
95
104
|
- bin/cassandra_helper
|
96
105
|
- conf/cassandra.in.sh
|
@@ -107,9 +116,9 @@ files:
|
|
107
116
|
- lib/cassandra/ordered_hash.rb
|
108
117
|
- lib/cassandra/protocol.rb
|
109
118
|
- lib/cassandra/time.rb
|
110
|
-
- lib/cassandra/uuid.rb
|
111
119
|
- test/cassandra_test.rb
|
112
120
|
- test/comparable_types_test.rb
|
121
|
+
- test/ordered_hash_test.rb
|
113
122
|
- test/test_helper.rb
|
114
123
|
- vendor/gen-rb/cassandra.rb
|
115
124
|
- vendor/gen-rb/cassandra_constants.rb
|
@@ -126,7 +135,7 @@ rdoc_options:
|
|
126
135
|
- --title
|
127
136
|
- Cassandra
|
128
137
|
- --main
|
129
|
-
- README
|
138
|
+
- README.mkd
|
130
139
|
require_paths:
|
131
140
|
- lib
|
132
141
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -151,4 +160,5 @@ summary: A Ruby client for the Cassandra distributed database.
|
|
151
160
|
test_files:
|
152
161
|
- test/cassandra_test.rb
|
153
162
|
- test/comparable_types_test.rb
|
163
|
+
- test/ordered_hash_test.rb
|
154
164
|
- test/test_helper.rb
|
metadata.gz.sig
CHANGED
Binary file
|
data/README
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
cassandra
|
2
|
-
|
3
|
-
A Ruby client for the Cassandra distributed database.
|
4
|
-
|
5
|
-
== License
|
6
|
-
|
7
|
-
Copyright 2009 Twitter, Inc. See included LICENSE file. Portions copyright 2004-2009 David Heinemeier Hansson, and used with permission.
|
8
|
-
|
9
|
-
The public certificate for this gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem].
|
10
|
-
|
11
|
-
== Features
|
12
|
-
|
13
|
-
* clean encapsulation of the Thrift API
|
14
|
-
* compatible UUID and Long classes, for GUID generation
|
15
|
-
* Ruby 1.9 compatibility
|
16
|
-
|
17
|
-
The Github source repository is {here}[http://github.com/fauna/cassandra/]. Patches and contributions are very welcome.
|
18
|
-
|
19
|
-
== Installation
|
20
|
-
|
21
|
-
You need Ruby 1.8 or 1.9. If you have those, just run:
|
22
|
-
|
23
|
-
sudo gem install cassandra
|
24
|
-
|
25
|
-
Cassandra itself is a rapidly moving target. In order to get a working server, use the <tt>bin/cassandra_helper</tt> script:
|
26
|
-
|
27
|
-
cassandra_helper cassandra
|
28
|
-
|
29
|
-
A server will be installed in <tt>$HOME/cassandra/server</tt>, and started in debug mode.
|
30
|
-
|
31
|
-
== Usage
|
32
|
-
|
33
|
-
Now, start IRb and require the library:
|
34
|
-
|
35
|
-
require 'cassandra'
|
36
|
-
|
37
|
-
Connect to a server and keyspace:
|
38
|
-
|
39
|
-
client = Cassandra.new('Twitter', '127.0.0.1:9160')
|
40
|
-
|
41
|
-
Insert into a column family. You can insert a Cassandra::OrderedHash, or a regular Hash, if order doesn't matter:
|
42
|
-
|
43
|
-
client.insert(:Users, "5", {'screen_name' => "buttonscat"})
|
44
|
-
|
45
|
-
Insert into a super column family:
|
46
|
-
|
47
|
-
client.insert(:UserRelationships, "5", {"user_timeline" => {UUID.new => "1"}})
|
48
|
-
|
49
|
-
Query a super column:
|
50
|
-
|
51
|
-
timeline = client.get(:UserRelationships, "5", "user_timeline")
|
52
|
-
|
53
|
-
The returned result will always be a Cassandra::OrderedHash.
|
54
|
-
|
55
|
-
See Cassandra for more methods.
|
56
|
-
|
57
|
-
== Further reading
|
58
|
-
|
59
|
-
* {Up and Running With Cassandra}[http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra]
|
60
|
-
|
61
|
-
== Reporting problems
|
62
|
-
|
63
|
-
The Github issue tracker is {here}[http://github.com/fauna/cassandra/issues]. If you have problems with Cassandra itself, please use the {cassandra-user mailing list}[http://mail-archives.apache.org/mod_mbox/incubator-cassandra-user/].
|
64
|
-
|
data/lib/cassandra/uuid.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
|
2
|
-
class Cassandra
|
3
|
-
|
4
|
-
# UUID format version 1, as specified in RFC 4122, with jitter in place of the mac address and sequence counter.
|
5
|
-
class UUID < Comparable
|
6
|
-
|
7
|
-
class InvalidVersion < StandardError #:nodoc:
|
8
|
-
end
|
9
|
-
|
10
|
-
GREGORIAN_EPOCH_OFFSET = 0x01B2_1DD2_1381_4000 # Oct 15, 1582
|
11
|
-
|
12
|
-
VARIANT = 0b1000_0000_0000_0000
|
13
|
-
|
14
|
-
def initialize(bytes = nil)
|
15
|
-
case bytes
|
16
|
-
when self.class # UUID
|
17
|
-
@bytes = bytes.to_s
|
18
|
-
when String
|
19
|
-
case bytes.size
|
20
|
-
when 16 # Raw byte array
|
21
|
-
@bytes = bytes
|
22
|
-
when 36 # Human-readable UUID representation; inverse of #to_guid
|
23
|
-
elements = bytes.split("-")
|
24
|
-
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (malformed UUID representation)" if elements.size != 5
|
25
|
-
@bytes = elements.join.to_a.pack('H32')
|
26
|
-
else
|
27
|
-
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (invalid bytecount)"
|
28
|
-
end
|
29
|
-
|
30
|
-
when Integer
|
31
|
-
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (integer out of range)" if bytes < 0 or bytes > 2**128
|
32
|
-
@bytes = [
|
33
|
-
(bytes >> 96) & 0xFFFF_FFFF,
|
34
|
-
(bytes >> 64) & 0xFFFF_FFFF,
|
35
|
-
(bytes >> 32) & 0xFFFF_FFFF,
|
36
|
-
bytes & 0xFFFF_FFFF
|
37
|
-
].pack("NNNN")
|
38
|
-
|
39
|
-
when NilClass, Time
|
40
|
-
time = (bytes || Time).stamp * 10 + GREGORIAN_EPOCH_OFFSET
|
41
|
-
# See http://github.com/spectra/ruby-uuid/
|
42
|
-
@bytes = [
|
43
|
-
time & 0xFFFF_FFFF,
|
44
|
-
time >> 32,
|
45
|
-
((time >> 48) & 0x0FFF) | 0x1000,
|
46
|
-
# Top 3 bytes reserved
|
47
|
-
rand(2**13) | VARIANT,
|
48
|
-
rand(2**16),
|
49
|
-
rand(2**32)
|
50
|
-
].pack("NnnnnN")
|
51
|
-
|
52
|
-
else
|
53
|
-
raise TypeError, "Expected #{bytes.inspect} to cast to a #{self.class} (unknown source class)"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_i
|
58
|
-
ints = @bytes.unpack("NNNN")
|
59
|
-
(ints[0] << 96) +
|
60
|
-
(ints[1] << 64) +
|
61
|
-
(ints[2] << 32) +
|
62
|
-
ints[3]
|
63
|
-
end
|
64
|
-
|
65
|
-
def version
|
66
|
-
time_high = @bytes.unpack("NnnQ")[2]
|
67
|
-
version = (time_high & 0xF000).to_s(16)[0].chr.to_i
|
68
|
-
version > 0 and version < 6 ? version : -1
|
69
|
-
end
|
70
|
-
|
71
|
-
def variant
|
72
|
-
@bytes.unpack('QnnN')[1] >> 13
|
73
|
-
end
|
74
|
-
|
75
|
-
def to_guid
|
76
|
-
elements = @bytes.unpack("NnnCCa6")
|
77
|
-
node = elements[-1].unpack('C*')
|
78
|
-
elements[-1] = '%02x%02x%02x%02x%02x%02x' % node
|
79
|
-
"%08x-%04x-%04x-%02x%02x-%s" % elements
|
80
|
-
end
|
81
|
-
|
82
|
-
def seconds
|
83
|
-
total_usecs / 1_000_000
|
84
|
-
end
|
85
|
-
|
86
|
-
def usecs
|
87
|
-
total_usecs % 1_000_000
|
88
|
-
end
|
89
|
-
|
90
|
-
def <=>(other)
|
91
|
-
total_usecs <=> other.send(:total_usecs)
|
92
|
-
end
|
93
|
-
|
94
|
-
def ==(other)
|
95
|
-
to_s == other.to_s
|
96
|
-
end
|
97
|
-
|
98
|
-
def inspect(long = false)
|
99
|
-
"<Cassandra::UUID##{object_id} time: #{
|
100
|
-
Time.at(seconds).inspect
|
101
|
-
}, usecs: #{
|
102
|
-
usecs
|
103
|
-
} jitter: #{
|
104
|
-
@bytes.unpack('QQ')[1]
|
105
|
-
}" + (long ? ", version: #{version}, variant: #{variant}, guid: #{to_guid}>" : ">")
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
def total_usecs
|
111
|
-
elements = @bytes.unpack("NnnQ")
|
112
|
-
(elements[0] + (elements[1] << 32) + ((elements[2] & 0x0FFF) << 48) - GREGORIAN_EPOCH_OFFSET) / 10
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|