consistent-hashing 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ # RubyMine
2
+ .idea
3
+ *.gemspec
4
+
5
+ # gem/bones
6
+ announcement.txt
7
+ coverage
8
+ doc
9
+ pkg
@@ -0,0 +1,3 @@
1
+ == 0.0.1 / 2012-04-15
2
+
3
+ * Birthday!
@@ -0,0 +1,60 @@
1
+ consistent-hashing
2
+ ==================
3
+
4
+ A generic implementation of the Consistent Hashing algorithm.
5
+
6
+ Features
7
+ --------
8
+
9
+ * set number of replicas to create multiple virtual points in the ring for each node
10
+
11
+ Examples
12
+ --------
13
+
14
+ ```ruby
15
+ ring = ConsistentHashing::Ring.new
16
+ ring << "192.168.1.101" << "192.168.1.102"
17
+
18
+ ring.node_for("foobar") # => 192.168.1.101
19
+ ring.delete("192.168.1.101")
20
+
21
+ # after removing 192.168.1.101, all keys previously mapped to it move clockwise to
22
+ # the next node
23
+ ring.node_for("foobar") # => 192.168.1.102
24
+ ```
25
+
26
+ Install
27
+ -------
28
+
29
+ * `[sudo] gem install consistent-hashing`
30
+
31
+ Author
32
+ ------
33
+
34
+ Original author: Dominik Liebler <liebler.dominik@googlemail.com>
35
+
36
+ License
37
+ -------
38
+
39
+ (The MIT License)
40
+
41
+ Copyright (c) 2012 Dominik Liebler
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ 'Software'), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
57
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
58
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
59
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
60
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'bones'
5
+ rescue LoadError
6
+ abort '### Please install the "bones" gem ###'
7
+ end
8
+
9
+ task :default => 'test:run'
10
+ task 'gem:release' => 'test:run'
11
+
12
+ Bones {
13
+ name 'consistent-hashing'
14
+ authors 'Dominik Liebler'
15
+ email 'liebler.dominik@googlemail.com'
16
+ url 'https://github.com/domnikl/consistent-hashing'
17
+ ignore_file '.gitignore'
18
+ }
@@ -0,0 +1,15 @@
1
+ # Main module
2
+ #
3
+ module ConsistentHashing
4
+ LIBPATH = ::File.expand_path('..', __FILE__) + ::File::SEPARATOR
5
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
6
+ VERSION = ::File.read(PATH + 'version.txt').strip
7
+
8
+ # Internal: loads all necessary lib files
9
+ #
10
+ def self.load_lib
11
+ require File.join(LIBPATH, 'consistent_hashing', 'ring')
12
+ end
13
+ end
14
+
15
+ ConsistentHashing.load_lib
@@ -0,0 +1,78 @@
1
+ require 'digest/md5'
2
+
3
+ module ConsistentHashing
4
+ class Ring
5
+ attr_reader :ring
6
+
7
+ # Public: returns a new ring object
8
+ def initialize(nodes = [], replicas = 3)
9
+ @replicas = replicas
10
+ @sorted_keys = []
11
+ @ring = Hash.new
12
+
13
+ nodes.each { |node| add(node) }
14
+ end
15
+
16
+ # Public: returns the (virtual) points in the hash ring
17
+ #
18
+ # Returns: a Fixnum
19
+ def length
20
+ @ring.length
21
+ end
22
+
23
+ # Public: adds a new node into the hash ring
24
+ #
25
+ def add(node)
26
+ @replicas.times do |i|
27
+ # generate the key of this (virtual) point in the hash
28
+ key = hash_key(node, i)
29
+
30
+ @ring[key] = node
31
+ @sorted_keys << key
32
+ end
33
+
34
+ @sorted_keys.sort!
35
+
36
+ self
37
+ end
38
+ alias :<< :add
39
+
40
+ # Public: removes a node from the hash ring
41
+ #
42
+ def delete(node)
43
+ @replicas.times do |i|
44
+ key = hash_key(node, i)
45
+
46
+ @ring.delete key
47
+ @sorted_keys.delete key
48
+ end
49
+
50
+ self
51
+ end
52
+
53
+ # Public: gets the node for an arbitrary key
54
+ #
55
+ #
56
+ def node_for(key)
57
+ return [nil, 0] if @ring.empty?
58
+
59
+ key = hash_key(key)
60
+
61
+ @sorted_keys.each do |i|
62
+ return [@ring[i], i] if key <= i
63
+ end
64
+
65
+ [@ring[@sorted_keys[0]], 0]
66
+ end
67
+
68
+ protected
69
+
70
+ # Internal: hashes the key
71
+ #
72
+ # Returns: a String
73
+ def hash_key(key, index = nil)
74
+ key = "#{key}:#{index}" if index
75
+ Digest::MD5.hexdigest(key.to_s)[0..16].hex
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__), %w{ .. test_consistent_hashing})
2
+
3
+ class TestRing < ConsistentHashing::TestCase
4
+ def setup
5
+ @ring = ConsistentHashing::Ring.new %w{A B C}
6
+
7
+ @examples = {
8
+ "A" => "foobar",
9
+ "B" => "123",
10
+ "C" => "baz",
11
+ "not_found" => 0
12
+ }
13
+ end
14
+
15
+ def test_init
16
+ ring = ConsistentHashing::Ring.new
17
+ assert_equal 0, ring.length
18
+ end
19
+
20
+ def test_length
21
+ ring = ConsistentHashing::Ring.new([], 3)
22
+ assert_equal 0, ring.length
23
+
24
+ ring << "A" << "B"
25
+ assert_equal 6, ring.length
26
+ end
27
+
28
+ def test_get_node
29
+ assert_equal "A", @ring.node_for(@examples["A"])[0]
30
+ assert_equal "B", @ring.node_for(@examples["B"])[0]
31
+ assert_equal "C", @ring.node_for(@examples["C"])[0]
32
+ end
33
+
34
+ # should fall back to the first node, if key > last node
35
+ def test_get_node_fallback_to_first
36
+ ring = ConsistentHashing::Ring.new ["A"], 1
37
+
38
+ assert_equal "A", ring.node_for(@examples["not_found"])[0]
39
+ assert_equal 0, ring.node_for(@examples["not_found"])[1]
40
+ end
41
+
42
+ # if I remove node C, all keys previously mapped to C should be moved clockwise to
43
+ # the next node. That's a virtual point of B here
44
+ def test_remove_node
45
+ @ring.delete("C")
46
+ assert_equal "B", @ring.node_for(@examples["C"])[0]
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), %w{.. lib}))
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'consistent_hashing'
7
+ require 'test/unit'
8
+
9
+ module ConsistentHashing
10
+ class TestCase < Test::Unit::TestCase
11
+ def test_module
12
+ assert_not_nil ConsistentHashing::VERSION
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ 0.0.1
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: consistent-hashing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dominik Liebler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bones
16
+ requirement: &70330988436160 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.8.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70330988436160
25
+ description: A generic implementation of the Consistent Hashing algorithm.
26
+ email: liebler.dominik@googlemail.com
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files:
30
+ - History.txt
31
+ files:
32
+ - .gitignore
33
+ - History.txt
34
+ - README.md
35
+ - Rakefile
36
+ - lib/consistent_hashing.rb
37
+ - lib/consistent_hashing/ring.rb
38
+ - test/consistent_hashing/test_ring.rb
39
+ - test/test_consistent_hashing.rb
40
+ - version.txt
41
+ homepage: https://github.com/domnikl/consistent-hashing
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --main
46
+ - README.md
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project: consistent-hashing
63
+ rubygems_version: 1.8.16
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: A generic implementation of the Consistent Hashing algorithm.
67
+ test_files:
68
+ - test/consistent_hashing/test_ring.rb
69
+ - test/test_consistent_hashing.rb