abundance 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/abundance.rb CHANGED
@@ -2,10 +2,10 @@
2
2
  # Based on the low maintenance Gardener,Garden,Seed natural design pattern.
3
3
  #
4
4
  # Its for:
5
- # * forking otherwise blocking loops in a non-blocking fashion
5
+ # * running otherwise blocking loops in a non-blocking fashion
6
6
  # * a simple abstraction for loopback communication with a forked execution
7
7
  # * concurrent batch processing
8
- # * scaling process intensive computations to multi-core parallel execution
8
+ # * scaling process intensive computations for SMP execution
9
9
  #
10
10
  # And not:
11
11
  # * a replacement for Thread.new invocations
@@ -14,7 +14,7 @@
14
14
  # Its initial implementation uses:
15
15
  # * pure ruby
16
16
  # * standard forks as mean to parallel non-blocking execution
17
- # * fast UDP loopback sockets for process fork communication.
17
+ # * fast loopback sockets for process fork communication.
18
18
  # * serialization friendly communication with process forks
19
19
  # * a tier queuing fork, as a packet control middle man between process forks and the non-blocking process client
20
20
  # * an elemental namespace: a process queue, named the Garden, with concurrent workers, named Rows, all this getting orchestrated by a Gardener.
data/lib/garden.rb CHANGED
@@ -56,8 +56,6 @@ class Garden
56
56
  ask_for_init_status(message_block)
57
57
  when :init_crop
58
58
  answer_init_status(message_block)
59
- when :seed_all
60
- seed_for_all_rows(message_block)
61
59
  when :seed_all_crop
62
60
  special_crop_seed_all(message_block)
63
61
  when :close
data/lib/garden_cycles.rb CHANGED
@@ -5,7 +5,7 @@ class Garden
5
5
  module Cycles
6
6
 
7
7
  def set_my_containers
8
- @quit = false; @full_crop = false; @do_init = nil; @seed_all = nil; @init_all_crop = []
8
+ @quit = false; @full_crop = false; @do_init = nil; @seed_all_message_block = nil; @init_all_crop = []
9
9
  @harvest = []; @rows_socket_paths = []; @init_done = []; @seed_all_done = []; @seed_all_crop = []
10
10
  @seeds = []; @sprouts = []; @crops = []; @id = 0
11
11
  end
@@ -13,10 +13,10 @@ class Garden
13
13
  def seed_if_row_available
14
14
  catch :fill_rows do
15
15
  loop do
16
- if ! @seed_all.nil? && ! @rows_socket_paths.empty? && @seed_all_done.size != @seed_all[0]
16
+ if ! @seed_all_message_block.nil? && ! @rows_socket_paths.empty? && @seed_all_done.size != @seed_all_message_block[1]
17
17
  row_socket_path = @rows_socket_paths.shift
18
18
  unless @seed_all_done.include?( row_socket_path )
19
- socket_send(:seed_all,:garden,@seed_all[1],row_socket_path)
19
+ socket_send([:seed,:all,@seed_all_message_block[2],row_socket_path])
20
20
  @seed_all_done << row_socket_path
21
21
  else
22
22
  @rows_socket_paths << row_socket_path
@@ -24,7 +24,7 @@ class Garden
24
24
  elsif ! @do_init.nil? && ! @rows_socket_paths.empty? && @init_done.size != @do_init
25
25
  row_socket_path = @rows_socket_paths.shift
26
26
  unless @init_done.include?( row_socket_path )
27
- socket_send(:init,:garden,'init_status',row_socket_path)
27
+ socket_send([:seed,:init,'init_status',row_socket_path])
28
28
  @init_done << row_socket_path
29
29
  else
30
30
  @rows_socket_paths << row_socket_path
@@ -33,11 +33,11 @@ class Garden
33
33
  seed = @seeds.shift
34
34
  @sprouts[seed[:id]] = seed
35
35
  row_socket_path = @rows_socket_paths.shift
36
- socket_send(:sprout,:garden,seed,row_socket_path)
36
+ socket_send([:seed,:sprout,seed,row_socket_path])
37
37
  elsif @quit && ! @rows_socket_paths.empty?
38
38
  seed = nil
39
39
  row_socket_path = @rows_socket_paths.shift
40
- socket_send(:quit,:garden,seed,row_socket_path)
40
+ socket_send([:seed,:quit,seed,row_socket_path])
41
41
  else
42
42
  throw :fill_rows
43
43
  end
@@ -46,29 +46,42 @@ class Garden
46
46
  end
47
47
 
48
48
  def place_seed_in_queue(message_block)
49
- @id += 1; @seeds << {:id => @id , :seed => message_block[2]}
50
- socket_send(message_block[0],:garden,@id,message_block[3])
49
+ case message_block[1]
50
+ when :one
51
+ @id += 1; @seeds << {:id => @id , :seed => message_block[2]}
52
+ socket_send([message_block[0],:garden,@id,message_block[3]])
53
+ else
54
+ @seed_all_message_block = Array.new(message_block)
55
+ end
51
56
  end
52
57
 
53
58
  def this_row_is_available(message_block)
54
59
  if @quit
55
- message_block[0] = :quit; seed = nil
60
+ message_block = [:row, :quit, nil, message_block[3]]
61
+ elsif ! @seed_all_message_block.nil? && @seed_all_done.size != @seed_all_message_block[1] && ! @seed_all_done.include?( message_block[3] )
62
+ message_block = [:row, :all, @seed_all_message_block[2], message_block[3]]
63
+ @seed_all_done << message_block[3]
64
+ elsif ! @do_init.nil? && @init_done.size != @do_init && ! @init_done.include?( message_block[3] )
65
+ message_block = [:row, :init, 'init_status', message_block[3]]
66
+ @init_done << message_block[3]
56
67
  elsif @seeds.empty?
57
- seed = nil; @rows_socket_paths << message_block[2]
68
+ @rows_socket_paths << message_block[2]
69
+ message_block = [:row, :wait, nil, message_block[3]]
58
70
  else
59
71
  seed = @seeds.shift; @sprouts[seed[:id]] = seed
72
+ message_block = [:row, :sprout, seed, message_block[3]]
60
73
  end
61
- socket_send(message_block[0],:garden,seed,message_block[3])
74
+ socket_send(message_block)
62
75
  end
63
76
 
64
77
  def save_crop_for(message_block)
65
78
  @sprouts[message_block[2][:id]] = nil
66
79
  @crops[message_block[2][:id]] = message_block[2]
67
80
  if @harvest[message_block[2][:id]]
68
- socket_send(message_block[0],:garden,message_block[2], @harvest[message_block[2][:id]][:client_socket_path])
81
+ socket_send([message_block[0],:garden,message_block[2], @harvest[message_block[2][:id]][:client_socket_path]])
69
82
  @crops[message_block[2][:id]] = @harvest[message_block[2][:id]] = nil
70
83
  elsif @full_crop && @seeds.compact.empty? && @sprouts.compact.empty?
71
- socket_send(message_block[0],:garden,@crops.compact,@mem_client_socket_path)
84
+ socket_send([message_block[0],:garden,@crops.compact,@mem_client_socket_path])
72
85
  @crops.clear; @full_crop = false
73
86
  end
74
87
  end
@@ -78,32 +91,32 @@ class Garden
78
91
  when :progress
79
92
  value = @crops.size.to_f / (@crops.size + @sprouts.compact.size + @seeds.size)
80
93
  value = 1 if value.nan?; progress = sprintf( "%.2f", value)
81
- socket_send(message_block[0],:garden,progress,message_block[3])
94
+ socket_send([message_block[0],:garden,progress,message_block[3]])
82
95
  when :seed
83
- socket_send(message_block[0],:garden,@seeds.size,message_block[3])
96
+ socket_send([message_block[0],:garden,@seeds.size,message_block[3]])
84
97
  when :sprout
85
- socket_send(message_block[0],:garden,@sprouts.compact.size,message_block[3])
98
+ socket_send([message_block[0],:garden,@sprouts.compact.size,message_block[3]])
86
99
  when :crop
87
- socket_send(message_block[0],:garden,@crops.size,message_block[3])
100
+ socket_send([message_block[0],:garden,@crops.size,message_block[3]])
88
101
  else
89
- socket_send(message_block[0],:garden,false,message_block[3])
102
+ socket_send([message_block[0],:garden,false,message_block[3]])
90
103
  end
91
104
  end
92
105
 
93
106
  def harvest_some(message_block)
94
107
  case message_block[2]
95
108
  when :all
96
- socket_send(message_block[0],:garden,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact},message_block[3])
109
+ socket_send([message_block[0],:garden,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact},message_block[3]])
97
110
  when :seed
98
- socket_send(message_block[0],:garden,@seeds,message_block[3])
111
+ socket_send([message_block[0],:garden,@seeds,message_block[3]])
99
112
  when :sprout
100
- socket_send(message_block[0],:garden,@sprouts.compact,message_block[3])
113
+ socket_send([message_block[0],:garden,@sprouts.compact,message_block[3]])
101
114
  when :crop
102
- socket_send(message_block[0],:garden,@crops.compact,message_block[3])
115
+ socket_send([message_block[0],:garden,@crops.compact,message_block[3]])
103
116
  @crops.clear
104
117
  when :full_crop
105
118
  if @seeds.compact.empty? && @sprouts.compact.empty?
106
- socket_send(message_block[0],:garden,@crops.compact,message_block[3])
119
+ socket_send([message_block[0],:garden,@crops.compact,message_block[3]])
107
120
  @crops.clear
108
121
  else
109
122
  @full_crop = true
@@ -112,13 +125,13 @@ class Garden
112
125
  else
113
126
  if message_block[2].is_a? Integer
114
127
  if @crops[message_block[2]]
115
- socket_send(message_block[0],:garden,@crops[message_block[2]],message_block[3])
128
+ socket_send([message_block[0],:garden,@crops[message_block[2]],message_block[3]])
116
129
  @crops[message_block[2]] = nil
117
130
  else
118
131
  @harvest[message_block[2]] = {:client_socket_path => message_block[3]}
119
132
  end
120
133
  else
121
- socket_send(message_block[0],:garden,false,message_block[3])
134
+ socket_send([message_block[0],:garden,false,message_block[3]])
122
135
  end
123
136
  end
124
137
  end
@@ -131,21 +144,16 @@ class Garden
131
144
  def answer_init_status(message_block)
132
145
  @init_all_crop << message_block[2]
133
146
  if @init_all_crop.size == @do_init
134
- socket_send(message_block[0],:garden,@init_all_crop, @init_return[:client_socket_path])
147
+ socket_send([message_block[0],:garden,@init_all_crop, @init_return[:client_socket_path]])
135
148
  @init_return = Hash.new; @init_done = Array.new; @do_init = nil; @init_all_crop = Array.new
136
149
  end
137
150
  end
138
151
 
139
- def seed_for_all_rows(message_block)
140
- @seed_all = message_block[2]
141
- @seed_all_return = {:client_socket_path => message_block[3], :data => []}
142
- end
143
-
144
152
  def special_crop_seed_all(message_block)
145
153
  @seed_all_crop << message_block[2]
146
- if @seed_all_crop.size == @seed_all[0]
147
- socket_send(message_block[0],:garden,@seed_all_crop, @seed_all_return[:client_socket_path])
148
- @seed_all = nil; @seed_all_return = Hash.new; @seed_all_done = Array.new; @seed_all_crop = Array.new
154
+ if @seed_all_crop.size == @seed_all_message_block[1]
155
+ socket_send([message_block[0],:garden,@seed_all_crop, @seed_all_message_block[3]])
156
+ @seed_all_message_block = nil; @seed_all_done = Array.new; @seed_all_crop = Array.new
149
157
  end
150
158
  end
151
159
 
@@ -157,7 +165,7 @@ class Garden
157
165
  else
158
166
  @seeds_pid.delete(message_block[2][:pid].to_i)
159
167
  if @seeds_pid.empty?
160
- socket_send(:close,:garden,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact}, @mem_client_socket_path)
168
+ socket_send([:close,:garden,{:seeds => @seeds, :sprouts => @sprouts.compact, :crops => @crops.compact}, @mem_client_socket_path])
161
169
  exit
162
170
  end
163
171
  end
data/lib/garden_rows.rb CHANGED
@@ -51,32 +51,43 @@ class Garden
51
51
  t2 = Thread.new do
52
52
  loop do
53
53
  if $seed.nil?
54
- message_block = socket_duplex(:row,:row,my_socket_path)
55
- if message_block[0] == :quit
56
- pid = Process.pid
57
- socket_send(:close,:row,{:level => :seed, :pid => pid})
58
- exit
59
- end
60
- $seed = message_block[2]
61
- if $seed.nil?
54
+ message_block = socket_duplex([:row,:row,my_socket_path,@garden_path])
55
+ case message_block[1]
56
+ when :sprout
57
+ $seed = message_block[2]
58
+ when :all
59
+ @seed_all = true
60
+ $seed = {:id => Process.pid, :seed => message_block[2]}
61
+ when :wait
62
62
  message_block = socket_recv
63
- case message_block[0]
63
+ case message_block[1]
64
64
  when :sprout
65
65
  $seed = message_block[2]
66
- when :seed_all
66
+ when :all
67
67
  @seed_all = true
68
68
  $seed = {:id => Process.pid, :seed => message_block[2]}
69
69
  when :init
70
70
  $init = {:seed => 'init_status', :message => 'No Init Message', :id => Process.pid} if $init.nil?
71
- socket_send(:init_crop,:row,$init)
71
+ socket_send([:init_crop,:row,$init,@garden_path])
72
+ when :quit
73
+ pid = Process.pid
74
+ socket_send([:close,:row,{:level => :seed, :pid => pid},@garden_path])
75
+ exit
72
76
  end
77
+ when :init
78
+ $init = {:seed => 'init_status', :message => 'No Init Message', :id => Process.pid} if $init.nil?
79
+ socket_send([:init_crop,:row,$init,@garden_path])
80
+ when :quit
81
+ pid = Process.pid
82
+ socket_send([:close,:row,{:level => :seed, :pid => pid},@garden_path])
83
+ exit
73
84
  end
74
85
  elsif ! $seed[:success].nil?
75
86
  if @seed_all
76
- socket_send(:seed_all_crop,:row,$seed)
87
+ socket_send([:seed_all_crop,:row,$seed,@garden_path])
77
88
  @seed_all = false
78
89
  else
79
- socket_send(:crop,:row,$seed)
90
+ socket_send([:crop,:row,$seed,@garden_path])
80
91
  end
81
92
  $seed = nil;
82
93
  else
data/lib/gardener.rb CHANGED
@@ -48,7 +48,7 @@ class Gardener
48
48
  # === Example
49
49
  # puts gardener.init_status.inspect # => [{:message=>"init ok", :success=>true, :pid=>4760}, {:message=>"init failed", :success=>false, :pid=>4761}]
50
50
  def init_status
51
- message_block = socket_duplex(:init,:gardener,@garden_rows.pids.size)
51
+ message_block = socket_duplex([:init,:gardener,@garden_rows.pids.size,@garden_path])
52
52
  message_block[2].map! do |row|
53
53
  {:success => row[:success], :message => row[:message], :pid => row[:id]}
54
54
  end
@@ -62,7 +62,7 @@ class Gardener
62
62
  # id_seed_1 = gardener.seed("system 'ruby -v'")
63
63
 
64
64
  def seed(data)
65
- message_block = socket_duplex(:seed,:gardener,data)
65
+ message_block = socket_duplex([:seed,:one,data,@garden_path])
66
66
  return message_block[2]
67
67
  end
68
68
 
@@ -74,8 +74,7 @@ class Gardener
74
74
  # result = gardener.seed_all("pref local") # => [{:success=>true, :message=>["row pref changed to local"], :seed=>"pref local", :pid=>14915},
75
75
  # {:success=>true, :message=>["row pref changed to local"], :seed=>"pref local", :pid=>14913}]
76
76
  def seed_all(data)
77
- seed = [@garden_rows.pids.size, data]
78
- message_block = socket_duplex(:seed_all,:gardener,seed)
77
+ message_block = socket_duplex([:seed,@garden_rows.pids.size,data,@garden_path])
79
78
  message_block[2].map! do |row|
80
79
  {:success => row[:success], :message => row[:message], :pid => row[:id]}
81
80
  end
@@ -94,7 +93,7 @@ class Gardener
94
93
  # puts "progress is now #{progress}" # => progress is now 0.75
95
94
 
96
95
  def growth(data=:progress)
97
- message_block = socket_duplex(:growth,:gardener,data)
96
+ message_block = socket_duplex([:growth,:gardener,data,@garden_path])
98
97
  return message_block[2]
99
98
  end
100
99
 
@@ -113,7 +112,7 @@ class Gardener
113
112
  # seed1_result = gardener.harvest(id_seed_1)
114
113
 
115
114
  def harvest(data)
116
- message_block = socket_duplex(:harvest,:gardener,data)
115
+ message_block = socket_duplex([:harvest,:gardener,data,@garden_path])
117
116
  return message_block[2]
118
117
  end
119
118
 
@@ -123,7 +122,7 @@ class Gardener
123
122
  # final_harvest = gardener.close
124
123
 
125
124
  def close
126
- message_block = socket_duplex(:close,:gardener,{:level => :garden, :pid => @garden_rows.pids})
125
+ message_block = socket_duplex([:close,:gardener,{:level => :garden, :pid => @garden_rows.pids},@garden_path])
127
126
  return message_block[2]
128
127
  end
129
128
 
data/lib/toolshed.rb CHANGED
@@ -52,8 +52,8 @@ module Toolshed
52
52
  # * _command_ = command part of the sent packet
53
53
  # * _data_ = data part of the sent packet
54
54
  # * _server_socket_path_ = a UNIXServer socket path for the packets to be sent to
55
- def socket_send(command,option,data,server_socket_path=@garden_path)
56
- send_block(command,option,data,server_socket_path)
55
+ def socket_send(message_block)
56
+ send_block(message_block)
57
57
  end
58
58
 
59
59
  # The +socket_duplex+ method open a UNIXSocket and send packets to a UNIXServer socket, then wait for loopback communication from destination and return results like +socket_recv+.
@@ -61,8 +61,8 @@ module Toolshed
61
61
  # * _command_ = command part of the sent packet
62
62
  # * _data_ = data part of the sent packet
63
63
  # * _server_socket_path_ = a UNIXServer socket path for the packets to be sent to
64
- def socket_duplex(command,option,data,server_socket_path=@garden_path)
65
- send_block(command,option,data,server_socket_path)
64
+ def socket_duplex(message_block)
65
+ send_block(message_block)
66
66
  Marshal.load(recv_whole_block)
67
67
  end
68
68
 
@@ -121,10 +121,10 @@ module Toolshed
121
121
  # * _command_ = command part of the sent packet
122
122
  # * _data_ = data part of the sent packet
123
123
  # * _server_socket_path_ = the UNIXServer socket path to send to
124
- def send_block(command,option,data,server_socket_path)
124
+ def send_block(message_block)
125
125
  begin
126
- client = UNIXSocket.open(server_socket_path)
127
- client.send(Marshal.dump([command,option,data,@my_socket_path]),0)
126
+ client = UNIXSocket.open(message_block[3])
127
+ client.send(Marshal.dump(message_block[0..2] + [@my_socket_path]),0)
128
128
  client.close
129
129
  rescue Errno::EADDRINUSE
130
130
  retry
data/test/tc_burst.rb ADDED
@@ -0,0 +1,84 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ require 'test/unit'
3
+ require 'abundance'
4
+
5
+ class TestHighAPI < Test::Unit::TestCase
6
+
7
+ def test_burst1
8
+ check_init
9
+ seed_1000x10
10
+ check_init
11
+ seed_2000
12
+ check_seed_all
13
+ seed_2000
14
+ check_crop
15
+ end
16
+
17
+
18
+ def setup
19
+ @g = Abundance.gardener(:wheelbarrow => 124, :rows => 8, :init_timeout => 2) do
20
+ Abundance.init_status(true,Process.pid)
21
+ Abundance.grow do |seed|
22
+ sprout = seed.sprout
23
+ if sprout.is_a?(Hash)
24
+ seed.crop(true, "gardener: #{sprout[:jo]} - #{sprout[:lo]}")
25
+ elsif sprout.is_a?(Array)
26
+ result = sprout[0] ** sprout[1]
27
+ seed.crop(true, "gardener: #{result.to_s}")
28
+ else
29
+ seed.crop(true, "????????????????")
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ def teardown
36
+ @g.close
37
+ end
38
+
39
+ private
40
+
41
+ def seed_1000x10
42
+ (1..1000).each do |num1|
43
+ (1..10).each do |num2|
44
+ @g.seed([num1,num2])
45
+ end
46
+ end
47
+ end
48
+
49
+ def seed_2000
50
+ seed = {:jo => 'ker', :lo => 'ver'}
51
+ 2000.times do
52
+ @g.seed(seed)
53
+ end
54
+ end
55
+
56
+ def check_init
57
+ @g.init_status.each do |init|
58
+ assert_not_nil(init[:message])
59
+ assert_not_nil(init[:success])
60
+ assert_not_nil(init[:pid])
61
+
62
+ assert_not_equal(Process.pid,init[:message])
63
+ assert_equal(init[:message],init[:pid])
64
+ end
65
+ end
66
+
67
+ def check_seed_all
68
+ all = @g.seed_all([1000,1000])
69
+ assert_equal(8,all.size)
70
+ all.map! { |seed| seed[:message] == "gardener: #{(1000**1000).to_s}" }
71
+ assert( all.uniq.size == 1 && all[0] == true )
72
+ end
73
+
74
+ def check_crop
75
+ crop = @g.harvest(:full_crop)
76
+ assert_equal(14000,crop.size)
77
+ assert_kind_of(Array,crop)
78
+ assert_kind_of(Hash,crop[0])
79
+ assert( ! crop[0][:success].nil? && (crop[0][:success] == true || crop[0][:success] == false))
80
+ assert(crop[0][:seed].class == Array || crop[0][:seed].class == Hash)
81
+ assert_kind_of(String,crop[0][:message])
82
+ assert_kind_of(Numeric,crop[0][:id])
83
+ end
84
+ end
data/test/ts_abundance.rb CHANGED
@@ -2,4 +2,5 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
2
  require 'test/unit'
3
3
  require 'test/tc_high_api'
4
4
  require 'test/tc_robustness'
5
- require 'test/tc_multi_gardener'
5
+ require 'test/tc_multi_gardener'
6
+ require 'test/tc_burst'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abundance
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Louis-Philippe Perron
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-14 00:00:00 -05:00
12
+ date: 2009-01-16 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -29,6 +29,7 @@ files:
29
29
  - lib/gardener.rb
30
30
  - lib/seed.rb
31
31
  - lib/toolshed.rb
32
+ - test/tc_burst.rb
32
33
  - test/tc_high_api.rb
33
34
  - test/tc_multi_gardener.rb
34
35
  - test/tc_robustness.rb