bud 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/docs/README.md CHANGED
@@ -3,11 +3,13 @@ Welcome to the documentation for *Bud*, a prototype of Bloom under development.
3
3
 
4
4
  The documents here are organized to be read in any order, but you might like to try the following:
5
5
 
6
- * [intro.md](intro.md): A brief introduction to Bud and Bloom
7
- * [getstarted.md](getstarted.md): A quickstart to teach you basic Bloom concepts, the use of `rebl` interactive terminal, and the embedding of Bloom code in Ruby via the `Bud` module.
8
- * [operational.md](operational.md): an operational view of Bloom, to provide a more detailed model of how Bloom code is evaluated by Bud.
9
- * [Bud RubyDoc](http://rubydoc.info/github/bloom-lang/bud/): RubyDoc on the language constructs and runtime hooks provided by the Bud module
10
- * [cheat.md](cheat.md): A concise "cheat sheet" to remind you about Bloom syntax.
11
- * [ruby_hooks.md](ruby_hooks.md): Bud module methods that allow you to interact with the Bud evaluator from other Ruby threads.
12
- * [bud-sandbox](http://github.com/bloom-lang/bud-sandbox): a github repository including lots of useful libraries and examples.
13
- * [bfs.md](bfs.md): A walkthrough of the Bloom distributed filesystem.
6
+ * **intro.md**: A brief introduction to Bud and Bloom
7
+ * **getstarted.md**: A quickstart to teach you basic Bloom concepts, the use of `rebl` interactive terminal, and the embedding of Bloom code in Ruby via the `Bud` module.
8
+ * **operational.md**: an operational view of Bloom, to provide a more detailed model of how Bloom code is evaluated by Bud.
9
+ * **cheat.md**: A concise "cheat sheet" to remind you about Bloom syntax.
10
+ * **modules.md**: An overview of Bloom's modularity features.
11
+ * **ruby_hooks.md**: Bud module methods that allow you to interact with the Bud evaluator from other Ruby threads.
12
+ * **visualizations.md**: Overview of the `budvis` and `budplot` tools for visualizing Bloom program analyses.
13
+ * **bfs.md**: A walkthrough of the Bloom distributed filesystem.
14
+ * **bud-sandbox**: a github repository including lots of useful libraries and examples.
15
+ * **Bud RubyDoc**: The Bud gem ships with RubyDoc on the language constructs and runtime hooks provided by the Bud module. (To see rdoc, you run `gem server` from a command line and open [http://0.0.0.0:8808/](http://0.0.0.0:8808/))
data/docs/bfs.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BFS: A distributed file system in Bloom
2
2
 
3
- In this document we'll use what we've learned to build a piece of systems software using Bloom. The libraries that ship with BUD provide many of the building blocks we'll need to create a distributed,
3
+ In this document we'll use what we've learned to build a piece of systems software using Bloom. The libraries that ship with Bud provide many of the building blocks we'll need to create a distributed,
4
4
  ``chunked'' file system in the style of the Google File System (GFS):
5
5
 
6
6
  * a [key-value store](https://github.com/bloom-lang/bud-sandbox/blob/master/kvs/kvs.rb) (KVS)
@@ -360,20 +360,42 @@ To maintain the durability requirement that `REP_FACTOR` copies of every chunk a
360
360
  that maintains a near-consistent view of global state, and takes steps to correct violated requirements.
361
361
 
362
362
  __chunk_cache__ is the master's view of datanode state, maintained as described by collecting and pruning heartbeat messages.
363
+ After defining some helper aggregates (__chunk_cnts_chunk__ or replica count by chunk, and __chunk_cnt_host__ or datanode fill factor),
363
364
 
364
365
  cc_demand <= (bg_timer * chunk_cache_alive).rights
365
366
  cc_demand <= (bg_timer * last_heartbeat).pairs {|b, h| [h.peer, nil, nil]}
366
367
  chunk_cnts_chunk <= cc_demand.group([cc_demand.chunkid], count(cc_demand.node))
367
368
  chunk_cnts_host <= cc_demand.group([cc_demand.node], count(cc_demand.chunkid))
368
369
 
369
- After defining some helper aggregates (__chunk_cnts_chunk__ or replica count by chunk, and __chunk_cnt_host__ or datanode fill factor),
370
+ we define __lowchunks__ as the set of chunks whose replication factor is too low:
371
+
370
372
 
371
373
  lowchunks <= chunk_cnts_chunk { |c| [c.chunkid] if c.replicas < REP_FACTOR and !c.chunkid.nil?}
372
-
373
- # nodes in possession of such chunks
374
+
375
+ We define __chosen_dest__ for a given underreplicated chunk as the datanode with
376
+ the lowest fill factor that is not already in possession of the chunk:
377
+
374
378
  sources <= (cc_demand * lowchunks).pairs(:chunkid => :chunkid) {|a, b| [a.chunkid, a.node]}
375
379
  # nodes not in possession of such chunks, and their fill factor
376
380
  candidate_nodes <= (chunk_cnts_host * lowchunks).pairs do |c, p|
377
381
  unless chunk_cache_alive.map{|a| a.node if a.chunkid == p.chunkid}.include? c.host
378
382
  [p.chunkid, c.host, c.chunks]
379
- ### I am autogenerated. Please do not edit me.
383
+ end
384
+ end
385
+
386
+ best_dest <= candidate_nodes.argagg(:min, [candidate_nodes.chunkid], candidate_nodes.chunks)
387
+ chosen_dest <= best_dest.group([best_dest.chunkid], choose(best_dest.host))
388
+
389
+ and the __best_src__ as any arbitrary node that is in possession of the chunk:
390
+
391
+ best_src <= sources.group([sources.chunkid], choose(sources.host))
392
+
393
+ Finally, we initiate a background replication job for a given chunk by inserting
394
+ the chosen chunkid, source and destination into __copy_chunk__
395
+
396
+ copy_chunk <= (chosen_dest * best_src).pairs(:chunkid => :chunkid) do |d, s|
397
+ [d.chunkid, s.host, d.host]
398
+ end
399
+
400
+
401
+
data/docs/bfs.raw CHANGED
@@ -1,6 +1,6 @@
1
1
  # BFS: A distributed file system in Bloom
2
2
 
3
- In this document we'll use what we've learned to build a piece of systems software using Bloom. The libraries that ship with BUD provide many of the building blocks we'll need to create a distributed,
3
+ In this document we'll use what we've learned to build a piece of systems software using Bloom. The libraries that ship with Bud provide many of the building blocks we'll need to create a distributed,
4
4
  ``chunked'' file system in the style of the Google File System (GFS):
5
5
 
6
6
  * a [key-value store](https://github.com/bloom-lang/bud-sandbox/blob/master/kvs/kvs.rb) (KVS)
data/docs/bust.md CHANGED
@@ -1,4 +1,4 @@
1
- BUST stands for BUd State Transfer and it is a REST interface to BUD. BUST consists of a Bud implementation of a client and server. The client implements bindings to a subset of the Ruby Nestful library, and the server is a lightweight HTTP server written in Ruby. Note that the BUST server currently sets the "Access-Control-Allow-Origin: *" HTTP header to override web browsers' same-origin policy.
1
+ BUST stands for BUd State Transfer and it is a REST interface to Bud. BUST consists of a Bud implementation of a client and server. The client implements bindings to a subset of the Ruby Nestful library, and the server is a lightweight HTTP server written in Ruby. Note that the BUST server currently sets the "Access-Control-Allow-Origin: *" HTTP header to override web browsers' same-origin policy.
2
2
 
3
3
  Right now BUST supports "GET" and "POST" requests, and may support "DELETE" and "PUT" requests in the future.
4
4
 
@@ -18,7 +18,7 @@ In your class, make sure to:
18
18
 
19
19
  include Bust
20
20
 
21
- That's it! Now a BUST server will be started up when your class is instantiated. By default, this server will listen on port 8080, but you can change this by passing a port via the "bust_port" option when you instantiate your class.
21
+ That's it! Now a BUST server will be started up when your class is instantiated. This server will listen on an open port; it will print out "Bust server listening on port xxxxx" to let you know which port it has selected. But you can select a specific port by passing a port via the "bust_port" option when you instantiate your class.
22
22
 
23
23
  You can test out the BUST server using Ruby's "net/http" library if you want, and you can also check out "BUST Inspector", a sample AJAX application that allows you to view the state of a bud instance.
24
24
 
data/docs/cheat.md CHANGED
@@ -55,7 +55,7 @@ Default attributes: `[:@address, :val] => []`
55
55
  (Bloom statements with channel on lhs must use async merge (`<~`).)
56
56
 
57
57
  channel :msgs
58
- channel :req_chan, [:@address, :cartnum, :storenum] => [:command, :params]
58
+ channel :req_chan, [:cartnum, :storenum, :@server] => [:command, :params]
59
59
 
60
60
  ### periodic ###
61
61
  System timer manifested as a scratch collection.<br>
@@ -97,7 +97,7 @@ Left-hand-side (lhs) is a named `BudCollection` object.<br>
97
97
  Right-hand-side (rhs) is a Ruby expression producing a `BudCollection` or `Array` of `Arrays`.<br>
98
98
  BloomOp is one of the 5 operators listed below.
99
99
 
100
- ## Bloom Operators ##
100
+ ### Bloom Operators ###
101
101
  merges:
102
102
 
103
103
  * `left <= right` &nbsp;&nbsp;&nbsp;&nbsp; (*instantaneous*)
@@ -115,7 +115,7 @@ insert:<br>
115
115
  Note that unlike merge/delete, insert expects a single fact on the rhs, rather
116
116
  than a collection.
117
117
 
118
- ## Collection Methods ##
118
+ ### Collection Methods ###
119
119
  Standard Ruby methods used on a BudCollection `bc`:
120
120
 
121
121
  implicit map:
@@ -154,7 +154,7 @@ implicit map:
154
154
 
155
155
  stdio <~ bc.inspected
156
156
 
157
- `chan.payloads`: shorthand for `chan {|t| t.val}`, only defined for channels
157
+ `chan.payloads`: projects `chan` to non-address columns. only defined for channels
158
158
 
159
159
  # at sender
160
160
  msgs <~ requests {|r| "127.0.0.1:12345", r}
@@ -183,6 +183,8 @@ implicit map:
183
183
  * Summary aggs: `count`, `sum`, `avg`
184
184
  * Structural aggs: `accum`
185
185
 
186
+ Note that custom aggregation can be written using `reduce`.
187
+
186
188
  ## Collection Combination (Join) ###
187
189
  To match items across two (or more) collections, use the `*` operator, followed by methods to filter/format the result (`pairs`, `matches`, `combos`, `lefts`, `rights`).
188
190
 
@@ -225,7 +227,7 @@ Like `pairs`, but implicitly includes a block that projects down to the left ite
225
227
  `rights(`*hash pairs*`)`:
226
228
  Like `pairs`, but implicitly includes a block that projects down to the right item in each pair.
227
229
 
228
- `flatten`<br>
230
+ `flatten`:<br>
229
231
  `flatten` is a bit like SQL's `SELECT *`: it produces a collection of concatenated objects, with a schema that is the concatenation of the schemas in tablelist (with duplicate names disambiguated.) Useful for chaining to operators that expect input collections with schemas, e.g. group:
230
232
 
231
233
  out <= (r * s).matches.flatten.group([:a], max(:b))
data/docs/getstarted.md CHANGED
@@ -107,14 +107,14 @@ See how the second tick produced no output this time? After the first timestep,
107
107
  ### Summing Up ###
108
108
  In these initial examples we learned about a few simple but important things:
109
109
 
110
- * **rebl**: the interactive Bloom terminal and its `/` commands.
111
- * **Bloom collections**: unordered sets of items, which are set up by collection declarations. So far we have seen persistent `table` and transient `scratch` collections. By default, collections are structured as \[key,value\] pairs.
110
+ * **rebl**: the interactive Bloom terminal and its slash (`/`) commands.
111
+ * **Bloom collections**: unordered sets of items, which are set up by collection declarations. So far we have seen persistent `table` and transient `scratch` collections. By default, collections are structured as \[key,val\] pairs.
112
112
  * **Bloom statements**: expressions of the form *lhs op rhs*, where the lhs is a collection and the rhs is either a collection or an array-of-arrays.
113
113
  * **Bloom timestep**: an atomic single-machine evaluation of a block of Bloom statements.
114
114
  * **Bloom merge operators**:
115
115
  * The `<=` merge operator for *instantaneously* merging things into a collection.
116
- * The `<~` merge operator for *asynchronously* merging things into collections outside the control of tick evaluation: e.g. terminal output.*
117
- * **stdio**: a built-in Bloom collection that, when place on the rhs of an asynch merge operator `<~`, prints its contents to stdout.
116
+ * The `<~` merge operator for *asynchronously* merging things into collections outside the control of tick evaluation: e.g. terminal output.
117
+ * **stdio**: a built-in Bloom collection that, when placed on the lhs of an asynch merge operator `<~`, prints its contents to stdout.
118
118
  * **inspected**: a method of Bloom collections that transforms the elements to be suitable for textual display on the terminal.
119
119
 
120
120
  ## Chat, World! ##
@@ -147,7 +147,7 @@ This defines a [Ruby mixin module](http://www.ruby-doc.org/docs/ProgrammingRuby/
147
147
  1. It contains a Bloom `state` block, containing collection declarations. When embedding Bloom in Ruby, all Bloom collection declarations must appear in a `state` block of this sort.
148
148
  2. This particular state block uses a kind of Bloom collection we have not seen before: a `channel`. A channel collection is a special kind of scratch used for network communication. It has a few key features:
149
149
 
150
- * Unlike the default \[key,value\] structure of scratches and tables, channels default to the structure \[address,payload\]: the first field is a destination IP string of the form 'host:port', and the second field is a payload to be delivered to that destination--typically a Ruby array. (For the record, the default key of a channel collection is the *pair* \[address,payload\]).
150
+ * Unlike the default \[key,val\] structure of scratches and tables, channels default to the structure \[address,val\]: the first field is a destination IP string of the form 'host:port', and the second field is a payload to be delivered to that destination--typically a Ruby array. (For the record, the default key of a channel collection is the *pair* \[address,val\]).
151
151
  * Any Bloom statement with a channel on the lhs must use the async merge (`<~`) operator. This instructs the runtime to attempt to deliver each rhs item to the address stored therein. In an async merge, each item in the collection on the right will appear in the collection on the lhs *eventually*. But this will not happen instantaneously, and it might not happen atomically--items in the collection on the rhs may "straggle in" individually over time at the destination. And if you're unlucky, this may happen after an arbitrarily long delay (possibly never). The use of `<~` for channels reflects the typical uncertainty of real-world network delivery. (Don't worry, the Bud sandbox provides libraries to wrap that uncertainty up in convenient ways.)
152
152
 
153
153
  Given this protocol (and the Ruby constant at the bottom), we're now ready to examine `examples/chat/chat_server.rb` in more detail:
@@ -188,7 +188,7 @@ The first is pretty simple:
188
188
 
189
189
  nodelist <= connect.payloads
190
190
 
191
- This says that whenever messages arrive on the channel named "connect", their payloads (i.e. their non-address field) should be instantaneously merged into the table nodelist, which will store them persistently. Note that nodelist has a \[key/value\] pair structure, so we expect the payloads will have that structure as well.
191
+ This says that whenever messages arrive on the channel named "connect", their payloads (i.e. their non-address field) should be instantaneously merged into the table nodelist, which will store them persistently. Note that nodelist has a \[key/val\] pair structure, so we expect the payloads will have that structure as well.
192
192
 
193
193
  The next Bloom statement is more complex. Remember the description in the "basic idea" at the beginning of this section: the server needs to accept inbound chat messages from clients, and forward them to other clients.
194
194
 
@@ -196,16 +196,16 @@ The next Bloom statement is more complex. Remember the description in the "basi
196
196
 
197
197
  The first thing to note is the lhs and operator in this statement. We are merging items (asynchronously, of course!) into the mcast channel, where they will be sent to their eventual destination.
198
198
 
199
- The rhs is our first introduction to the `*` operator of Bloom collections, and the `pairs` method after it. You can think of the `*` operator as "all-pairs": it produces a Bloom collection containing all pairs of mcast and nodelist items. The `pairs` method iterates through these pairs, passing them through a code block via the block arguments `m` and `n`. Finally, for each such pair the block produces an item containing the `key` attribute of the nodelist item, and the `val` attribute of the mcast item. This is structured as a proper \[address, value\] entry to be merged back into the mcast channel. Putting this together, this statement *multicasts inbound payloads on the mcast channel to all nodes in the chat*.
199
+ The rhs is our first introduction to the `*` operator of Bloom collections, and the `pairs` method after it. You can think of the `*` operator as "all-pairs": it produces a Bloom collection containing all pairs of mcast and nodelist items. The `pairs` method iterates through these pairs, passing them through a code block via the block arguments `m` and `n`. Finally, for each such pair the block produces an item containing the `key` attribute of the nodelist item, and the `val` attribute of the mcast item. This is structured as a proper \[address, val\] entry to be merged back into the mcast channel. Putting this together, this statement *multicasts inbound payloads on the mcast channel to all nodes in the chat*.
200
200
 
201
201
  The remaining lines of plain Ruby simply instantiate and run the ChatServer class (which includes the `Bud` module) using an ip and port given on the command line (or the default from ChatProtocol.rb).
202
202
 
203
203
  #### `*`'s and Clouds ####
204
204
  You can think of out use of the `*` operator in the rhs of the second statement in a few different ways:
205
205
 
206
- * If you're familiar with event-loop programming, this implements an *event handler* for messages on the mcast channel: whenever an mcast message arrives, this handler performs lookups in the nodelist table to form new messages. (It is easy to add "filters" to these handlers.) The resulting messages are dispatched via the mcast channel accordingly. This is a very common pattern in Bloom programs: handling channel messages via lookups in a table.
206
+ * If you're familiar with event-loop programming, this implements an *event handler* for messages on the mcast channel: whenever an mcast message arrives, this handler performs lookups in the nodelist table to form new messages. (It is easy to add "filters" to these handlers as arguments to `pairs`.) The resulting messages are dispatched via the mcast channel accordingly. This is a very common pattern in Bloom programs: handling channel messages via lookups in a table.
207
207
 
208
- * If you're familiar with SQL databases, the rhs is essentially a query that is run at each timestep, performing a CROSS JOIN of the mcast and nodelist "tables", with the SELECT clause captured by the block. (It is easy to add WHERE clauses to these joins.) The resulting "tuples" are "inserted" into the lhs asynchronously (and typical on remote nodes). This is a general-purpose way to think about the * operator. But as you've already seen, many common use cases for Bloom's * operator don't "feel" like database queries, because one or more of the collections is a scratch that is "driving" the program.
208
+ * If you're familiar with SQL databases, the rhs is essentially a query that is run at each timestep, performing a CROSS JOIN of the mcast and nodelist "tables", with the SELECT clause captured by the block. (It is easy to add WHERE clauses to these joins as arguments to `pairs`.) The resulting "tuples" are "inserted" into the lhs asynchronously (and typical on remote nodes). This is a general-purpose way to think about the * operator. But as you've already seen, many common use cases for Bloom's * operator don't "feel" like database queries, because one or more of the collections is a scratch that is "driving" the program.
209
209
 
210
210
  We expect that people doing distributed programming are probably familiar with both of these metaphors, and they're both useful. It's fairly common to think about rules in the first form, although the second form is actually closer to the underlying semantics of the language (which come from a temporal logic called [Dedalus](http://www.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.html)).
211
211
 
@@ -222,36 +222,34 @@ And here's the code:
222
222
  include Bud
223
223
  include ChatProtocol
224
224
 
225
- def initialize(nick, server, opts)
225
+ def initialize(nick, server, opts={})
226
226
  @nick = nick
227
227
  @server = server
228
228
  super opts
229
229
  end
230
230
 
231
- # send connection request to server on startup
232
231
  bootstrap do
233
232
  connect <~ [[@server, [ip_port, @nick]]]
234
233
  end
235
234
 
236
- bloom :chatter do
237
- # send mcast requests to server
235
+ bloom do
238
236
  mcast <~ stdio do |s|
239
237
  [@server, [ip_port, @nick, Time.new.strftime("%I:%M.%S"), s.line]]
240
238
  end
241
- # pretty-print mcast msgs from server on terminal
242
- stdio <~ mcast do |m|
243
- [left_right_align(m.val[1].to_s + ": " \
244
- + (m.val[3].to_s || ''),
245
- "(" + m.val[2].to_s + ")")]
246
- end
239
+
240
+ stdio <~ mcast { |m| [pretty_print(m.val)] }
247
241
  end
248
242
 
249
243
  # format chat messages with timestamp on the right of the screen
250
- def left_right_align(x, y)
251
- return x + " "*[66 - x.length,2].max + y
244
+ def pretty_print(val)
245
+ str = val[1].to_s + ": " + (val[3].to_s || '')
246
+ pad = "(" + val[2].to_s + ")"
247
+ return str + " "*[66 - str.length,2].max + pad
252
248
  end
253
249
  end
254
250
 
251
+
252
+
255
253
  if ARGV.length == 2
256
254
  server = ARGV[1]
257
255
  else
@@ -260,13 +258,13 @@ And here's the code:
260
258
 
261
259
  puts "Server address: #{server}"
262
260
  program = ChatClient.new(ARGV[0], server, :read_stdin => true)
263
- program.run
261
+ program.run_fg
264
262
 
265
263
  The ChatClient class has a typical Ruby `initialize` method that sets up two local instance variables: one for this client's nickname, and another for the 'IP:port' address string for the server. It then calls the initializer of the Bud superclass passing along a hash of options.
266
264
 
267
265
  The next block in the class is the first Bloom `bootstrap` block we've seen. This is a set of Bloom statements that are evaluated only once, just before the first "regular" timestep of the system. In this case, we bootstrap the client by sending a message to the server on the connect channel, containing the client's address (via the built-in Bud instance method `ip_port`) and chosen nickname.
268
266
 
269
- After that comes a bloom block, with the name `:chatter`. It contains two statements: one to take stdio input from the terminal and send it to the server via mcast, and another to receive mcasts and place them on stdio output. The first statement has the built-in `stdio` scratch on the rhs: this includes any lines of terminal input that arrived since the last timestep. For each line of terminal input, the `do...end` block formats an `mcast` message destined to the address in the instance variable `@server`, with an array as the payload. The rhs of the second statement takes `mcast` messages that arrived since the last timestep. For each message `m`, the `m.val` expression in the block returns the message payload; the call to the Ruby instance method `left_right_align` formats the message so it will look nice on-screen. These formatted strings are placed (asynchronously, as before) into `stdio` on the left.
267
+ After that comes a bloom block, with the name `:chatter`. It contains two statements: one to take stdio input from the terminal and send it to the server via mcast, and another to receive mcasts and place them on stdio output. The first statement has the built-in `stdio` scratch on the rhs: this includes any lines of terminal input that arrived since the last timestep. For each line of terminal input, the `do...end` block formats an `mcast` message destined to the address in the instance variable `@server`, with an array as the payload. The rhs of the second statement takes `mcast` messages that arrived since the last timestep. For each message `m`, the `m.val` expression in the block returns the message payload; the call to the Ruby instance method `pretty_print` formats the message so it will look nice on-screen. These formatted strings are placed (asynchronously, as before) into `stdio` on the left.
270
268
 
271
269
  The remaining lines are Ruby driver code to instantiate and run the ChatClient class (which includes the `Bud` module) using arguments from the command line. Note the option `:read_stdin => true` to `ChatClient.new`: this causes the Bud runtime to capture stdin via the built-in `stdio` collection.
272
270
 
data/docs/intro.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # *Bud*: Ruby <~ Bloom #
2
2
 
3
- Bud is a prototype of the [*Bloom*](http://bloom-lang.org) language for distributed programming, embedded as a DSL in Ruby. "Bud" stands for *Bloom under development*. The current 0.0.1 release is the initial alpha, targeted at "friends and family" who would like to engage at an early stage in the language design.
3
+ Bud is a prototype of the [*Bloom*](http://bloom-lang.org) language for distributed programming, embedded as a DSL in Ruby. "Bud" stands for *Bloom under development*. The current release is the initial alpha, targeted at "friends and family" who would like to engage at an early stage in the language design.
4
4
 
5
5
  ## Distributed Code in Bloom ##
6
6
  The goal of Bloom is to make distributed programming far easier than it has been with traditional languages. The key features of Bloom are:
@@ -15,22 +15,22 @@ The goal of Bloom is to make distributed programming far easier than it has been
15
15
 
16
16
  ## Alpha Goals and Limitations ##
17
17
 
18
- We had three main goals in preparing this release. The first was to flesh out the shape of the Bloom language: initial syntax and semantics, and the "feel" of embedding it as a DSL. The second goal was to build tools for reasoning about Bloom programs: both automatic program analysis, and tools for surfacing that analysis to developers.
18
+ We had three main goals in preparing this release. The first was to flesh out the shape of the Bloom language: initial syntax and semantics, and the "feel" of embedding it as a DSL. The second goal was to build tools for reasoning about Bloom programs: both automatic program analyses, and tools for surfacing those analyses to developers.
19
19
 
20
20
  The third goal was to start a feedback loop with developers interested in the potential of the ideas behind the language. We are optimistic that the principles underlying Bloom can make distributed programming radically simpler. But we realize that those ideas only matter if programmers can adopt them naturally. We intend Bud to be the beginning of an iterative design partnership with developers who see value in betting early on these ideas, and shaping the design of the language.
21
21
 
22
- In developing this alpha release, we explicitly set aside some issues that we intend to revisit in future. The first limitation is performance: Bud 0.0.1 is not intended to excel in single-node performance in terms of either latency, throughput or scale. We do expect major improvements on all these fronts in future releases: many of the known performance problems have known solutions that we've implemented in prior systems, and we intend to revisit them for our beta release. The second main limitation involves integration issues embedding Bloom as a DSL in Ruby. In the spectrum from flexibility to purity, we leaned decidedly toward flexibility. The barriers between Ruby and Bloom code are very fluid in the alpha, and we do relatively little to prevent programmers from ad-hoc mixtures of the two. Aggressive use of Ruby within Bloom statements is likely to do something *interesting*, but not necessarily predictable or desirable. This is an area where we expect to learn more from experience, and make some more refined decisions for the beta release.
22
+ In developing this alpha release, we explicitly set aside some issues that we intend to revisit in future. The first limitation is performance: Bud alpha is not intended to excel in single-node performance in terms of either latency, throughput or scale. We do expect major improvements on all these fronts in future releases: many of the known performance problems have known solutions that we've implemented in prior systems. The second main limitation involves integration issues embedding Bloom as a DSL in Ruby. In the spectrum from flexibility to purity, we leaned decidedly toward flexibility. The barriers between Ruby and Bloom code are very fluid in the alpha, and we do relatively little to prevent programmers from ad-hoc mixtures of the two. Aggressive use of Ruby within Bloom statements is likely to do something *interesting*, but not necessarily predictable or desirable. This is an area where we expect to learn more from experience, and make some more refined decisions for the beta release.
23
23
 
24
24
  ### Friends and Family: Come On In ###
25
- Although our team has many years of development experience, Bud is still open-source academic software built on a decidedly personal scale.
25
+ Although our team has many years of development experience, Bud is still open-source academic software built by a small group of researchers.
26
26
 
27
- This 0.0.1 alpha is targeted at "friends and family", and at developers who'd like to become same. This is definitely the bleeding edge: we're in a rapid cycle of learning about this new style of programming, and exposing what we learn in new iterations of the language. If you'd like to jump on the wheel with us and play with Bud, we'd love your feedback--both success stories and constructive criticism.
27
+ This alpha is targeted at "friends and family", and at developers who'd like to become same. This is definitely the bleeding edge: we're in a rapid cycle of learning about this new style of programming, and exposing what we learn in new iterations of the language. If you'd like to jump on the wheel with us and play with Bud, we'd love your feedback--both success stories and constructive criticism.
28
28
 
29
29
  ## Getting Started ##
30
30
  We're shipping Bud with a [sandbox](http://github.com/bloom-lang/bud-sandbox) of libraries and example applications for distributed systems. These illustrate the language and how it can be used, and also can serve as mixins for new code you might want to write. You may be surprised at how short the provided Bud code is, but don't be fooled.
31
31
 
32
- To get you started with Bud, we've provided a [quick-start tutorial](getstarted.md), instructions for [deploying distributed Bud](deployer.md) programs on Amazon's EC2 cloud, and a number of other docs you can find linked from the [README](README.md).
32
+ To get you started with Bud, we've provided a [quick-start tutorial](getstarted.md), instructions for [deploying distributed Bud](deploy.md) programs on Amazon's EC2 cloud, and a number of other docs you can find linked from the [README](README.md).
33
33
 
34
- We welcome both constructive criticism and (hopefully occasional) smoke-out-your-ears, hair-tearing shouts of frustration. Please point your feedback cannon at the [Bloom mailing list](http://groups.google.com/group/bloom-lang) on Google Groups.
34
+ We welcome both constructive criticism and (hopefully occasional) smoke-out-your-ears, hair-tearing shouts of frustration. Please point your feedback cannon at the [Bloom mailing list](http://groups.google.com/group/bloom-lang).
35
35
 
36
36
  Happy Blooming!
data/docs/modules.md CHANGED
@@ -1,19 +1,19 @@
1
- # Code Structuring and Reuse in BUD
1
+ # Code Structuring and Reuse in Bud
2
2
 
3
3
  ## Language Support
4
4
 
5
5
  ### Ruby Mixins
6
6
 
7
- The basic unit of reuse in BUD is the mixin functionality provided by Ruby itself. BUD code is structured into modules, each of which may have its own __state__ and__bootstrap__ block and any number of __bloom__ blocks (described below). A module or class may mix in a BUD module via Ruby's _include_ statement. _include_ causes the specified module's code to be expanded into the local scope.
7
+ The basic unit of reuse in Bud is the mixin functionality provided by Ruby itself. Bud code is structured into modules, each of which may have its own __state__ and __bootstrap__ block and any number of __bloom__ blocks (described below). A module or class may mix in a Bud module via Ruby's _include_ statement. _include_ causes the specified module's code to be expanded into the local scope.
8
8
 
9
9
  ### Bloom Blocks
10
10
 
11
- While the order and grouping of BUD rules have no semantic significance, rules can be grouped and tagged within a single module using __bloom__ blocks. Bloom blocks serve two purposes:
11
+ While the order and grouping of Bud rules have no semantic significance, rules can be grouped and tagged within a single module using __bloom__ blocks. Bloom blocks serve two purposes:
12
12
 
13
13
  1. Improving readability by grouping related or dependent rules together.
14
14
  2. Supporting name-based overriding.
15
15
 
16
- (1) is self-explanatory. (2) represents one of several extensibility mechanisms provided by BUD. If a Module B includes a module A which contains a basket X, B may supply a bloom block X and in so doing replaces the set of rules defined by (A.)X with its own set. For example:
16
+ (1) is self-explanatory. (2) represents one of several extensibility mechanisms provided by Bud. If a Module B includes a module A which contains a basket X, B may supply a bloom block X and in so doing replaces the set of rules defined by (A.)X with its own set. For example:
17
17
 
18
18
  require 'rubygems'
19
19
  require 'bud'
@@ -46,11 +46,11 @@ While the order and grouping of BUD rules have no semantic significance, rules c
46
46
  The program above will print "Hello, 1", because the module HelloTwo overrides the bloom block named __hi__. If we give the bloom block in HelloTwo a distinct name, the program will print "Hello, 1" and "Hello, 2" (in no guaranteed order).
47
47
 
48
48
 
49
- ### The BUD Module Import System
49
+ ### The Bud Module Import System
50
50
 
51
51
  For simple programs, composing modules via _include_ is often sufficient. But the flat namespace provided by mixins can make it difficult or impossible to support certain types of reuse. Consider a module Q that provides a queue-like functionality via an input interface _enqueue_ and an output interface _dequeue_, each with a single attribute (payload). A later module may wish to employ two queues (say, to implement a scheduler). But it cannot include Q twice! It would be necessary to rewrite Q's interfaces so as to support multiple ``users.''
52
52
 
53
- In addition to _include_, BUD supports the _import_ keyword, which instantiates a BUD module under a namespace alias. For example:
53
+ In addition to _include_, Bud supports the _import_ keyword, which instantiates a Bud module under a namespace alias. For example:
54
54
 
55
55
  module UserCode
56
56
  import Q => :q1
@@ -67,18 +67,18 @@ In addition to _include_, BUD supports the _import_ keyword, which instantiates
67
67
 
68
68
  ### Structuring
69
69
 
70
- In summary, BUD extends the basic Ruby code structuring mechanisms (classes and modules) with bloom blocks, for finer-granularity grouping of rules
70
+ In summary, Bud extends the basic Ruby code structuring mechanisms (classes and modules) with bloom blocks, for finer-granularity grouping of rules
71
71
  within modules, and the import system, for scoped inclusion.
72
72
 
73
73
  ### Composition
74
74
 
75
- Basic code composition can achieved using the Ruby mixin system. If the flat namespace causes ambiguity (as above) or hinders readability, the import system provides the ability to scope code inclusions.
75
+ Basic code composition can achieved using the Ruby mixin system. If the flat namespace causes ambiguity (as above) or hinders readability, the Bud import system provides the ability to scope code inclusions.
76
76
 
77
77
  ### Extension and Overriding
78
78
 
79
- Extending the existing functionality of a BUD program can be achieved in a number of ways. The simplest (but arguably least flexible) is via bloom block overriding, as described in the Hello example above.
79
+ Extending the existing functionality of a Bud program can be achieved in a number of ways. The simplest (but arguably least flexible) is via bloom block overriding, as described in the Hello example above.
80
80
 
81
- The import system can be used to implement finer-grained overriding, at the collection level. Consider a module BlackBox that provides an input interface __iin__ and an output interface __iout__. Suppose that we wish to "use" BlackBox, but need to provide additional functionality. We may extend one or both of its interfaces by _import_'ing BlackBox, redeclaring the interfaces, and gluing them together. For example, the module UsesBlackBox shown below interposes additional logic (indicated by ellipses) upstream of BlackBox's input interface, and provides ``extended'' BlackBox functionality.
81
+ The import system can be used to implement finer-grained overriding, at the collection level. Consider a module BlackBox that provides an input interface __iin__ and an output interface __iout__. Suppose that we wish to "use" BlackBox, but need to provide additional functionality. We may extend one or both of its interfaces by _import_-ing BlackBox, redeclaring the interfaces, and gluing them together. For example, the module UsesBlackBox shown below interposes additional logic (indicated by ellipses) upstream of BlackBox's input interface, and provides ``extended'' BlackBox functionality.
82
82
 
83
83
  module UsesBlackBox
84
84
  import BlackBox => :bb
data/docs/operational.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # An Operational View Of Bloom #
2
- You may ask yourself: well, what does a Bloom program *mean*? You may ask yourself: How do I read this Bloom code? ([You may tell yourself, this is not my beautiful house.](http://www.youtube.com/watch?v=I1wg1DNHbNU) But I digress.)
2
+ You may ask yourself: well, what does a Bloom program *mean*? You may ask yourself: How do I read this Bloom code? ([You may tell yourself, this is not my beautiful house.](http://www.youtube.com/watch?v=I1wg1DNHbNU))
3
3
 
4
- There is a formal answer to these questions about Bloom, but there's also a more more approachable answer. *Very* briefly, the formal answer is that Bloom's semantics are based in model theory, via a temporal logic language called *Dedalus* that is described in [a paper from Berkeley](http://www.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.html).
4
+ There is a formal answer to these questions about Bloom, but there's also a more more approachable answer. Briefly, the formal answer is that Bloom's semantics are based in finite model theory, via a temporal logic language called *Dedalus* that is described in [a paper from Berkeley](http://www.eecs.berkeley.edu/Pubs/TechRpts/2009/EECS-2009-173.html).
5
5
 
6
6
  While that's nice for proving theorems (and writing [program analysis tools](visualizations.md)), many programmers don't find model-theoretic discussions of semantics terribly helpful or even interesting. It's usually easier to think about how the language *works* at some level, so you can reason about how to use it.
7
7
 
@@ -16,7 +16,7 @@ Each machine runs an evaluator that works in a loop, as depicted in this figure:
16
16
 
17
17
  Each iteration of this loop is a *timestep* for that node; each timestep is associated with a monotonically increasing timestamp (which is accessible via the `budtime` method in Bud). Timesteps and timestamps are not coordinated across nodes; any such coordination has to be programmed in the Bloom language itself.
18
18
 
19
- A Bloom timestep has 3 main phases:
19
+ A Bloom timestep has 3 main phases (from left to right):
20
20
 
21
21
  1. *setup*: All scratch collections are set to empty. Network messages and periodic timer events are received from the runtime and placed into their designated `channel` and `periodic` scratches, respectively, to be read in the rhs of statements. Note that a batch of multiple messages/events may be received at once.
22
22
  2. *logic*: All Bloom statements for the program are evaluated. In programs with recursion through instantaneous merges (`<=`), the statements are repeatedly evaluated until a *fixpoint* is reached: i.e. no new lhs items are derived from any rhs.
@@ -31,7 +31,7 @@ It is important to understand how the Bloom collection operators fit into these
31
31
 
32
32
  ## Atomicity: Timesteps and Deferred Operators ##
33
33
 
34
- The only instantaneous Bloom operator is a merge (`<=`), which can only introduce additional items into a collection--it can not delete or change existing items. As a result, all state within a Bloom timestep is *immutable*: once an item is in a collection at timestep *T*, it stays in that collection throughout timestep *T*.
34
+ The only instantaneous Bloom operator is a merge (`<=`), which can only introduce additional items into a collection--it can not delete or change existing items. As a result, all state within a Bloom timestep is *immutable*: once an item is in a collection at timestep *T*, it stays in that collection throughout timestep *T*. (And forever after, the fact that the item was in that collection at timestep *T* remains true.)
35
35
 
36
36
  To get atomic state change in Bloom, you exploit the combination of two language features:
37
37
 
@@ -45,7 +45,7 @@ State "update" is achieved in Bloom via a pair of deferred statements, one posit
45
45
 
46
46
  This atomically replaces the entry for key 1 with the value "newval" at the start of the next timestep.
47
47
 
48
- Any reasoning about atomicity in Bloom programs is built on this simple foundation. It's really all you need. In the bud-sandbox we show how to build more powerful atomicity constructs using it, including things like enforcing [message ordering across timesteps](https://github.com/bloom-lang/bud-sandbox/tree/master/ordering), and protocols for [agreeing on ordering of distributed updates](https://github.com/bloom-lang/bud-sandbox/tree/master/paxos) across all nodes.
48
+ Any reasoning about atomicity in Bloom programs is built on this simple foundation. It's really all you need. In the bud-sandbox we show how to build more powerful atomicity constructs using it, including things like enforcing [ordering of items across timesteps](https://github.com/bloom-lang/bud-sandbox/tree/master/ordering), and protocols for [agreeing on ordering of distributed updates](https://github.com/bloom-lang/bud-sandbox/tree/master/paxos) across all nodes.
49
49
 
50
50
  ## Recursion in Bloom ##
51
51
  Because Bloom is data-driven rather than call-stack-driven, recursion may feel a bit unfamiliar at first.
@@ -69,7 +69,7 @@ Have a look at the following classic "transitive closure" example, which compute
69
69
 
70
70
  The recursion in the second Bloom statement is easy to see: the lhs and rhs both contain the path collection, so path is defined in terms of itself.
71
71
 
72
- You can think of this being computed by reevaluating the bloom block over and over--within a single timestep--until no more new paths are found. In each iteration, we find new paths that are one hop longer than the longest paths found previously. When no new items are found in an iteration, we are at what's called a *fixpoint*.
72
+ You can think of this being computed by reevaluating the bloom block over and over--within phase 2 of a single timestep--until no more new paths are found. In each iteration, we find new paths that are one hop longer than the longest paths found previously. When no new items are found in an iteration, we are at what's called a *fixpoint*, and we can move to phase 3.
73
73
 
74
74
  Hopefully that description is fairly easy to understand. You can certainly construct more complicated examples of recursion--just as you can in a traditional language (e.g., simultaneous recursion.) But understanding this example of simple recursion is probably sufficient for most needs.
75
75
 
@@ -85,7 +85,7 @@ The `argmax` expression in the rhs of this statement finds the items in path tha
85
85
 
86
86
  It's interesting to think about how to evaluate this statement. Consider what happens after a single iteration of the path-finding logic listed above. We will have 1-hop paths between some pairs. But there will likely be multi-hop paths between those pairs that cost more. So it would be premature after a single iteration to put anything out on stdio. In fact, we can't be sure what should go out to stdio until we have hit a fixpoint with respect to the path collection. That's because `argmax` is a logically *non-monotonic* operator: as we merge more items into its input collection, it may have to "retract" an output they would previously have produced.
87
87
 
88
- The Bud runtime takes care of this problem for you under the covers, by breaking your statements in *strata* (layers) via a process called *stratification*. The basic idea is simple. The goal is to postpone evaluating non-monotonic operators until fixpoint is reached on their input collections. Stratification basically breaks up the statements in a Bloom program into layers that are separated by non-monotonic operators, and evaluates the layers in order.
88
+ The Bud runtime takes care of this problem for you under the covers, by breaking your statements in *strata* (layers) via a process called *stratification*. The basic idea is simple. The goal is to postpone evaluating non-monotonic operators until fixpoint is reached on their input collections. Stratification basically breaks up the statements in a Bloom program into layers that are separated by non-monotonic operators, and evaluates the layers in order. (Note: the singular form of strata is *stratum*).
89
89
 
90
90
  For your reference, the basic non-monotonic Bloom operators include `group, reduce, argmin, argmax`. Also, statements that embed Ruby collection methods in their blocks are often non-monotonic--e.g., methods like `all?, empty?, include?, none?` and `size`.
91
91
 
data/docs/ruby_hooks.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ## Ruby/Bloom interactions in Bud ##
2
- Bud embeds Bloom as a [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) in Ruby. On a given node, it is often useful to run a Ruby thread, and pass information to and from Bloom-land and Ruby-land. If nothing else, this allows the Ruby process hosting the Bud evaluator to monitor its progress.
2
+ Bud embeds Bloom as a [DSL](http://en.wikipedia.org/wiki/Domain-specific_language) in Ruby. On a given node, it is often useful to run a Ruby thread, and pass information between one vanilla Ruby thread, and another one running Bloom code.
3
3
 
4
- As described in the [Getting Started](getstarted.md) document, we embed Bloom code into Ruby by including the `Bud` module in some Ruby class, and putting Bloom blocks into the class. We then typically allocate a new instance of that class in Ruby, and invoke either its `run` method or `run_bg` method. Since the Bud runtime typically runs indefinitely, the blocking `run` call essentially hands the thread over to Bud. The `run_bg` call puts the Bud runtime into a second thread and returns to the caller.
4
+ As described in the [Getting Started](getstarted.md) document, we embed Bloom code into Ruby by including the `Bud` module in some Ruby class, and putting Bloom blocks into the class. We then typically allocate a new instance of that class in Ruby, and invoke either its `run_fg` method or `run_bg` method. Since the Bud runtime typically runs indefinitely, the blocking `run_fg` call essentially hands the thread over to Bud. The `run_bg` call puts the Bud runtime into a second thread and returns to the caller.
5
5
 
6
6
  To support the `run_bg` case further, the Bud runtime provides hooks for Ruby threads to register code with the runtime for execution during Bloom timesteps. These hooks always run at the end of a timestep, after all Bloom statements have been processed for that timestep. There are two basic types of hooks:
7
7
 
@@ -12,7 +12,7 @@ To support the `run_bg` case further, the Bud runtime provides hooks for Ruby t
12
12
  ## Bud and Ruby-driven Side Effects ##
13
13
  The Bloom language itself is a pure logic language based in Dedalus. Like any logic language, it has no notion of "mutable state" or "side effects". Each item that appears in a Bloom collection at timestep T will *forever* be recorded as having been in that collection at timestep T, at least in a formal sense. The temporal logic of Dedalus is a lot like a versioning system, where old versions of items are never removed.
14
14
 
15
- In the context of the existing Bud prototype, though, it easy to step outside the bright lines of pure Bloom using straight Ruby code and libraries. Methods like `sync_do` and callbacks allow Ruby code to be run that can mess with Bloom collections in a way that Bloom doesn't model. Similarly, Ruby blocks *within* the rhs of a Bloom statement (e.g. after a collection name or a `pairs` call) can produce visible side-effects in unpredictable ways. In particular, be aware that side-effecting Ruby code within a Bloom block may be called an *arbitrary* number of times during a single Bloom timestep, as it works its way to fixpoint.
15
+ In the context of the existing Bud prototype, though, it easy to step outside the bright lines of pure Bloom using straight Ruby code and libraries. Methods like `sync_do` and callbacks allow Ruby code to be run that can mess with Bloom collections in a way that Bloom doesn't model. Similarly, Ruby blocks *within* the rhs of a Bloom statement (e.g. after a collection name or a `pairs` call) can produce visible side-effects in unpredictable ways. In particular, be aware that any side-effect-producing Ruby code within a Bloom block may be called an *arbitrary* number of times during a single Bloom timestep, as Bud works its way to fixpoint.
16
16
 
17
17
  If you must pollute your Bloom statements with side-effecting Ruby, please do it with *idempotent* side-effecting Ruby. Thank you.
18
18
 
@@ -1,8 +1,8 @@
1
1
  # Visualizations
2
2
 
3
- BUD programs compile naturally to dataflows, and dataflows have a natural graphical representation. Plotting a program as a graph can be useful to developers at various stages of program design, implementation and debugging. BUD predicate dependency graphs (or PDGs) are described on [[PDGs]].
3
+ Bud programs compile naturally to dataflows, and dataflows have a natural graphical representation. Plotting a program as a graph can be useful to developers at various stages of program design, implementation and debugging. Bud predicate dependency graphs (or PDGs) are described on [[PDGs]].
4
4
 
5
- BUD ships with two visualization utilities, __plotter__ and __visualizer__. Both use _GraphViz_ to draw a directed graph representing the program state and logic. __plotter__ provides a static analysis of the program, identifying sources and sinks of the dataflow, unconnected components, and points of order corresponding to logically nonmonotonic path edges. __visualizer__ is an offline debugging tool that analyses the trace of a (local) BUD execution and provides an interactive representation of runtime state over time.
5
+ Bud ships with two visualization utilities, __plotter__ and __visualizer__. Both use _GraphViz_ to draw a directed graph representing the program state and logic. __plotter__ provides a static analysis of the program, identifying sources and sinks of the dataflow, unconnected components, and points of order corresponding to logically nonmonotonic path edges. __visualizer__ is an offline debugging tool that analyses the trace of a (local) Bud execution and provides an interactive representation of runtime state over time.
6
6
 
7
7
  ## The Plotter
8
8
 
@@ -22,7 +22,7 @@ The __plotter__ is a visual static analysis tool that aids in design and early i
22
22
  USAGE:
23
23
  ruby budplot LIST_OF_FILES LIST_OF_MODULES
24
24
 
25
- As its usage message indicates, __plotter__ expects a list of ruby input files, followed by a list of BUD modules to mix in.
25
+ As its usage message indicates, __plotter__ expects a list of ruby input files, followed by a list of Bud modules to mix in.
26
26
 
27
27
  $ ruby budplot kvs/kvs.rb ReplicatedKVS
28
28
  Warning: underspecified dataflow: ["my_id", true]
@@ -43,7 +43,7 @@ __ReplicatedKVS__ includes the __MulticastProtocol__ and __MembershipProtocol__
43
43
 
44
44
  [[https://github.com/bloom-lang/bud/blob/master/util/budvis]]
45
45
 
46
- To enable tracing, we need to set __:trace => true__ in the __BUD__ constructor, and optionally provide a __:tag__ to differentiate between traces by a human-readable name (rather than by object_id). I modified the unit test `test/tc_kvs.rb` as follows:
46
+ To enable tracing, we need to set __:trace => true__ in the __Bud__ constructor, and optionally provide a __:tag__ to differentiate between traces by a human-readable name (rather than by object_id). I modified the unit test `test/tc_kvs.rb` as follows:
47
47
 
48
48
  - v = BestEffortReplicatedKVS.new(@opts.merge(:port => 12345))
49
49
  - v2 = BestEffortReplicatedKVS.new(@opts.merge(:port => 12346))
@@ -15,4 +15,4 @@ class BustExample # :nodoc: all
15
15
  end
16
16
  end
17
17
 
18
- BustExample.new.run_fg
18
+ BustExample.new(:bust_port => 8080).run_fg
@@ -30,7 +30,7 @@ module TokenRing
30
30
  bloom :pass_token do
31
31
  # Persist the token for as long as necessary
32
32
  token_persist <= token
33
- token_persist <- join([token_persist, next_node]).map {|t,_| [t]}
33
+ token_persist <- join([token_persist, next_node]).map {|t,_| [t.loc]}
34
34
  # Pass on the token
35
35
  token <~ join([token_persist, next_node]).map {[next_node[[]].node]}
36
36
  stdio <~ token.map {["#{ip_port}: Got token!"]}
data/lib/bud.rb CHANGED
@@ -17,6 +17,8 @@ require 'bud/storage/tokyocabinet'
17
17
  require 'bud/storage/zookeeper'
18
18
  require 'bud/viz'
19
19
 
20
+ $em_stopped = Queue.new
21
+
20
22
  # We monkeypatch Module to add support for Bloom state and code declarations.
21
23
  class Module
22
24
 
@@ -165,7 +167,6 @@ module Bud
165
167
  @budtime = 0
166
168
  @inbound = []
167
169
  @done_bootstrap = false
168
- @em_stopped = Queue.new
169
170
  @joinstate = {} # joins are stateful, their state needs to be kept inside the Bud instance
170
171
 
171
172
  # Setup options (named arguments), along with default values
@@ -372,7 +373,7 @@ module Bud
372
373
  if stop_em
373
374
  schedule_shutdown(true)
374
375
  # Wait until EM has completely shutdown before we return.
375
- @em_stopped.pop
376
+ $em_stopped.pop
376
377
  else
377
378
  schedule_and_wait do
378
379
  do_shutdown(false)
@@ -519,7 +520,7 @@ module Bud
519
520
  q << true
520
521
  end
521
522
  # Executed only after EventMachine::stop_event_loop is done
522
- @em_stopped << true
523
+ $em_stopped << true
523
524
  end
524
525
  # Block waiting for EM's event loop to start up.
525
526
  q.pop
data/lib/bud/bust/bust.rb CHANGED
@@ -10,6 +10,7 @@ HTTP_VERBS = ["GET", "POST"] #, "DELETE"]
10
10
  # a RESTful interface to Bloom code
11
11
  module Bust
12
12
  include Bud
13
+ attr_reader :bust_port
13
14
 
14
15
  # used this for inspiration:
15
16
  # http://blogs.msdn.com/b/abhinaba/archive/2005/10/14/474841.aspx
@@ -33,7 +34,7 @@ module Bust
33
34
  BustClass.new(bud, q)
34
35
  end
35
36
  # Wait for socket to be ready before we return from bootstrap.
36
- q.pop
37
+ @bust_port = q.pop
37
38
  end
38
39
 
39
40
  class BustClass
@@ -100,9 +101,11 @@ module Bust
100
101
 
101
102
  def initialize(bud, q)
102
103
  # allow user-configurable port
103
- server = TCPServer.new(bud.ip, (bud.options[:bust_port] or 8080))
104
+ server = TCPServer.new(bud.ip, (bud.options[:bust_port] or 0))
105
+ port = server.addr[1]
106
+ puts "Bust server listening on #{bud.ip}:#{port}"
104
107
  # We're now ready to accept connections.
105
- q << true
108
+ q << port
106
109
 
107
110
  loop do
108
111
  session = server.accept
@@ -298,7 +298,7 @@ module Bud
298
298
  public
299
299
  def insert(o) # :nodoc: all
300
300
  # puts "insert: #{o.inspect} into #{tabname}"
301
- do_insert(o, @delta)
301
+ do_insert(o, @storage)
302
302
  end
303
303
 
304
304
  # instantaneously place an individual item from rhs into collection on lhs
@@ -160,8 +160,8 @@ module EC2Deploy
160
160
  raise "Couldn't open a PTY on #{t.node}" if !success
161
161
  end
162
162
  channel.exec("sudo gem update --no-ri --no-rdoc bud")
163
- channel.wait
164
163
  end
164
+ channel.wait
165
165
  # Run the ruby_command
166
166
  session.exec!('nohup ' + ruby_command[[]].cmd + ' ' + t.localip +
167
167
  ' ' + t.node + ' >metarecv.out 2>metarecv.err </dev/null &')
@@ -7,17 +7,27 @@ require 'bud/deploy/deployer'
7
7
  module LocalDeploy
8
8
  include Deployer
9
9
 
10
- trap("CLD") {
11
- pid = Process.wait
12
- puts "Child pid #{pid}: terminated"
13
- }
10
+ def stop_bg
11
+ super
12
+ for p in @pids
13
+ Process.kill("INT", p)
14
+ end
15
+ Process.waitall
16
+ trap("CLD", "DEFAULT")
17
+ end
14
18
 
15
19
  deploystrap do
20
+ trap("CLD") {
21
+ pid = Process.wait
22
+ puts "Child pid #{pid}: terminated"
23
+ }
24
+
16
25
  read, write = IO.pipe
17
26
  if node_count[[]]
18
27
  print "Forking local processes"
28
+ @pids = []
19
29
  (0..node_count[[]].num-1).map do |i|
20
- Process.fork do
30
+ @pids << Process.fork do
21
31
  # Don't want to inherit our parent's random stuff.
22
32
  srand
23
33
  foo = self.class.new
@@ -34,6 +44,8 @@ module LocalDeploy
34
44
  (0..node_count[[]].num-1).map do |i|
35
45
  node << [i, "localhost:" + read.readline.rstrip]
36
46
  end
47
+ read.close
48
+ write.close
37
49
  puts "done"
38
50
  end
39
51
  end
data/lib/bud/rewrite.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'ruby2ruby'
3
3
 
4
- class RuleRewriter < Ruby2Ruby #:nodoc: all
4
+ class RuleRewriter < Ruby2Ruby # :nodoc: all
5
5
  attr_accessor :rule_indx, :rules, :depends
6
6
 
7
7
  def initialize(seed, bud_instance)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bud
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Peter Alvaro
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2011-04-06 00:00:00 -07:00
21
+ date: 2011-04-07 00:00:00 -07:00
22
22
  default_executable: rebl
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency