madrox-cluster 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/Readme.md +68 -0
- data/bin/madrox +10 -0
- data/lib/madrox-cluster/host.rb +38 -0
- data/lib/madrox-cluster/hosts_manager.rb +33 -0
- data/lib/madrox-cluster/json_builder.rb +22 -0
- data/lib/madrox-cluster/server/server.rb +22 -0
- data/lib/madrox-cluster/server/server_handler.rb +35 -0
- data/lib/madrox-cluster/version.rb +3 -0
- data/lib/madrox-cluster/workers.rb +58 -0
- data/lib/madrox-cluster.rb +47 -0
- data/madrox-cluster.gemspec +30 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
data.tar.gz: 5c3dad986634c21d65fd78e0ea57689f5362e0a8
|
4
|
+
metadata.gz: 6bec33f51f16851df54d14d8a8fe56591ce83806
|
5
|
+
SHA512:
|
6
|
+
data.tar.gz: d8e0028ab40eec52ac32ad4f0d74d19328d7f2c1e38efe1b2ca7315d27c095e4cfd2316f3603683d024c734d5950549ef517d14c4b1598a2551e30b159d8d511
|
7
|
+
metadata.gz: 397ccd35cb71082be4d7e5f4e2809dd48826ca4e5c158d7d1d7609d61a12df829ec40ed1c9e0cf9b6d3770a2422c17b4b309dbbeaa9455bc1eeedabc971382d4
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/Readme.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
Madrox [![Code Climate](https://codeclimate.com/github/iurimatias/madrox-cluster.png)](https://codeclimate.com/github/iurimatias/madrox-cluster)
|
2
|
+
======
|
3
|
+
|
4
|
+
Easily distribute any code across multiple servers
|
5
|
+
|
6
|
+
Install
|
7
|
+
=======
|
8
|
+
|
9
|
+
```Bash
|
10
|
+
gem install madrox-cluster
|
11
|
+
```
|
12
|
+
|
13
|
+
Usage
|
14
|
+
=====
|
15
|
+
|
16
|
+
###Starting a Server
|
17
|
+
|
18
|
+
```Bash
|
19
|
+
madrox 127.0.0.1 5000
|
20
|
+
```
|
21
|
+
|
22
|
+
###Adding servers
|
23
|
+
|
24
|
+
```Ruby
|
25
|
+
#configure a server
|
26
|
+
Madrox.config(["server_1:5000", "server_1:5001", "server_2:5000", "server_2:5001"])
|
27
|
+
```
|
28
|
+
|
29
|
+
###Executing a block
|
30
|
+
|
31
|
+
|
32
|
+
```Ruby
|
33
|
+
#Distribute processing across the servers
|
34
|
+
result = Madrox.collect([35, 30, 35, 37, 25, 30]) do |x|
|
35
|
+
def fib(n)
|
36
|
+
n<=1 ? n : fib(n-2) + fib(n-1)
|
37
|
+
end
|
38
|
+
fib(x)
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
###Register code in advance
|
43
|
+
|
44
|
+
```Ruby
|
45
|
+
CalcClass = Proc.new { |x|
|
46
|
+
class Calc
|
47
|
+
def fib(n)
|
48
|
+
n<=1 ? n : fib(n-2) + fib(n-1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Calc
|
53
|
+
}
|
54
|
+
|
55
|
+
#stores this class in all servers
|
56
|
+
Madrox.register("Calc", CalcClass)
|
57
|
+
|
58
|
+
result = Madrox.collect([35, 30, 35, 37, 25, 30]) do |x|
|
59
|
+
Calc.new.fib(x)
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Disclaimer
|
64
|
+
=====
|
65
|
+
|
66
|
+
This gem is provided as is - therefore, the creators and contributors of this gem are not responsible for any damages that may result from its usage. Although Authentication and SSL may be added later, Madrox is experimental and is meant to be used in private trusted local networks. Use at your own risk.
|
67
|
+
|
68
|
+
Madrox is an experiment. For a more solid solution please check [dRuby](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/drb/rdoc/DRb.html)
|
data/bin/madrox
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Madrox
|
2
|
+
class Host
|
3
|
+
attr_accessor :jobs, :connection
|
4
|
+
|
5
|
+
def initialize(hostname, port)
|
6
|
+
@hostname = hostname
|
7
|
+
@port = port
|
8
|
+
@jobs = 0
|
9
|
+
@semaphore = Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect
|
13
|
+
@connection = TCPSocket.new(@hostname, @port)
|
14
|
+
rescue Errno::ECONNREFUSED => e
|
15
|
+
raise "problem connecting to #{@hostname}:#{@port}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def send(package, should_get_reply=true)
|
19
|
+
@semaphore.lock
|
20
|
+
connect
|
21
|
+
@jobs += 1
|
22
|
+
@connection.sendmsg package #add \n
|
23
|
+
|
24
|
+
result = should_get_reply ? @connection.gets.chop : nil
|
25
|
+
@jobs -= 1
|
26
|
+
@semaphore.unlock
|
27
|
+
|
28
|
+
result
|
29
|
+
#rescue
|
30
|
+
# retry
|
31
|
+
end
|
32
|
+
|
33
|
+
def close_connection
|
34
|
+
@connection.close
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Madrox
|
2
|
+
class HostsManager
|
3
|
+
|
4
|
+
def self.add_hosts(host_list)
|
5
|
+
host_list.each do |host|
|
6
|
+
hostname, port = host.split(":")
|
7
|
+
add_host(hostname, port)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.add_host(hostname, port)
|
12
|
+
@@hosts ||= []
|
13
|
+
@@hosts << Host.new(hostname, port)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_next_free_host
|
17
|
+
@@hosts.min_by { |h| h.jobs }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.get_free_hosts()
|
21
|
+
@@hosts.select { |host| host.jobs == 0 }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.send_to_all(payload)
|
25
|
+
@@hosts.each { |host| host.send payload, false }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.close_connections
|
29
|
+
@@hosts.map(&:close_connection)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Madrox
|
2
|
+
class JsonPackage
|
3
|
+
|
4
|
+
def self.register(reference, code)
|
5
|
+
{:type => "register", :reference => reference, :code => code.to_source}.to_json
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.execute(block, args=[])
|
9
|
+
{:type => "execute", :code => block.to_source, :args => args}.to_json
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.result(result)
|
13
|
+
{:type => "result", :result => result}.to_json
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.parse(package)
|
17
|
+
json = JSON.parse(package)
|
18
|
+
OpenStruct.new(json)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sourcify'
|
2
|
+
require 'socket'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'json'
|
5
|
+
require 'parallel'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
require 'madrox-cluster/json_builder'
|
9
|
+
require 'madrox-cluster/server/server_handler'
|
10
|
+
|
11
|
+
module Madrox
|
12
|
+
|
13
|
+
class Server
|
14
|
+
def self.start(hostname, port=2000)
|
15
|
+
puts "starting server on #{hostname}:#{port}"
|
16
|
+
EventMachine.run {
|
17
|
+
EventMachine.start_server hostname, port, ServerHandler
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Madrox
|
2
|
+
module ServerHandler
|
3
|
+
|
4
|
+
def post_init
|
5
|
+
port, ip = Socket.unpack_sockaddr_in(self.get_peername)
|
6
|
+
puts "#{ip} has connected"
|
7
|
+
end
|
8
|
+
|
9
|
+
def register(reference, code)
|
10
|
+
eval("#{reference} = #{code}.call()")
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(code, args)
|
14
|
+
args = args.first if args.size == 1
|
15
|
+
result = eval(code).call(args)
|
16
|
+
JsonPackage.result(result)
|
17
|
+
end
|
18
|
+
|
19
|
+
def receive_data(package)
|
20
|
+
Thread.new do
|
21
|
+
data = JsonPackage.parse(package)
|
22
|
+
puts "-----"
|
23
|
+
puts data
|
24
|
+
case data.type
|
25
|
+
when "register"
|
26
|
+
register(data.reference, data.code)
|
27
|
+
when "execute"
|
28
|
+
result = execute(data.code, data.args)
|
29
|
+
send_data result.to_s + "\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Madrox
|
2
|
+
class Workers
|
3
|
+
|
4
|
+
def initialize(array, block)
|
5
|
+
@result = []
|
6
|
+
@job_queue = array.to_a
|
7
|
+
@threads = []
|
8
|
+
@block = block
|
9
|
+
@semaphore = Mutex.new
|
10
|
+
@index = -1
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
execute_jobs
|
15
|
+
@threads.map(&:join) #wait for all threads to finish
|
16
|
+
HostsManager.close_connections
|
17
|
+
@result
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def execute_jobs
|
23
|
+
connections = HostsManager.get_free_hosts
|
24
|
+
initial_jobs = @job_queue.shift connections.count
|
25
|
+
|
26
|
+
initial_jobs.each_with_index do |value, index|
|
27
|
+
@semaphore.lock
|
28
|
+
@index += 1
|
29
|
+
@semaphore.unlock
|
30
|
+
execute_job(connections[index], value, index)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute_job(connection, value, index)
|
35
|
+
@threads << Thread.new {
|
36
|
+
response = connection.send JsonPackage.execute(@block, [value])
|
37
|
+
result = JsonPackage.parse(response)
|
38
|
+
|
39
|
+
res = eval(result.result.to_s)
|
40
|
+
@result[index] = res
|
41
|
+
execute_next_job
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def execute_next_job
|
46
|
+
@semaphore.lock
|
47
|
+
connection = HostsManager.get_next_free_host
|
48
|
+
value = @job_queue.shift
|
49
|
+
@index += 1
|
50
|
+
index = @index
|
51
|
+
@semaphore.unlock
|
52
|
+
|
53
|
+
return if value.nil?
|
54
|
+
execute_job(connection, value, index)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sourcify'
|
2
|
+
require 'socket'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'json'
|
5
|
+
require 'parallel'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
require "madrox-cluster/version"
|
9
|
+
require "madrox-cluster/host"
|
10
|
+
require "madrox-cluster/hosts_manager"
|
11
|
+
require "madrox-cluster/json_builder"
|
12
|
+
require "madrox-cluster/workers"
|
13
|
+
|
14
|
+
module Madrox
|
15
|
+
|
16
|
+
def self.config(host_list)
|
17
|
+
HostsManager.add_hosts(host_list)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.register(reference, code)
|
21
|
+
HostsManager.send_to_all JsonPackage.register(reference, code)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.execute(&block)
|
25
|
+
host = HostsManager.get_next_free_host
|
26
|
+
response = host.send JsonPackage.execute(block)
|
27
|
+
result = JsonPackage.parse(response)
|
28
|
+
eval(result.result.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.each(array, options = {}, &block)
|
32
|
+
self.collect(array, options, &block)
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.map(array, options={}, &block)
|
37
|
+
self.collect(array, options, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.collect(array, options = {}, &block)
|
41
|
+
workers = Workers.new(array, block)
|
42
|
+
result = workers.execute
|
43
|
+
|
44
|
+
return result
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "madrox-cluster/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "madrox-cluster"
|
7
|
+
s.version = Madrox::VERSION
|
8
|
+
s.authors = ["Iuri Matias"]
|
9
|
+
s.email = ["iuri.matias@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/iurimatias/madrox-cluster"
|
11
|
+
s.summary = %q{Straightforward distributed computing in ruby}
|
12
|
+
s.description = %q{Easily distribute any code in multiple servers}
|
13
|
+
|
14
|
+
s.rubyforge_project = "madrox-cluster"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "pry"
|
23
|
+
|
24
|
+
s.add_runtime_dependency 'ruby_parser'
|
25
|
+
s.add_runtime_dependency 'file-tail'
|
26
|
+
s.add_runtime_dependency 'sourcify'
|
27
|
+
s.add_runtime_dependency 'eventmachine'
|
28
|
+
s.add_runtime_dependency 'parallel'
|
29
|
+
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: madrox-cluster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Iuri Matias
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2013-09-22 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- &id002
|
20
|
+
- ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
type: :development
|
24
|
+
version_requirements: *id001
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: ruby_parser
|
27
|
+
prerelease: false
|
28
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- *id002
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id003
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: file-tail
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- *id002
|
39
|
+
type: :runtime
|
40
|
+
version_requirements: *id004
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sourcify
|
43
|
+
prerelease: false
|
44
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- *id002
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id005
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: eventmachine
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- *id002
|
55
|
+
type: :runtime
|
56
|
+
version_requirements: *id006
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: parallel
|
59
|
+
prerelease: false
|
60
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- *id002
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id007
|
65
|
+
description: Easily distribute any code in multiple servers
|
66
|
+
email:
|
67
|
+
- iuri.matias@gmail.com
|
68
|
+
executables:
|
69
|
+
- madrox
|
70
|
+
extensions: []
|
71
|
+
|
72
|
+
extra_rdoc_files: []
|
73
|
+
|
74
|
+
files:
|
75
|
+
- .gitignore
|
76
|
+
- Gemfile
|
77
|
+
- Rakefile
|
78
|
+
- Readme.md
|
79
|
+
- bin/madrox
|
80
|
+
- lib/madrox-cluster.rb
|
81
|
+
- lib/madrox-cluster/host.rb
|
82
|
+
- lib/madrox-cluster/hosts_manager.rb
|
83
|
+
- lib/madrox-cluster/json_builder.rb
|
84
|
+
- lib/madrox-cluster/server/server.rb
|
85
|
+
- lib/madrox-cluster/server/server_handler.rb
|
86
|
+
- lib/madrox-cluster/version.rb
|
87
|
+
- lib/madrox-cluster/workers.rb
|
88
|
+
- madrox-cluster.gemspec
|
89
|
+
homepage: https://github.com/iurimatias/madrox-cluster
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
metadata: {}
|
93
|
+
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- *id002
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- *id002
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project: madrox-cluster
|
108
|
+
rubygems_version: 2.0.3
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Straightforward distributed computing in ruby
|
112
|
+
test_files: []
|
113
|
+
|