tiamat 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES.rdoc +7 -0
- data/MANIFEST +42 -0
- data/README.rdoc +194 -0
- data/Rakefile +19 -0
- data/bin/tiamat-server +31 -0
- data/devel/jumpstart.rb +987 -0
- data/install.rb +2 -0
- data/lib/tiamat.rb +43 -0
- data/lib/tiamat/autoconfig.rb +8 -0
- data/lib/tiamat/child_server.rb +21 -0
- data/lib/tiamat/config/ruby_parser.rb +6 -0
- data/lib/tiamat/connector.rb +23 -0
- data/lib/tiamat/error.rb +24 -0
- data/lib/tiamat/farm.rb +32 -0
- data/lib/tiamat/local_child_farm.rb +23 -0
- data/lib/tiamat/local_child_server.rb +25 -0
- data/lib/tiamat/local_child_worker.rb +11 -0
- data/lib/tiamat/remote_farm.rb +11 -0
- data/lib/tiamat/remote_worker.rb +10 -0
- data/lib/tiamat/server.rb +42 -0
- data/lib/tiamat/tiamat.rb +49 -0
- data/lib/tiamat/tiamat_server.rb +48 -0
- data/lib/tiamat/util.rb +37 -0
- data/lib/tiamat/version.rb +4 -0
- data/lib/tiamat/worker.rb +61 -0
- data/spec/connector_spec.rb +11 -0
- data/spec/drb_connection_spec.rb +18 -0
- data/spec/local_child_farm_spec.rb +29 -0
- data/spec/local_child_server_path_spec.rb +37 -0
- data/spec/local_child_server_spec.rb +24 -0
- data/spec/local_child_worker_spec.rb +140 -0
- data/spec/pure_spec.rb +59 -0
- data/spec/readme_spec.rb +29 -0
- data/spec/remote_farm_spec.rb +36 -0
- data/spec/remote_worker_spec.rb +59 -0
- data/spec/server_spec.rb +48 -0
- data/spec/tiamat_open_local_spec.rb +77 -0
- data/spec/tiamat_open_remote_spec.rb +67 -0
- data/spec/tiamat_server_spec.rb +51 -0
- data/spec/tiamat_spec_base.rb +36 -0
- data/spec/util_spec.rb +29 -0
- data/spec/worker_spec.rb +19 -0
- metadata +209 -0
data/install.rb
ADDED
data/lib/tiamat.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2009 James M. Lawrence. All rights reserved.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person
|
5
|
+
# obtaining a copy of this software and associated documentation files
|
6
|
+
# (the "Software"), to deal in the Software without restriction,
|
7
|
+
# including without limitation the rights to use, copy, modify, merge,
|
8
|
+
# publish, distribute, sublicense, and/or sell copies of the Software,
|
9
|
+
# and to permit persons to whom the Software is furnished to do so,
|
10
|
+
# subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
19
|
+
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
20
|
+
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
21
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
23
|
+
#
|
24
|
+
|
25
|
+
require 'rbconfig'
|
26
|
+
require 'drb'
|
27
|
+
|
28
|
+
require 'pure'
|
29
|
+
|
30
|
+
require 'tiamat/error'
|
31
|
+
require 'tiamat/version'
|
32
|
+
require 'tiamat/util'
|
33
|
+
require 'tiamat/connector'
|
34
|
+
require 'tiamat/server'
|
35
|
+
require 'tiamat/farm'
|
36
|
+
require 'tiamat/worker'
|
37
|
+
require 'tiamat/remote_farm'
|
38
|
+
require 'tiamat/remote_worker'
|
39
|
+
require 'tiamat/child_server'
|
40
|
+
require 'tiamat/local_child_server'
|
41
|
+
require 'tiamat/local_child_farm'
|
42
|
+
require 'tiamat/local_child_worker'
|
43
|
+
require 'tiamat/tiamat'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class ChildServer < Server
|
4
|
+
def initialize(uri, *args)
|
5
|
+
@thread = Thread.new {
|
6
|
+
launch(uri, *args)
|
7
|
+
}
|
8
|
+
super(uri)
|
9
|
+
end
|
10
|
+
|
11
|
+
def close
|
12
|
+
begin
|
13
|
+
@drb_object.close
|
14
|
+
rescue DRb::DRbConnError
|
15
|
+
nil # rcov workaround
|
16
|
+
end
|
17
|
+
super
|
18
|
+
@thread.join
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
module Connector
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def connect(wait_interval, timeout)
|
7
|
+
begin
|
8
|
+
yield
|
9
|
+
rescue DRb::DRbConnError
|
10
|
+
start = Time.now
|
11
|
+
begin
|
12
|
+
Kernel.sleep(wait_interval)
|
13
|
+
yield
|
14
|
+
rescue DRb::DRbConnError
|
15
|
+
if Time.now - start > timeout
|
16
|
+
raise
|
17
|
+
end
|
18
|
+
retry
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/tiamat/error.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class AlreadyOpenError < Error
|
7
|
+
def initialize(object)
|
8
|
+
@object = object
|
9
|
+
super("open called on object which is already open: #{@object.inspect}")
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :object
|
13
|
+
end
|
14
|
+
|
15
|
+
class RunRubyError < Error
|
16
|
+
def initialize(command, status)
|
17
|
+
@command, @status = command, status
|
18
|
+
command_str = command.map { |a| "'#{a}'" }.join(", ")
|
19
|
+
super("system(#{command_str}) failed with status #{@status}")
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :command, :status
|
23
|
+
end
|
24
|
+
end
|
data/lib/tiamat/farm.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class Farm
|
4
|
+
def initialize(servers)
|
5
|
+
@servers = servers
|
6
|
+
@available = Queue.new
|
7
|
+
|
8
|
+
@servers.each { |server|
|
9
|
+
@available.push(server)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def num_servers
|
14
|
+
@servers.size
|
15
|
+
end
|
16
|
+
|
17
|
+
def lend_server
|
18
|
+
server = @available.pop
|
19
|
+
begin
|
20
|
+
yield server
|
21
|
+
ensure
|
22
|
+
@available.push(server)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
@servers.each { |server|
|
28
|
+
server.close
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class LocalChildFarm < Farm
|
4
|
+
def initialize(num_servers, *args)
|
5
|
+
base_uri = self.class.base_uri
|
6
|
+
port_begin = self.class.port_begin
|
7
|
+
servers = (0...num_servers).map { |n|
|
8
|
+
LocalChildServer.new("#{base_uri}:#{port_begin + n}", *args)
|
9
|
+
}
|
10
|
+
super(servers)
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def base_uri
|
15
|
+
"druby://localhost"
|
16
|
+
end
|
17
|
+
|
18
|
+
def port_begin
|
19
|
+
48727
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class LocalChildServer < ChildServer
|
4
|
+
def launch(uri, compiler_name, *requires)
|
5
|
+
args = [compiler_name] + requires
|
6
|
+
Util.run_ruby(self.class.server_path, uri, *args)
|
7
|
+
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def server_basename
|
11
|
+
"tiamat-server"
|
12
|
+
end
|
13
|
+
|
14
|
+
def server_path
|
15
|
+
if server = Util.find_executable(server_basename)
|
16
|
+
server
|
17
|
+
else
|
18
|
+
File.expand_path(
|
19
|
+
File.dirname(__FILE__) + "/../../bin/" + server_basename
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class Server
|
4
|
+
include Connector
|
5
|
+
|
6
|
+
def initialize(uri)
|
7
|
+
@uri = uri
|
8
|
+
@drb_object = DRbObject.new_with_uri(uri)
|
9
|
+
connect {
|
10
|
+
@drb_object.ping
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :uri
|
15
|
+
|
16
|
+
def close
|
17
|
+
end
|
18
|
+
|
19
|
+
def evaluate_function(*args)
|
20
|
+
@drb_object.evaluate_function(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def connect(&block)
|
26
|
+
super(self.class.wait_interval, self.class.timeout, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
attr_writer :wait_interval
|
31
|
+
attr_writer :timeout
|
32
|
+
|
33
|
+
def wait_interval
|
34
|
+
@wait_interval ||= 0.02
|
35
|
+
end
|
36
|
+
|
37
|
+
def timeout
|
38
|
+
@timeout ||= 3
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
class << self
|
4
|
+
#
|
5
|
+
# Launch _num_parallel_ local Ruby interpreters.
|
6
|
+
#
|
7
|
+
# If a block is given:
|
8
|
+
# * Pure.worker is replaced for the duration of the block.
|
9
|
+
# * The return value is the block result.
|
10
|
+
# * The interpreters are stopped when the block finishes.
|
11
|
+
#
|
12
|
+
# If no block is given, an opened worker is returned. You are
|
13
|
+
# responsible for closing it.
|
14
|
+
#
|
15
|
+
def open_local(num_parallel, *requires, &block)
|
16
|
+
args = [num_parallel] + Tiamat.compiler.reverse + requires
|
17
|
+
open_worker(LocalChildWorker, *args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Connect to the already-running tiamat servers given by the URIs,
|
22
|
+
# e.g. druby://192.168.4.1:27272.
|
23
|
+
#
|
24
|
+
# If a block is given:
|
25
|
+
# * Pure.worker is replaced for the duration of the block.
|
26
|
+
# * The return value is the block result.
|
27
|
+
#
|
28
|
+
# If no block is given, an opened worker is returned. You are
|
29
|
+
# responsible for closing it.
|
30
|
+
#
|
31
|
+
def open_remote(*uris, &block)
|
32
|
+
open_worker(RemoteWorker, *uris, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :compiler
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def open_worker(worker, *args, &block)
|
40
|
+
result = worker.open(*args, &block)
|
41
|
+
if block
|
42
|
+
result
|
43
|
+
else
|
44
|
+
worker
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@compiler = nil
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#
|
2
|
+
# This is the core of bin/tiamat-server, the code which runs on the
|
3
|
+
# remote Ruby interpreter.
|
4
|
+
#
|
5
|
+
# This file is not required by the top-level tiamat.rb.
|
6
|
+
#
|
7
|
+
|
8
|
+
module Tiamat
|
9
|
+
class TiamatServer
|
10
|
+
FINISH = Queue.new
|
11
|
+
|
12
|
+
def initialize(compiler_name, *requires)
|
13
|
+
@compiler_name = compiler_name
|
14
|
+
|
15
|
+
requires.each { |path| require path }
|
16
|
+
|
17
|
+
@compiler = compiler_name.split("::").inject(Object) { |acc, name|
|
18
|
+
acc.const_get(name)
|
19
|
+
}.new
|
20
|
+
|
21
|
+
nil # rcov workaround
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :compiler_name
|
25
|
+
|
26
|
+
def evaluate_function(spec, *args)
|
27
|
+
@compiler.evaluate_function(spec, *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ping
|
31
|
+
end
|
32
|
+
|
33
|
+
def close
|
34
|
+
FINISH.push nil
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def run(uri, *args)
|
39
|
+
DRb.start_service(uri, new(*args))
|
40
|
+
begin
|
41
|
+
FINISH.pop
|
42
|
+
ensure
|
43
|
+
DRb.stop_service
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/tiamat/util.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module Tiamat
|
3
|
+
module Util
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def ruby_executable
|
7
|
+
require 'rbconfig'
|
8
|
+
name = File.join(
|
9
|
+
Config::CONFIG["bindir"],
|
10
|
+
Config::CONFIG["RUBY_INSTALL_NAME"]
|
11
|
+
)
|
12
|
+
if Config::CONFIG["host"] =~ %r!(mswin|cygwin|mingw)! and
|
13
|
+
File.basename(name) !~ %r!\.(exe|com|bat|cmd)\Z!i
|
14
|
+
name + Config::CONFIG["EXEEXT"]
|
15
|
+
else
|
16
|
+
name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def run_ruby(*args)
|
21
|
+
cmd = [ruby_executable, *args]
|
22
|
+
unless system(*cmd)
|
23
|
+
raise RunRubyError.new(cmd, $?.exitstatus)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_executable(basename)
|
28
|
+
ENV["PATH"].split(File::PATH_SEPARATOR).each { |path|
|
29
|
+
candidate = path + "/" + basename
|
30
|
+
if File.exist?(candidate)
|
31
|
+
return candidate
|
32
|
+
end
|
33
|
+
}
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|