rlrw 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rlrw.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,21 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rlrw (0.0.1)
5
+ murmurhash3 (= 0.1.4)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ minitest (5.4.3)
11
+ murmurhash3 (0.1.4)
12
+ rake (10.4.2)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ bundler (~> 1.7)
19
+ minitest (= 5.4.3)
20
+ rake (~> 10.0)
21
+ rlrw!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Omar Yasin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Rendezvous or Lowest Random Weight (LRW) hashing
2
+
3
+ This is a Ruby implementation of LRW. It is a port of Ferd's
4
+ [LRW](https://github.com/ferd/lrw). Even if it is a port, it cannot be used with
5
+ the original implementation as it uses another hash function.
6
+
7
+ This hashing mechanism allows you to consistently hash to a specific node
8
+ without needing to do bucketing first a'la Consistent Hashing. It also
9
+ guarantees as little key redistribution as possible.
10
+
11
+ ## Interface
12
+
13
+ The `all/2` function gives an ordering of all nodes:
14
+
15
+ ```
16
+ <= Rlrw::LRW.all("my_item", ["127.0.0.1", "255.0.0.1", "192.2.1.2", "192.198.2.1"])
17
+ => ["255.0.0.1", "192.2.1.2", "127.0.0.1", "192.198.2.1"]
18
+ <= Rlrw::LRW.all("my_item", ["127.0.0.1","198.2.1.2","192.198.2.1","10.10.100.10"])
19
+ => ["198.2.1.2", "10.10.100.10", "127.0.0.1", "192.198.2.1"]
20
+ <= Rlrw::LRW.all("my_item", ["127.0.0.1","192.198.2.1"])
21
+ => ["127.0.0.1", "192.198.2.1"]
22
+ <= Rlrw::LRW.all("my_item", ["127.0.0.1","192.18.211.12","23.66.77.88","252.11.11.11"])
23
+ => ["192.18.211.12", "23.66.77.88", "127.0.0.1", "252.11.11.11"]
24
+ <= Rlrw::LRW.all("my_other_item", ["127.0.0.1","192.18.211.12","23.66.77.88","252.11.11.11"])
25
+ => ["252.11.11.11", "23.66.77.88", "192.18.211.12", "127.0.0.1"]
26
+ <= Rlrw::LRW.all("my_other_item", ["127.0.0.1","192.18.211.12","23.66.77.88","252.11.11.11"])
27
+ => ["252.11.11.11", "23.66.77.88", "192.18.211.12", "127.0.0.1"]
28
+ ```
29
+
30
+ The `top/3` function returns a subset. It is using `all/2` in its implementation
31
+
32
+ ```
33
+ <= Rlrw::LRW.top("12123", ["127.0.0.1","255.0.0.1","198.2.1.2","192.198.2.1"], 2)
34
+ => ["127.0.0.1", "198.2.1.2"]
35
+ ```
36
+
37
+ Custom hashing functions can be passed by calling `all/3` and `top/3`, where the
38
+ argument of each function must be a lambda that accepts two arguments, `key`, and
39
+ `node` and returns a number.
40
+
41
+ ## Test
42
+
43
+ ```
44
+ $ bundle install
45
+ $ bundle exec rake
46
+ ```
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task :default => :test
5
+
6
+ task :test do
7
+ Rake::TestTask.new do |t|
8
+ t.pattern = "test/*.rb"
9
+ end
10
+ end
data/lib/rlrw.rb ADDED
@@ -0,0 +1,34 @@
1
+ require "rlrw/version"
2
+ require "murmurhash3"
3
+
4
+ module Rlrw
5
+ module LRW
6
+ MOD = 2147483648
7
+
8
+ PHASH = lambda { |key, node| MurmurHash3::V32.str_hash("#{node}#{key}", MOD) }
9
+
10
+ def self.all(key, nodes, phash=PHASH)
11
+ self.all_weights(key, nodes, phash).map do | node |
12
+ node[:node]
13
+ end
14
+ end
15
+
16
+ def self.top(key, nodes, len, phash=PHASH)
17
+ self.top_weights(key, nodes, len, phash).map do | node |
18
+ node[:node]
19
+ end
20
+ end
21
+
22
+ def self.all_weights(key, nodes, phash=PHASH)
23
+ res = nodes.map do |node|
24
+ { node: node, weight: phash.call(key, node) }
25
+ end
26
+ res.sort_by { |res| res[:weight] }
27
+ end
28
+
29
+ def self.top_weights(key, nodes, len, phash=PHASH)
30
+ self.all_weights(key, nodes, phash).take(len)
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module Rlrw
2
+ VERSION = "0.0.1"
3
+ end
data/rlrw.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rlrw/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rlrw"
8
+ spec.version = Rlrw::VERSION
9
+ spec.authors = ["omarkj"]
10
+ spec.email = ["omarkj@gmail.com"]
11
+ spec.summary = "Lowest Random Weight hashing"
12
+ spec.description = %q{This hashing mechanism allows you to consistently hash to a specific node without needing to do bucketing first a'la Consistent Hashing. It also guarantees as little key redistribution as possible.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+
22
+ spec.add_runtime_dependency "murmurhash3", "= 0.1.4"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest", "= 5.4.3"
27
+ end
data/test/rlrw.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'minitest/autorun'
2
+ require 'digest/sha1'
3
+ require 'rlrw'
4
+
5
+ describe Rlrw::LRW, "LRW" do
6
+
7
+ it "calculates all" do
8
+ Rlrw::LRW.all("my_item", ["b","c","d"]).must_equal(["d", "b", "c"])
9
+ end
10
+
11
+ it "calculates top" do
12
+ Rlrw::LRW.top("my_item", ["b","c","d"], 2).must_equal(["d", "b"])
13
+ end
14
+
15
+ it "calculates all and returns weights" do
16
+ Rlrw::LRW.all_weights("my_item", ["b","c","d"]).must_equal([{:node=>"d", :weight=>815949913},
17
+ {:node=>"b", :weight=>3970763645},
18
+ {:node=>"c", :weight=>4112589638}])
19
+ end
20
+
21
+ it "calculates top and returns weights" do
22
+ Rlrw::LRW.top_weights("my_item", ["b","c","d"], 2).must_equal([{:node=>"d", :weight=>815949913},
23
+ {:node=>"b", :weight=>3970763645}])
24
+ end
25
+
26
+ it "calculates all with another hash function" do
27
+ f = lambda { |key, node| Digest::SHA1.hexdigest("#{node}#{key}").to_i(16) }
28
+ Rlrw::LRW.all("my_item", ["b","c","d"], f).must_equal(["b", "c", "d"])
29
+ end
30
+
31
+ it "calculates top with another hash function" do
32
+ require 'digest/sha1'
33
+ f = lambda { |key, node| Digest::SHA1.hexdigest("#{node}#{key}").to_i(16) }
34
+ Rlrw::LRW.top("my_item", ["b","c","d"], 2, f).must_equal(["b", "c"])
35
+ end
36
+
37
+ it "calculates all and returns weights with another hash function" do
38
+ f = lambda { |key, node| Digest::SHA1.hexdigest("#{node}#{key}").to_i(16) }
39
+ Rlrw::LRW.all_weights("my_item", ["b","c","d"], f).must_equal([{:node=>"b", :weight=>12535624296688143233642322168769247078306177530},
40
+ {:node=>"c", :weight=>437434023516257654645300587808082606734576988647},
41
+ {:node=>"d", :weight=>1257752084205904020026775133107610541280950115641}])
42
+ end
43
+
44
+ it "calculates top and returns weights with another hash function" do
45
+ f = lambda { |key, node| Digest::SHA1.hexdigest("#{node}#{key}").to_i(16) }
46
+ Rlrw::LRW.top_weights("my_item", ["b","c","d"], 2, f).must_equal([{:node=>"b", :weight=>12535624296688143233642322168769247078306177530},
47
+ {:node=>"c", :weight=>437434023516257654645300587808082606734576988647}])
48
+ end
49
+
50
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlrw
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - omarkj
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-01-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: murmurhash3
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.1.4
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.7'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.7'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '10.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: minitest
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 5.4.3
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - '='
76
+ - !ruby/object:Gem::Version
77
+ version: 5.4.3
78
+ description: This hashing mechanism allows you to consistently hash to a specific
79
+ node without needing to do bucketing first a'la Consistent Hashing. It also guarantees
80
+ as little key redistribution as possible.
81
+ email:
82
+ - omarkj@gmail.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/rlrw.rb
94
+ - lib/rlrw/version.rb
95
+ - rlrw.gemspec
96
+ - test/rlrw.rb
97
+ homepage: ''
98
+ licenses:
99
+ - MIT
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: -4168146116181610619
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ segments:
120
+ - 0
121
+ hash: -4168146116181610619
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 1.8.23.2
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Lowest Random Weight hashing
128
+ test_files:
129
+ - test/rlrw.rb