abundance 1.2.3 → 1.2.4

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/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