zillabyte-cli 0.9.0 → 0.9.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eea29081785924f4123050342b0106d98355f0c8
4
- data.tar.gz: 9e5e777aa135171b8230ced0011622519e450539
3
+ metadata.gz: 90127131598b38dedc88b0903dc0b984537442a1
4
+ data.tar.gz: acf6b8bb47b8476621ea36834310ed48d479463a
5
5
  SHA512:
6
- metadata.gz: 9b6441517bb14bd08ce83ddc6502e99287434f80403e6a1ee634c9880546ac772c32ea49bffe320737d72b7c70f1135e65862026df7ae89df3542f61447d5788
7
- data.tar.gz: ad27686e26e9ebe20d2a4e38879449108dc2f8df4be5c70fecd97617cd409ec2f457dc337a09f3b4772144d5cf586d0e71533150a3551d7d5b5e4537e73e7924
6
+ metadata.gz: d99663ba95dfbc8e76ef06656bf55621812f71c400c2ed170f00c5528cf04225b188b4b47e003fab82d8ac6f8f48f262261a47bd4f3750ef6d7715431ce85eee
7
+ data.tar.gz: 32ab54910d7b01b6171123ec1b7312a8fb8bafcb612c5465b3af5dfeaf77a0eda9e6c957bc179487bba29ea18550d63828b20e091a3640b03283448151d54d68
@@ -1,5 +1,5 @@
1
1
  module Zillabyte
2
2
  module CLI
3
- VERSION = "0.9.0"
3
+ VERSION = "0.9.1"
4
4
  end
5
5
  end
@@ -37,11 +37,13 @@ class Zillabyte::Runner::ComponentOperation
37
37
  end
38
38
  begin
39
39
  case @__type
40
- when "source"
40
+ when "input"
41
41
  self.run_input()
42
42
  when "component"
43
43
  self.run_rpc_component()
44
-
44
+ when "output"
45
+ node["type"] = "sink"
46
+ Zillabyte::Runner::MultilangOperation.run(node, dir, consumee_pipes, consumer_pipes, tester, meta, options)
45
47
  # Component outputs act in same manner as sinks
46
48
  else
47
49
  Zillabyte::Runner::MultilangOperation.run(node, dir, consumee_pipes, consumer_pipes, tester, meta, options)
@@ -50,6 +52,7 @@ class Zillabyte::Runner::ComponentOperation
50
52
  cdisplay e.message
51
53
  cdisplay e.backtrace
52
54
  end
55
+ cdisplay "EXIT"
53
56
  end
54
57
 
55
58
 
@@ -142,9 +145,8 @@ class Zillabyte::Runner::ComponentOperation
142
145
  loop do
143
146
 
144
147
  msg = stdin.gets
145
- if msg == END_CYCLE_MESSAGE
146
- send_to_consumers(END_CYCLE_MESSAGE)
147
- send_to_consumers(DONE_MESSAGE)
148
+ if msg == KILL_CYCLE_MESSAGE
149
+ send_to_consumers(KILL_CYCLE_MESSAGE)
148
150
  return
149
151
  else
150
152
  # Build tuples
@@ -271,13 +273,6 @@ class Zillabyte::Runner::ComponentOperation
271
273
  # Handle Tuple in here
272
274
  data_streams = hash['data']
273
275
 
274
- # if stream_hash.nil?
275
- # cdisplay("error : no results!")
276
- # next
277
- # else
278
- # stream_hash.each_pair
279
- # end
280
-
281
276
  # Handle each resulting tuple
282
277
  data_streams.each_pair do |stream, data_tuples|
283
278
  data_tuples.each do |data_tuple|
@@ -334,7 +329,7 @@ class Zillabyte::Runner::ComponentOperation
334
329
  send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
335
330
  consumers_running -= 1
336
331
  if consumers_running == 0
337
- break
332
+ return
338
333
  end
339
334
 
340
335
  # TODO break if last consumer
@@ -356,7 +351,7 @@ class Zillabyte::Runner::ComponentOperation
356
351
 
357
352
  # Exit after ending consumer cycles
358
353
  if consumers_running == 0
359
- break
354
+ return
360
355
  end
361
356
  end
362
357
 
@@ -5,7 +5,7 @@ require "zillabyte/runner/component_operation"
5
5
  class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
6
6
  include Zillabyte::Helpers
7
7
 
8
- END_CYCLE_MESSAGE = "{\"command\": \"end_cycle\"}\n"
8
+ KILL_CYCLE_MESSAGE = "{\"command\": \"kill_cycle\"}\n"
9
9
 
10
10
  def run (meta, dir = Dir.pwd, session = nil, options = {})
11
11
 
@@ -154,7 +154,7 @@ class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
154
154
  out_pipes = {}
155
155
 
156
156
  # Check if you are the consumee for a downstream join in order to select the correct pipe
157
- if type != "sink"
157
+ if type != "output"
158
158
  @arc_map[name].each_pair do |stream, destinations|
159
159
  out_pipes[stream] ||= {}
160
160
 
@@ -216,7 +216,7 @@ class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
216
216
  name = n["name"]
217
217
  type = n["type"]
218
218
 
219
- if type == "source"
219
+ if type == "input"
220
220
  if source == ""
221
221
  source = name
222
222
  else
@@ -235,8 +235,13 @@ class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
235
235
  fields = @node_map[source]['fields'].map {|h| h.keys[0].upcase }
236
236
  display "Enter an input tuple in the form : #{fields.join(' ')}"
237
237
  msg = ask
238
+
239
+ # Kill the cycle
238
240
  if msg == 'end'
239
- msg = END_CYCLE_MESSAGE
241
+ @operation_pipes[source]["wr_parent_1"].puts KILL_CYCLE_MESSAGE
242
+ break
243
+
244
+ # Check arguments
240
245
  else
241
246
  args = msg.scan(/(?:\w|"[^"]*")+/)
242
247
  if (args.length % fields.length != 0)
@@ -244,11 +249,12 @@ class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
244
249
  next
245
250
  end
246
251
  end
247
-
248
252
  # Send tuple to source
249
253
  @operation_pipes[source]["wr_parent_1"].puts msg
254
+
250
255
  end
251
256
  end
257
+
252
258
  rescue => e
253
259
  display e.message
254
260
  display e.backtrace
@@ -311,12 +317,12 @@ class Zillabyte::Runner::ComponentRunner < Zillabyte::Command::Base
311
317
  display "#{"name".rjust(rjust)}: #{node['name'].to_s.colorize(color)}"
312
318
 
313
319
  # Convert metadata typing to that of components
314
- if node['type'] == "source"
320
+ if node['type'] == "input"
315
321
  type = "input"
316
322
  display "#{"type".rjust(rjust)}: #{type.to_s.colorize(color)}"
317
323
  display "#{"fields".rjust(rjust)}: #{node['fields'].to_s.colorize(color)}"
318
324
  display "#{"matches".rjust(rjust)}: #{JSON.pretty_generate(node['matches']).indent(rjust+2).lstrip.colorize(color)}" if node['matches']
319
- elsif node['type'] == "sink"
325
+ elsif node['type'] == "output"
320
326
  type = "output"
321
327
  display "#{"type".rjust(rjust)}: #{type.to_s.colorize(color)}"
322
328
  display "#{"columns".rjust(rjust)}: #{node['columns'].to_s.colorize(color)}"
@@ -3,6 +3,7 @@
3
3
  module Zillabyte; module Runner; class MultilangOperation
4
4
 
5
5
  HANDSHAKE_MESSAGE = "{\"pidDir\": \"/tmp\"}\n"
6
+ PREPARE_MESSAGE = " {\"command\": \"prepare\"}\n"
6
7
  DONE_MESSAGE = "{\"command\": \"done\"}\n"
7
8
  NEXT_MESSAGE = "{\"command\": \"next\"}\n"
8
9
  BEGIN_CYCLE_MESSAGE = "{\"command\": \"begin_cycle\"}\n"
@@ -77,9 +78,8 @@ module Zillabyte; module Runner; class MultilangOperation
77
78
 
78
79
  msg = @__consumee_pipes["rd_child_1"].gets
79
80
 
80
- if msg == END_CYCLE_MESSAGE
81
- send_to_consumers(END_CYCLE_MESSAGE)
82
- send_to_consumers(DONE_MESSAGE)
81
+ if msg == KILL_CYCLE_MESSAGE
82
+ send_to_consumers(KILL_CYCLE_MESSAGE)
83
83
  return
84
84
  else
85
85
  # Build tuple
@@ -193,217 +193,211 @@ module Zillabyte; module Runner; class MultilangOperation
193
193
  # Kill the cycle on error
194
194
  cycle_killed = false
195
195
 
196
- # Setup multilang pipe
197
- ml_pipe = "#{@__name}_pipe"
198
- if File.exists?("#{ml_pipe}.in")
199
- File.delete("#{ml_pipe}.in")
200
- end
201
- File.mkfifo("#{ml_pipe}.in")
202
-
203
-
196
+ # Setup multilang socket
197
+ require 'socket'
198
+ host = "0.0.0.0"
199
+ server = TCPServer.new(0)
200
+ port = server.addr[1]
201
+
204
202
  # Spawn multilang process
205
- cmd = command("--execute_live --name #{@__name} --pipe #{ml_pipe}")
203
+ cmd = command("--execute_live --name #{@__name} --host \"#{host}\" --port #{port}")
204
+
206
205
  begin
207
206
 
208
- Open3.popen3(cmd) do |ml_input, stdout, stderr, wait_thread|
207
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thread|
209
208
  begin
209
+ server_thread = Thread.new do
210
+ ml_socket = server.accept()
210
211
 
211
- # Multilang output tuples
212
- ml_output = File.open("#{ml_pipe}.in", "r")
213
-
214
- # Setup streams from consumers and multilang
215
- read_streams = consumer_hash.keys.concat [stdout, ml_output]
216
-
217
-
218
- # Handshake
219
- handshake(ml_input, ml_output)
220
-
221
- # Begin cycle
222
- begin_cycle(ml_input, ml_output)
223
- emitted = false
224
- write_message(ml_input, NEXT_MESSAGE)
225
- multilang_queue = []
226
- end_cycle_policy = @__options[:end_cycle_policy]
227
- end_cycle_received = false
228
-
229
- # Receive and handle messages
230
- loop do
231
-
232
- # Read from a stream
233
- rs = select_read_streams(read_streams)
234
- rs.each do |r|
235
-
236
- # Read stdout straight to user
237
- if r == stdout && consumers_running > 0
238
- msg = r.gets
239
- msg = msg.sub(/\n/, "")
240
- cdisplay("log: #{msg}")
241
- next
242
- end
243
-
244
- obj = read_message(r)
245
-
246
- if obj.nil?
247
- next
248
- end
212
+ # RUN SOURCE
213
+ begin
214
+ # Setup streams from consumers and multilang(stdout and socket communication)
215
+ read_streams = consumer_hash.keys.concat [stdout, ml_socket]
249
216
 
250
- if obj["command"]
217
+ # Handshake
218
+ handshake(ml_socket, ml_socket)
219
+ prepare(ml_socket, ml_socket)
251
220
 
252
- case obj["command"]
221
+ # Begin cycle
222
+ begin_cycle(ml_socket, ml_socket)
223
+ emitted = false
224
+ write_message(ml_socket, NEXT_MESSAGE)
225
+ multilang_queue = []
226
+ end_cycle_policy = @__options[:end_cycle_policy]
227
+ end_cycle_received = false
228
+
229
+ # Receive and handle messages
230
+ loop do
231
+ # Read from a stream
232
+ rs = select_read_streams(read_streams)
233
+ rs.each do |r|
234
+ # Read stdout straight to user
235
+ if r == stdout && consumers_running > 0
236
+ msg = r.gets
237
+ msg = msg.sub(/\n/, "")
238
+ cdisplay("log: #{msg}")
239
+ next
240
+ end
253
241
 
254
- # Multilang emitted a tuple
255
- when "emit"
256
- stream = obj['stream']
257
- # Check for null emit
258
- if end_cycle_policy != "explicit"
242
+ obj = read_message(r)
259
243
 
260
- if obj['tuple'].nil?
261
- end_cycle_received = true
262
- else
263
- nil_values = false
264
- obj['tuple'].each_value do |v|
265
- if v.nil?
266
- nil_values = true
267
- break
268
- end
269
- end
270
- end_cycle_received = nil_values
271
- next unless !end_cycle_received
272
- end
244
+ if obj.nil?
245
+ next
273
246
  end
274
247
 
275
- # Valid emit
276
- emitted = true
277
-
278
- # Send or enqueue tuple for each consumer
279
- tuple_json = build_tuple_json(obj['tuple'], obj['meta'], obj['column_aliases'])
248
+ if obj["command"]
249
+ case obj["command"]
250
+
251
+ # Multilang emitted a tuple
252
+ when "emit"
253
+ stream = obj['stream']
254
+ # Check for null emit
255
+ if end_cycle_policy != "explicit"
256
+
257
+ if obj['tuple'].nil?
258
+ end_cycle_received = true
259
+ else
260
+ nil_values = false
261
+ obj['tuple'].each_value do |v|
262
+ if v.nil?
263
+ nil_values = true
264
+ break
265
+ end
266
+ end
267
+ end_cycle_received = nil_values
268
+ next unless !end_cycle_received
269
+ end
270
+ end
280
271
 
281
- @__emit_queues[stream].each_pair do |consumer, emitter|
282
- if emitter[:ready]
283
- emit_consumer_tuple(stream, consumer, tuple_json)
272
+ # Valid emit
273
+ emitted = true
284
274
 
285
- else
286
- @__emit_queues[stream][consumer][:write_queue] << tuple_json
287
- end
288
- end
275
+ # Send or enqueue tuple for each consumer
276
+ tuple_json = build_tuple_json(obj['tuple'], obj['meta'], obj['column_aliases'])
289
277
 
290
- # Consumer is ready for a message
291
- when "next"
292
- stream = consumer_hash[r][:stream]
293
- consumer = consumer_hash[r][:consumer]
294
- @__emit_queues[stream][consumer][:ready] = true
295
- tuple_json = get_consumer_tuple(stream, consumer)
278
+ @__emit_queues[stream].each_pair do |consumer, emitter|
279
+ if emitter[:ready]
280
+ emit_consumer_tuple(stream, consumer, tuple_json)
296
281
 
297
- # End cycle for consumer if it has processed all tuples
298
- if tuple_json.nil? && end_cycle_received
282
+ else
283
+ @__emit_queues[stream][consumer][:write_queue] << tuple_json
284
+ end
285
+ end
299
286
 
300
- send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
301
- consumers_running -= 1
302
- if consumers_running == 0
303
- break
304
- end
287
+ # Consumer is ready for a message
288
+ when "next"
289
+ stream = consumer_hash[r][:stream]
290
+ consumer = consumer_hash[r][:consumer]
291
+ @__emit_queues[stream][consumer][:ready] = true
292
+ tuple_json = get_consumer_tuple(stream, consumer)
305
293
 
306
- # TODO break if last consumer
307
- elsif !tuple_json.nil?
308
- # Emit tuple to consumer
309
- emit_consumer_tuple(stream, consumer, tuple_json)
310
- emitted = true
311
- end
294
+ # End cycle for consumer if it has processed all tuples
295
+ if tuple_json.nil? && end_cycle_received
312
296
 
313
- # Multilang is done emitting a group of tuples
314
- when "done"
315
- # End cycle if no tuples were emitted
316
- if !emitted && end_cycle_policy == "null_emit"
317
- end_cycle_received = true
318
- else
319
- emitted = false
320
- end
321
-
322
- # Send the next tuple to multilang
323
- if !multilang_queue.empty?
324
- write_message(ml_input, multilang_queue.shift)
297
+ send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
298
+ consumers_running -= 1
299
+ if consumers_running == 0
300
+ exit(0)
301
+ end
325
302
 
326
- # Request next tuple from mutilang
327
- elsif !end_cycle_received
328
- write_message(ml_input, NEXT_MESSAGE)
303
+ # TODO break if last consumer
304
+ elsif !tuple_json.nil?
305
+ # Emit tuple to consumer
306
+ emit_consumer_tuple(stream, consumer, tuple_json)
307
+ emitted = true
308
+ end
329
309
 
330
- # If there are no more messages to send, we are done
331
- else end_cycle_received
332
- finished = true
333
- # End cycle for ready consumers
334
- @__emit_queues.each_pair do |stream, consumers|
335
- consumers.each_pair do |consumer, emitter|
336
- if emitter[:ready]
337
- send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
338
- consumers_running -= 1
339
- if consumers_running == 0
340
- break
310
+ # Multilang is done emitting a group of tuples
311
+ when "done"
312
+ # End cycle if no tuples were emitted
313
+ if !emitted && end_cycle_policy == "null_emit"
314
+ end_cycle_received = true
315
+ else
316
+ emitted = false
317
+ end
318
+
319
+ # Send the next tuple to multilang
320
+ if !multilang_queue.empty?
321
+ write_message(ml_socket, multilang_queue.shift)
322
+
323
+ # Request next tuple from mutilang
324
+ elsif !end_cycle_received
325
+ write_message(ml_socket, NEXT_MESSAGE)
326
+
327
+ # If there are no more messages to send, we are done
328
+ else end_cycle_received
329
+ finished = true
330
+ # End cycle for ready consumers
331
+ @__emit_queues.each_pair do |stream, consumers|
332
+ consumers.each_pair do |consumer, emitter|
333
+ if emitter[:ready]
334
+ send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
335
+ consumers_running -= 1
336
+ if consumers_running == 0
337
+ exit(0)
338
+ end
339
+ end
341
340
  end
341
+
342
342
  end
343
343
  end
344
344
 
345
+ # Multilang sent an error message
346
+ when "fail"
347
+ cdisplay("ERROR : #{obj['msg']}")
348
+ cycle_killed = true
349
+ exit(0)
350
+
351
+ # Multilang sent a log message
352
+ when "log"
353
+ cdisplay "LOG: #{obj['msg']}"
354
+
355
+ # Multilang sent signal to end the cycle
356
+ when "end_cycle"
357
+ if end_cycle_policy != "explicit"
358
+ cdisplay "received end_cycle command for non explicit policy"
359
+ next
360
+ end
361
+ end_cycle_received = true
362
+ when "kill_cycle"
363
+ cycle_killed = true
364
+ exit(0)
345
365
  end
346
- end
347
-
348
- # Multilang sent an error message
349
- when "fail"
350
- cdisplay("ERROR : #{obj['msg']}")
351
366
 
352
- # Multilang sent a log message
353
- when "log"
354
- cdisplay "LOG: #{obj['msg']}"
355
-
356
- # Multilang sent signal to end the cycle
357
- when "end_cycle"
358
- if end_cycle_policy != "explicit"
359
- cdisplay "received end_cycle command for non explicit policy"
360
- next
367
+ # Multilang sent a ping
368
+ elsif obj['ping']
369
+ write_message(ml_socket, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
361
370
  end
362
- end_cycle_received = true
363
- when "kill_cycle"
364
- cycle_killed = true
365
- return
366
371
  end
367
-
368
- # Multilang sent a ping
369
- elsif obj['ping']
370
- write_message(ml_input, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
371
372
  end
372
- end
373
373
 
374
- # Exit after ending consumer cycles
375
- if consumers_running == 0
376
- return
374
+ # Exit after ending consumer cycles
375
+ if consumers_running == 0
376
+ exit(0)
377
+ end
378
+ rescue => e
379
+ cycle_killed = true
380
+ cdisplay e.message
381
+ cdisplay e.backtrace
382
+ ensure
383
+ ml_socket.close()
377
384
  end
378
-
379
385
  end
386
+ server_thread.join()
380
387
  rescue => e
381
- cycle_killed = true
382
- cdisplay e.message
383
- cdisplay e.backtrace
384
388
  ensure
385
-
386
389
  # cleanup
387
390
  if cycle_killed
388
391
  send_to_consumers(KILL_CYCLE_MESSAGE, false)
389
392
  end
390
393
  pid = wait_thread[:pid]
391
- ml_input.close
392
- if File.exists?("#{ml_pipe}.in")
393
- ml_output.close
394
- File.delete("#{ml_pipe}.in")
395
- end
396
394
  stdout.close
397
- stderr.close
398
395
  Process.kill('INT', pid)
399
396
  Process.exit!(true)
400
397
  end
401
398
  end
402
399
 
403
400
  rescue PTY::ChildExited
404
- if File.exists?("#{ml_pipe}.in")
405
- File.delete("#{ml_pipe}.in")
406
- end
407
401
  end
408
402
  end
409
403
  end
@@ -411,7 +405,6 @@ module Zillabyte; module Runner; class MultilangOperation
411
405
 
412
406
  def self.run_each()
413
407
 
414
-
415
408
  # Index streams and consumers by their pipes for lookup
416
409
  consumer_hash = build_consumer_hash()
417
410
 
@@ -421,182 +414,187 @@ module Zillabyte; module Runner; class MultilangOperation
421
414
  # Kill the cycle on error
422
415
  cycle_killed = false
423
416
 
424
- # Setup multilang pipe
425
- ml_pipe = "#{@__name}_pipe"
426
- if File.exists?("#{ml_pipe}.in")
427
- File.delete("#{ml_pipe}.in")
428
- end
429
- File.mkfifo("#{ml_pipe}.in")
430
-
431
- cmd = command("--execute_live --name #{@__name} --pipe #{ml_pipe}")
417
+ # Setup multilang socket
418
+ require 'socket'
419
+ host = "0.0.0.0"
420
+ server = TCPServer.new(0)
421
+ port = server.addr[1]
422
+
423
+ # Spawn multilang process
424
+ cmd = command("--execute_live --name #{@__name} --host \"#{host}\" --port #{port}")
425
+
432
426
  begin
433
427
  # Start the operation...
434
- Open3.popen3(cmd) do |ml_input, stdout, stderr, wait_thread|
428
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thread|
435
429
  begin
430
+ server_thread = Thread.new do
431
+ ml_socket = server.accept()
432
+ begin
433
+ # Setup streams from consumers, multilang, and the consumee
434
+ read_streams = consumer_hash.keys.concat [@__consumee_pipes["rd_child_1"], ml_socket, stdout]
436
435
 
437
- # Multilang output tuples
438
- ml_output = File.open("#{ml_pipe}.in", "r+")
439
-
440
- # Setup streams from consumers, multilang, and the consumee
441
- read_streams = consumer_hash.keys.concat [@__consumee_pipes["rd_child_1"], ml_output, stdout]
442
-
443
- # Handshake
444
- handshake(ml_input, ml_output)
436
+ # Handshake
437
+ handshake(ml_socket, ml_socket)
438
+ prepare(ml_socket, ml_socket)
445
439
 
446
- # Begin cycle
447
- multilang_queue = []
448
- mutlilang_count = 0
449
- end_cycle_received = false
450
- column_aliases = nil
440
+ # Begin cycle
441
+ multilang_queue = []
442
+ mutlilang_count = 0
443
+ end_cycle_received = false
444
+ column_aliases = nil
451
445
 
452
446
 
453
- # Receive and handle messages
454
- loop do
447
+ # Receive and handle messages
448
+ loop do
455
449
 
456
- # Read from a stream
457
- rs = select_read_streams(read_streams)
458
- rs.each do |r|
450
+ # Read from a stream
451
+ rs = select_read_streams(read_streams)
452
+ rs.each do |r|
459
453
 
460
- # Read STDOUT from program straight to user
461
- if r == stdout
462
- msg = r.gets
463
- if !msg.nil?
464
- msg = msg.sub(/\n/, "")
465
- cdisplay("LOG: #{msg}")
466
- end
467
- next
468
- end
454
+ # Read STDOUT from program straight to user
455
+ if r == stdout
456
+ msg = r.gets
457
+ if !msg.nil?
458
+ msg = msg.sub(/\n/, "")
459
+ cdisplay("LOG: #{msg}")
460
+ end
461
+ next
462
+ end
469
463
 
470
- # Receive an object
471
- obj = read_message(r)
464
+ # Receive an object
465
+ obj = read_message(r)
472
466
 
473
- if obj["command"]
474
- case obj["command"]
467
+ if obj["command"]
468
+ case obj["command"]
475
469
 
476
- # Multilang emitted a tuple
477
- when "emit"
470
+ # Multilang emitted a tuple
471
+ when "emit"
478
472
 
479
- stream = obj["stream"]
480
-
481
- # Send or enqueue tuple for each consumer
482
- tuple_json = build_tuple_json(obj['tuple'], obj['meta'], column_aliases)
473
+ stream = obj["stream"]
474
+
475
+ # Send or enqueue tuple for each consumer
476
+ tuple_json = build_tuple_json(obj['tuple'], obj['meta'], column_aliases)
483
477
 
484
- @__emit_queues[stream].each_pair do |consumer, emitter|
485
- if emitter[:ready]
486
- emit_consumer_tuple(stream, consumer, tuple_json)
487
- else
488
- @__emit_queues[stream][consumer][:write_queue] << tuple_json
489
- end
490
- end
491
-
492
- # Consumer is ready for a message
493
- when "next"
494
- stream = consumer_hash[r][:stream]
495
- consumer = consumer_hash[r][:consumer]
478
+ @__emit_queues[stream].each_pair do |consumer, emitter|
479
+ if emitter[:ready]
480
+ emit_consumer_tuple(stream, consumer, tuple_json)
481
+ else
482
+ @__emit_queues[stream][consumer][:write_queue] << tuple_json
483
+ end
484
+ end
496
485
 
486
+ # Consumer is ready for a message
487
+ when "next"
488
+ stream = consumer_hash[r][:stream]
489
+ consumer = consumer_hash[r][:consumer]
497
490
 
498
- @__emit_queues[stream][consumer][:ready] = true
499
- tuple_json = get_consumer_tuple(stream, consumer)
500
491
 
501
- # End cycle for consumer if it has processed all tuples
502
- if tuple_json.nil? && end_cycle_received
503
- send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
504
- consumers_running -= 1
505
- if consumers_running == 0
506
- break
507
- end
492
+ @__emit_queues[stream][consumer][:ready] = true
493
+ tuple_json = get_consumer_tuple(stream, consumer)
508
494
 
495
+ # End cycle for consumer if it has processed all tuples
496
+ if tuple_json.nil? && end_cycle_received
497
+ send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
498
+ consumers_running -= 1
499
+ if consumers_running == 0
500
+ break
501
+ end
509
502
 
510
- # TODO break if last consumer
511
- elsif !tuple_json.nil?
512
- # Emit tuple to consumer
513
- emit_consumer_tuple(stream, consumer, tuple_json)
514
- emitted = true
515
- end
516
503
 
517
- # Multilang is done emitting a group of tuples
518
- when "done"
519
- mutlilang_count -= 1
504
+ # TODO break if last consumer
505
+ elsif !tuple_json.nil?
506
+ # Emit tuple to consumer
507
+ emit_consumer_tuple(stream, consumer, tuple_json)
508
+ emitted = true
509
+ end
520
510
 
521
- # Send the next tuple to multilang
522
- if !multilang_queue.empty?
523
- write_message(ml_input, multilang_queue.shift)
511
+ # Multilang is done emitting a group of tuples
512
+ when "done"
513
+ mutlilang_count -= 1
524
514
 
525
- # Request next tuple from consumee
526
- elsif !end_cycle_received
527
- write_message(@__consumee_pipes["wr_child_1"], NEXT_MESSAGE)
515
+ # Send the next tuple to multilang
516
+ if !multilang_queue.empty?
517
+ write_message(ml_socket, multilang_queue.shift)
528
518
 
529
- # If there are no more messages to send, we are done
530
- elsif end_cycle_received && mutlilang_count == 0
531
- finished = true
519
+ # If there are no more messages to send, we are done
520
+ elsif end_cycle_received && mutlilang_count == 0
521
+ finished = true
532
522
 
533
- # End cycle for ready consumers
534
- @__emit_queues.each_pair do |stream, consumers|
535
- consumers.each_pair do |consumer, emitter|
536
- if emitter[:ready]
537
- send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
538
- consumers_running -= 1
539
- if consumers_running == 0
540
- break
523
+ # End cycle for ready consumers
524
+ @__emit_queues.each_pair do |stream, consumers|
525
+ consumers.each_pair do |consumer, emitter|
526
+ if emitter[:ready]
527
+ send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
528
+ consumers_running -= 1
529
+ if consumers_running == 0
530
+ break
531
+ end
532
+ end
541
533
  end
542
534
  end
543
535
  end
544
- end
545
- end
546
536
 
547
- # Multilang sent an error message
548
- when "fail"
549
- cdisplay("ERROR : #{obj['msg']}")
550
-
551
- # Multilang sent a log message
552
- when "log"
553
- cdisplay "LOG: #{obj['msg']}"
554
-
555
- # Consumee operation sent signal to end_cycle
556
- when "end_cycle"
557
- end_cycle_received = true
558
- if mutlilang_count == 0
559
- @__emit_queues.each_pair do |stream, consumers|
560
- consumers.each_pair do |consumer, emitter|
561
- if emitter[:ready]
562
- send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
563
- consumers_running -= 1
564
- if consumers_running == 0
565
- return
537
+ # Multilang sent an error message
538
+ when "fail"
539
+ cdisplay("ERROR : #{obj['msg']}")
540
+ cycle_killed = true
541
+ exit(0)
542
+
543
+ # Multilang sent a log message
544
+ when "log"
545
+ cdisplay "LOG: #{obj['msg']}"
546
+
547
+ # Consumee operation sent signal to end_cycle
548
+ when "end_cycle"
549
+ end_cycle_received = true
550
+ if mutlilang_count == 0
551
+ @__emit_queues.each_pair do |stream, consumers|
552
+ consumers.each_pair do |consumer, emitter|
553
+ if emitter[:ready]
554
+ send_command_tuple(stream, consumer, END_CYCLE_MESSAGE)
555
+ consumers_running -= 1
556
+ if consumers_running == 0
557
+ exit(0)
558
+ end
559
+ end
566
560
  end
567
561
  end
568
562
  end
563
+
564
+ when "kill_cycle"
565
+ cycle_killed = true
566
+ exit(0)
569
567
  end
568
+
569
+ # Received a tuple from consumee
570
+ elsif obj['tuple']
571
+ column_aliases = obj['column_aliases']
572
+ # Send or enqueue to multilang
573
+ mutlilang_count += 1
574
+ if multilang_queue.empty?
575
+ write_message(ml_socket, obj.to_json)
576
+ else
577
+ multilang_queue << obj.to_json
578
+ end
579
+ write_message(@__consumee_pipes["wr_child_1"], NEXT_MESSAGE)
580
+
581
+ # Multilang sent a ping
582
+ elsif obj['ping']
583
+ write_message(ml_socket, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
570
584
  end
571
-
572
- when "kill_cycle"
573
- cycle_killed = true
574
- return
575
585
  end
576
586
 
577
- # Received a tuple from consumee
578
- elsif obj['tuple']
579
- column_aliases = obj['column_aliases']
580
- # Send or enqueue to multilang
581
- mutlilang_count += 1
582
- if multilang_queue.empty?
583
- write_message(ml_input, obj.to_json)
584
- else
585
- multilang_queue << obj.to_json
587
+ # Exit after ending consumer cycles
588
+ if consumers_running == 0
589
+ exit(0)
586
590
  end
587
-
588
- # Multilang sent a ping
589
- elsif obj['ping']
590
- write_message(ml_input, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
591
- end
592
- end
593
591
 
594
- # Exit after ending consumer cycles
595
- if consumers_running == 0
596
- return
592
+ end
593
+ ensure
594
+ ml_socket.close()
597
595
  end
598
-
599
596
  end
597
+ server_thread.join()
600
598
  rescue => e
601
599
  cdisplay e.message
602
600
  cdisplay e.backtrace
@@ -604,28 +602,18 @@ module Zillabyte; module Runner; class MultilangOperation
604
602
  # cleanup
605
603
  if cycle_killed
606
604
  send_to_consumers(KILL_CYCLE_MESSAGE, false)
607
- send_to_consumees(KILL_CYCLE_MESSAGE, false)
605
+ send_to_consumees(KILL_CYCLE_MESSAGE)
608
606
  end
609
607
  pid = wait_thread[:pid]
610
- ml_input.close
611
- if File.exists?("#{ml_pipe}.in")
612
- ml_output.close
613
- File.delete("#{ml_pipe}.in")
614
- end
608
+ stdin.close
615
609
  stdout.close
616
610
  stderr.close
617
- Process.kill('INT', pid)
618
- Process.exit!(true)
619
611
  end
620
612
  end
621
613
  rescue PTY::ChildExited
622
-
623
614
  cdisplay("The child process exited!")
624
- ensure
625
- if File.exists?("#{ml_pipe}.in")
626
- File.delete("#{ml_pipe}.in")
627
- end
628
615
  end
616
+
629
617
  end
630
618
 
631
619
 
@@ -648,219 +636,223 @@ module Zillabyte; module Runner; class MultilangOperation
648
636
  tuple_queue = []
649
637
 
650
638
  # Setup multilang pipe
651
- ml_pipe = "#{@__name}_pipe"
652
- if File.exists?("#{ml_pipe}.in")
653
- File.delete("#{ml_pipe}.in")
654
- end
655
- File.mkfifo("#{ml_pipe}.in")
656
-
657
- cmd = command("--execute_live --name #{@__name} --pipe #{ml_pipe}")
639
+ require 'socket'
640
+ host = "0.0.0.0"
641
+ server = TCPServer.new(0)
642
+ port = server.addr[1]
643
+
644
+ # Spawn multilang process
645
+ cmd = command("--execute_live --name #{@__name} --host \"#{host}\" --port #{port}")
646
+
658
647
  begin
659
648
  # Start the operation...
660
- Open3.popen3(cmd) do |ml_input, stdout, stderr, wait_thread|
649
+ Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thread|
661
650
  begin
651
+ server_thread = Thread.new do
652
+ ml_socket = server.accept()
653
+ begin
654
+ # Setup streams from consumers, multilang, and the consumee
655
+ read_streams = consumer_hash.keys.concat [stdout, ml_socket, @__consumee_pipes["rd_child_1"]]
662
656
 
663
- # Multilang output tuples
664
- ml_output = File.open("#{ml_pipe}.in", "r+")
665
- # Setup streams from consumers, multilang, and the consumee
666
- read_streams = consumer_hash.keys.concat [stdout, ml_output, @__consumee_pipes["rd_child_1"]]
667
-
668
- # Handshake
669
- handshake(ml_input, ml_output)
657
+ # Handshake
658
+ handshake(ml_socket, ml_socket)
659
+ prepare(ml_socket, ml_socket)
670
660
 
671
- # Begin cycle
672
- end_cycle_received = false
673
- finished_emitting = false
661
+ # Begin cycle
662
+ end_cycle_received = false
663
+ finished_emitting = false
674
664
 
675
- # select a stream
676
- loop do
665
+ # Handle streams
666
+ loop do
667
+ # Read from a stream
668
+ rs = select_read_streams(read_streams)
669
+ rs.each do |r|
677
670
 
678
- # Read from a stream
679
- rs = select_read_streams(read_streams)
680
- rs.each do |r|
671
+ # Read STDOUT from program straight to user
672
+ if r == stdout
673
+ msg = r.gets
674
+ msg = msg.sub(/\n/, "")
675
+ cdisplay("log: #{msg}")
676
+ next
677
+ end
681
678
 
682
- # Read STDOUT from program straight to user
683
- if r == stdout
684
- msg = r.gets
685
- msg = msg.sub(/\n/, "")
686
- cdisplay("log: #{msg}")
687
- next
688
- end
689
679
 
680
+ # Receive an object
681
+ obj = read_message(r)
682
+
683
+ if obj["command"]
684
+ case obj["command"]
690
685
 
691
- # Receive an object
692
- obj = read_message(r)
693
-
694
- if obj["command"]
695
- case obj["command"]
686
+ when "done"
696
687
 
697
- when "done"
688
+ if end_cycle_received
689
+ tuple_json = tuple_queue.shift
690
+ if !tuple_json.nil?
691
+ write_message(ml_socket, tuple_json)
692
+ end
693
+ end
698
694
 
699
- if end_cycle_received
700
- tuple_json = tuple_queue.shift
701
- if !tuple_json.nil?
702
- write_message(ml_input, tuple_json)
703
- end
704
- end
695
+ next
705
696
 
706
- next
697
+ # Begin aggregation
698
+ when "end_cycle"
699
+ end_cycle_received = true
700
+ read_streams = [ml_socket]
707
701
 
708
- # Begin aggregation
709
- when "end_cycle"
710
- end_cycle_received = true
711
- read_streams = [ml_output]
702
+ group_tuples.each do |group_tuple, tuples|
703
+ tuple_queue << "{\"command\": \"begin_group\", \"tuple\": #{group_tuple.to_json}, \"meta\":{}}\n"
704
+ tuples.each do |t|
705
+ tuple_queue << "{\"command\": \"aggregate\", #{t}}\n"
706
+ end
707
+ tuple_queue << "{\"command\": \"end_group\"}\n"
712
708
 
713
- group_tuples.each do |group_tuple, tuples|
714
- tuple_queue << "{\"command\": \"begin_group\", \"tuple\": #{group_tuple.to_json}, \"meta\":{}}\n"
715
- tuples.each do |t|
716
- tuple_queue << "{\"command\": \"aggregate\", #{t}}\n"
717
- end
718
- tuple_queue << "{\"command\": \"end_group\"}\n"
709
+ # keep track of how many emits are expected
710
+ emit_count += 1
711
+ end
719
712
 
720
- # keep track of how many emits are expected
721
- emit_count += 1
722
- end
713
+ tuple_json = tuple_queue.shift
714
+ if !tuple_json.nil?
715
+ write_message(ml_socket, tuple_json)
716
+ end
723
717
 
724
- tuple_json = tuple_queue.shift
725
- if !tuple_json.nil?
726
- write_message(ml_input, tuple_json)
727
- end
718
+ # Multilang has emitted a grouped tuple
719
+ when "emit"
720
+ stream = obj['stream']
721
+ emit_count -= 1
722
+ # Enqueue for consumers
723
+ tuple_json = build_tuple_json(obj['tuple'], obj['meta'], obj['column_aliases'])
724
+ @__emit_queues.each_pair do |stream, consumers|
725
+ consumers.each_key do |consumer|
726
+ @__emit_queues[stream][consumer][:write_queue] << tuple_json
727
+ end
728
+ end
728
729
 
729
- # Multilang has emitted a grouped tuple
730
- when "emit"
731
- stream = obj['stream']
732
- emit_count -= 1
733
- # Enqueue for consumers
734
- tuple_json = build_tuple_json(obj['tuple'], obj['meta'], obj['column_aliases'])
735
- @__emit_queues.each_pair do |stream, consumers|
736
- consumers.each_key do |consumer|
737
- @__emit_queues[stream][consumer][:write_queue] << tuple_json
730
+ # End cycle when done emitting
731
+ if end_cycle_received && emit_count == 0
732
+ finished_emitting = true
733
+ break
734
+ elsif end_cycle_received
735
+ tuple_json = tuple_queue.shift
736
+ if !tuple_json.nil?
737
+ write_message(ml_socket, tuple_json)
738
+ end
739
+ end
740
+
741
+ # An error has occured
742
+ when "kill_cycle"
743
+ cycle_killed = true
744
+ exit(0)
738
745
  end
739
- end
740
746
 
741
- # End cycle when done emitting
742
- if end_cycle_received && emit_count == 0
743
- finished_emitting = true
744
- break
745
- elsif end_cycle_received
746
- tuple_json = tuple_queue.shift
747
- if !tuple_json.nil?
748
- write_message(ml_input, tuple_json)
747
+ # Received a tuple from operation
748
+ elsif obj["tuple"]
749
+ tuple = obj["tuple"].to_json
750
+ meta = obj["meta"].to_json
751
+ column_aliases = obj["column_aliases"] || {}
752
+ aliases = Hash[column_aliases.map{|h| [h["alias"],h["concrete_name"]]}]
753
+ gt = {}
754
+
755
+ # Get the column names to group on
756
+ group_by.each do |field|
757
+ field_name = aliases[field] || field
758
+ gt[field] = obj["tuple"][field_name]
749
759
  end
750
- end
751
-
752
- # An error has occured
753
- when "kill_cycle"
754
- cycle_killed = true
755
- return
756
- end
757
760
 
758
- # Received a tuple from operation
759
- elsif obj["tuple"]
760
- tuple = obj["tuple"].to_json
761
- meta = obj["meta"].to_json
762
- column_aliases = obj["column_aliases"] || {}
763
- aliases = Hash[column_aliases.map{|h| [h["alias"],h["concrete_name"]]}]
764
- gt = {}
765
-
766
- # Get the column names to group on
767
- group_by.each do |field|
768
- field_name = aliases[field] || field
769
- gt[field] = obj["tuple"][field_name]
770
- end
761
+ msg_no_brackets = "\"tuple\": #{tuple}, \"meta\": #{meta}, \"column_aliases\": #{column_aliases.to_json}"
771
762
 
772
- msg_no_brackets = "\"tuple\": #{tuple}, \"meta\": #{meta}, \"column_aliases\": #{column_aliases.to_json}"
773
-
774
- # Group tuple into existing group or create new group
775
- if group_tuples[gt]
776
- group_tuples[gt] << msg_no_brackets
777
- else
778
- group_tuples[gt] = [msg_no_brackets]
779
- end
763
+ # Group tuple into existing group or create new group
764
+ if group_tuples[gt]
765
+ group_tuples[gt] << msg_no_brackets
766
+ else
767
+ group_tuples[gt] = [msg_no_brackets]
768
+ end
780
769
 
781
- # Ask operation for next tuple
782
- write_message(@__consumee_pipes["wr_child_1"], NEXT_MESSAGE)
770
+ # Ask operation for next tuple
771
+ write_message(@__consumee_pipes["wr_child_1"], NEXT_MESSAGE)
783
772
 
784
- # Multilang sent a ping
785
- elsif obj['ping']
786
- write_message(ml_input, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
787
- end
788
- end
773
+ # Multilang sent a ping
774
+ elsif obj['ping']
775
+ write_message(ml_socket, PONG_PREFIX + "#{Time.now.utc.to_f}" + PONG_SUFFIX)
776
+ end
777
+ end
789
778
 
790
- # Send tuples to consumers
791
- if finished_emitting && consumers_running > 0
779
+ # Send tuples to consumers
780
+ if finished_emitting && consumers_running > 0
792
781
 
793
- # Send first tuple
794
- @__emit_queues.each_pair do |stream, consumers|
795
- consumers.each_key do |consumer|
796
- tuple_json = get_consumer_tuple(stream, consumer)
797
- emit_consumer_tuple(stream, consumer, tuple_json)
798
- end
799
- end
782
+ # Send first tuple
783
+ @__emit_queues.each_pair do |stream, consumers|
784
+ consumers.each_key do |consumer|
785
+ tuple_json = get_consumer_tuple(stream, consumer)
786
+ emit_consumer_tuple(stream, consumer, tuple_json)
787
+ end
788
+ end
800
789
 
801
- # Sent tuples to consumers as appropriate
802
- loop do
790
+ # Sent tuples to consumers as appropriate
791
+ loop do
803
792
 
804
- # Retrieve messages from consumers
805
- rs, ws, es = IO.select(consumer_hash.keys, [], [])
793
+ # Retrieve messages from consumers
794
+ rs, ws, es = IO.select(consumer_hash.keys, [], [])
806
795
 
807
- # Emit tuples to consumers
808
- emitted = false
809
- rs.each do |r|
796
+ # Emit tuples to consumers
797
+ emitted = false
798
+ rs.each do |r|
810
799
 
811
- # Read from consumer
812
- msg = read_message(r)
813
- consumer = consumer_hash[r][:consumer]
814
- stream = consumer_hash[r][:stream]
800
+ # Read from consumer
801
+ msg = read_message(r)
802
+ consumer = consumer_hash[r][:consumer]
803
+ stream = consumer_hash[r][:stream]
815
804
 
816
- # Consumer is ready for next message
817
- if msg["command"] && msg["command"] == "next"
805
+ # Consumer is ready for next message
806
+ if msg["command"] && msg["command"] == "next"
818
807
 
819
- @__emit_queues[stream][consumer][:ready] = true
820
- tuple_json = get_consumer_tuple(stream, consumer)
808
+ @__emit_queues[stream][consumer][:ready] = true
809
+ tuple_json = get_consumer_tuple(stream, consumer)
821
810
 
822
- # If all messages have been sent to a consumer, end its cycle
823
- if tuple_json.nil?
824
- write_stream = get_write_stream(stream, consumer)
825
- write_message(write_stream, END_CYCLE_MESSAGE)
826
- consumers_running -= 1
827
- if consumers_running == 0
828
- break
811
+ # If all messages have been sent to a consumer, end its cycle
812
+ if tuple_json.nil?
813
+ write_stream = get_write_stream(stream, consumer)
814
+ write_message(write_stream, END_CYCLE_MESSAGE)
815
+ consumers_running -= 1
816
+ if consumers_running == 0
817
+ break
818
+ end
819
+ else
820
+ # Emit tuple to consumer
821
+ emit_consumer_tuple(stream, consumer, tuple_json)
822
+ emitted = true
823
+ end
829
824
  end
830
- else
831
- # Emit tuple to consumer
832
- emit_consumer_tuple(stream, consumer, tuple_json)
833
- emitted = true
825
+
826
+ end
827
+ # Exit when done emitting
828
+ if !emitted
829
+ exit(0)
834
830
  end
835
831
  end
832
+ break
836
833
 
837
- end
838
- # Exit when done emitting
839
- if !emitted
840
- return
841
- end
834
+ # Exit after ending all consumer cycles
835
+ elsif consumers_running == 0
836
+ break
837
+ end
842
838
  end
843
- break
844
-
845
- # Exit after ending all consumer cycles
846
- elsif consumers_running == 0
847
- break
839
+ ensure
840
+ ml_socket.close()
848
841
  end
849
-
850
842
  end
843
+ server_thread.join()
844
+
851
845
  rescue Errno::EIO
852
846
  cdisplay("Errno:EIO error")
853
847
  ensure
854
848
  # cleanup
855
849
  if cycle_killed
856
850
  send_to_consumers(KILL_CYCLE_MESSAGE, false)
857
- send_to_consumers(KILL_CYCLE_MESSAGE, false)
851
+ send_to_consumees(KILL_CYCLE_MESSAGE)
858
852
  end
859
853
 
860
854
  pid = wait_thread[:pid]
861
- ml_input.close
862
- ml_output.close
863
- File.delete("#{ml_pipe}.in")
855
+ stdin.close
864
856
  stdout.close
865
857
  stderr.close
866
858
  Process.kill('INT', pid)
@@ -1226,7 +1218,9 @@ module Zillabyte; module Runner; class MultilangOperation
1226
1218
  "string" => String,
1227
1219
  "double" => Float,
1228
1220
  "integer" => Integer,
1229
- "float" => Float
1221
+ "float" => Float,
1222
+ "array" => Array,
1223
+ "map" => Hash
1230
1224
  }
1231
1225
 
1232
1226
  col_map = {}
@@ -1449,6 +1443,18 @@ module Zillabyte; module Runner; class MultilangOperation
1449
1443
  end
1450
1444
 
1451
1445
 
1446
+ # Instruct multilang to run prepare step
1447
+ def self.prepare(write_stream, read_stream)
1448
+ begin
1449
+ write_message write_stream, PREPARE_MESSAGE
1450
+ msg = read_message(read_stream)
1451
+ rescue => e
1452
+ cdisplay("Error running prepare")
1453
+ raise e
1454
+ end
1455
+ end
1456
+
1457
+
1452
1458
  # Instruct multilang to begin cycle
1453
1459
  def self.begin_cycle(write_stream, read_stream)
1454
1460
  write_message(write_stream, BEGIN_CYCLE_MESSAGE)
@@ -1495,14 +1501,14 @@ module Zillabyte; module Runner; class MultilangOperation
1495
1501
  def self.send_to_consumees(json_obj)
1496
1502
  pipes = @__consumee_pipes
1497
1503
  # Left hand(or singular) input
1498
- if (pipes.has_key? "wr_parent_1")
1499
- write_stream = get_write_stream(stream, consumer, 1)
1504
+ if (pipes.has_key? "wr_child_1")
1505
+ write_stream = pipes["wr_child_1"]
1500
1506
  write_message(write_stream, json_obj)
1501
1507
  end
1502
1508
 
1503
1509
  # Right hand input
1504
- if (pipes.has_key? "wr_parent_2")
1505
- write_stream = get_write_stream(stream, consumer, 2)
1510
+ if (pipes.has_key? "wr_child_2")
1511
+ write_stream = pipes["wr_child_2"]
1506
1512
  write_message(write_stream, json_obj)
1507
1513
  end
1508
1514
  end
@@ -1511,7 +1517,6 @@ module Zillabyte; module Runner; class MultilangOperation
1511
1517
  def self.send_to_consumers(json_obj, display = false)
1512
1518
  @__consumer_pipes.each_pair do |stream, consumers|
1513
1519
  consumers.each_pair do |consumer, pipe|
1514
- @__consumee_pipes["wr_child_1"]
1515
1520
  # Single or Left hand pipe
1516
1521
  if (pipe.has_key? "wr_parent_1")
1517
1522
  write_stream = get_write_stream(stream, consumer, 1)
@@ -1626,7 +1631,6 @@ module Zillabyte; module Runner; class MultilangOperation
1626
1631
  # Construct a multilang command
1627
1632
  def self.command(arg, ignore_stderr=false)
1628
1633
  cdisplay("could not extract meta information. missing zillabyte.conf.yml?") if @__meta.nil?
1629
-
1630
1634
  full_script = File.join(@__dir, @__meta["script"])
1631
1635
  stderr_opt = "2> /dev/null" if ignore_stderr
1632
1636