bud 0.0.4 → 0.0.5
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/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
|