pacer-parallel 0.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 45fecca778590a9eedc6c7386894dd14847fb538
4
+ data.tar.gz: 07d3840329d2aaa564b395313ce622395058c6ba
5
+ SHA512:
6
+ metadata.gz: f1f15ee12ce896353781f578924cd6912f1bfda5d776c740a8ed79582e8dd9dcedc820b215263fd487bc35fe4cbdd507901a5d74559264c14f88b8594e94333f
7
+ data.tar.gz: 6dc2fab326c7ccfb7318e6be352b8309c0218f00fb13d0cfe5afc3203b9ba639a18aed6de70a8d93b877e8777d06537a268b456bfdbc0ca635288a61fed417fe
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ target
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'pacer', :path => '../pacer'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Darrick Wiebe
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Pacer::Parallel
2
+
3
+ Parallelize [Pacer](https://github.com/pangloss/pacer) Routes.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'pacer-parallel'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install pacer-parallel
18
+
19
+ ## Usage
20
+
21
+ ```ruby
22
+ g.v.parallel(threads: 8, in_buffer: 4, out_buffer: 10) do |v|
23
+ v.all(&:out)
24
+ end
25
+ ```
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
34
+
35
+
36
+ ## Notes
37
+
38
+
39
+ * eagerly consume (1) input and push into a channel
40
+ * ChannelCapPipe
41
+ * create a cap pipe that does this. The pipe's output is the channel
42
+ * source data may be slow. Should probably not use a go block
43
+ * 1 thread in a loop
44
+ * Control the construction of parallel pipes. Default 2 threads, make
45
+ it configurable.
46
+ * standard copy split pipe can push the channel to subchannels
47
+ * each parallel route pulls from the channel.
48
+ * in a go block (waits will not block go thread pool)
49
+ * ChannelReaderPipe
50
+ * PathChannelReaderPipe
51
+ * parallel routes are unmodified
52
+ * cap each route - eagerly consume input and push into a channel
53
+ * ChannelCapPipe again
54
+ * ExhaustMergePipe + GatherPipe to create a route to an list of
55
+ channels
56
+ * use alts to read from any of the channels
57
+ * ChannelFanInPipe
58
+
59
+
60
+
61
+ ## Pipe structure built to create parallel route:
62
+
63
+ CCP
64
+ CSP (parallelism is 1 thread per pipe being split into)
65
+ CRP -> Work ... -> CCP
66
+ CRP -> Work ... -> CCP
67
+ ...
68
+ EMP
69
+ GP
70
+ CARP
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :package do
4
+ system 'lein', 'with-profile', 'release', 'uberjar'
5
+ end
6
+
7
+ file Pacer::Parallel::JAR_PATH => FileList['project.clj', 'src/clojure/**/*.clj', 'src/java/**/*.java'] do
8
+ Rake::Task['package'].execute
9
+ end
10
+
11
+ task :jar => Pacer::Parallel::JAR_PATH
12
+
13
+ task :build => :jar
14
+ task :install => :jar
15
+
16
+ desc "Run the clojure test and integration suites"
17
+ task :expectations do
18
+ sh "lein with-profile integration expectations"
19
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../src/ruby', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pacer/parallel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pacer-parallel"
8
+ spec.version = Pacer::Parallel::VERSION
9
+ spec.platform = 'java'
10
+ spec.authors = ["Darrick Wiebe"]
11
+ spec.email = ["dw@xnlogic.com"]
12
+ spec.description = %q{Simple parallel routes in Pacer}
13
+ spec.summary = %q{With the magic of Clojure's core.async}
14
+ spec.homepage = "http://xnlogic.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/) + [Pacer::Parallel::JAR_PATH]
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["src/ruby"]
21
+
22
+ spec.add_dependency "pacer", "~> 1.3.3"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
data/project.clj ADDED
@@ -0,0 +1,28 @@
1
+ (defproject
2
+ pacer.parallel "0.1.0-SNAPSHOT"
3
+ :description "Leveraging core.async in Pacer"
4
+ :url "http://xnlogic.com"
5
+ :license {:name "MIT"}
6
+ :min-lein-version "2.0.0"
7
+ :dependencies [[org.clojure/clojure "1.5.1"]
8
+ [core.async "0.1.0-SNAPSHOT"]
9
+ [com.tinkerpop/pipes "2.3.0"]]
10
+ :global-vars {*warn-on-reflection* true}
11
+ :profiles
12
+ {:dev
13
+ {:source-paths ["src/clojure"]
14
+ :java-source-paths ["src/java"]}
15
+ :release
16
+ {:source-paths ["src/clojure"]
17
+ :java-source-paths ["src/java"]
18
+ :target-path "target/release"}
19
+ :integration
20
+ {:source-paths ["src/clojure"]
21
+ :java-source-paths ["src/java"]
22
+ :test-paths ["test_integration"]
23
+ :target-path "target/integration"}
24
+ }
25
+ :plugins [[lein-expectations "0.0.7"]
26
+ [lein-autoexpect "0.2.5"]
27
+ [lein-kibit "0.0.7"]
28
+ ])
@@ -0,0 +1,23 @@
1
+ (ns pacer.parallel
2
+ (:require [clojure.core.async :refer [chan >!! close! alts!!]])
3
+ (:import com.tinkerpop.pipes.Pipe))
4
+
5
+ (defn pipe->chan [^Pipe pipe buffer]
6
+ (let [c (if buffer (chan buffer) (chan))]
7
+ (if (.hasNext pipe)
8
+ (future
9
+ (loop [v (.next pipe)]
10
+ (when v (>!! c v))
11
+ (if (.hasNext pipe)
12
+ (recur (.next pipe))
13
+ (close! c))))
14
+ (close! c))
15
+ c))
16
+
17
+ (defn chan-select [chans]
18
+ (let [[v c] (alts!! chans)]
19
+ (if v
20
+ [v chans]
21
+ (if (= 1 (count chans))
22
+ nil
23
+ (recur (remove #{c} chans))))))
@@ -0,0 +1,47 @@
1
+ package com.xnlogic.pacer;
2
+
3
+ import com.tinkerpop.pipes.AbstractPipe;
4
+ import com.tinkerpop.pipes.Pipe;
5
+ import com.tinkerpop.pipes.transform.TransformPipe;
6
+ import com.tinkerpop.pipes.util.FastNoSuchElementException;
7
+
8
+ import clojure.lang.RT;
9
+ import clojure.lang.Var;
10
+ import clojure.lang.Symbol;
11
+
12
+ public class ChannelCapPipe<S> extends AbstractPipe<S, Object> implements TransformPipe<S, Object> {
13
+ private static final Var REQUIRE = RT.var("clojure.core", "require");
14
+ private static final Var PIPE_TO_CHAN = RT.var("pacer.parallel", "pipe->chan");
15
+ private static boolean environmentReady = false;
16
+
17
+ public static void setupEnvironment() {
18
+ if (!ChannelCapPipe.environmentReady) {
19
+ REQUIRE.invoke(Symbol.intern(null, "clojure.core"));
20
+ REQUIRE.invoke(Symbol.intern(null, "pacer.parallel"));
21
+ REQUIRE.invoke(Symbol.intern(null, "clojure.core.async"));
22
+ ChannelCapPipe.environmentReady = true;
23
+ }
24
+ }
25
+
26
+
27
+ private Object buffer;
28
+ private boolean hasRun = false;
29
+
30
+ public ChannelCapPipe(Object buffer) {
31
+ ChannelCapPipe.setupEnvironment();
32
+ this.buffer = buffer;
33
+ }
34
+
35
+ protected Object processNextStart() {
36
+ if (!this.hasRun) {
37
+ this.hasRun = true;
38
+ return PIPE_TO_CHAN.invoke(starts, buffer);
39
+ } else {
40
+ throw FastNoSuchElementException.instance();
41
+ }
42
+ }
43
+
44
+ public void reset() {
45
+ this.hasRun = false;
46
+ }
47
+ }
@@ -0,0 +1,41 @@
1
+ package com.xnlogic.pacer;
2
+
3
+ import com.tinkerpop.pipes.AbstractPipe;
4
+ import com.tinkerpop.pipes.Pipe;
5
+ import com.tinkerpop.pipes.transform.TransformPipe;
6
+ import com.tinkerpop.pipes.util.FastNoSuchElementException;
7
+
8
+ import java.util.List;
9
+ import clojure.lang.RT;
10
+ import clojure.lang.Var;
11
+
12
+ public class ChannelFanInPipe<S> extends AbstractPipe<List<Object>, S> implements TransformPipe<List<Object>, S> {
13
+ private static final Var VEC = RT.var("clojure.core", "vec");
14
+ private static final Var NTH = RT.var("clojure.core", "nth");
15
+ private static final Var CHAN_SELECT = RT.var("pacer.parallel", "chan-select");
16
+
17
+ private Object chans;
18
+
19
+ protected S processNextStart() {
20
+ while (true) {
21
+ if (this.chans == null) {
22
+ Object next = starts.next();
23
+ if (next != null)
24
+ this.chans = VEC.invoke(next);
25
+ } else {
26
+ Object vec = CHAN_SELECT.invoke(this.chans);
27
+ if (vec == null) {
28
+ this.chans = null;
29
+ } else {
30
+ this.chans = NTH.invoke(vec, 1);
31
+ return (S) NTH.invoke(vec, 0);
32
+ }
33
+ }
34
+ }
35
+ }
36
+
37
+ public void reset() {
38
+ this.chans = null;
39
+ }
40
+ }
41
+
@@ -0,0 +1,33 @@
1
+ package com.xnlogic.pacer;
2
+
3
+ import com.tinkerpop.pipes.AbstractPipe;
4
+ import com.tinkerpop.pipes.Pipe;
5
+ import com.tinkerpop.pipes.transform.TransformPipe;
6
+ import com.tinkerpop.pipes.util.FastNoSuchElementException;
7
+
8
+ import clojure.lang.RT;
9
+ import clojure.lang.Var;
10
+
11
+ public class ChannelReaderPipe<S> extends AbstractPipe<S, Object> implements TransformPipe<S, Object> {
12
+ private static final Var READ_CHAN = RT.var("clojure.core.async", "<!!");
13
+
14
+ private Object chan;
15
+
16
+ protected Object processNextStart() {
17
+ while (true) {
18
+ if (this.chan == null) {
19
+ this.chan = starts.next();
20
+ } else {
21
+ Object value = READ_CHAN.invoke(this.chan);
22
+ if (value == null)
23
+ this.chan = null;
24
+ else
25
+ return value;
26
+ }
27
+ }
28
+ }
29
+
30
+ public void reset() {
31
+ this.chan = null;
32
+ }
33
+ }
@@ -0,0 +1 @@
1
+ require 'pacer/parallel'
@@ -0,0 +1,13 @@
1
+ module Pacer
2
+ module Clojure
3
+ import 'clojure.lang.RT'
4
+ import 'clojure.lang.Symbol'
5
+ REQUIRE = RT.var("clojure.core", "require");
6
+
7
+ class << self
8
+ def require(namespace)
9
+ REQUIRE.invoke(Symbol.intern(nil, namespace));
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ require "pacer/parallel/version"
2
+ require File.join(Pacer::Parallel::PATH, Pacer::Parallel::JAR_PATH)
3
+ require "pacer/clojure"
4
+ require 'pacer'
5
+ require "pacer/parallel/channel_cap"
6
+ require "pacer/parallel/channel_reader"
7
+ require "pacer/parallel/channel_fan_in"
8
+
9
+ module Pacer
10
+ module Routes
11
+ module RouteOperations
12
+ def parallel(opts = {}, &block)
13
+ threads = opts.fetch(:threads, 2)
14
+ if threads > 0
15
+ branched = (0...threads).reduce(channel_cap buffer: opts.fetch(:in_buffer, threads)) do |r, n|
16
+ r.branch do |x|
17
+ b = block.call x.channel_reader(based_on: self)
18
+ b.channel_cap buffer: opts[:out_buffer]
19
+ end
20
+ end
21
+ branched.merge_exhaustive.gather.channel_fan_in(based_on: block.call(self))
22
+ else
23
+ block.call self
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module Pacer
2
+ module Routes
3
+ module RouteOperations
4
+ # This creates a channel, emits it and spawns a thread
5
+ # that will push all data in the source into the channel.
6
+ def channel_cap(opts = {})
7
+ chain_route(opts.merge transform: Pacer::Parallel::ChannelCap, element_type: :channel)
8
+ end
9
+ end
10
+ end
11
+
12
+ module Parallel
13
+ module ChannelCap
14
+ import com.xnlogic.pacer.ChannelCapPipe
15
+
16
+ attr_accessor :buffer
17
+
18
+ protected
19
+
20
+ def attach_pipe(end_pipe)
21
+ pipe = ChannelCapPipe.new(buffer)
22
+ pipe.setStarts end_pipe if end_pipe
23
+ pipe
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+
@@ -0,0 +1,27 @@
1
+ module Pacer
2
+ module Routes
3
+ module RouteOperations
4
+ # The source of this should be a pipe emitting lists of channels.
5
+ def channel_fan_in(opts = {})
6
+ chain_route(opts.merge transform: Pacer::Parallel::ChannelFanIn)
7
+ end
8
+ end
9
+ end
10
+
11
+ module Parallel
12
+ module ChannelFanIn
13
+ import com.xnlogic.pacer.ChannelFanInPipe
14
+
15
+ protected
16
+
17
+ def attach_pipe(end_pipe)
18
+ pipe = ChannelFanInPipe.new
19
+ pipe.setStarts end_pipe if end_pipe
20
+ pipe
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+
@@ -0,0 +1,24 @@
1
+ module Pacer
2
+ module Routes
3
+ module RouteOperations
4
+ # The source of this in a pipe emitting individual channels
5
+ def channel_reader(opts = {})
6
+ chain_route(opts.merge transform: Pacer::Parallel::ChannelReader)
7
+ end
8
+ end
9
+ end
10
+
11
+ module Parallel
12
+ module ChannelReader
13
+ import com.xnlogic.pacer.ChannelReaderPipe
14
+
15
+ protected
16
+
17
+ def attach_pipe(end_pipe)
18
+ pipe = ChannelReaderPipe.new
19
+ pipe.setStarts end_pipe if end_pipe
20
+ pipe
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ module Pacer
2
+ module Parallel
3
+ VERSION = "0.1.0"
4
+ JAR_VERSION = "#{VERSION}-SNAPSHOT"
5
+ JAR = "pacer.parallel-#{ JAR_VERSION }-standalone.jar"
6
+ JAR_PATH = "target/release/#{ JAR }"
7
+ PATH = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pacer-parallel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: java
6
+ authors:
7
+ - Darrick Wiebe
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pacer
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.3.3
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.3.3
25
+ prerelease: false
26
+ type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '1.3'
39
+ prerelease: false
40
+ type: :development
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ prerelease: false
54
+ type: :development
55
+ description: Simple parallel routes in Pacer
56
+ email:
57
+ - dw@xnlogic.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - pacer-parallel.gemspec
68
+ - project.clj
69
+ - src/clojure/pacer/parallel.clj
70
+ - src/java/com/xnlogic/pacer/ChannelCapPipe.java
71
+ - src/java/com/xnlogic/pacer/ChannelFanInPipe.java
72
+ - src/java/com/xnlogic/pacer/ChannelReaderPipe.java
73
+ - src/ruby/pacer-parallel.rb
74
+ - src/ruby/pacer/clojure.rb
75
+ - src/ruby/pacer/parallel.rb
76
+ - src/ruby/pacer/parallel/channel_cap.rb
77
+ - src/ruby/pacer/parallel/channel_fan_in.rb
78
+ - src/ruby/pacer/parallel/channel_reader.rb
79
+ - src/ruby/pacer/parallel/version.rb
80
+ - target/release/pacer.parallel-0.1.0-SNAPSHOT-standalone.jar
81
+ homepage: http://xnlogic.com
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - src/ruby
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.0.3
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: With the magic of Clojure's core.async
105
+ test_files: []