pacer-parallel 0.1.0-java

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 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: []