bud 0.0.8 → 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,90 +0,0 @@
1
- require 'bud/deploy/deployer'
2
-
3
- module ForkDeployProtocol
4
- state do
5
- channel :child_ack, [:@loc, :node_id] => [:node_addr]
6
- end
7
- end
8
-
9
- module ForkDeployChild
10
- include ForkDeployProtocol
11
-
12
- bootstrap do
13
- child_ack <~ [[@deployer_addr, @node_id, ip_port]]
14
- end
15
- end
16
-
17
- # An implementation of the Deployer that runs instances using forked local
18
- # processes (listening on an ephemeral port).
19
- #
20
- # Note that this module is included in both the deployer process and in the
21
- # deployed instances. To write code that only runs in one type of process,
22
- # consult the ":deploy" Bud option (which is false in deployed children).
23
- module ForkDeploy
24
- include Deployer
25
- include ForkDeployProtocol
26
-
27
- def initialize(opts={})
28
- super
29
- @child_modules = [ForkDeployChild]
30
- @child_pids = []
31
- @dead_pids = []
32
- end
33
-
34
- bloom :child_info do
35
- node <= child_ack {|a| [a.node_id, a.node_addr]}
36
- node_ready <= child_ack {|a| [a.node_id]}
37
- end
38
-
39
- bootstrap do
40
- return unless @options[:deploy]
41
-
42
- Signal.trap("CHLD") do
43
- # We receive SIGCHLD when a child process changes state; unfortunately,
44
- # there's no easy way to tell whether the child process we're getting the
45
- # signal for is one of ForkDeploy's children. Hence, check if any of the
46
- # forked children have exited. We also ignore Errno::ECHILD, because
47
- # someone else's waitpid() could easily race with us.
48
- @child_pids.each do |c|
49
- begin
50
- pid = Process.waitpid(c, Process::WNOHANG)
51
- unless pid.nil?
52
- @dead_pids << pid
53
- end
54
- rescue Errno::ECHILD
55
- end
56
- end
57
- end
58
-
59
- on_shutdown do
60
- # NB: Setting the SIGCHLD handler to "IGNORE" results in waitpid() being
61
- # called automatically (to cleanup zombies), at least on OSX. This is not
62
- # what we want, since it would cause a subsequent waitpid() to fail.
63
- Signal.trap("CHLD", "DEFAULT")
64
- pids = @child_pids - @dead_pids
65
- pids.each do |p|
66
- begin
67
- Process.kill("TERM", p)
68
- Process.waitpid(p)
69
- rescue Errno::ESRCH
70
- end
71
- end
72
- end
73
-
74
- child_opts = @options[:deploy_child_opts]
75
- child_opts ||= {}
76
- deployer_addr = self.ip_port
77
- node_count[[]].num.times do |i|
78
- @child_pids << Bud.do_fork do
79
- @child_modules.each do |m|
80
- # XXX: Can this be done without "instance_eval"?
81
- self.class.instance_eval "include #{m}"
82
- end
83
- child = self.class.new(child_opts)
84
- child.instance_variable_set('@deployer_addr', deployer_addr)
85
- child.instance_variable_set('@node_id', i)
86
- child.run_fg
87
- end
88
- end
89
- end
90
- end
@@ -1,38 +0,0 @@
1
- require 'bud/deploy/deployer'
2
-
3
- # An implementation of the Deployer that runs instances using the current Ruby
4
- # process (listening on an ephemeral port). ThreadDeploy is probably not the
5
- # best name: all the spawned instances are run by a single thread, they are just
6
- # multiplexed via EventMachine.
7
- #
8
- # Note that this module is included in both the deployer process and in the
9
- # deployed instances. To write code that only runs in one type of process,
10
- # consult the ":deploy" Bud option (which is false in deployed children).
11
- module ThreadDeploy
12
- include Deployer
13
-
14
- bootstrap do
15
- return unless @options[:deploy]
16
-
17
- @instances = []
18
- on_shutdown do
19
- @instances.each {|b| b.stop}
20
- end
21
-
22
- print "Spawning threads"
23
- child_opts = @options[:deploy_child_opts]
24
- child_opts ||= {}
25
- deployer_addr = self.ip_port
26
- node_count[[]].num.times do |i|
27
- b = self.class.new(child_opts)
28
- b.instance_variable_set('@deployer_addr', deployer_addr)
29
- b.instance_variable_set('@node_id', i)
30
- b.run_bg
31
- @instances << b
32
- node << [i, b.ip_port]
33
- node_ready << [i]
34
- print "."
35
- end
36
- puts "done"
37
- end
38
- end
@@ -1,190 +0,0 @@
1
- begin
2
- require 'tokyocabinet'
3
- Bud::HAVE_TOKYOCABINET = true
4
- rescue LoadError
5
- end
6
-
7
- module Bud
8
- # Persistent table implementation based on TokyoCabinet.
9
- class BudTcTable < BudCollection # :nodoc: all
10
- def initialize(name, bud_instance, given_schema)
11
- tc_dir = bud_instance.options[:tc_dir]
12
- raise Bud::Error, "TC support must be enabled via 'tc_dir'" unless tc_dir
13
- if bud_instance.port.nil?
14
- raise Bud::Error, "use of dbm storage requires an explicit port to be specified in Bud initialization options"
15
- end
16
-
17
- unless File.exists?(tc_dir)
18
- Dir.mkdir(tc_dir)
19
- puts "Created directory: #{tc_dir}" unless bud_instance.options[:quiet]
20
- end
21
-
22
- dirname = "#{tc_dir}/bud_#{bud_instance.port}"
23
- unless File.exists?(dirname)
24
- Dir.mkdir(dirname)
25
- puts "Created directory: #{dirname}" unless bud_instance.options[:quiet]
26
- end
27
-
28
- super(name, bud_instance, given_schema)
29
- @to_delete = []
30
-
31
- @hdb = TokyoCabinet::HDB.new
32
- db_fname = "#{dirname}/#{name}.tch"
33
- flags = TokyoCabinet::HDB::OWRITER | TokyoCabinet::HDB::OCREAT
34
- if bud_instance.options[:tc_truncate] == true
35
- flags |= TokyoCabinet::HDB::OTRUNC
36
- end
37
- if !@hdb.open(db_fname, flags)
38
- raise Bud::Error, "failed to open TokyoCabinet DB '#{db_fname}': #{@hdb.errmsg}"
39
- end
40
- @hdb.tranbegin
41
- end
42
-
43
- def init_storage
44
- # XXX: we can't easily use the @storage infrastructure provided by
45
- # BudCollection; issue #33
46
- @storage = nil
47
- end
48
-
49
- def [](key)
50
- check_enumerable(key)
51
- key_s = MessagePack.pack(key)
52
- val_s = @hdb[key_s]
53
- if val_s
54
- return make_tuple(key, MessagePack.unpack(val_s))
55
- else
56
- return @delta[key]
57
- end
58
- end
59
-
60
- def has_key?(k)
61
- check_enumerable(k)
62
- key_s = MessagePack.pack(k)
63
- return true if @hdb.has_key? key_s
64
- return @delta.has_key? k
65
- end
66
-
67
- def include?(tuple)
68
- key = get_key_vals(tuple)
69
- value = self[key]
70
- return (value == tuple)
71
- end
72
-
73
- def make_tuple(k_ary, v_ary)
74
- t = Array.new(k_ary.length + v_ary.length)
75
- @key_colnums.each_with_index do |k,i|
76
- t[k] = k_ary[i]
77
- end
78
- val_cols.each_with_index do |c,i|
79
- t[cols.index(c)] = v_ary[i]
80
- end
81
- tuple_accessors(t)
82
- end
83
-
84
- def each(&block)
85
- each_from([@delta], &block)
86
- each_storage(&block)
87
- end
88
-
89
- def each_from(bufs, &block)
90
- bufs.each do |b|
91
- if b == @storage then
92
- each_storage(&block)
93
- else
94
- b.each_value do |v|
95
- tick_metrics if bud_instance.options[:metrics]
96
- yield v
97
- end
98
- end
99
- end
100
- end
101
-
102
- def each_storage(&block)
103
- @hdb.each do |k,v|
104
- k_ary = MessagePack.unpack(k)
105
- v_ary = MessagePack.unpack(v)
106
- tick_metrics if bud_instance.options[:metrics]
107
- yield make_tuple(k_ary, v_ary)
108
- end
109
- end
110
-
111
- def flush
112
- @hdb.trancommit
113
- end
114
-
115
- def close
116
- @hdb.close
117
- end
118
-
119
- def merge_to_hdb(buf)
120
- buf.each do |key,tuple|
121
- merge_tuple_to_hdb(key, tuple)
122
- end
123
- end
124
-
125
- def merge_tuple_to_hdb(key, tuple)
126
- val = val_cols.map{|c| tuple[cols.index(c)]}
127
- key_s = MessagePack.pack(key)
128
- val_s = MessagePack.pack(val)
129
- if @hdb.putkeep(key_s, val_s) == false
130
- old_tuple = self[key]
131
- raise_pk_error(tuple, old_tuple) if tuple != old_tuple
132
- end
133
- end
134
-
135
- # move deltas to TC, and new_deltas to deltas
136
- def tick_deltas
137
- merge_to_hdb(@delta)
138
- @delta = @new_delta
139
- @new_delta = {}
140
- end
141
-
142
- superator "<-" do |o|
143
- o.each do |tuple|
144
- @to_delete << tuple unless tuple.nil?
145
- end
146
- end
147
-
148
- def insert(tuple)
149
- tuple = prep_tuple(tuple)
150
- key = get_key_vals(tuple)
151
- merge_tuple_to_hdb(key, tuple)
152
- end
153
-
154
- alias << insert
155
-
156
- # Remove to_delete and then add pending to HDB
157
- def tick
158
- raise Bud::Error, "orphaned tuples in @delta for #{@tabname}" unless @delta.empty?
159
- raise Bud::Error, "orphaned tuples in @new_delta for #{@tabname}" unless @new_delta.empty?
160
-
161
- @to_delete.each do |tuple|
162
- k = get_key_vals(tuple)
163
- k_str = MessagePack.pack(k)
164
- cols_str = @hdb[k_str]
165
- unless cols_str.nil?
166
- hdb_cols = MessagePack.unpack(cols_str)
167
- delete_cols = val_cols.map{|c| tuple[cols.index(c)]}
168
- if hdb_cols == delete_cols
169
- @hdb.delete k_str
170
- end
171
- end
172
- end
173
- @to_delete = []
174
-
175
- merge_to_hdb(@pending)
176
- @pending = {}
177
-
178
- @hdb.trancommit
179
- @hdb.tranbegin
180
- end
181
-
182
- def length
183
- @hdb.length
184
- end
185
-
186
- def empty?
187
- @hdb.empty?
188
- end
189
- end
190
- end
data/lib/bud/stratify.rb DELETED
@@ -1,85 +0,0 @@
1
- require 'rubygems'
2
- require 'bud'
3
-
4
- class Stratification # :nodoc: all
5
- include Bud
6
-
7
- state do
8
- # Data inserted by client (Bud rewrite code)
9
- table :depends, [:rule, :head, :op, :body, :neg]
10
-
11
- # Intermediate state
12
- scratch :depends_clean, [:head, :body, :neg, :temporal]
13
- scratch :depends_tc, [:head, :body, :via, :neg, :temporal]
14
- scratch :stratum_base, [:predicate, :stratum]
15
-
16
- # Output state
17
- scratch :cycle, [:predicate, :via, :neg, :temporal]
18
- scratch :stratum, [:predicate, :stratum]
19
- scratch :top_strat, [:stratum]
20
- end
21
-
22
- def declaration
23
- strata[0] = lambda {
24
- depends_clean <= depends do |d|
25
- is_temporal = (d.op.to_s =~ /<[\+\-\~]/)
26
- [d.head, d.body, d.neg, is_temporal]
27
- end
28
-
29
- # Compute the transitive closure of "depends_clean" to detect cycles in
30
- # the deductive fragment of the program.
31
- depends_tc <= depends_clean do |d|
32
- [d.head, d.body, d.body, d.neg, d.temporal]
33
- end
34
- depends_tc <= (depends_clean * depends_tc).pairs(:body => :head) do |b, r|
35
- [b.head, r.body, b.body, (b.neg or r.neg), (b.temporal or r.temporal)]
36
- end
37
-
38
- cycle <= depends_tc do |d|
39
- if d.head == d.body
40
- if d.neg and !d.temporal
41
- raise Bud::CompileError, "unstratifiable program: #{d.inspect}"
42
- else
43
- [d.head, d.via, d.neg, d.temporal]
44
- end
45
- end
46
- end
47
-
48
- # we initially assign all predicates to stratum 0
49
- stratum_base <= depends {|d| [d.body, 0]}
50
- }
51
-
52
- strata[1] = lambda {
53
- # classic stratification:
54
- # if A depends on B, A is >= B.
55
- # if A depends nonmonotonically on B, A > B.
56
- # if A are B are nonmonotonically co-dependent, give up.
57
- # (don't need to do this, b/c we've ruled out deductive cycles)
58
- #
59
- # Stratum choice controls local evaluation order, so we need only consider
60
- # deductive rules (<=). Temporal rules are placed in an extra "top"
61
- # stratum afterward.
62
- stratum_base <= (depends * stratum_base).pairs(:body => :predicate) do |d, s|
63
- if d.op.to_s == '<='
64
- if d.neg
65
- # BUMP
66
- [d.head, s.stratum + 1]
67
- else
68
- # HOIST
69
- [d.head, s.stratum]
70
- end
71
- end
72
- end
73
- }
74
-
75
- strata[2] = lambda {
76
- stratum <= stratum_base.group([stratum_base.predicate], max(stratum_base.stratum))
77
- }
78
-
79
- strata[3] = lambda {
80
- # there is no good reason that top_strat can't be computed in strata[2] over stratum_base.
81
- # however, when it is deduced that way, it is empty after a tick
82
- top_strat <= stratum.group([], max(stratum.stratum))
83
- }
84
- end
85
- end