bud 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -3
- data/bin/budvis +0 -66
- data/docs/README.md +27 -15
- data/docs/bust.md +1 -1
- data/docs/cheat.md +79 -30
- data/docs/operational.md +8 -4
- data/examples/basics/paths.rb +5 -3
- data/lib/bud/aggs.rb +1 -1
- data/lib/bud/bud_meta.rb +11 -2
- data/lib/bud/bust/bust.rb +1 -1
- data/lib/bud/collections.rb +78 -20
- data/lib/bud/deploy/threaddeploy.rb +1 -1
- data/lib/bud/errors.rb +3 -0
- data/lib/bud/graphs.rb +25 -26
- data/lib/bud/joins.rb +78 -33
- data/lib/bud/metrics.rb +43 -0
- data/lib/bud/monkeypatch.rb +1 -1
- data/lib/bud/rebl.rb +20 -13
- data/lib/bud/rewrite.rb +217 -39
- data/lib/bud/server.rb +16 -13
- data/lib/bud/state.rb +39 -25
- data/lib/bud/storage/dbm.rb +6 -1
- data/lib/bud/storage/tokyocabinet.rb +6 -0
- data/lib/bud/storage/zookeeper.rb +6 -6
- data/lib/bud/viz.rb +5 -1
- data/lib/bud/viz_util.rb +70 -0
- data/lib/bud.rb +227 -99
- metadata +33 -24
- data/docs/c.html +0 -251
- data/examples/deploy/deploy_ip_port +0 -1
- data/examples/deploy/keys.rb +0 -5
- data/lib/bud.rb.orig +0 -806
data/lib/bud/errors.rb
CHANGED
data/lib/bud/graphs.rb
CHANGED
@@ -27,18 +27,16 @@ class GraphGen #:nodoc: all
|
|
27
27
|
cycle.each do |c|
|
28
28
|
# assumption: !(c[2] and !c[3]), or stratification would have bombed out
|
29
29
|
if c[2] and c[3]
|
30
|
-
|
31
|
-
@redcycle[c[0]] = []
|
32
|
-
end
|
30
|
+
@redcycle[c[0]] ||= []
|
33
31
|
@redcycle[c[0]] << c[1]
|
34
|
-
end
|
32
|
+
end
|
35
33
|
end
|
36
|
-
|
34
|
+
|
37
35
|
@nodes = {}
|
38
36
|
@edges = {}
|
39
37
|
@labels = {}
|
40
38
|
end
|
41
|
-
|
39
|
+
|
42
40
|
def name_bag(predicate, bag)
|
43
41
|
if bag[predicate]
|
44
42
|
return bag
|
@@ -46,10 +44,10 @@ class GraphGen #:nodoc: all
|
|
46
44
|
bag[predicate] = true
|
47
45
|
res = bag
|
48
46
|
if @redcycle[predicate].nil?
|
49
|
-
return res
|
47
|
+
return res
|
50
48
|
end
|
51
49
|
@redcycle[predicate].each do |rp|
|
52
|
-
res = name_bag(rp, res)
|
50
|
+
res = name_bag(rp, res)
|
53
51
|
end
|
54
52
|
end
|
55
53
|
|
@@ -65,7 +63,7 @@ class GraphGen #:nodoc: all
|
|
65
63
|
return str
|
66
64
|
else
|
67
65
|
return predicate
|
68
|
-
end
|
66
|
+
end
|
69
67
|
end
|
70
68
|
|
71
69
|
def process(depends)
|
@@ -92,11 +90,13 @@ class GraphGen #:nodoc: all
|
|
92
90
|
|
93
91
|
def addonce(node, negcluster, inhead=false)
|
94
92
|
if !@nodes[node]
|
95
|
-
@nodes[node] = @graph.add_node(node)
|
93
|
+
@nodes[node] = @graph.add_node("n_#{node}")
|
96
94
|
if @cards and @cards[node]
|
97
|
-
@nodes[node].label = node
|
95
|
+
@nodes[node].label = "#{node}\n (#{@cards[node].to_s})"
|
96
|
+
else
|
97
|
+
@nodes[node].label = node
|
98
98
|
end
|
99
|
-
end
|
99
|
+
end
|
100
100
|
|
101
101
|
if @budtime == -1
|
102
102
|
@nodes[node].URL = "#{node}.html" if inhead
|
@@ -105,7 +105,7 @@ class GraphGen #:nodoc: all
|
|
105
105
|
end
|
106
106
|
|
107
107
|
if negcluster
|
108
|
-
# cleaning
|
108
|
+
# cleaning
|
109
109
|
res = node
|
110
110
|
# pretty-printing issues
|
111
111
|
node.split(", ").each_with_index do |p, i|
|
@@ -190,7 +190,7 @@ class GraphGen #:nodoc: all
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
|
193
|
-
unless depanalysis.nil?
|
193
|
+
unless depanalysis.nil?
|
194
194
|
depanalysis.source.each {|s| addedge("S", s.pred, false, false, false)}
|
195
195
|
depanalysis.sink.each {|s| addedge(s.pred, "T", false, false, false)}
|
196
196
|
|
@@ -218,19 +218,19 @@ class GraphGen #:nodoc: all
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
|
-
class SpaceTime
|
221
|
+
class SpaceTime
|
222
222
|
def initialize(input, links = false)
|
223
|
-
@input = input
|
223
|
+
@input = input
|
224
224
|
@links = links
|
225
225
|
processes = input.map {|i| i[1]}
|
226
226
|
input.map{|i| processes << i[2]}
|
227
227
|
processes.uniq!
|
228
228
|
|
229
|
-
@queues = {}
|
230
|
-
|
229
|
+
@queues = {}
|
230
|
+
|
231
231
|
@g = GraphViz.new(:G, :type => :digraph, :rankdir => "LR", :outputorder => "nodesfirst", :splines => "line")#, :clusterrank => "none")
|
232
232
|
@hdr = @g.subgraph("cluster_0")
|
233
|
-
|
233
|
+
|
234
234
|
@subs = {}
|
235
235
|
@head = {}
|
236
236
|
last = nil
|
@@ -238,7 +238,6 @@ class SpaceTime
|
|
238
238
|
#@head[p] = @hdr.add_node("process #{p}(#{i})")#, :color => "white", :label => "")
|
239
239
|
@subs[p] = @g.subgraph("buster_#{i+1}")
|
240
240
|
@head[p] = @hdr.add_node("process #{p}(#{i})", :group => p)#, :color => "white", :label => "")
|
241
|
-
|
242
241
|
end
|
243
242
|
end
|
244
243
|
|
@@ -251,13 +250,13 @@ class SpaceTime
|
|
251
250
|
@edges[lbl] = [f, t, l, 1]
|
252
251
|
end
|
253
252
|
end
|
254
|
-
|
253
|
+
|
255
254
|
def process
|
256
255
|
@edges = {}
|
257
256
|
queues = {}
|
258
257
|
@input.each do |i|
|
259
|
-
queues[i[1]]
|
260
|
-
queues[i[2]]
|
258
|
+
queues[i[1]] ||= []
|
259
|
+
queues[i[2]] ||= []
|
261
260
|
queues[i[1]] << i[3]
|
262
261
|
queues[i[2]] << i[4]
|
263
262
|
end
|
@@ -275,7 +274,7 @@ class SpaceTime
|
|
275
274
|
url = "DBM_#{k}_/tm_#{item}.svg"
|
276
275
|
#puts "URL is #{url}"
|
277
276
|
end
|
278
|
-
snd = @subs[k].add_node(label, {:label => item.to_s, :width => 0.1, :height => 0.1, :fontsize => 6, :pos => [1, i], :group => k, :URL => url})
|
277
|
+
snd = @subs[k].add_node(label, {:label => item.to_s, :width => 0.1, :height => 0.1, :fontsize => 6, :pos => [1, i], :group => k, :URL => url})
|
279
278
|
|
280
279
|
unless @head[k].id == snd.id
|
281
280
|
@subs[k].add_edge(@head[k], snd, :weight => 2)
|
@@ -294,10 +293,10 @@ class SpaceTime
|
|
294
293
|
msg_edge(snd_label, rcv_label, i[5])
|
295
294
|
end
|
296
295
|
end
|
297
|
-
|
296
|
+
|
298
297
|
def finish(file, fmt=nil)
|
299
298
|
@edges.each_pair do |k, v|
|
300
|
-
lbl =
|
299
|
+
lbl = v[3] > 1 ? "#{v[2]}(#{v[3]})" : v[2]
|
301
300
|
@g.add_edge(v[0], v[1], :label => lbl, :color => "red", :weight => 1)
|
302
301
|
end
|
303
302
|
if fmt.nil?
|
data/lib/bud/joins.rb
CHANGED
@@ -9,6 +9,7 @@ module Bud
|
|
9
9
|
@bud_instance = bud_instance
|
10
10
|
@localpreds = nil
|
11
11
|
@hashpreds = nil
|
12
|
+
@selfjoins = []
|
12
13
|
|
13
14
|
# if any elements on rellist are BudJoins, suck up their contents
|
14
15
|
tmprels = []
|
@@ -23,6 +24,18 @@ module Bud
|
|
23
24
|
rellist = tmprels
|
24
25
|
@origrels = rellist
|
25
26
|
|
27
|
+
# check for self-joins: we currently only handle 2 instances of the same table per rule
|
28
|
+
counts = @origrels.reduce({}) do |memo, r|
|
29
|
+
memo[r.tabname] ||= 0
|
30
|
+
memo[r.tabname] += 1
|
31
|
+
memo
|
32
|
+
end
|
33
|
+
counts.each do |name, cnt|
|
34
|
+
raise Bud::CompileError, "#{cnt} instances of #{name} in rule; only one self-join currently allowed per rule" if cnt > 2
|
35
|
+
@selfjoins << name if cnt == 2
|
36
|
+
end
|
37
|
+
|
38
|
+
|
26
39
|
# recurse to form a tree of binary BudJoins
|
27
40
|
@rels = [rellist[0]]
|
28
41
|
@rels << (rellist.length == 2 ? rellist[1] : BudJoin.new(rellist[1..rellist.length-1], @bud_instance))
|
@@ -39,7 +52,7 @@ module Bud
|
|
39
52
|
memo
|
40
53
|
end
|
41
54
|
|
42
|
-
setup_preds(preds)
|
55
|
+
setup_preds(preds)
|
43
56
|
setup_state
|
44
57
|
end
|
45
58
|
|
@@ -76,7 +89,7 @@ module Bud
|
|
76
89
|
# similar to <tt>SELECT * FROM ... WHERE...</tt> block in SQL.
|
77
90
|
public
|
78
91
|
def flatten(*preds)
|
79
|
-
setup_preds(preds)
|
92
|
+
setup_preds(preds)
|
80
93
|
flat_schema = @rels.map{|r| r.schema}.flatten(1)
|
81
94
|
dupfree_schema = []
|
82
95
|
# while loop here (inefficiently) ensures no collisions
|
@@ -148,14 +161,14 @@ module Bud
|
|
148
161
|
public
|
149
162
|
def pairs(*preds, &blk)
|
150
163
|
@origpreds = preds
|
151
|
-
setup_preds(preds)
|
164
|
+
setup_preds(preds)
|
152
165
|
# given new preds, the state for the join will be different. set it up again.
|
153
166
|
setup_state if self.class <= Bud::BudJoin
|
154
167
|
blk.nil? ? self : map(&blk)
|
155
168
|
end
|
156
169
|
|
157
170
|
alias combos pairs
|
158
|
-
|
171
|
+
|
159
172
|
# the natural join: given a * expression over n collections, form all
|
160
173
|
# combinations of items that have the same values in matching fields
|
161
174
|
public
|
@@ -169,7 +182,7 @@ module Bud
|
|
169
182
|
# of the first collection
|
170
183
|
public
|
171
184
|
def lefts(*preds, &blk)
|
172
|
-
setup_preds(preds)
|
185
|
+
setup_preds(preds)
|
173
186
|
# given new preds, the state for the join will be different. set it up again.
|
174
187
|
setup_state if self.class <= Bud::BudJoin
|
175
188
|
map{ |l,r| blk.nil? ? l : blk.call(l) }
|
@@ -180,7 +193,7 @@ module Bud
|
|
180
193
|
# of the second item
|
181
194
|
public
|
182
195
|
def rights(*preds, &blk)
|
183
|
-
setup_preds(preds)
|
196
|
+
setup_preds(preds)
|
184
197
|
# given new preds, the state for the join will be different. set it up again.
|
185
198
|
setup_state if self.class <= Bud::BudJoin
|
186
199
|
map{ |l,r| blk.nil? ? r : blk.call(r) }
|
@@ -190,16 +203,36 @@ module Bud
|
|
190
203
|
# satisfy +preds+, and for any item from the 1st collection that has no
|
191
204
|
# matches in the 2nd, nil-pad it and include it in the output.
|
192
205
|
public
|
193
|
-
def outer(*preds)
|
206
|
+
def outer(*preds, &blk)
|
194
207
|
@origpreds = preds
|
195
|
-
|
208
|
+
setup_preds(preds)
|
196
209
|
self.extend(Bud::BudOuterJoin)
|
197
|
-
map
|
210
|
+
blk.nil? ? self : map(&blk)
|
211
|
+
end
|
212
|
+
|
213
|
+
# AntiJoin
|
214
|
+
# note: unlike other join methods (e.g. lefts) all we do with the return value
|
215
|
+
# of block is check whether it's nil. Putting "projection" logic in the block
|
216
|
+
# has no effect on the output.
|
217
|
+
public
|
218
|
+
def anti(*preds, &blk)
|
219
|
+
@origpreds = preds
|
220
|
+
# no projection involved here, so we can propagate the schema
|
221
|
+
@schema = rels[0].schema
|
222
|
+
setup_preds(preds)
|
223
|
+
setup_state if self.class <= Bud::BudJoin
|
224
|
+
if @bud_instance.stratum_first_iter
|
225
|
+
@matches = map { |r, s| (blk.nil?) ? r : blk.call(r,s) }.compact
|
226
|
+
@rels[0].map {|r| (@matches.include? r) ? nil : r}.compact
|
227
|
+
else
|
228
|
+
[]
|
229
|
+
end
|
198
230
|
end
|
199
231
|
|
200
232
|
# extract predicates on rellist[0] and recurse to right side with remainder
|
201
233
|
protected
|
202
234
|
def setup_preds(preds) # :nodoc: all
|
235
|
+
return if preds.empty?
|
203
236
|
allpreds = disambiguate_preds(preds)
|
204
237
|
allpreds = canonicalize_localpreds(@rels, allpreds)
|
205
238
|
# check for refs to collections that aren't being joined, Issue 191
|
@@ -211,8 +244,16 @@ module Bud
|
|
211
244
|
end
|
212
245
|
end
|
213
246
|
end
|
214
|
-
@hashpreds = allpreds.reject {
|
247
|
+
@hashpreds = allpreds.reject {|p| p[0][0] != @rels[0].tabname}
|
215
248
|
@localpreds = @hashpreds
|
249
|
+
|
250
|
+
# only allow preds on the same table name if they're on a self-joined table
|
251
|
+
@localpreds.each do |p|
|
252
|
+
if p[0][0] == p[1][0] and not @selfjoins.include? p[0][0]
|
253
|
+
raise Bud::CompileError, "single-table predicate on #{p[0][0]} disallowed in joins"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
216
257
|
@localpreds += allpreds.map do |p|
|
217
258
|
p if p[0][0] == p[1][0] and (p[0][0] == @rels[0].tabname or p[0][0] == @rels[1].tabname)
|
218
259
|
end.compact
|
@@ -284,7 +325,8 @@ module Bud
|
|
284
325
|
protected
|
285
326
|
def canonicalize_localpreds(rel_list, preds) # :nodoc:all
|
286
327
|
retval = preds.map do |p|
|
287
|
-
|
328
|
+
# reverse if rhs is rel_list[0], *unless* it's a self-join!
|
329
|
+
(p[1][0] == rel_list[0].tabname and p[1][0] != p[0][0]) ? p.reverse : p
|
288
330
|
end
|
289
331
|
end
|
290
332
|
|
@@ -303,7 +345,8 @@ module Bud
|
|
303
345
|
if (@localpreds and skips and @localpreds.length > skips.length)
|
304
346
|
# check remainder of the predicates
|
305
347
|
@localpreds.each do |pred|
|
306
|
-
|
348
|
+
# skip skips, and self-join preds
|
349
|
+
next if (skips.include? pred or pred[0][0] == pred[1][0])
|
307
350
|
vals = []
|
308
351
|
(0..1).each do |i|
|
309
352
|
if pred[i][0] == @rels[0].tabname
|
@@ -327,7 +370,9 @@ module Bud
|
|
327
370
|
@rels[0].each_from_sym([left_rel]) do |r|
|
328
371
|
@rels[1].each_from_sym([right_rel]) do |s|
|
329
372
|
s = [s] if origrels.length == 2
|
330
|
-
|
373
|
+
if test_locals(r, s)
|
374
|
+
yield([r] + s)
|
375
|
+
end
|
331
376
|
end
|
332
377
|
end
|
333
378
|
end
|
@@ -340,12 +385,8 @@ module Bud
|
|
340
385
|
name, offset = entry[0], entry[1]
|
341
386
|
|
342
387
|
# determine which subtuple of the collection contains the table
|
343
|
-
# referenced in entry.
|
344
|
-
# on the left of the join, hence we shouldn't be calling join_offset on it
|
388
|
+
# referenced in entry.
|
345
389
|
subtuple = 0
|
346
|
-
if origrels[0].tabname == entry[0]
|
347
|
-
raise BudError, "join_offset called on the result of a single collection #{entry[0]}"
|
348
|
-
end
|
349
390
|
origrels[1..origrels.length].each_with_index do |t,i|
|
350
391
|
if t.tabname == entry[0]
|
351
392
|
subtuple = i
|
@@ -393,38 +434,42 @@ module Bud
|
|
393
434
|
r = [r] unless probe_ix == 1 and origrels.length > 2
|
394
435
|
attrval = (probe_ix == 0) ? r[0][left_offset] : r[right_subtuple][right_offset]
|
395
436
|
|
396
|
-
# insert into the prober's hashtable only if symmetric
|
437
|
+
# insert into the prober's hashtable only if symmetric
|
397
438
|
if probe_sym == other_sym
|
398
439
|
@hash_tables[probe_ix][probe_sym][attrval] ||= []
|
399
440
|
@hash_tables[probe_ix][probe_sym][attrval] << r
|
400
441
|
end
|
401
442
|
|
402
443
|
# ...and probe the other hashtable
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
444
|
+
if @hash_tables[other_ix][other_sym][attrval].nil?
|
445
|
+
next
|
446
|
+
else
|
447
|
+
@hash_tables[other_ix][other_sym][attrval].each do |s_tup|
|
448
|
+
if probe_ix == 0
|
449
|
+
left = r; right = s_tup
|
450
|
+
else
|
451
|
+
left = s_tup; right = r
|
452
|
+
end
|
453
|
+
retval = left + right
|
454
|
+
yield retval if test_locals(left[0], right, @hashpreds.first)
|
409
455
|
end
|
410
|
-
retval = left + right
|
411
|
-
yield retval if test_locals(left[0], right, @hashpreds.first)
|
412
456
|
end
|
413
457
|
end
|
414
458
|
end
|
415
459
|
end
|
416
460
|
end
|
417
461
|
|
462
|
+
# intended to be used to extend a BudJoin instance
|
418
463
|
module BudOuterJoin
|
419
464
|
public
|
420
465
|
def each(&block) # :nodoc:all
|
421
466
|
super(&block)
|
422
|
-
#
|
423
|
-
#
|
424
|
-
#
|
425
|
-
#
|
426
|
-
#
|
427
|
-
#
|
467
|
+
# Previous line finds all the matches. Now its time to ``preserve'' the
|
468
|
+
# outer tuples with no matches. Our trick: for each tuple of the outer,
|
469
|
+
# generate a singleton relation and join with inner. If result is empty,
|
470
|
+
# preserve tuple.
|
471
|
+
# XXX: This is totally inefficient: we should fold the identification of
|
472
|
+
# non-matches into the join algorithms. Another day.
|
428
473
|
@rels[0].each do |r|
|
429
474
|
t = @origrels[0].clone_empty
|
430
475
|
# need to uniquify the tablename here to avoid sharing join state with original
|
data/lib/bud/metrics.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "bud/errors"
|
2
|
+
require 'faster_csv'
|
3
|
+
|
4
|
+
# metrics are reported in a nested hash representing a collection of relational tables.
|
5
|
+
# The metrics hash has the following form:
|
6
|
+
# - key of the metrics hash is the name of the metric (table), e.g. "tickstats", "collections", "rules", etc.
|
7
|
+
# - value of the metrics is itself a hash holding the rows of the table, keyed by key columns.
|
8
|
+
# - It has the following form:
|
9
|
+
# - key is a hash of key attributes, with the following form:
|
10
|
+
# - key is the name of an attribute
|
11
|
+
# - value is the attribute's value
|
12
|
+
# - value is a single dependent value, e.g. a statistic like a count
|
13
|
+
|
14
|
+
def report_metrics
|
15
|
+
metrics.each do |k,v|
|
16
|
+
if v.first
|
17
|
+
csvstr = FasterCSV.generate(:force_quotes=>true) do |csv|
|
18
|
+
csv << [k.to_s] + v.first[0].keys + [:val]
|
19
|
+
v.each do |row|
|
20
|
+
csv << [nil] + row[0].values + [row[1]]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
puts csvstr
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize_stats
|
29
|
+
return {{:name=>:count} => 0, {:name=>:mean} => 0, {:name=>:Q} => 0, {:name=>:stddev} => 0}
|
30
|
+
end
|
31
|
+
|
32
|
+
# see http://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
|
33
|
+
def running_stats(stats, elapsed)
|
34
|
+
raise Bud::BudError, "running_stats called with negative elapsed time" if elapsed < 0
|
35
|
+
stats[{:name=>:count}] += 1
|
36
|
+
oldmean = stats[{:name=>:mean}]
|
37
|
+
stats[{:name=>:mean}] = stats[{:name=>:mean}] + \
|
38
|
+
(elapsed - stats[{:name=>:mean}]) / stats[{:name=>:count}]
|
39
|
+
stats[{:name=>:Q}] = stats[{:name=>:Q}] + \
|
40
|
+
(elapsed - oldmean) * (elapsed - stats[{:name=>:mean}])
|
41
|
+
stats[{:name=>:stddev}] = Math.sqrt(stats[{:name=>:Q}]/stats[{:name=>:count}])
|
42
|
+
stats
|
43
|
+
end
|
data/lib/bud/monkeypatch.rb
CHANGED
@@ -12,7 +12,7 @@ class Module
|
|
12
12
|
# module X points to X's own nested import table.
|
13
13
|
@bud_import_tbl ||= {}
|
14
14
|
child_tbl = mod.bud_import_table
|
15
|
-
raise Bud::CompileError if @bud_import_tbl.has_key? local_name
|
15
|
+
raise Bud::CompileError, "import symbol #{local_name} already in use" if @bud_import_tbl.has_key? local_name
|
16
16
|
@bud_import_tbl[local_name] = child_tbl.clone # XXX: clone needed?
|
17
17
|
|
18
18
|
rewritten_mod_name = ModuleRewriter.do_import(self, mod, local_name)
|
data/lib/bud/rebl.rb
CHANGED
@@ -4,7 +4,7 @@ require 'rubygems'
|
|
4
4
|
require 'bud'
|
5
5
|
require 'abbrev'
|
6
6
|
|
7
|
-
TABLE_TYPES = ["table", "scratch", "channel"]
|
7
|
+
TABLE_TYPES = ["table", "scratch", "channel", "loopback", "periodic", "sync", "store"]
|
8
8
|
|
9
9
|
# The class to which rebl adds user-specified rules and declarations.
|
10
10
|
class ReblClass
|
@@ -97,7 +97,8 @@ class ReblShell
|
|
97
97
|
line = Readline::readline('rebl> ') unless noreadline
|
98
98
|
line = gets if noreadline
|
99
99
|
do_exit if line.nil?
|
100
|
-
line
|
100
|
+
line.strip!
|
101
|
+
return if line.empty?
|
101
102
|
Readline::HISTORY.push(line) unless noreadline
|
102
103
|
split_line = line.split(" ")
|
103
104
|
if line[0..0] == @@escape_char then
|
@@ -180,7 +181,7 @@ class ReblShell
|
|
180
181
|
rescue Exception
|
181
182
|
puts "Error when saving permanent history: #{$!}"
|
182
183
|
end
|
183
|
-
@rebl_class_inst.
|
184
|
+
@rebl_class_inst.stop if @rebl_class_inst
|
184
185
|
puts "\n" + @@exit_message
|
185
186
|
exit!
|
186
187
|
end
|
@@ -212,12 +213,12 @@ class LibRebl
|
|
212
213
|
|
213
214
|
# Runs the bud instance (until a breakpoint, or stop() is called)
|
214
215
|
def run
|
215
|
-
@rebl_class_inst.
|
216
|
+
@rebl_class_inst.run_bg
|
216
217
|
end
|
217
218
|
|
218
219
|
# Stops the bud instance (and then performs another tick)
|
219
220
|
def stop
|
220
|
-
@rebl_class_inst.
|
221
|
+
@rebl_class_inst.pause
|
221
222
|
end
|
222
223
|
|
223
224
|
# Ticks the bud instance a specified integer number of times.
|
@@ -274,13 +275,20 @@ class LibRebl
|
|
274
275
|
if not @state.empty?
|
275
276
|
@rebl_class.class_eval("state do\n" + @state.values.join("\n") + "\nend")
|
276
277
|
end
|
277
|
-
rescue
|
278
|
+
rescue Exception
|
278
279
|
raise
|
279
280
|
end
|
280
281
|
|
281
282
|
@old_inst = @rebl_class_inst
|
282
|
-
@rebl_class_inst = @rebl_class.new(:
|
283
|
-
:port => @port
|
283
|
+
@rebl_class_inst = @rebl_class.new(:signal_handling => :none, :ip => @ip,
|
284
|
+
:port => @port)
|
285
|
+
|
286
|
+
# Stop the old instance. We want to copy the old instance's state over to
|
287
|
+
# the new instance and then startup the new instance. Any network messages
|
288
|
+
# received before the new instance has been started will be lost, but that
|
289
|
+
# can't easily be avoided; the best we can do is ensure we get a consistent
|
290
|
+
# snapshot of the old instance's state.
|
291
|
+
@old_inst.stop if @old_inst
|
284
292
|
|
285
293
|
# Copy the tables over.
|
286
294
|
if @old_inst
|
@@ -302,17 +310,16 @@ class LibRebl
|
|
302
310
|
|
303
311
|
# Run lazily in background, shutting down old instance.
|
304
312
|
begin
|
305
|
-
@old_inst.stop_bg if @old_inst
|
306
313
|
# Lazify the instance upon a breakpoint (no effect if instance is
|
307
314
|
# already lazy)
|
308
315
|
@rebl_class_inst.register_callback(:rebl_breakpoint) do
|
309
|
-
@rebl_class_inst.
|
316
|
+
@rebl_class_inst.pause
|
310
317
|
end
|
311
|
-
@rebl_class_inst.
|
318
|
+
@rebl_class_inst.start
|
312
319
|
@ip = @rebl_class_inst.ip
|
313
320
|
@port = @rebl_class_inst.port
|
314
|
-
puts "Listening on #{@
|
315
|
-
rescue
|
321
|
+
puts "Listening on #{@ip}:#{@port}" unless @old_inst
|
322
|
+
rescue Exception
|
316
323
|
# The above two need to be atomic, or we're in trouble.
|
317
324
|
puts "unrecoverable error, please file a bug: #{$!}"
|
318
325
|
abort
|