bud 0.0.8 → 0.1.0.pre1

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.
@@ -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