redstorm 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,4 +12,11 @@
12
12
  - more doc in README
13
13
 
14
14
  # 0.2.1, 11-23-2011
15
- - gems support in production cluster
15
+ - gems support in production cluster
16
+
17
+ # 0.3.0, 12-08-2011
18
+ - Storm 0.6.0
19
+
20
+ # 0.4.0, 02-08-2012
21
+ - Storm 0.6.2
22
+ - JRuby 1.6.6
data/README.md CHANGED
@@ -1,17 +1,10 @@
1
- # RedStorm v0.2.1 - JRuby on Storm
1
+ # RedStorm v0.4.0 - JRuby on Storm
2
2
 
3
3
  RedStorm provides the JRuby integration for the [Storm][storm] distributed realtime computation system.
4
4
 
5
- ## Changes from 0.1.x
6
-
7
- - this release introduces the *simple* DSL. Topology, Spout and Bolt classes can inherit from the SimpleTopology, SimpleSpout and SimpleBolt classes which provides a very clean and consise DSL. See [examples/simple](https://github.com/colinsurprenant/redstorm/tree/master/examples/simple).
8
- - use the same SimpleTopology class for local development cluster or remote production cluster.
9
- - the `redstorm` command has a new syntax.
10
- - gems support in production cluster
11
-
12
5
  ## Dependencies
13
6
 
14
- This has been tested on OSX 10.6.8 and Linux 10.04 using Storm 0.5.4 and JRuby 1.6.5
7
+ This has been tested on OSX 10.6.8 and Linux 10.04 using Storm 0.6.2 and JRuby 1.6.6
15
8
 
16
9
  ## Installation
17
10
  ``` sh
@@ -241,7 +234,7 @@ configure topology_name do |env|
241
234
  end
242
235
  ```
243
236
 
244
- The `configure` statement is **optional**.
237
+ The `configure` statement is **required**.
245
238
 
246
239
  - `topology_name` — alternate topology name (**default** is topology class name)
247
240
  - `env` — is set to `:local` or `:cluster` for you to set enviroment specific configurations
@@ -463,10 +456,10 @@ end
463
456
 
464
457
  ### Requirements
465
458
 
466
- - JRuby 1.6.5
467
- - rake gem
468
- - ruby-maven gem
469
- - rspec gem
459
+ - JRuby 1.6.6
460
+ - rake gem ~> 0.9.2.2
461
+ - ruby-maven gem ~> 3.0.3.0.28.5
462
+ - rspec gem ~> 2.8.0
470
463
 
471
464
  ### Contribute
472
465
 
@@ -1,18 +1,25 @@
1
+ require 'red_storm'
1
2
  require 'examples/native/random_sentence_spout'
2
3
  require 'examples/native/split_sentence_bolt'
3
4
  require 'examples/native/word_count_bolt'
4
5
 
5
- class ClusterWordCountTopology
6
- def start(base_class_path, env)
7
- builder = TopologyBuilder.new
8
- builder.setSpout(1, JRubySpout.new(base_class_path, "RandomSentenceSpout"), 5)
9
- builder.setBolt(2, JRubyBolt.new(base_class_path, "SplitSentenceBolt"), 4).shuffleGrouping(1)
10
- builder.setBolt(3, JRubyBolt.new(base_class_path, "WordCountBolt"), 4).fieldsGrouping(2, Fields.new("word"))
6
+ module RedStorm
7
+ module Examples
8
+ class ClusterWordCountTopology
9
+ RedStorm::Configuration.topology_class = self
11
10
 
12
- conf = Config.new
13
- conf.setDebug(true)
14
- conf.setNumWorkers(20);
15
- conf.setMaxSpoutPending(1000);
16
- StormSubmitter.submitTopology("word-count", conf, builder.createTopology);
11
+ def start(base_class_path, env)
12
+ builder = TopologyBuilder.new
13
+ builder.setSpout('RandomSentenceSpout', JRubySpout.new(base_class_path, "RedStorm::Examples::RandomSentenceSpout"), 5)
14
+ builder.setBolt('SplitSentenceBolt', JRubyBolt.new(base_class_path, "RedStorm::Examples::SplitSentenceBolt"), 4).shuffleGrouping('RandomSentenceSpout')
15
+ builder.setBolt('WordCountBolt', JRubyBolt.new(base_class_path, "RedStorm::Examples::WordCountBolt"), 4).fieldsGrouping('SplitSentenceBolt', Fields.new("word"))
16
+
17
+ conf = Config.new
18
+ conf.setDebug(true)
19
+ conf.setNumWorkers(20);
20
+ conf.setMaxSpoutPending(1000);
21
+ StormSubmitter.submitTopology("word_count", conf, builder.createTopology);
22
+ end
23
+ end
17
24
  end
18
25
  end
@@ -1,14 +1,18 @@
1
- class ExclamationBolt
2
- def prepare(conf, context, collector)
3
- @collector = collector
4
- end
1
+ module RedStorm
2
+ module Examples
3
+ class ExclamationBolt
4
+ def prepare(conf, context, collector)
5
+ @collector = collector
6
+ end
5
7
 
6
- def execute(tuple)
7
- @collector.emit(tuple, Values.new(tuple.getString(0) + "!!!"))
8
- @collector.ack(tuple)
9
- end
8
+ def execute(tuple)
9
+ @collector.emit(tuple, Values.new(tuple.getString(0) + "!!!"))
10
+ @collector.ack(tuple)
11
+ end
10
12
 
11
- def declare_output_fields(declarer)
12
- declarer.declare(Fields.new("word"))
13
+ def declare_output_fields(declarer)
14
+ declarer.declare(Fields.new("word"))
15
+ end
16
+ end
13
17
  end
14
18
  end
@@ -1,23 +1,31 @@
1
1
  java_import 'backtype.storm.testing.TestWordSpout'
2
+
3
+ require 'lib/red_storm'
2
4
  require 'examples/native/exclamation_bolt'
3
5
 
4
6
  # this example topology uses the Storm TestWordSpout and our own JRuby ExclamationBolt
5
7
 
6
- class LocalExclamationTopology
7
- def start(base_class_path, env)
8
- builder = TopologyBuilder.new
9
-
10
- builder.setSpout(1, TestWordSpout.new, 10)
11
- builder.setBolt(2, JRubyBolt.new(base_class_path, "ExclamationBolt"), 3).shuffleGrouping(1)
12
- builder.setBolt(3, JRubyBolt.new(base_class_path, "ExclamationBolt"), 2).shuffleGrouping(2)
13
-
14
- conf = Config.new
15
- conf.setDebug(true)
16
-
17
- cluster = LocalCluster.new
18
- cluster.submitTopology("test", conf, builder.createTopology)
19
- sleep(5)
20
- cluster.killTopology("test")
21
- cluster.shutdown
8
+ module RedStorm
9
+ module Examples
10
+ class LocalExclamationTopology
11
+ RedStorm::Configuration.topology_class = self
12
+
13
+ def start(base_class_path, env)
14
+ builder = TopologyBuilder.new
15
+
16
+ builder.setSpout('TestWordSpout', TestWordSpout.new, 10)
17
+ builder.setBolt('ExclamationBolt1', JRubyBolt.new(base_class_path, 'RedStorm::Examples::ExclamationBolt'), 3).shuffleGrouping('TestWordSpout')
18
+ builder.setBolt('ExclamationBolt2', JRubyBolt.new(base_class_path, 'RedStorm::Examples::ExclamationBolt'), 3).shuffleGrouping('ExclamationBolt1')
19
+
20
+ conf = Config.new
21
+ conf.setDebug(true)
22
+
23
+ cluster = LocalCluster.new
24
+ cluster.submitTopology("exclamation", conf, builder.createTopology)
25
+ sleep(5)
26
+ cluster.killTopology("exclamation")
27
+ cluster.shutdown
28
+ end
29
+ end
22
30
  end
23
- end
31
+ end
@@ -1,37 +1,45 @@
1
1
  java_import 'backtype.storm.testing.TestWordSpout'
2
2
 
3
- class ExclamationBolt2
4
- def prepare(conf, context, collector)
5
- @collector = collector
6
- end
3
+ require 'lib/red_storm'
7
4
 
8
- def execute(tuple)
9
- @collector.emit(tuple, Values.new(tuple.getString(0) + "!!!"))
10
- @collector.ack(tuple)
11
- end
5
+ module RedStorm
6
+ module Examples
7
+ class ExclamationBolt2
8
+ def prepare(conf, context, collector)
9
+ @collector = collector
10
+ end
12
11
 
13
- def declare_output_fields(declarer)
14
- declarer.declare(Fields.new("word"))
15
- end
16
- end
12
+ def execute(tuple)
13
+ @collector.emit(tuple, Values.new("!#{tuple.getString(0)}!"))
14
+ @collector.ack(tuple)
15
+ end
16
+
17
+ def declare_output_fields(declarer)
18
+ declarer.declare(Fields.new("word"))
19
+ end
20
+ end
21
+
22
+ # this example topology uses the Storm TestWordSpout and our own JRuby ExclamationBolt
17
23
 
18
- # this example topology uses the Storm TestWordSpout and our own JRuby ExclamationBolt
24
+ class LocalExclamationTopology2
25
+ RedStorm::Configuration.topology_class = self
19
26
 
20
- class LocalExclamationTopology2
21
- def start(base_class_path, env)
22
- builder = TopologyBuilder.new
23
-
24
- builder.setSpout(1, TestWordSpout.new, 10)
25
- builder.setBolt(2, JRubyBolt.new(base_class_path, "ExclamationBolt2"), 3).shuffleGrouping(1)
26
- builder.setBolt(3, JRubyBolt.new(base_class_path, "ExclamationBolt2"), 2).shuffleGrouping(2)
27
-
28
- conf = Config.new
29
- conf.setDebug(true)
30
-
31
- cluster = LocalCluster.new
32
- cluster.submitTopology("test", conf, builder.createTopology)
33
- sleep(5)
34
- cluster.killTopology("test")
35
- cluster.shutdown
27
+ def start(base_class_path, env)
28
+ builder = TopologyBuilder.new
29
+
30
+ builder.setSpout('TestWordSpout', TestWordSpout.new, 10)
31
+ builder.setBolt('ExclamationBolt21', JRubyBolt.new(base_class_path, "RedStorm::Examples::ExclamationBolt2"), 3).shuffleGrouping('TestWordSpout')
32
+ builder.setBolt('ExclamationBolt22', JRubyBolt.new(base_class_path, "RedStorm::Examples::ExclamationBolt2"), 2).shuffleGrouping('ExclamationBolt21')
33
+
34
+ conf = Config.new
35
+ conf.setDebug(true)
36
+
37
+ cluster = LocalCluster.new
38
+ cluster.submitTopology("exclamation", conf, builder.createTopology)
39
+ sleep(5)
40
+ cluster.killTopology("exclamation")
41
+ cluster.shutdown
42
+ end
43
+ end
36
44
  end
37
45
  end
@@ -1,58 +1,65 @@
1
1
  require 'redis'
2
2
  require 'thread'
3
+ require 'lib/red_storm'
3
4
  require 'examples/native/word_count_bolt'
4
5
 
5
- # RedisWordSpout reads the Redis queue "test" on localhost:6379
6
- # and emits each word items pop'ed from the queue.
7
- class RedisWordSpout
8
- def open(conf, context, collector)
9
- @collector = collector
10
- @q = Queue.new
11
- @redis_reader = detach_redis_reader
12
- end
13
-
14
- def next_tuple
15
- # per doc nextTuple should not block, and sleep a bit when there's no data to process.
16
- if @q.size > 0
17
- @collector.emit(Values.new(@q.pop))
18
- else
19
- sleep(0.1)
20
- end
21
- end
6
+ module RedStorm
7
+ module Examples
8
+ # RedisWordSpout reads the Redis queue "test" on localhost:6379
9
+ # and emits each word items pop'ed from the queue.
10
+ class RedisWordSpout
11
+ def open(conf, context, collector)
12
+ @collector = collector
13
+ @q = Queue.new
14
+ @redis_reader = detach_redis_reader
15
+ end
16
+
17
+ def next_tuple
18
+ # per doc nextTuple should not block, and sleep a bit when there's no data to process.
19
+ if @q.size > 0
20
+ @collector.emit(Values.new(@q.pop))
21
+ else
22
+ sleep(0.1)
23
+ end
24
+ end
22
25
 
23
- def declare_output_fields(declarer)
24
- declarer.declare(Fields.new("word"))
25
- end
26
+ def declare_output_fields(declarer)
27
+ declarer.declare(Fields.new("word"))
28
+ end
26
29
 
27
- private
30
+ private
28
31
 
29
- def detach_redis_reader
30
- Thread.new do
31
- Thread.current.abort_on_exception = true
32
+ def detach_redis_reader
33
+ Thread.new do
34
+ Thread.current.abort_on_exception = true
32
35
 
33
- redis = Redis.new(:host => "localhost", :port => 6379)
34
- loop do
35
- if data = redis.blpop("test", 0)
36
- @q << data[1]
36
+ redis = Redis.new(:host => "localhost", :port => 6379)
37
+ loop do
38
+ if data = redis.blpop("test", 0)
39
+ @q << data[1]
40
+ end
41
+ end
37
42
  end
38
43
  end
39
44
  end
40
- end
41
- end
42
-
43
- class LocalRedisWordCountTopology
44
- def start(base_class_path, env)
45
- builder = TopologyBuilder.new
46
- builder.setSpout(1, JRubySpout.new(base_class_path, "RedisWordSpout"), 1)
47
- builder.setBolt(2, JRubyBolt.new(base_class_path, "WordCountBolt"), 3).fieldsGrouping(1, Fields.new("word"))
48
-
49
- conf = Config.new
50
- conf.setDebug(true)
51
- conf.setMaxTaskParallelism(3)
52
-
53
- cluster = LocalCluster.new
54
- cluster.submitTopology("redis-word-count", conf, builder.createTopology)
55
- sleep(600)
56
- cluster.shutdown
45
+
46
+ class LocalRedisWordCountTopology
47
+ RedStorm::Configuration.topology_class = self
48
+
49
+ def start(base_class_path, env)
50
+ builder = TopologyBuilder.new
51
+ builder.setSpout('RedisWordSpout', JRubySpout.new(base_class_path, "RedStorm::Examples::RedisWordSpout"), 1)
52
+ builder.setBolt('WordCountBolt', JRubyBolt.new(base_class_path, "RedStorm::Examples::WordCountBolt"), 3).fieldsGrouping('RedisWordSpout', Fields.new("word"))
53
+
54
+ conf = Config.new
55
+ conf.setDebug(true)
56
+ conf.setMaxTaskParallelism(3)
57
+
58
+ cluster = LocalCluster.new
59
+ cluster.submitTopology("redis_word_count", conf, builder.createTopology)
60
+ sleep(600)
61
+ cluster.shutdown
62
+ end
63
+ end
57
64
  end
58
65
  end
@@ -1,21 +1,27 @@
1
+ require 'lib/red_storm'
1
2
  require 'examples/native/random_sentence_spout'
2
3
  require 'examples/native/split_sentence_bolt'
3
4
  require 'examples/native/word_count_bolt'
4
5
 
5
- class LocalWordCountTopology
6
- def start(base_class_path, env)
7
- builder = TopologyBuilder.new
8
- builder.setSpout(1, JRubySpout.new(base_class_path, "RandomSentenceSpout"), 5)
9
- builder.setBolt(2, JRubyBolt.new(base_class_path, "SplitSentenceBolt"), 8).shuffleGrouping(1)
10
- builder.setBolt(3, JRubyBolt.new(base_class_path, "WordCountBolt"), 12).fieldsGrouping(2, Fields.new("word"))
11
6
 
12
- conf = Config.new
13
- conf.setDebug(true)
14
- conf.setMaxTaskParallelism(3)
7
+ module Examples
8
+ class LocalWordCountTopology
9
+ RedStorm::Configuration.topology_class = self
15
10
 
16
- cluster = LocalCluster.new
17
- cluster.submitTopology("word-count", conf, builder.createTopology)
18
- sleep(5)
19
- cluster.shutdown
11
+ def start(base_class_path, env)
12
+ builder = TopologyBuilder.new
13
+ builder.setSpout('RandomSentenceSpout', JRubySpout.new(base_class_path, "RedStorm::Examples::RandomSentenceSpout"), 5)
14
+ builder.setBolt('SplitSentenceBolt', JRubyBolt.new(base_class_path, "RedStorm::Examples::SplitSentenceBolt"), 8).shuffleGrouping('RandomSentenceSpout')
15
+ builder.setBolt('WordCountBolt', JRubyBolt.new(base_class_path, "RedStorm::Examples::WordCountBolt"), 12).fieldsGrouping('SplitSentenceBolt', Fields.new("word"))
16
+
17
+ conf = Config.new
18
+ conf.setDebug(true)
19
+ conf.setMaxTaskParallelism(3)
20
+
21
+ cluster = LocalCluster.new
22
+ cluster.submitTopology("word_count", conf, builder.createTopology)
23
+ sleep(5)
24
+ cluster.shutdown
25
+ end
20
26
  end
21
27
  end
@@ -1,26 +1,30 @@
1
- class RandomSentenceSpout
2
- attr_reader :is_distributed
1
+ module RedStorm
2
+ module Examples
3
+ class RandomSentenceSpout
4
+ attr_reader :is_distributed
3
5
 
4
- def initialize
5
- @is_distributed = true
6
- @sentences = [
7
- "the cow jumped over the moon",
8
- "an apple a day keeps the doctor away",
9
- "four score and seven years ago",
10
- "snow white and the seven dwarfs",
11
- "i am at two with nature"
12
- ]
13
- end
6
+ def initialize
7
+ @is_distributed = true
8
+ @sentences = [
9
+ "the cow jumped over the moon",
10
+ "an apple a day keeps the doctor away",
11
+ "four score and seven years ago",
12
+ "snow white and the seven dwarfs",
13
+ "i am at two with nature"
14
+ ]
15
+ end
14
16
 
15
- def open(conf, context, collector)
16
- @collector = collector
17
- end
18
-
19
- def next_tuple
20
- @collector.emit(Values.new(@sentences[rand(@sentences.length)]))
21
- end
17
+ def open(conf, context, collector)
18
+ @collector = collector
19
+ end
20
+
21
+ def next_tuple
22
+ @collector.emit(Values.new(@sentences[rand(@sentences.length)]))
23
+ end
22
24
 
23
- def declare_output_fields(declarer)
24
- declarer.declare(Fields.new("word"))
25
+ def declare_output_fields(declarer)
26
+ declarer.declare(Fields.new("word"))
27
+ end
28
+ end
25
29
  end
26
- end
30
+ end
@@ -1,13 +1,17 @@
1
- class SplitSentenceBolt
2
- def prepare(conf, context, collector)
3
- @collector = collector
4
- end
1
+ module RedStorm
2
+ module Examples
3
+ class SplitSentenceBolt
4
+ def prepare(conf, context, collector)
5
+ @collector = collector
6
+ end
5
7
 
6
- def execute(tuple)
7
- tuple.getString(0).split(" ").each {|w| @collector.emit(Values.new(w)) }
8
- end
8
+ def execute(tuple)
9
+ tuple.getString(0).split(" ").each {|w| @collector.emit(Values.new(w)) }
10
+ end
9
11
 
10
- def declare_output_fields(declarer)
11
- declarer.declare(Fields.new("word"))
12
+ def declare_output_fields(declarer)
13
+ declarer.declare(Fields.new("word"))
14
+ end
15
+ end
12
16
  end
13
17
  end
@@ -1,19 +1,23 @@
1
- class WordCountBolt
2
- def initialize
3
- @counts = Hash.new{|h, k| h[k] = 0}
4
- end
1
+ module RedStorm
2
+ module Examples
3
+ class WordCountBolt
4
+ def initialize
5
+ @counts = Hash.new{|h, k| h[k] = 0}
6
+ end
5
7
 
6
- def prepare(conf, context, collector)
7
- @collector = collector
8
- end
8
+ def prepare(conf, context, collector)
9
+ @collector = collector
10
+ end
9
11
 
10
- def execute(tuple)
11
- word = tuple.getString(0)
12
- @counts[word] += 1
13
- @collector.emit(Values.new(word, @counts[word]))
14
- end
12
+ def execute(tuple)
13
+ word = tuple.getString(0)
14
+ @counts[word] += 1
15
+ @collector.emit(Values.new(word, @counts[word]))
16
+ end
15
17
 
16
- def declare_output_fields(declarer)
17
- declarer.declare(Fields.new("word", "count"))
18
+ def declare_output_fields(declarer)
19
+ declarer.declare(Fields.new("word", "count"))
20
+ end
21
+ end
18
22
  end
19
23
  end
@@ -1,6 +1,10 @@
1
1
  require 'red_storm'
2
2
 
3
- class ExclamationBolt < RedStorm::SimpleBolt
4
- output_fields :word
5
- on_receive (:ack => true, :anchor => true) {|tuple| tuple.getString(0) + "!!!"}
3
+ module RedStorm
4
+ module Examples
5
+ class ExclamationBolt < RedStorm::SimpleBolt
6
+ output_fields :word
7
+ on_receive(:ack => true, :anchor => true) {|tuple| tuple.getString(0) + "!!!"}
8
+ end
9
+ end
6
10
  end
@@ -4,33 +4,36 @@ require 'examples/simple/exclamation_bolt'
4
4
 
5
5
  # this example topology uses the Storm TestWordSpout and our own JRuby ExclamationBolt
6
6
 
7
- class ExclamationTopology < RedStorm::SimpleTopology
8
- spout TestWordSpout, :parallelism => 10
9
-
10
- bolt ExclamationBolt, :parallelism => 3 do
11
- source TestWordSpout, :shuffle
12
- end
13
-
14
- bolt ExclamationBolt, :id => :ignore, :parallelism => 2 do
15
- source ExclamationBolt, :shuffle
16
- end
7
+ module RedStorm
8
+ module Examples
9
+ class ExclamationTopology < RedStorm::SimpleTopology
10
+ spout TestWordSpout, :parallelism => 10
11
+
12
+ bolt ExclamationBolt, :parallelism => 3 do
13
+ source TestWordSpout, :shuffle
14
+ end
15
+
16
+ bolt ExclamationBolt, :id => :ExclamationBolt2, :parallelism => 2 do
17
+ source ExclamationBolt, :shuffle
18
+ end
17
19
 
18
- configure do |env|
19
- case env
20
- when :local
21
- debug true
22
- max_task_parallelism 3
23
- when :cluster
24
- debug true
25
- num_workers 20
26
- max_spout_pending(1000);
27
- end
28
- end
20
+ configure do |env|
21
+ debug true
22
+ case env
23
+ when :local
24
+ max_task_parallelism 3
25
+ when :cluster
26
+ num_workers 20
27
+ max_spout_pending(1000);
28
+ end
29
+ end
29
30
 
30
- on_submit do |env|
31
- if env == :local
32
- sleep(5)
33
- cluster.shutdown
31
+ on_submit do |env|
32
+ if env == :local
33
+ sleep(5)
34
+ cluster.shutdown
35
+ end
36
+ end
34
37
  end
35
38
  end
36
39
  end
@@ -4,38 +4,41 @@ require 'red_storm'
4
4
  # this example topology uses the Storm TestWordSpout and our own JRuby ExclamationBolt
5
5
  # and a locally defined ExclamationBolt
6
6
 
7
- class ExclamationBolt < RedStorm::SimpleBolt
8
- output_fields :word
9
- on_receive(:ack => true, :anchor => true) {|tuple| "!#{tuple.getString(0)}!"}
10
- end
7
+ module RedStorm
8
+ module Examples
9
+ class ExclamationBolt < RedStorm::SimpleBolt
10
+ output_fields :word
11
+ on_receive(:ack => true, :anchor => true) {|tuple| "!#{tuple.getString(0)}!"}
12
+ end
11
13
 
12
- class ExclamationTopology2 < RedStorm::SimpleTopology
13
- spout TestWordSpout, :parallelism => 10
14
-
15
- bolt ExclamationBolt, :parallelism => 3 do
16
- source TestWordSpout, :shuffle
17
- end
18
-
19
- bolt ExclamationBolt, :id => :ignore, :parallelism => 2 do
20
- source ExclamationBolt, :shuffle
21
- end
14
+ class ExclamationTopology2 < RedStorm::SimpleTopology
15
+ spout TestWordSpout, :parallelism => 10
16
+
17
+ bolt ExclamationBolt, :parallelism => 3 do
18
+ source TestWordSpout, :shuffle
19
+ end
20
+
21
+ bolt ExclamationBolt, :id => :ExclamationBolt2, :parallelism => 2 do
22
+ source ExclamationBolt, :shuffle
23
+ end
22
24
 
23
- configure do |env|
24
- case env
25
- when :local
26
- debug true
27
- max_task_parallelism 3
28
- when :cluster
29
- debug true
30
- num_workers 20
31
- max_spout_pending(1000);
32
- end
33
- end
25
+ configure do |env|
26
+ debug true
27
+ case env
28
+ when :local
29
+ max_task_parallelism 3
30
+ when :cluster
31
+ num_workers 20
32
+ max_spout_pending(1000);
33
+ end
34
+ end
34
35
 
35
- on_submit do |env|
36
- if env == :local
37
- sleep(5)
38
- cluster.shutdown
36
+ on_submit do |env|
37
+ if env == :local
38
+ sleep(5)
39
+ cluster.shutdown
40
+ end
41
+ end
39
42
  end
40
43
  end
41
44
  end
@@ -1,18 +1,22 @@
1
1
  require 'red_storm'
2
2
 
3
- class RandomSentenceSpout < RedStorm::SimpleSpout
4
- set :is_distributed => true
5
- output_fields :word
3
+ module RedStorm
4
+ module Examples
5
+ class RandomSentenceSpout < RedStorm::SimpleSpout
6
+ set :is_distributed => true
7
+ output_fields :word
6
8
 
7
- on_send {@sentences[rand(@sentences.length)]}
9
+ on_send {@sentences[rand(@sentences.length)]}
8
10
 
9
- on_init do
10
- @sentences = [
11
- "the cow jumped over the moon",
12
- "an apple a day keeps the doctor away",
13
- "four score and seven years ago",
14
- "snow white and the seven dwarfs",
15
- "i am at two with nature"
16
- ]
11
+ on_init do
12
+ @sentences = [
13
+ "the cow jumped over the moon",
14
+ "an apple a day keeps the doctor away",
15
+ "four score and seven years ago",
16
+ "snow white and the seven dwarfs",
17
+ "i am at two with nature"
18
+ ]
19
+ end
20
+ end
17
21
  end
18
- end
22
+ end
@@ -5,51 +5,55 @@ require 'red_storm'
5
5
 
6
6
  require 'examples/simple/word_count_bolt'
7
7
 
8
- # RedisWordSpout reads the Redis queue "test" on localhost:6379
9
- # and emits each word items pop'ed from the queue.
8
+ module RedStorm
9
+ module Examples
10
10
 
11
- class RedisWordSpout < RedStorm::SimpleSpout
12
- output_fields :word
11
+ # RedisWordSpout reads the Redis queue "test" on localhost:6379
12
+ # and emits each word items pop'ed from the queue.
13
13
 
14
- on_send {@q.pop if @q.size > 0}
14
+ class RedisWordSpout < RedStorm::SimpleSpout
15
+ output_fields :word
15
16
 
16
- on_init do
17
- @q = Queue.new
18
- @redis_reader = detach_redis_reader
19
- end
20
-
21
- private
22
-
23
- def detach_redis_reader
24
- Thread.new do
25
- Thread.current.abort_on_exception = true
17
+ on_send {@q.pop if @q.size > 0}
26
18
 
27
- redis = Redis.new(:host => "localhost", :port => 6379)
28
- loop do
29
- if data = redis.blpop("test", 0)
30
- @q << data[1]
19
+ on_init do
20
+ @q = Queue.new
21
+ @redis_reader = detach_redis_reader
22
+ end
23
+
24
+ private
25
+
26
+ def detach_redis_reader
27
+ Thread.new do
28
+ Thread.current.abort_on_exception = true
29
+
30
+ redis = Redis.new(:host => "localhost", :port => 6379)
31
+ loop do
32
+ if data = redis.blpop("test", 0)
33
+ @q << data[1]
34
+ end
35
+ end
31
36
  end
32
37
  end
33
38
  end
34
- end
35
- end
36
39
 
37
- class RedisWordCountTopology < RedStorm::SimpleTopology
38
- spout RedisWordSpout
39
-
40
- bolt WordCountBolt, :parallelism => 3 do
41
- source RedisWordSpout, :fields => ["word"]
42
- end
40
+ class RedisWordCountTopology < RedStorm::SimpleTopology
41
+ spout RedisWordSpout
42
+
43
+ bolt WordCountBolt, :parallelism => 3 do
44
+ source RedisWordSpout, :fields => ["word"]
45
+ end
43
46
 
44
- configure do |env|
45
- case env
46
- when :local
47
- debug true
48
- max_task_parallelism 3
49
- when :cluster
50
- debug true
51
- num_workers 20
52
- max_spout_pending(1000);
47
+ configure do |env|
48
+ debug true
49
+ case env
50
+ when :local
51
+ max_task_parallelism 3
52
+ when :cluster
53
+ num_workers 20
54
+ max_spout_pending(1000);
55
+ end
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -1,29 +1,33 @@
1
1
  require 'red_storm'
2
2
 
3
- class SplitSentenceBolt < RedStorm::SimpleBolt
4
- output_fields :word
3
+ module RedStorm
4
+ module Examples
5
+ class SplitSentenceBolt < RedStorm::SimpleBolt
6
+ output_fields :word
5
7
 
6
- # block declaration style using auto-emit (default)
7
- #
8
- on_receive {|tuple| tuple.getString(0).split(' ').map{|w| [w]}}
8
+ # block declaration style using auto-emit (default)
9
+ #
10
+ on_receive {|tuple| tuple.getString(0).split(' ').map{|w| [w]}}
9
11
 
10
- # block declaration style no auto-emit
11
- #
12
- # on_receive :emit => false do |tuple|
13
- # tuple.getString(0).split(' ').each{|w| unanchored_emit(w)}
14
- # end
12
+ # block declaration style no auto-emit
13
+ #
14
+ # on_receive :emit => false do |tuple|
15
+ # tuple.getString(0).split(' ').each{|w| unanchored_emit(w)}
16
+ # end
15
17
 
16
- # alternate declaration style using on_receive method
17
- #
18
- # on_receive :emit => true
19
- # def on_receive(tuple)
20
- # tuple.getString(0).split(' ').map{|w| [w]}
21
- # end
18
+ # alternate declaration style using on_receive method
19
+ #
20
+ # on_receive :emit => true
21
+ # def on_receive(tuple)
22
+ # tuple.getString(0).split(' ').map{|w| [w]}
23
+ # end
22
24
 
23
- # alternate declaration style using any specific method
24
- #
25
- # on_receive :my_method, :emit => true
26
- # def my_method(tuple)
27
- # tuple.getString(0).split(' ').map{|w| [w]}
28
- # end
25
+ # alternate declaration style using any specific method
26
+ #
27
+ # on_receive :my_method, :emit => true
28
+ # def my_method(tuple)
29
+ # tuple.getString(0).split(' ').map{|w| [w]}
30
+ # end
31
+ end
32
+ end
29
33
  end
@@ -1,15 +1,19 @@
1
1
  require 'red_storm'
2
2
 
3
- class WordCountBolt < RedStorm::SimpleBolt
4
- output_fields :word, :count
5
- on_init {@counts = Hash.new{|h, k| h[k] = 0}}
3
+ module RedStorm
4
+ module Examples
5
+ class WordCountBolt < RedStorm::SimpleBolt
6
+ output_fields :word, :count
7
+ on_init {@counts = Hash.new{|h, k| h[k] = 0}}
6
8
 
7
- # block declaration style using auto-emit (default)
8
- #
9
- on_receive do |tuple|
10
- word = tuple.getString(0)
11
- @counts[word] += 1
9
+ # block declaration style using auto-emit (default)
10
+ #
11
+ on_receive do |tuple|
12
+ word = tuple.getString(0)
13
+ @counts[word] += 1
12
14
 
13
- [word, @counts[word]]
15
+ [word, @counts[word]]
16
+ end
17
+ end
14
18
  end
15
19
  end
@@ -2,33 +2,36 @@ require 'examples/simple/random_sentence_spout'
2
2
  require 'examples/simple/split_sentence_bolt'
3
3
  require 'examples/simple/word_count_bolt'
4
4
 
5
- class WordCountTopology < RedStorm::SimpleTopology
6
- spout RandomSentenceSpout, :parallelism => 5
7
-
8
- bolt SplitSentenceBolt, :parallelism => 8 do
9
- source RandomSentenceSpout, :shuffle
10
- end
11
-
12
- bolt WordCountBolt, :parallelism => 12 do
13
- source SplitSentenceBolt, :fields => ["word"]
14
- end
5
+ module RedStorm
6
+ module Examples
7
+ class WordCountTopology < SimpleTopology
8
+ spout RandomSentenceSpout, :parallelism => 5
9
+
10
+ bolt SplitSentenceBolt, :parallelism => 8 do
11
+ source RandomSentenceSpout, :shuffle
12
+ end
13
+
14
+ bolt WordCountBolt, :parallelism => 12 do
15
+ source SplitSentenceBolt, :fields => ["word"]
16
+ end
15
17
 
16
- configure :word_count do |env|
17
- case env
18
- when :local
19
- debug true
20
- max_task_parallelism 3
21
- when :cluster
22
- debug true
23
- num_workers 20
24
- max_spout_pending(1000);
25
- end
26
- end
18
+ configure :word_count do |env|
19
+ debug true
20
+ case env
21
+ when :local
22
+ max_task_parallelism 3
23
+ when :cluster
24
+ num_workers 20
25
+ max_spout_pending(1000);
26
+ end
27
+ end
27
28
 
28
- on_submit do |env|
29
- if env == :local
30
- sleep(5)
31
- cluster.shutdown
29
+ on_submit do |env|
30
+ if env == :local
31
+ sleep(5)
32
+ cluster.shutdown
33
+ end
34
+ end
32
35
  end
33
36
  end
34
37
  end
@@ -3,6 +3,7 @@ module RedStorm
3
3
  end
4
4
 
5
5
  require 'red_storm/version'
6
+ require 'red_storm/configuration'
6
7
  require 'red_storm/application'
7
8
  require 'red_storm/simple_bolt'
8
9
  require 'red_storm/simple_spout'
@@ -0,0 +1,16 @@
1
+ module RedStorm
2
+ module Configuration
3
+ extend self
4
+
5
+ @topology_class = nil
6
+
7
+ def topology_class=(clazz)
8
+ @topology_class = clazz
9
+ end
10
+
11
+ def topology_class
12
+ @topology_class
13
+ end
14
+
15
+ end
16
+ end
@@ -1,3 +1,5 @@
1
+ require 'red_storm/configuration'
2
+
1
3
  module RedStorm
2
4
 
3
5
  class SimpleTopology
@@ -8,11 +10,11 @@ module RedStorm
8
10
 
9
11
  class ComponentDefinition
10
12
  attr_reader :clazz, :parallelism
11
- attr_accessor :id
13
+ attr_accessor :id # ids are forced to string
12
14
 
13
15
  def initialize(component_class, id, parallelism)
14
16
  @clazz = component_class
15
- @id = id
17
+ @id = id.to_s
16
18
  @parallelism = parallelism
17
19
  end
18
20
  end
@@ -28,16 +30,16 @@ module RedStorm
28
30
  end
29
31
 
30
32
  def source(source_id, grouping)
31
- @sources << [source_id.is_a?(Class) ? SimpleTopology.underscore(source_id) : source_id, grouping.is_a?(Hash) ? grouping : {grouping => nil}]
33
+ @sources << [source_id.is_a?(Class) ? SimpleTopology.underscore(source_id) : source_id.to_s, grouping.is_a?(Hash) ? grouping : {grouping => nil}]
32
34
  end
33
35
 
34
36
  def define_grouping(declarer)
35
37
  @sources.each do |source_id, grouping|
36
38
  grouper, params = grouping.first
37
-
39
+ # declarer.fieldsGrouping(source_id, Fields.new())
38
40
  case grouper
39
41
  when :fields
40
- declarer.fieldsGrouping(source_id, Fields.new(*params))
42
+ declarer.fieldsGrouping(source_id, Fields.new(*([params].flatten.map(&:to_s))))
41
43
  when :global
42
44
  declarer.globalGrouping(source_id)
43
45
  when :shuffle
@@ -88,6 +90,7 @@ module RedStorm
88
90
  end
89
91
 
90
92
  def self.configure(name = nil, &configure_block)
93
+ Configuration.topology_class = self
91
94
  @topology_name = name if name
92
95
  @configure_block = configure_block if block_given?
93
96
  end
@@ -131,31 +134,13 @@ module RedStorm
131
134
  private
132
135
 
133
136
  def self.resolve_ids!(components)
134
- next_numeric_id = 1
135
- resolved_names = {}
136
-
137
- numeric_components, symbolic_components = components.partition{|c| c.id.is_a?(Fixnum)}
138
- numeric_ids = numeric_components.map(&:id)
139
-
140
- # assign numeric ids to symbolic ids
141
- symbolic_components.each do |component|
142
- id = component.id.to_s
143
- raise("duplicate symbolic id in #{component.clazz.name} on id=#{id}") if resolved_names.has_key?(id)
144
- next_numeric_id += 1 while numeric_ids.include?(next_numeric_id)
145
- numeric_ids << next_numeric_id
146
- resolved_names[id] = next_numeric_id
147
- end
148
-
149
- # reassign numeric ids to all components
150
- components.each do |component|
151
- unless component.id.is_a?(Fixnum)
152
- component.id = resolved_names[component.id.to_s] || raise("cannot resolve #{component.clazz.name} id=#{component.id.to_s}")
153
- end
137
+ # verify duplicate implicit ids
138
+ ids = components.map(&:id)
139
+ components.reverse.each do |component|
140
+ raise("duplicate id in #{component.clazz.name} on id=#{component.id}") if ids.select{|id| id == component.id}.size > 1
141
+ # verify source_id references
154
142
  if component.respond_to?(:sources)
155
- component.sources.map! do |source_id, grouping|
156
- id = source_id.is_a?(Fixnum) ? source_id : resolved_names[source_id.to_s] || raise("cannot resolve #{component.clazz.name} source id=#{source_id.to_s}")
157
- [id, grouping]
158
- end
143
+ component.sources.each{|source_id, grouping| raise("cannot resolve #{component.clazz.name} source id=#{source_id}") unless ids.include?(source_id)}
159
144
  end
160
145
  end
161
146
  end
@@ -24,7 +24,7 @@ java_import 'redstorm.storm.jruby.JRubySpout'
24
24
  java_package 'redstorm'
25
25
 
26
26
  # TopologyLauncher is the application entry point when launching a topology. Basically it will
27
- # call require on the specified Ruby topology/project class file path and call its start method
27
+ # call require on the specified Ruby topology class file path and call its start method
28
28
  class TopologyLauncher
29
29
 
30
30
  java_signature 'void main(String[])'
@@ -35,12 +35,12 @@ class TopologyLauncher
35
35
  end
36
36
  env = args[0].to_sym
37
37
  class_path = args[1]
38
- clazz = camel_case(class_path.split('/').last.split('.').first)
39
-
40
- puts("RedStorm v#{RedStorm::VERSION} starting topology #{clazz} in #{env.to_s} environment")
41
38
 
42
39
  require class_path
43
- Object.module_eval(clazz).new.start(class_path, env)
40
+
41
+ topology_name = RedStorm::Configuration.topology_class.respond_to?(:topology_name) ? "/#{RedStorm::Configuration.topology_class.topology_name}" : ''
42
+ puts("RedStorm v#{RedStorm::VERSION} starting topology #{RedStorm::Configuration.topology_class.name}#{topology_name} in #{env.to_s} environment")
43
+ RedStorm::Configuration.topology_class.new.start(class_path, env)
44
44
  end
45
45
 
46
46
  private
@@ -1,3 +1,3 @@
1
1
  module RedStorm
2
- VERSION = '0.2.1'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -15,6 +15,7 @@ TARGET_SRC_DIR = "#{TARGET_DIR}/src"
15
15
  TARGET_CLASSES_DIR = "#{TARGET_DIR}/classes"
16
16
  TARGET_DEPENDENCY_DIR = "#{TARGET_DIR}/dependency"
17
17
  TARGET_DEPENDENCY_UNPACKED_DIR = "#{TARGET_DIR}/dependency-unpacked"
18
+ TARGET_MARKERS_DIR = "#{TARGET_DIR}/dependency-markers"
18
19
  TARGET_GEMS_DIR = "#{TARGET_DIR}/gems"
19
20
  TARGET_CLUSTER_JAR = "#{TARGET_DIR}/cluster-topology.jar"
20
21
 
@@ -55,7 +56,7 @@ task :install => [:deps, :build] do
55
56
  end
56
57
 
57
58
  task :unpack do
58
- system("rmvn dependency:unpack -f #{RedStorm::REDSTORM_HOME}/pom.xml -DoutputDirectory=#{TARGET_DEPENDENCY_UNPACKED_DIR}")
59
+ system("rmvn dependency:unpack -f #{RedStorm::REDSTORM_HOME}/pom.xml -DoutputDirectory=#{TARGET_DEPENDENCY_UNPACKED_DIR} -DmarkersDirectory=#{TARGET_MARKERS_DIR}")
59
60
  end
60
61
 
61
62
  task :devjar => [:unpack, :clean_jar] do
@@ -111,7 +112,7 @@ task :examples do
111
112
  end
112
113
 
113
114
  task :deps do
114
- system("rmvn dependency:copy-dependencies -f #{RedStorm::REDSTORM_HOME}/pom.xml -DoutputDirectory=#{TARGET_DEPENDENCY_DIR}")
115
+ system("rmvn dependency:copy-dependencies -f #{RedStorm::REDSTORM_HOME}/pom.xml -DoutputDirectory=#{TARGET_DEPENDENCY_DIR} -DmarkersDirectory=#{TARGET_MARKERS_DIR}")
115
116
  end
116
117
 
117
118
  task :build => :setup do
@@ -148,5 +149,5 @@ end
148
149
 
149
150
  def build_jruby(source_path)
150
151
  puts("\n--> Compiling JRuby")
151
- system("cd #{RedStorm::REDSTORM_HOME}; jrubyc -t #{TARGET_SRC_DIR} --verbose --java -c \"#{TARGET_DEPENDENCY_DIR}/storm-0.5.3.jar\" -c \"#{TARGET_CLASSES_DIR}\" #{source_path}")
152
+ system("cd #{RedStorm::REDSTORM_HOME}; jrubyc -t #{TARGET_SRC_DIR} --verbose --java -c \"#{TARGET_DEPENDENCY_DIR}/storm-0.6.2.jar\" -c \"#{TARGET_CLASSES_DIR}\" #{source_path}")
152
153
  end
data/pom.xml CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <groupId>redstorm</groupId>
6
6
  <artifactId>redstorm</artifactId>
7
- <version>0.2.1</version>
7
+ <version>0.4.0</version>
8
8
  <name>RedStorm JRuby on Storm</name>
9
9
 
10
10
  <properties>
@@ -27,13 +27,13 @@
27
27
  <dependency>
28
28
  <groupId>storm</groupId>
29
29
  <artifactId>storm</artifactId>
30
- <version>0.5.4</version>
30
+ <version>0.6.2</version>
31
31
  </dependency>
32
32
 
33
33
  <dependency>
34
34
  <groupId>org.jruby</groupId>
35
35
  <artifactId>jruby-complete</artifactId>
36
- <version>1.6.5</version>
36
+ <version>1.6.6</version>
37
37
  </dependency>
38
38
  </dependencies>
39
39
 
@@ -48,11 +48,12 @@
48
48
  <artifactItem>
49
49
  <groupId>org.jruby</groupId>
50
50
  <artifactId>jruby-complete</artifactId>
51
- <version>1.6.5</version>
51
+ <version>1.6.6</version>
52
52
  <type>jar</type>
53
53
  <overWrite>false</overWrite>
54
54
  </artifactItem>
55
55
  </artifactItems>
56
+ <markersDirectory>${markersDirectory}</markersDirectory>
56
57
  </configuration>
57
58
  <executions>
58
59
  <execution>
@@ -66,4 +67,4 @@
66
67
  </plugins>
67
68
  </build>
68
69
 
69
- </project>
70
+ </project>
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: redstorm
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.1
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Colin Surprenant
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-11-23 00:00:00 Z
13
+ date: 2012-02-08 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubyforge
@@ -57,6 +57,7 @@ extra_rdoc_files: []
57
57
  files:
58
58
  - lib/red_storm.rb
59
59
  - lib/red_storm/application.rb
60
+ - lib/red_storm/configuration.rb
60
61
  - lib/red_storm/simple_bolt.rb
61
62
  - lib/red_storm/simple_spout.rb
62
63
  - lib/red_storm/simple_topology.rb
@@ -114,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
114
115
  requirements: []
115
116
 
116
117
  rubyforge_project: redstorm
117
- rubygems_version: 1.8.9
118
+ rubygems_version: 1.8.15
118
119
  signing_key:
119
120
  specification_version: 3
120
121
  summary: JRuby on Storm