zillabyte 0.0.6
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 +15 -0
- data/ruby/README.md +2 -0
- data/ruby/lib/zillabyte.rb +20 -0
- data/ruby/lib/zillabyte/common/progress.rb +17 -0
- data/ruby/lib/zillabyte/harness.rb +16 -0
- data/ruby/lib/zillabyte/harness/aggregate.rb +29 -0
- data/ruby/lib/zillabyte/harness/counter.rb +11 -0
- data/ruby/lib/zillabyte/harness/each.rb +29 -0
- data/ruby/lib/zillabyte/harness/groupby.rb +9 -0
- data/ruby/lib/zillabyte/harness/helper.rb +326 -0
- data/ruby/lib/zillabyte/harness/live_delegator.rb +369 -0
- data/ruby/lib/zillabyte/harness/simple_function.rb +131 -0
- data/ruby/lib/zillabyte/harness/simple_spout.rb +90 -0
- data/ruby/lib/zillabyte/harness/sink.rb +23 -0
- data/ruby/lib/zillabyte/harness/spout.rb +48 -0
- data/ruby/lib/zillabyte/harness/topology.rb +132 -0
- data/ruby/lib/zillabyte/harness/tuple.rb +32 -0
- data/ruby/lib/zillabyte/version.rb +3 -0
- metadata +103 -0
@@ -0,0 +1,369 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Zillabyte
|
5
|
+
|
6
|
+
module Storm
|
7
|
+
|
8
|
+
module Protocol
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :mode, :pending_commands, :pipe_name, :pipe_to_java, :pipe_from_java
|
12
|
+
end
|
13
|
+
|
14
|
+
self.pending_commands = []
|
15
|
+
|
16
|
+
def setup_pipes
|
17
|
+
pipe_name = Storm::Protocol.pipe_name
|
18
|
+
if(pipe_name and File.exist?(pipe_name+".in"))
|
19
|
+
Storm::Protocol.pipe_to_java = File.open("#{pipe_name}.in","w+")
|
20
|
+
else
|
21
|
+
Storm::Protocol.pipe_to_java = $stdout
|
22
|
+
end
|
23
|
+
|
24
|
+
if(pipe_name and File.exist?(pipe_name+".out"))
|
25
|
+
Storm::Protocol.pipe_from_java = File.open("#{pipe_name}.out","r+")
|
26
|
+
else
|
27
|
+
Storm::Protocol.pipe_from_java = $stdin
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_message
|
32
|
+
msg = ""
|
33
|
+
loop do
|
34
|
+
line = Storm::Protocol.pipe_from_java.readline.chomp#STDIN.readline.chomp
|
35
|
+
break if line == "end"
|
36
|
+
msg << line
|
37
|
+
msg << "\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
encoding_options = {
|
41
|
+
:invalid => :replace, # Replace invalid byte sequences
|
42
|
+
:undef => :replace, # Replace anything not defined in ASCII
|
43
|
+
:replace => '' # Use a blank for those replacements
|
44
|
+
}
|
45
|
+
msg.encode! Encoding.find('ASCII'), encoding_options
|
46
|
+
|
47
|
+
JSON.parse msg.chomp
|
48
|
+
end
|
49
|
+
|
50
|
+
def read_command
|
51
|
+
Storm::Protocol.pending_commands.shift ||
|
52
|
+
begin
|
53
|
+
msg = read_message
|
54
|
+
while msg.is_a? Array
|
55
|
+
Storm::Protocol.pending_taskids.push(msg)
|
56
|
+
msg = read_message
|
57
|
+
end
|
58
|
+
msg
|
59
|
+
rescue JSON::ParserError => e
|
60
|
+
fail "error: #{e}"
|
61
|
+
{}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def send_msg_to_parent(msg)
|
66
|
+
# log msg
|
67
|
+
# log msg.to_json
|
68
|
+
Storm::Protocol.pipe_to_java.write(msg.to_json+"\n")
|
69
|
+
Storm::Protocol.pipe_to_java.write("end\n")
|
70
|
+
Storm::Protocol.pipe_to_java.flush
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_pid(heartbeat_dir)
|
74
|
+
pid = Process.pid
|
75
|
+
send_msg_to_parent({'pid' => pid})
|
76
|
+
File.open("#{heartbeat_dir}/#{pid}", "w").close
|
77
|
+
end
|
78
|
+
|
79
|
+
def emit(*args)
|
80
|
+
|
81
|
+
stream = nil
|
82
|
+
tuple = nil
|
83
|
+
meta = {}
|
84
|
+
|
85
|
+
if (args.size == 1)
|
86
|
+
tuple = args[0]
|
87
|
+
elsif(args.size == 2)
|
88
|
+
stream = args[0]
|
89
|
+
tuple = args[1]
|
90
|
+
else
|
91
|
+
stream = args[0]
|
92
|
+
tuple = args[1]
|
93
|
+
meta = args[2]
|
94
|
+
end
|
95
|
+
|
96
|
+
m = {:command => :emit, :tuple => tuple, :stream => stream, :meta => meta}
|
97
|
+
send_msg_to_parent m
|
98
|
+
end
|
99
|
+
|
100
|
+
def ack(tup)
|
101
|
+
send_msg_to_parent :command => :ack, :id => tup.id
|
102
|
+
end
|
103
|
+
|
104
|
+
def done()
|
105
|
+
send_msg_to_parent :command => :done #, :id => tup.id
|
106
|
+
# read_task_ids
|
107
|
+
end
|
108
|
+
|
109
|
+
def fail(msg)
|
110
|
+
send_msg_to_parent :command => :fail, :msg => msg.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def log(msg)
|
114
|
+
send_msg_to_parent :command => :log, :msg => msg.to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
def handshake
|
118
|
+
setup_info = read_message
|
119
|
+
send_pid setup_info['pidDir']
|
120
|
+
[setup_info['conf'], setup_info['context']]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
class Spout
|
126
|
+
include Storm::Protocol
|
127
|
+
|
128
|
+
def open(conf, context); end
|
129
|
+
|
130
|
+
def next_batch; end
|
131
|
+
|
132
|
+
def ack(id); end
|
133
|
+
|
134
|
+
def run(pipe_name)
|
135
|
+
Storm::Protocol.mode = 'spout'
|
136
|
+
Storm::Protocol.pipe_name = pipe_name
|
137
|
+
setup_pipes
|
138
|
+
open(*handshake)
|
139
|
+
|
140
|
+
begin
|
141
|
+
while true
|
142
|
+
msg = read_command
|
143
|
+
case msg['command']
|
144
|
+
when 'next'
|
145
|
+
next_batch
|
146
|
+
done
|
147
|
+
when 'ack'
|
148
|
+
ack(msg['id'])
|
149
|
+
when 'fail'
|
150
|
+
fail(msg['id'])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
rescue Exception => e
|
154
|
+
fail 'Exception in spout: ' + e.message + ' - ' + e.backtrace.join('\n')
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class Each
|
160
|
+
include Storm::Protocol
|
161
|
+
|
162
|
+
def prepare(conf, context); end
|
163
|
+
|
164
|
+
def execute(tuple); end
|
165
|
+
|
166
|
+
def run(pipe_name)
|
167
|
+
Storm::Protocol.mode = 'each'
|
168
|
+
Storm::Protocol.pipe_name = pipe_name
|
169
|
+
setup_pipes
|
170
|
+
prepare(*handshake)
|
171
|
+
|
172
|
+
begin
|
173
|
+
while true
|
174
|
+
t = nil
|
175
|
+
begin
|
176
|
+
t = Tuple.from_hash(read_command)
|
177
|
+
if(!t)
|
178
|
+
next
|
179
|
+
end
|
180
|
+
execute t
|
181
|
+
rescue Exception => e
|
182
|
+
fail 'Exception in bolt (A): ' + e.message + ' - ' + e.backtrace.join('\n')
|
183
|
+
ensure
|
184
|
+
done()
|
185
|
+
end
|
186
|
+
end
|
187
|
+
rescue Exception => e
|
188
|
+
fail 'Exception in bolt (B): ' + e.message + ' - ' + e.backtrace.join('\n')
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
class AggregateStart
|
194
|
+
include Storm::Protocol
|
195
|
+
|
196
|
+
def start(tuple); end
|
197
|
+
|
198
|
+
def run(pipe_name)
|
199
|
+
Storm::Protocol.mode = 'agg_start'
|
200
|
+
Storm::Protocol.pipe_name = pipe_name
|
201
|
+
setup_pipes
|
202
|
+
handshake
|
203
|
+
|
204
|
+
begin
|
205
|
+
while true
|
206
|
+
t = nil
|
207
|
+
begin
|
208
|
+
t = Tuple.from_hash(read_command)
|
209
|
+
if(!t)
|
210
|
+
next
|
211
|
+
end
|
212
|
+
start t
|
213
|
+
rescue Exception => e
|
214
|
+
fail 'Exception in bolt (A): ' + e.message + ' - ' + e.backtrace.join('\n')
|
215
|
+
ensure
|
216
|
+
done()
|
217
|
+
end
|
218
|
+
end
|
219
|
+
rescue Exception => e
|
220
|
+
fail 'Exception in bolt (B): ' + e.message + ' - ' + e.backtrace.join('\n')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
class AggregateAggregate
|
226
|
+
include Storm::Protocol
|
227
|
+
|
228
|
+
def aggregate(tuple1, tuple2); end
|
229
|
+
|
230
|
+
def run(pipe_name)
|
231
|
+
Storm::Protocol.mode = 'agg_aggregate'
|
232
|
+
Storm::Protocol.pipe_name = pipe_name
|
233
|
+
setup_pipes
|
234
|
+
handshake
|
235
|
+
|
236
|
+
begin
|
237
|
+
while true
|
238
|
+
t = nil
|
239
|
+
begin
|
240
|
+
t1 = Tuple.from_hash(read_command)
|
241
|
+
if(!t1)
|
242
|
+
next
|
243
|
+
end
|
244
|
+
t2 = Tuple.from_hash(read_command)
|
245
|
+
if(!t2)
|
246
|
+
next
|
247
|
+
end
|
248
|
+
aggregate t1, t2
|
249
|
+
rescue Exception => e
|
250
|
+
fail 'Exception in bolt (A): ' + e.message + ' - ' + e.backtrace.join('\n')
|
251
|
+
ensure
|
252
|
+
done()
|
253
|
+
end
|
254
|
+
end
|
255
|
+
rescue Exception => e
|
256
|
+
fail 'Exception in bolt (B): ' + e.message + ' - ' + e.backtrace.join('\n')
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
class AggregateComplete
|
262
|
+
include Storm::Protocol
|
263
|
+
|
264
|
+
def complete(tuple); end
|
265
|
+
|
266
|
+
def run(pipe_name)
|
267
|
+
Storm::Protocol.mode = 'agg_complete'
|
268
|
+
Storm::Protocol.pipe_name = pipe_name
|
269
|
+
setup_pipes
|
270
|
+
handshake
|
271
|
+
|
272
|
+
begin
|
273
|
+
while true
|
274
|
+
t = nil
|
275
|
+
begin
|
276
|
+
t = Tuple.from_hash(read_command)
|
277
|
+
if(!t)
|
278
|
+
next
|
279
|
+
end
|
280
|
+
complete t
|
281
|
+
rescue Exception => e
|
282
|
+
fail 'Exception in bolt (A): ' + e.message + ' - ' + e.backtrace.join('\n')
|
283
|
+
ensure
|
284
|
+
done()
|
285
|
+
end
|
286
|
+
end
|
287
|
+
rescue Exception => e
|
288
|
+
fail 'Exception in bolt (B): ' + e.message + ' - ' + e.backtrace.join('\n')
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
module Harness
|
295
|
+
|
296
|
+
class SpoutController < Storm::Spout
|
297
|
+
|
298
|
+
def initialize(harness, progress)
|
299
|
+
@harness = harness
|
300
|
+
@progress = progress
|
301
|
+
end
|
302
|
+
|
303
|
+
def open(*args)
|
304
|
+
@harness._prepare.call(self, *args) if @harness._prepare
|
305
|
+
end
|
306
|
+
|
307
|
+
def next_batch
|
308
|
+
@harness._next_batch.call(self)
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
class EachController < Storm::Each
|
314
|
+
|
315
|
+
def initialize(harness, progress)
|
316
|
+
@harness = harness
|
317
|
+
@progress = progress
|
318
|
+
end
|
319
|
+
|
320
|
+
def execute(*args)
|
321
|
+
@harness._execute.call(self, *args)
|
322
|
+
end
|
323
|
+
|
324
|
+
def prepare(*args)
|
325
|
+
@harness._prepare.call(self, *args) if @harness._prepare
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
|
330
|
+
class AggregateStartController < Storm::AggregateStart
|
331
|
+
|
332
|
+
def initialize(harness, progress)
|
333
|
+
@harness = harness
|
334
|
+
@progress = progress
|
335
|
+
end
|
336
|
+
|
337
|
+
def start(*args)
|
338
|
+
@harness._start.call(self, *args)
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
class AggregateAggregateController < Storm::AggregateAggregate
|
344
|
+
|
345
|
+
def initialize(harness, progress)
|
346
|
+
@harness = harness
|
347
|
+
@progress = progress
|
348
|
+
end
|
349
|
+
|
350
|
+
def aggregate(*args)
|
351
|
+
@harness._aggregate.call(self, *args)
|
352
|
+
end
|
353
|
+
|
354
|
+
end
|
355
|
+
|
356
|
+
class AggregateCompleteController < Storm::AggregateComplete
|
357
|
+
|
358
|
+
def initialize(harness, progress)
|
359
|
+
@harness = harness
|
360
|
+
@progress = progress
|
361
|
+
end
|
362
|
+
|
363
|
+
def complete(*args)
|
364
|
+
@harness._complete.call(self, *args)
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class Zillabyte::Harness::SimpleFunction
|
4
|
+
attr_accessor :_nodes, :_relation, :_matches, :_emits, :_prepare, :_execute, :_name, :_info_file, :_options
|
5
|
+
|
6
|
+
def self.build()
|
7
|
+
h = Zillabyte::Harness::SimpleFunction.new()
|
8
|
+
yield(h)
|
9
|
+
h._name = h._name || Dir.pwd.split("/")[-1]
|
10
|
+
Zillabyte::Harness::Helper.check_name("simple_function", h._name, {})
|
11
|
+
Zillabyte::Harness::Helper.check_emits("simple_function", h._emits, {})
|
12
|
+
generic_emits = h.get_generic_emits
|
13
|
+
|
14
|
+
h._nodes = []
|
15
|
+
h._options = Zillabyte::Harness::Helper.opt_parser()
|
16
|
+
|
17
|
+
if(h._options[:command] == :info)
|
18
|
+
h._info_file = File.open(h._options[:file],"w+")
|
19
|
+
hash = {"language" => "ruby", "name" => h._name}
|
20
|
+
Zillabyte::Harness::Helper.write_hash_to_file(hash, h._info_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
h.build_spout()
|
24
|
+
fn = h.build_each(generic_emits)
|
25
|
+
h.build_sink()
|
26
|
+
|
27
|
+
if(h._options[:command] == :execute and h._options[:name] == h._name)
|
28
|
+
pipe_name = h._options[:pipe]
|
29
|
+
c = Zillabyte::Harness::EachController.new(fn, progress = Zillabyte::Common::Progress.new)
|
30
|
+
c.run(pipe_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
h
|
34
|
+
end
|
35
|
+
|
36
|
+
def name(v)
|
37
|
+
@_name = v
|
38
|
+
end
|
39
|
+
|
40
|
+
def matches(v, options = {})
|
41
|
+
case v
|
42
|
+
when String
|
43
|
+
@_relation = { :query => v, :options => options.is_a?(Hash) ? options : {} }
|
44
|
+
when Array
|
45
|
+
@_matches = v
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def emits(v)
|
50
|
+
@_emits = v
|
51
|
+
end
|
52
|
+
|
53
|
+
def prepare(&block)
|
54
|
+
@_prepare = block
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute(&block)
|
58
|
+
@_execute = block
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_generic_emits()
|
62
|
+
generic_emits = []
|
63
|
+
@_emits.each do |relation|
|
64
|
+
temit = []
|
65
|
+
relation[1].each do |column|
|
66
|
+
column.each do |col, type|
|
67
|
+
temit << col
|
68
|
+
end
|
69
|
+
end
|
70
|
+
generic_emits << [relation[0], temit]
|
71
|
+
end
|
72
|
+
generic_emits
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_spout()
|
76
|
+
h = Zillabyte::Harness::Spout.new(false)
|
77
|
+
h._matches = @_matches if @_matches
|
78
|
+
h._relation = @_relation if @_relation
|
79
|
+
@_nodes << h
|
80
|
+
if(@_options[:command] == :info)
|
81
|
+
info_hash = {"name" => h._name, "type" => h._type}
|
82
|
+
if(h._relation)
|
83
|
+
info_hash["relation"] = h._relation
|
84
|
+
elsif(h._matches)
|
85
|
+
info_hash["matches"] = h._matches
|
86
|
+
end
|
87
|
+
Zillabyte::Harness::Helper.write_hash_to_file(info_hash, @_info_file)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def build_each(generic_emits)
|
92
|
+
h = Zillabyte::Harness::Each.new()
|
93
|
+
h._name = @_name
|
94
|
+
h._emits = generic_emits
|
95
|
+
h._prepare = @_prepare
|
96
|
+
h._execute = @_execute
|
97
|
+
@_nodes << h
|
98
|
+
if(@_options[:command] == :info)
|
99
|
+
info_hash = {"name" => h._name, "type" => h._type, "emits" => h._emits}
|
100
|
+
Zillabyte::Harness::Helper.write_hash_to_file(info_hash, @_info_file)
|
101
|
+
end
|
102
|
+
h
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_sink()
|
106
|
+
# Construct the sink...
|
107
|
+
n_sinks = @_emits.length
|
108
|
+
@_emits.each do |emit|
|
109
|
+
h = Zillabyte::Harness::Sink.new()
|
110
|
+
h._name = emit[0]
|
111
|
+
columns = emit[1]
|
112
|
+
columns.each do |col|
|
113
|
+
col.each do |cname, ctype|
|
114
|
+
h.column(cname, ctype)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
if(n_sinks > 1)
|
118
|
+
h._consumes = h._name
|
119
|
+
end
|
120
|
+
@_nodes << h
|
121
|
+
if(@_options[:command] == :info)
|
122
|
+
info_hash = {"name" => h._name, "type" => h._type, "columns" => h._columns}
|
123
|
+
if(h._consumes)
|
124
|
+
info_hash["consumes"] = h._consumes
|
125
|
+
end
|
126
|
+
Zillabyte::Harness::Helper.write_hash_to_file(info_hash, @_info_file)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|