pacer 2.0.10.pre-java → 2.0.12-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -13
  2. data/.autotest +0 -4
  3. data/.gitignore +1 -0
  4. data/.travis.yml +2 -2
  5. data/Rakefile +25 -0
  6. data/blog/detach_benchmarks.txt +56 -0
  7. data/ext/.classpath +26 -0
  8. data/ext/.gitignore +44 -0
  9. data/ext/.project +23 -0
  10. data/ext/pom.xml +76 -0
  11. data/ext/src/main/java/com/xnlogic/pacer/pipes/BlackboxPipeline.java +56 -0
  12. data/ext/src/main/java/com/xnlogic/pacer/pipes/CollectionFilterPipe.java +18 -0
  13. data/ext/src/main/java/com/xnlogic/pacer/pipes/EdgesPipe.java +26 -0
  14. data/ext/src/main/java/com/xnlogic/pacer/pipes/ExpandablePipe.java +93 -0
  15. data/ext/src/main/java/com/xnlogic/pacer/pipes/IdCollectionFilterPipe.java +50 -0
  16. data/ext/src/main/java/com/xnlogic/pacer/pipes/IsEmptyPipe.java +35 -0
  17. data/ext/src/main/java/com/xnlogic/pacer/pipes/IsUniquePipe.java +58 -0
  18. data/ext/src/main/java/com/xnlogic/pacer/pipes/LabelCollectionFilterPipe.java +32 -0
  19. data/ext/src/main/java/com/xnlogic/pacer/pipes/LabelPrefixPipe.java +23 -0
  20. data/ext/src/main/java/com/xnlogic/pacer/pipes/NeverPipe.java +10 -0
  21. data/ext/src/main/java/com/xnlogic/pacer/pipes/VerticesPipe.java +26 -0
  22. data/ext/src/test/java/com/xnlogic/pacer/pipes/BlackboxPipelineTest.java +33 -0
  23. data/ext/src/test/java/com/xnlogic/pacer/pipes/CollectionFilterPipeTest.java +50 -0
  24. data/ext/src/test/java/com/xnlogic/pacer/pipes/EdgesPipeTest.java +103 -0
  25. data/ext/src/test/java/com/xnlogic/pacer/pipes/ExpandablePipeTest.java +66 -0
  26. data/ext/src/test/java/com/xnlogic/pacer/pipes/IdCollectionFilterPipeTest.java +85 -0
  27. data/ext/src/test/java/com/xnlogic/pacer/pipes/IsUniquePipeTest.java +62 -0
  28. data/ext/src/test/java/com/xnlogic/pacer/pipes/LabelCollectionFilterPipeTest.java +97 -0
  29. data/ext/src/test/java/com/xnlogic/pacer/pipes/LabelPrefixPipeTest.java +69 -0
  30. data/ext/src/test/java/com/xnlogic/pacer/pipes/NeverPipeTest.java +17 -0
  31. data/ext/src/test/java/com/xnlogic/pacer/pipes/VerticesPipeTest.java +97 -0
  32. data/lib/pacer/core/graph/element_route.rb +2 -2
  33. data/lib/pacer/core/graph/path_route.rb +2 -2
  34. data/lib/pacer/core/route.rb +77 -1
  35. data/lib/pacer/filter/property_filter/edge_filters.rb +5 -1
  36. data/lib/pacer/filter/property_filter/filters.rb +23 -7
  37. data/lib/pacer/pipe/path_wrapping_pipe.rb +14 -3
  38. data/lib/pacer/pipe/wrapping_pipe.rb +15 -4
  39. data/lib/pacer/pipes.rb +15 -13
  40. data/lib/pacer/route.rb +1 -0
  41. data/lib/pacer/side_effect/as_var.rb +1 -1
  42. data/lib/pacer/side_effect/is_unique.rb +2 -2
  43. data/lib/pacer/transform/branch.rb +1 -1
  44. data/lib/pacer/transform/lookup_ids.rb +1 -1
  45. data/lib/pacer/transform/path_tree.rb +1 -1
  46. data/lib/pacer/transform/reduce.rb +1 -1
  47. data/lib/pacer/transform/sort_section.rb +17 -9
  48. data/lib/pacer/transform/stream_sort.rb +1 -0
  49. data/lib/pacer/transform/stream_uniq.rb +1 -0
  50. data/lib/pacer/transform/wrapped_path.rb +1 -1
  51. data/lib/pacer/version.rb +1 -1
  52. data/lib/pacer/visitors/section.rb +10 -3
  53. data/lib/pacer/visitors/visits_section.rb +4 -4
  54. data/lib/pacer-ext.jar +0 -0
  55. data/lib/pacer.rb +1 -0
  56. data/pacer.gemspec +2 -1
  57. data/spec/pacer/filter/property_filter_spec.rb +17 -0
  58. data/spec/pacer/transform/path_spec.rb +10 -0
  59. data/spec/pacer/transform/sort_section_spec.rb +8 -1
  60. metadata +59 -30
  61. data/lib/pacer/pipe/blackbox_pipeline.rb +0 -55
  62. data/lib/pacer/pipe/collection_filter_pipe.rb +0 -12
  63. data/lib/pacer/pipe/edges_pipe.rb +0 -22
  64. data/lib/pacer/pipe/expandable_pipe.rb +0 -51
  65. data/lib/pacer/pipe/id_collection_filter_pipe.rb +0 -37
  66. data/lib/pacer/pipe/is_empty_pipe.rb +0 -23
  67. data/lib/pacer/pipe/is_unique_pipe.rb +0 -51
  68. data/lib/pacer/pipe/label_collection_filter_pipe.rb +0 -15
  69. data/lib/pacer/pipe/label_prefix_pipe.rb +0 -15
  70. data/lib/pacer/pipe/never_pipe.rb +0 -9
  71. data/lib/pacer/pipe/vertices_pipe.rb +0 -22
@@ -0,0 +1,97 @@
1
+ package com.xnlogic.pacer.pipes;
2
+
3
+ import static org.junit.Assert.*;
4
+ import org.junit.Test;
5
+ import org.junit.Before;
6
+ import org.junit.After;
7
+ import com.tinkerpop.blueprints.impls.tg.TinkerGraph;
8
+ import com.tinkerpop.blueprints.Graph;
9
+ import com.tinkerpop.blueprints.Vertex;
10
+ import java.util.Collection;
11
+ import java.util.Arrays;
12
+ import java.util.ArrayList;
13
+ import com.xnlogic.pacer.pipes.VerticesPipe;
14
+
15
+ public class VerticesPipeTest {
16
+ private TinkerGraph graph = null;
17
+ private Collection<Graph> graphs;
18
+ private Collection<Vertex> verticesThatCount;
19
+
20
+ @Before
21
+ public void setup() throws Exception {
22
+ this.graph = new TinkerGraph();
23
+ this.graphs = Arrays.asList((Graph)this.graph);
24
+ }
25
+
26
+ private void createVertices() {
27
+ Vertex v1 = this.graph.addVertex(1);
28
+ Vertex v2 = this.graph.addVertex(2);
29
+ Vertex v3 = this.graph.addVertex(3);
30
+
31
+ this.verticesThatCount = Arrays.asList(v1, v2, v3);
32
+ }
33
+
34
+ @After
35
+ public void teardown() throws Exception {
36
+ this.graph.shutdown();
37
+ this.graph = null;
38
+ }
39
+
40
+ @Test
41
+ public void getVerticesFromGraphTest() {
42
+ this.createVertices();
43
+
44
+ VerticesPipe verticesPipe = new VerticesPipe();
45
+ verticesPipe.setStarts(this.graphs);
46
+
47
+ Collection<Vertex> vertices = new ArrayList<Vertex>();
48
+
49
+ while (verticesPipe.hasNext()) {
50
+ vertices.add(verticesPipe.next());
51
+ }
52
+
53
+ assertEquals(3, vertices.size());
54
+ assertTrue(vertices.containsAll(this.verticesThatCount));
55
+ }
56
+
57
+ @Test
58
+ public void getVerticesFromGraphAfterResetTest() {
59
+ this.createVertices();
60
+
61
+ VerticesPipe verticesPipe = new VerticesPipe();
62
+ verticesPipe.setStarts(this.graphs);
63
+
64
+ Collection<Vertex> vertices = new ArrayList<Vertex>();
65
+
66
+ while (verticesPipe.hasNext()) {
67
+ vertices.add(verticesPipe.next());
68
+ }
69
+
70
+ assertEquals(3, vertices.size());
71
+ assertTrue(vertices.containsAll(this.verticesThatCount));
72
+
73
+ verticesPipe.reset();
74
+ vertices.clear();
75
+
76
+ while (verticesPipe.hasNext()) {
77
+ vertices.add(verticesPipe.next());
78
+ }
79
+
80
+ assertEquals(3, vertices.size());
81
+ assertTrue(vertices.containsAll(this.verticesThatCount));
82
+ }
83
+
84
+ @Test
85
+ public void getNoVerticesFromGraphTest() {
86
+ VerticesPipe verticesPipe = new VerticesPipe();
87
+ verticesPipe.setStarts(this.graphs);
88
+
89
+ Collection<Vertex> vertices = new ArrayList<Vertex>();
90
+
91
+ while (verticesPipe.hasNext()) {
92
+ vertices.add(verticesPipe.next());
93
+ }
94
+
95
+ assertEquals(0, vertices.size());
96
+ }
97
+ }
@@ -166,8 +166,8 @@ module Pacer::Core::Graph
166
166
 
167
167
  protected
168
168
 
169
- def configure_iterator(iter)
170
- pipe = Pacer::Pipes::WrappingPipe.new graph, element_type, extensions
169
+ def configure_iterator(iter = nil, g = nil)
170
+ pipe = Pacer::Pipes::WrappingPipe.new((g || graph), element_type, extensions)
171
171
  pipe.wrapper = wrapper if wrapper
172
172
  pipe.setStarts iter
173
173
  pipe
@@ -96,9 +96,9 @@ HELP
96
96
  end
97
97
  protected
98
98
 
99
- def configure_iterator(iter)
99
+ def configure_iterator(iter = nil, g = nil)
100
100
  if respond_to? :graph
101
- pipe = Pacer::Pipes::PathWrappingPipe.new(graph)
101
+ pipe = Pacer::Pipes::PathWrappingPipe.new(g || graph)
102
102
  pipe.setStarts iter
103
103
  pipe
104
104
  else
@@ -380,6 +380,25 @@ HELP
380
380
  chain_route(:extensions => [], :wrapper => nil)
381
381
  end
382
382
 
383
+ # Returns an outer proc that returns an inner proc that will execute the given route for a given input data or element.
384
+ #
385
+ # The outer proc contains the already-compiled route (the most expensive part of the process). When you call it, it returns
386
+ # the inner proc. If you call it with no arguments, it will prepare the proc in the context of the original route used to create
387
+ # it. In a multi-tenant or multi-graph system, call the outer proc with the current graph to prepare so that it correctly wraps
388
+ # returned elements.
389
+ #
390
+ # The inner proc contains a non-thread-safe data pipeline compiled from the route. Call it with an item of input data for the detached
391
+ # pipe and it will execute the pipeline for that piece of data and return the result or results.
392
+ #
393
+ # A detached route can be configured with or without gather enabled. If enabled (default), the result will be an ArrayList of
394
+ # all result data produced by the detached route. If not, the result will be either the first thing produced by the route or null if
395
+ # nothing was produced.
396
+ def detach
397
+ route = yield Pacer::Route.empty(self)
398
+ DetachedRoute.new route
399
+ end
400
+
401
+
383
402
  # Change the source of this route.
384
403
  #
385
404
  # @note all routes derived from any route in the chain will be
@@ -421,7 +440,7 @@ HELP
421
440
 
422
441
  # Overridden to extend the iterator to apply mixins
423
442
  # or wrap elements
424
- def configure_iterator(iter)
443
+ def configure_iterator(iter = nil, g = nil)
425
444
  iter
426
445
  end
427
446
 
@@ -617,6 +636,63 @@ HELP
617
636
  end
618
637
  end
619
638
 
639
+
640
+ class DetachedRoute
641
+ attr_reader :route, :preconfig
642
+
643
+ def initialize(route)
644
+ @route = route
645
+ w = route.send(:configure_iterator)
646
+ if w.respond_to? :instance
647
+ @preconfig = w
648
+ end
649
+ end
650
+
651
+ def build(graph, gather = true)
652
+ if route.is_a? Pacer::Filter::EmptyFilter
653
+ pipe = Pacer::Pipes::IdentityPipe.new
654
+ else
655
+ pipe = Pacer::Route.pipeline route
656
+ end
657
+ expando = Pacer::Pipes::ExpandablePipe.new
658
+ expando.enablePath true
659
+ expando.setStarts(Pacer::Pipes::EmptyIterator::INSTANCE)
660
+ pipe.setStarts expando
661
+ if preconfig
662
+ pipe = preconfig.instance pipe, graph
663
+ else
664
+ pipe = route.send(:configure_iterator, pipe, graph)
665
+ end
666
+ pipe = yield pipe if block_given?
667
+ if gather
668
+ g = Pacer::Pipes::GatherPipe.new
669
+ g.setStarts pipe
670
+ DetachedPipe.new(expando, g, true)
671
+ else
672
+ DetachedPipe.new(expando, pipe, false)
673
+ end
674
+ end
675
+ end
676
+
677
+ class DetachedPipe
678
+ attr_reader :expando, :pipe, :collection
679
+
680
+ def initialize(expando, pipe, collection)
681
+ @expando = expando
682
+ @pipe = pipe
683
+ @collection = collection
684
+ end
685
+
686
+ def read(element)
687
+ pipe.reset unless collection
688
+ expando.add element
689
+ if pipe.hasNext
690
+ pipe.next
691
+ elsif collection
692
+ []
693
+ end
694
+ end
695
+ end
620
696
  end
621
697
  end
622
698
  end
@@ -31,7 +31,7 @@ module Pacer
31
31
  def build_pipeline(route, start_pipe = nil, pipe = nil)
32
32
  pipe ||= start_pipe
33
33
  if labels.any?
34
- label_pipe = Pacer::Pipes::LabelCollectionFilterPipe.new labels
34
+ label_pipe = Pacer::Pipes::LabelCollectionFilterPipe.new labels.map(&:to_s)
35
35
  label_pipe.set_starts pipe if pipe
36
36
  Pacer.debug_pipes << { :name => labels.inspect, :start => pipe, :end => block_pipe } if Pacer.debug_pipes
37
37
  pipe = label_pipe
@@ -44,6 +44,10 @@ module Pacer
44
44
  labels.any? or super
45
45
  end
46
46
 
47
+ def extensions_only?
48
+ labels.empty? and super
49
+ end
50
+
47
51
  def to_s
48
52
  if labels.any?
49
53
  [labels.map { |l| l.to_sym.inspect }.join(', '), super].reject { |s| s == '' }.join ', '
@@ -134,15 +134,30 @@ module Pacer
134
134
  end
135
135
  end
136
136
 
137
+ # Not used for regular filtering, but useful to test an element against
138
+ # a complex set of conditions without having to build a route.
139
+ #
140
+ # Returns a proc that can be called with an element to test and returns
141
+ # true if the element matches the conditions.
142
+ def to_predicate
143
+ expando, pipe = build_pipeline(nil, com.tinkerpop.pipes.util.iterators.ExpandableIterator.new)
144
+ proc do |e|
145
+ expando.add e
146
+ pipe.next if pipe.hasNext
147
+ end
148
+ end
149
+
137
150
  def build_pipeline(route, start_pipe, pipe = nil)
138
- self.graph = route.graph
139
151
  pipe ||= start_pipe
140
- route_modules.each do |mod|
141
- extension_route = mod.route(Pacer::Route.empty(route))
142
- s, e = extension_route.send :build_pipeline
143
- s.setStarts(pipe) if pipe
144
- start_pipe ||= s
145
- pipe = e
152
+ if route
153
+ self.graph = route.graph
154
+ route_modules.each do |mod|
155
+ extension_route = mod.route(Pacer::Route.empty(route))
156
+ s, e = extension_route.send :build_pipeline
157
+ s.setStarts(pipe) if pipe
158
+ start_pipe ||= s
159
+ pipe = e
160
+ end
146
161
  end
147
162
  encoded_properties.each do |key, value|
148
163
  case value
@@ -161,6 +176,7 @@ module Pacer
161
176
  end
162
177
  end
163
178
  blocks.each do |block|
179
+ # Will work if route is nil.
164
180
  block_pipe = Pacer::Pipes::BlockFilterPipe.new(route, block)
165
181
  block_pipe.set_starts pipe if pipe
166
182
  Pacer.debug_pipes << { :name => 'block', :start => pipe, :end => block_pipe } if Pacer.debug_pipes
@@ -6,9 +6,20 @@ module Pacer
6
6
 
7
7
  def initialize(graph, vertex_extensions = [], edge_extensions = [])
8
8
  super()
9
- @graph = graph
10
- @vertex_wrapper = Pacer::Wrappers::WrapperSelector.build graph, :vertex, vertex_extensions || Set[]
11
- @edge_wrapper = Pacer::Wrappers::WrapperSelector.build graph, :edge, edge_extensions || Set[]
9
+ if graph.is_a? Array
10
+ @graph, @vertex_wrapper, @edge_wrapper = graph
11
+ else
12
+ @graph = graph
13
+ @vertex_wrapper = Pacer::Wrappers::WrapperSelector.build graph, :vertex, vertex_extensions || Set[]
14
+ @edge_wrapper = Pacer::Wrappers::WrapperSelector.build graph, :edge, edge_extensions || Set[]
15
+ end
16
+ end
17
+
18
+ def instance(pipe, g)
19
+ g ||= graph
20
+ p = PathWrappingPipe.new [g, vertex_wrapper, edge_wrapper]
21
+ p.setStarts pipe
22
+ p
12
23
  end
13
24
 
14
25
  def getCurrentPath
@@ -5,10 +5,21 @@ module Pacer
5
5
 
6
6
  def initialize(graph, element_type = nil, extensions = [])
7
7
  super()
8
- @graph = graph
9
- @element_type = element_type
10
- @extensions = extensions || []
11
- @wrapper = Pacer::Wrappers::WrapperSelector.build graph, element_type, @extensions
8
+ if graph.is_a? Array
9
+ @graph, @wrapper = graph
10
+ else
11
+ @graph = graph
12
+ @element_type = element_type
13
+ @extensions = extensions || []
14
+ @wrapper = Pacer::Wrappers::WrapperSelector.build graph, element_type, @extensions
15
+ end
16
+ end
17
+
18
+ def instance(pipe, g)
19
+ g ||= graph
20
+ p = WrappingPipe.new [g, wrapper]
21
+ p.setStarts pipe
22
+ p
12
23
  end
13
24
 
14
25
  def getSideEffect
data/lib/pacer/pipes.rb CHANGED
@@ -15,6 +15,21 @@ module Pacer
15
15
  import com.tinkerpop.pipes.transform.PropertyPipe
16
16
  import com.tinkerpop.pipes.transform.PropertyMapPipe
17
17
 
18
+ import com.xnlogic.pacer.pipes.BlackboxPipeline
19
+ import com.xnlogic.pacer.pipes.EdgesPipe
20
+ import com.xnlogic.pacer.pipes.CollectionFilterPipe
21
+ import com.xnlogic.pacer.pipes.ExpandablePipe
22
+ SimpleExpandablePipe = com.tinkerpop.pipes.util.ExpandablePipe
23
+ import com.xnlogic.pacer.pipes.IdCollectionFilterPipe
24
+ import com.xnlogic.pacer.pipes.IsEmptyPipe
25
+ import com.xnlogic.pacer.pipes.LabelCollectionFilterPipe
26
+ import com.xnlogic.pacer.pipes.IsUniquePipe
27
+ import com.xnlogic.pacer.pipes.VerticesPipe
28
+ import com.xnlogic.pacer.pipes.LabelPrefixPipe
29
+ import com.xnlogic.pacer.pipes.NeverPipe
30
+ import com.tinkerpop.pipes.util.iterators.EmptyIterator
31
+ import com.tinkerpop.pipes.transform.GatherPipe
32
+
18
33
  IN = com.tinkerpop.blueprints.Direction::IN
19
34
  OUT = com.tinkerpop.blueprints.Direction::OUT
20
35
  BOTH = com.tinkerpop.blueprints.Direction::BOTH
@@ -33,32 +48,19 @@ end
33
48
 
34
49
  require 'pacer/pipe/ruby_pipe'
35
50
 
36
- require 'pacer/pipe/vertices_pipe'
37
- require 'pacer/pipe/edges_pipe'
38
-
39
- require 'pacer/pipe/never_pipe'
40
51
  require 'pacer/pipe/multi_pipe'
41
52
  require 'pacer/pipe/block_filter_pipe'
42
- require 'pacer/pipe/collection_filter_pipe'
43
53
  require 'pacer/pipe/enumerable_pipe'
44
- require 'pacer/pipe/expandable_pipe'
45
54
  require 'pacer/pipe/loop_pipe'
46
55
  require 'pacer/pipe/process_pipe'
47
56
  require 'pacer/pipe/visitor_pipe'
48
57
  require 'pacer/pipe/simple_visitor_pipe'
49
- require 'pacer/pipe/is_unique_pipe'
50
- require 'pacer/pipe/is_empty_pipe'
51
58
  require 'pacer/pipe/stream_sort_pipe'
52
59
  require 'pacer/pipe/stream_uniq_pipe'
53
60
  require 'pacer/pipe/type_filter_pipe'
54
- require 'pacer/pipe/label_collection_filter_pipe'
55
- require 'pacer/pipe/id_collection_filter_pipe'
56
- require 'pacer/pipe/label_prefix_pipe'
57
61
 
58
62
  require 'pacer/pipe/property_comparison_pipe'
59
63
 
60
- require 'pacer/pipe/blackbox_pipeline'
61
-
62
64
  require 'pacer/pipe/unary_transform_pipe'
63
65
  require 'pacer/pipe/cross_product_transform_pipe'
64
66
 
data/lib/pacer/route.rb CHANGED
@@ -18,6 +18,7 @@ module Pacer
18
18
  # @return [Pacer::Pipes::BlackboxPipeline] an instantiated pipeline
19
19
  def pipeline(route)
20
20
  s, e = route.send(:build_pipeline)
21
+ e = yield e if block_given?
21
22
  if s.equal?(e)
22
23
  s
23
24
  else
@@ -44,7 +44,7 @@ module Pacer
44
44
  def attach_pipe(pipe)
45
45
  if element_type == :vertex or element_type == :edge or element_type == :mixed
46
46
  wrapped = Pacer::Pipes::WrappingPipe.new graph, element_type, extensions
47
- wrapped.setStarts pipe
47
+ wrapped.setStarts pipe if pipe
48
48
  as_pipe = AsPipe.new(wrapped, vars, variable_name)
49
49
  unwrapped = Pacer::Pipes::UnwrappingPipe.new
50
50
  unwrapped.setStarts as_pipe
@@ -14,7 +14,7 @@ module Pacer
14
14
  def unique?
15
15
  check = nil
16
16
  is_unique { |pipe| check = pipe }.each do
17
- return false unless check.unique?
17
+ return false unless check.isUnique
18
18
  end
19
19
  true
20
20
  end
@@ -30,7 +30,7 @@ module Pacer
30
30
 
31
31
  def attach_pipe(end_pipe)
32
32
  checked = Pacer::Pipes::IsUniquePipe.new
33
- checked.setStarts end_pipe
33
+ checked.setStarts end_pipe if end_pipe
34
34
  on_build_pipe.call checked if on_build_pipe
35
35
  checked
36
36
  end
@@ -44,7 +44,7 @@ module Pacer
44
44
  def clone(conf = {})
45
45
  back.chain_route({transform: Branch,
46
46
  branches: branches.clone,
47
- element_type: back.element_type,
47
+ element_type: element_type,
48
48
  conds: conds.clone,
49
49
  extensions: extensions.clone,
50
50
  split_pipe_class: split_pipe_class,
@@ -28,7 +28,7 @@ module Pacer
28
28
  else
29
29
  fail ClientError, 'Can not look up elements without the element_type'
30
30
  end
31
- pipe.setStarts end_pipe
31
+ pipe.setStarts end_pipe if end_pipe
32
32
  pipe
33
33
  end
34
34
  end
@@ -29,7 +29,7 @@ module Pacer
29
29
 
30
30
  def attach_pipe(end_pipe)
31
31
  pipe = PathTreePipe.new compare
32
- pipe.setStarts end_pipe
32
+ pipe.setStarts end_pipe if end_pipe
33
33
  pipe
34
34
  end
35
35
 
@@ -86,7 +86,7 @@ HELP
86
86
  def attach_pipe(end_pipe)
87
87
  if @enter and @reduce and @leave
88
88
  pipe = ReducerPipe.new self, @enter, @reduce, @leave
89
- pipe.setStarts end_pipe
89
+ pipe.setStarts end_pipe if end_pipe
90
90
  pipe
91
91
  else
92
92
  fail Pacer::ClientError, 'enter, reduce, and leave must all be specified for reducers'
@@ -1,10 +1,18 @@
1
1
  module Pacer
2
2
  module Routes
3
3
  module RouteOperations
4
+ # Arity 2 uses custom sort logic. Arity 1 uses sort_by logic.
4
5
  def sort_section(section = nil, &block)
5
- chain_route transform: :sort_section, sort_by_block: block, section: section
6
+ if not block
7
+ chain_route transform: :sort_section, section: section
8
+ elsif block.arity == 2
9
+ chain_route transform: :sort_section, custom_sort_block: block, section: section
10
+ else
11
+ chain_route transform: :sort_section, sort_by_block: block, section: section
12
+ end
6
13
  end
7
14
 
15
+ # Deprecated: use sort_section
8
16
  def custom_sort_section(section = nil, &block)
9
17
  chain_route transform: :sort_section, custom_sort_block: block, section: section
10
18
  end
@@ -40,27 +48,27 @@ module Pacer
40
48
  attr_reader :pf_1, :pf_2, :to_sort, :to_emit, :section, :route
41
49
  attr_reader :getPathToHere
42
50
 
43
- def initialize(route, section, pipe_function)
51
+ def initialize(route, visitor_pipe, pipe_function)
44
52
  super()
45
53
  @to_emit = []
46
- @section = section
54
+ @visitor_pipe = visitor_pipe
47
55
  @route = route
48
56
  @to_sort = []
49
57
  @paths = []
50
- if section
51
- section.visitor = self
58
+ if visitor_pipe
59
+ visitor_pipe.visitor = self
52
60
  else
53
61
  on_element nil
54
62
  end
55
63
  if pipe_function
56
64
  if pipe_function.arity == 1
57
65
  @pf_1 = pipe_function
58
- section.use_on_element = false
66
+ visitor_pipe.use_on_element = false
59
67
  else
60
68
  @pf_2 = pipe_function
61
69
  end
62
70
  else
63
- section.use_on_element = false
71
+ visitor_pipe.use_on_element = false
64
72
  end
65
73
  end
66
74
 
@@ -119,8 +127,8 @@ module Pacer
119
127
  class CustomSortPipe < SortBySectionPipe
120
128
  attr_reader :sort_block
121
129
 
122
- def initialize(route, section, sort_block, graph, wrapper)
123
- super route, section, nil
130
+ def initialize(route, visitor_pipe, sort_block, graph, wrapper)
131
+ super route, visitor_pipe, nil
124
132
  @sort_block = sort_block
125
133
  @graph = graph
126
134
  @wrapper = wrapper
@@ -1,5 +1,6 @@
1
1
  module Pacer
2
2
  module Routes::RouteOperations
3
+ # Deprecated: use sort_section instead.
3
4
  def stream_sort(buffer = 1000, silo = 100)
4
5
  chain_route :transform => :stream_sort, :buffer => buffer, :silo => silo
5
6
  end
@@ -1,5 +1,6 @@
1
1
  module Pacer
2
2
  module Routes::RouteOperations
3
+ # Deprecated: use uniq_section instead.
3
4
  def stream_uniq(buffer = 1000)
4
5
  chain_route :transform => :stream_uniq, :buffer => buffer
5
6
  end
@@ -15,7 +15,7 @@ module Pacer
15
15
 
16
16
  def attach_pipe(end_pipe)
17
17
  pipe = Pacer::Pipes::PathWrappingPipe.new(graph)
18
- pipe.setStarts end_pipe
18
+ pipe.setStarts end_pipe if end_pipe
19
19
  pipe
20
20
  end
21
21
  end
data/lib/pacer/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Pacer
2
- VERSION = "2.0.10.pre"
2
+ VERSION = "2.0.12"
3
3
  # Clients may optionally define the following constants in the Pacer namespace:
4
4
  # - LOAD_JARS : set to false to manage jar loading in the client. Be sure to load the jars defined in JARFILES.
5
5
  # - LOCKJAR_LOCK_OPTS : set some options to be passed to LockJar.lock (ie. :lockfile, :download_artifacts, :local_repo)
@@ -18,10 +18,14 @@ module Pacer
18
18
 
19
19
  def will_visit!
20
20
  @visitor_count = visitor_count + 1
21
+ visitor_count - 1
21
22
  end
22
23
 
23
- def section_visitor
24
- section_visitors.pop
24
+ def section_visitor!(visitor_num)
25
+ vpipes = Thread.current["visitors_#{object_id}"]
26
+ vpipe = vpipes[visitor_num]
27
+ vpipes[visitor_num] = nil
28
+ vpipe
25
29
  end
26
30
 
27
31
  protected
@@ -34,12 +38,15 @@ module Pacer
34
38
  attr_reader :section_visitors
35
39
 
36
40
  def attach_pipe(end_pipe)
41
+ # With detached pipes, pipe construction happens in
42
+ # multiple threads, multiple times.
37
43
  pipe = end_pipe
38
- @section_visitors = (1..visitor_count).map do
44
+ vpipes = (1..visitor_count).map do
39
45
  pipe = Pacer::Pipes::SimpleVisitorPipe.new Pacer::Wrappers::WrapperSelector.build(graph, element_type, extensions), graph
40
46
  pipe.setStarts end_pipe if end_pipe
41
47
  end_pipe = pipe
42
48
  end
49
+ Thread.current["visitors_#{object_id}"] = vpipes
43
50
  pipe
44
51
  end
45
52
 
@@ -2,7 +2,7 @@ module Pacer
2
2
  module Visitors
3
3
  # This module is mixed in to the route that actually refers to this section.
4
4
  module VisitsSection
5
- attr_reader :section, :section_route
5
+ attr_reader :section, :section_route, :visitor_num
6
6
 
7
7
  def section=(section)
8
8
  if section.is_a? Symbol
@@ -14,14 +14,14 @@ module Pacer
14
14
  else
15
15
  raise ArgumentError, "Unknown section #{ section }. Provide either a name or a route created with the #section methed."
16
16
  end
17
- @section_route.will_visit!
18
- @section_route
17
+ @visitor_num = section_route.will_visit!
18
+ section_route
19
19
  end
20
20
 
21
21
  protected
22
22
 
23
23
  def section_visitor
24
- section_route.section_visitor if section_route
24
+ section_route.section_visitor!(visitor_num) if visitor_num
25
25
  end
26
26
 
27
27
  def section_visitor_target
data/lib/pacer-ext.jar ADDED
Binary file
data/lib/pacer.rb CHANGED
@@ -23,6 +23,7 @@ require 'pp'
23
23
  require 'rubygems'
24
24
  require 'lock_jar'
25
25
  require 'pacer/support/lock_jar'
26
+ require 'pacer-ext.jar'
26
27
 
27
28
  if (not defined? Pacer::LOAD_JARS) or Pacer::LOAD_JARS == true
28
29
  bundle_jarfiles = LockJar.register_bundled_jarfiles # defined in pacer/support/lock_jar.rb
data/pacer.gemspec CHANGED
@@ -13,10 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.summary = %Q{A very efficient and easy to use graph traversal engine.}
14
14
  s.description = %Q{Pacer defines composeable routes through a graph and then traverses them very quickly.}
15
15
 
16
- s.files = `git ls-files`.split("\n")
16
+ s.files = `git ls-files`.split("\n") + ['lib/pacer-ext.jar']
17
17
  s.test_files = `git ls-files -- spec/*`.split("\n")
18
18
  s.require_paths = ['lib']
19
19
  s.add_dependency "lock_jar", "~> 0.10.2"
20
20
  s.add_development_dependency 'xn_gem_release_tasks'
21
+ s.add_development_dependency "rake-compiler", "~> 0.9.2"
21
22
  end
22
23