madrox-cluster 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in madrox-cluster.gemspec
4
+ gemspec
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,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
4
+ require 'madrox-cluster/server/server'
5
+
6
+ hostname = ARGV[0] || "0.0.0.0"
7
+ port = ARGV[1] || 2000
8
+
9
+ Madrox::Server.start(hostname, port)
10
+
@@ -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,3 @@
1
+ module Madrox
2
+ VERSION = "0.0.4"
3
+ 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
+