zk-eventmachine 0.2.0.beta.1 → 0.2.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
data/.dev_extras/rvmrc CHANGED
@@ -1 +1 @@
1
- rvm 1.9.2@zk-em
1
+ rvm 1.9.2@zk-em --create
@@ -29,6 +29,9 @@ module ZK
29
29
  def connect(&blk)
30
30
  # XXX: maybe move this into initialize, need to figure out how to schedule it properly
31
31
  @cnx ||= ZookeeperEM::Client.new(@host, DEFAULT_TIMEOUT, event_handler.get_default_watcher_block)
32
+ # @cnx.on_attached do
33
+ # $stderr.puts "@cnx, obj_id: %x" % [@cnx.object_id]
34
+ # end
32
35
  @cnx.on_attached(&blk)
33
36
  end
34
37
 
@@ -63,8 +66,11 @@ module ZK
63
66
 
64
67
  logger.debug { "#{self.class.name}: calling @cnx.close" }
65
68
  @cnx.close do
66
- logger.debug { "firing on_close handler" }
67
- on_close.succeed
69
+ # fire the on_close handler in next_tick so that @cnx is nil
70
+ EM.next_tick do
71
+ logger.debug { "firing on_close handler" }
72
+ on_close.succeed
73
+ end
68
74
  @cnx = nil
69
75
  end
70
76
  else
@@ -144,6 +150,16 @@ module ZK
144
150
  end
145
151
  end
146
152
 
153
+ # returns an EM::Synchrony compatible wrapper around this client
154
+ def to_synchrony
155
+ @synchrony_client ||= SynchronyClient.new(self)
156
+ end
157
+
158
+ # returns self
159
+ def to_async
160
+ self
161
+ end
162
+
147
163
  protected
148
164
  def connection_lost_hook(exc)
149
165
  if exc and exc.kind_of?(ZK::Exceptions::ConnectionLoss)
@@ -58,7 +58,7 @@ module ZK
58
58
  @event_handler = SynchronyEventHandlerWrapper.new(@client.event_handler)
59
59
  end
60
60
 
61
- %w[connect close close! get set create stat delete children get_acl set_acl mkdir_p rm_rf].each do |meth|
61
+ %w[connect get set create stat delete children get_acl set_acl mkdir_p rm_rf].each do |meth|
62
62
  class_eval(<<-EOMETH, __FILE__, __LINE__ + 1)
63
63
  def #{meth}(*args,&blk)
64
64
  sync!(@client.#{meth}(*args, &blk))
@@ -66,6 +66,18 @@ module ZK
66
66
  EOMETH
67
67
  end
68
68
 
69
+ # it is *crucially* important that close and close! be wrapped in a fiber.
70
+ # it's possible under very odd corner cases with the 1.9.3 GC to cause a
71
+ # '[BUG] cfp consistency error - send'
72
+ #
73
+ %w[close close!].each do |meth|
74
+ class_eval(<<-EOMETH, __FILE__, __LINE__ + 1)
75
+ def #{meth}(*args,&blk)
76
+ Fiber.new { sync!(@client.#{meth}(*args, &blk)) }.resume
77
+ end
78
+ EOMETH
79
+ end
80
+
69
81
  # @deprecated for backwards compatibility only
70
82
  def watcher
71
83
  event_handler
@@ -75,6 +87,16 @@ module ZK
75
87
  stat(path, opts={}).exists?
76
88
  end
77
89
 
90
+ # returns self
91
+ def to_synchrony
92
+ self
93
+ end
94
+
95
+ # returns the wrapped async client
96
+ def to_async
97
+ @client
98
+ end
99
+
78
100
  protected
79
101
  # a modification of EM::Synchrony.sync to handle multiple callback arguments properly
80
102
  def sync(df)
@@ -3,7 +3,7 @@ module ZK
3
3
  module Unixisms
4
4
  def mkdir_p(paths, &block)
5
5
  dfr = Deferred::Default.new.tap do |my_dfr|
6
- Iterator.new(Array(paths).flatten.compact, 1).map(
6
+ EM::Iterator.new(Array(paths).flatten.compact, 1).map(
7
7
  lambda { |path,iter| # foreach
8
8
  d = _mkdir_p_dfr(path)
9
9
  d.callback { |p| iter.return(p) }
@@ -18,7 +18,7 @@ module ZK
18
18
 
19
19
  def rm_rf(paths, &blk)
20
20
  dfr = Deferred::Default.new.tap do |my_dfr|
21
- Iterator.new(Array(paths).flatten.compact, 1).each(
21
+ EM::Iterator.new(Array(paths).flatten.compact, 1).each(
22
22
  lambda { |path,iter| # foreach
23
23
  d = _rm_rf_dfr(path)
24
24
  d.callback { iter.next }
@@ -60,7 +60,7 @@ module ZK
60
60
  my_dfr.succeed
61
61
  when nil
62
62
  abspaths = chldrn.map { |n| [path, n].join('/') }
63
- Iterator.new(abspaths).each(
63
+ EM::Iterator.new(abspaths).each(
64
64
  lambda { |absp,iter|
65
65
  d = _rm_rf_dfr(absp)
66
66
  d.callback { |*|
@@ -1,5 +1,5 @@
1
1
  module ZK
2
2
  module ZKEventMachine
3
- VERSION = "0.2.0.beta.1"
3
+ VERSION = "0.2.0.beta.2"
4
4
  end
5
5
  end
@@ -6,7 +6,6 @@ require 'zookeeper/em_client'
6
6
 
7
7
  require 'zk'
8
8
 
9
-
10
9
  module ZK
11
10
  module ZKEventMachine
12
11
  end
@@ -15,7 +14,6 @@ end
15
14
 
16
15
  $LOAD_PATH.unshift(File.expand_path('../..', __FILE__)).uniq!
17
16
 
18
- require 'z_k/z_k_event_machine/iterator'
19
17
  require 'z_k/z_k_event_machine/deferred'
20
18
  require 'z_k/z_k_event_machine/callback'
21
19
  require 'z_k/z_k_event_machine/event_handler_e_m'
@@ -29,7 +29,8 @@ module ZK
29
29
  @base_path = '/zk-em-testing'
30
30
  @zk.rm_rf(@base_path)
31
31
  @zk.mkdir_p(@base_path)
32
- @zksync = ZK::ZKEventMachine::SynchronyClient.new('localhost:2181')
32
+ # $stderr.puts "zk obj_id: %x" % [@zk.object_id]
33
+ @zksync = ZK::ZKEventMachine::SynchronyClient.new('localhost:2181', :zkc_log_level => 4)
33
34
  end
34
35
 
35
36
  after do
@@ -324,6 +325,8 @@ module ZK
324
325
  @zksync.event_handler.register(@new_path) do |event|
325
326
  logger.debug { "got event #{event}" }
326
327
 
328
+ # without close! wrapping itself in Fiber.new, this causes a
329
+ # '[BUG] cfp consistency error - send' under 1.9.3
327
330
  done { @zksync.close! }
328
331
  end
329
332
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zk-eventmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.beta.1
4
+ version: 0.2.0.beta.2
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-01 00:00:00.000000000Z
12
+ date: 2011-11-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: zk
16
- requirement: &2169005720 !ruby/object:Gem::Requirement
16
+ requirement: &2156053200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.8.5
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2169005720
24
+ version_requirements: *2156053200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: slyphon-zookeeper
27
- requirement: &2169005220 !ruby/object:Gem::Requirement
27
+ requirement: &2156052080 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.2.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2169005220
35
+ version_requirements: *2156052080
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: eventmachine
38
- requirement: &2169004760 !ruby/object:Gem::Requirement
38
+ requirement: &2156051200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.0.beta.3
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2169004760
46
+ version_requirements: *2156051200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: em-synchrony
49
- requirement: &2169004260 !ruby/object:Gem::Requirement
49
+ requirement: &2156050280 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *2169004260
57
+ version_requirements: *2156050280
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rspec
60
- requirement: &2169003800 !ruby/object:Gem::Requirement
60
+ requirement: &2156049400 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 2.5.0
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2169003800
68
+ version_requirements: *2156049400
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yard
71
- requirement: &2169003260 !ruby/object:Gem::Requirement
71
+ requirement: &2156048620 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.7.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2169003260
79
+ version_requirements: *2156048620
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: autotest
82
- requirement: &2169002720 !ruby/object:Gem::Requirement
82
+ requirement: &2156047400 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 4.4.0
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2169002720
90
+ version_requirements: *2156047400
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: flexmock
93
- requirement: &2169002220 !ruby/object:Gem::Requirement
93
+ requirement: &2156046380 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 0.8.10
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *2169002220
101
+ version_requirements: *2156046380
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: evented-spec
104
- requirement: &2169001680 !ruby/object:Gem::Requirement
104
+ requirement: &2156045160 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ~>
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: 0.4.1
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *2169001680
112
+ version_requirements: *2156045160
113
113
  description: ''
114
114
  email:
115
115
  - slyphon@hp.com
@@ -131,7 +131,6 @@ files:
131
131
  - lib/z_k/z_k_event_machine/client.rb
132
132
  - lib/z_k/z_k_event_machine/deferred.rb
133
133
  - lib/z_k/z_k_event_machine/event_handler_e_m.rb
134
- - lib/z_k/z_k_event_machine/iterator.rb
135
134
  - lib/z_k/z_k_event_machine/synchrony_client.rb
136
135
  - lib/z_k/z_k_event_machine/unixisms.rb
137
136
  - lib/z_k/z_k_event_machine/version.rb
@@ -1,229 +0,0 @@
1
- # Taken from EventMachine release candidate
2
- module ZK
3
- module ZKEventMachine
4
- # A simple iterator for concurrent asynchronous work.
5
- #
6
- # Unlike ruby's built-in iterators, the end of the current iteration cycle is signaled manually,
7
- # instead of happening automatically after the yielded block finishes executing. For example:
8
- #
9
- # (0..10).each{ |num| }
10
- #
11
- # becomes:
12
- #
13
- # EM::Iterator.new(0..10).each{ |num,iter| iter.next }
14
- #
15
- # This is especially useful when doing asynchronous work via reactor libraries and
16
- # functions. For example, given a sync and async http api:
17
- #
18
- # response = sync_http_get(url); ...
19
- # async_http_get(url){ |response| ... }
20
- #
21
- # a synchronous iterator such as:
22
- #
23
- # responses = urls.map{ |url| sync_http_get(url) }
24
- # ...
25
- # puts 'all done!'
26
- #
27
- # could be written as:
28
- #
29
- # EM::Iterator.new(urls).map(proc{ |url,iter|
30
- # async_http_get(url){ |res|
31
- # iter.return(res)
32
- # }
33
- # }, proc{ |responses|
34
- # ...
35
- # puts 'all done!'
36
- # })
37
- #
38
- # Now, you can take advantage of the asynchronous api to issue requests in parallel. For example,
39
- # to fetch 10 urls at a time, simply pass in a concurrency of 10:
40
- #
41
- # EM::Iterator.new(urls, 10).each do |url,iter|
42
- # async_http_get(url){ iter.next }
43
- # end
44
- #
45
- class Iterator
46
- # Create a new parallel async iterator with specified concurrency.
47
- #
48
- # i = EM::Iterator.new(1..100, 10)
49
- #
50
- # will create an iterator over the range that processes 10 items at a time. Iteration
51
- # is started via #each, #map or #inject
52
- #
53
- def initialize(list, concurrency = 1)
54
- raise ArgumentError, 'argument must be an array' unless list.respond_to?(:to_a)
55
- @list = list.to_a.dup
56
- @concurrency = concurrency
57
-
58
- @started = false
59
- @ended = false
60
- end
61
-
62
- # Change the concurrency of this iterator. Workers will automatically be spawned or destroyed
63
- # to accomodate the new concurrency level.
64
- #
65
- def concurrency=(val)
66
- old = @concurrency
67
- @concurrency = val
68
-
69
- spawn_workers if val > old and @started and !@ended
70
- end
71
- attr_reader :concurrency
72
-
73
- # Iterate over a set of items using the specified block or proc.
74
- #
75
- # EM::Iterator.new(1..100).each do |num, iter|
76
- # puts num
77
- # iter.next
78
- # end
79
- #
80
- # An optional second proc is invoked after the iteration is complete.
81
- #
82
- # EM::Iterator.new(1..100).each(
83
- # proc{ |num,iter| iter.next },
84
- # proc{ puts 'all done' }
85
- # )
86
- #
87
- def each(foreach=nil, after=nil, &blk)
88
- raise ArgumentError, 'proc or block required for iteration' unless foreach ||= blk
89
- raise RuntimeError, 'cannot iterate over an iterator more than once' if @started or @ended
90
-
91
- @started = true
92
- @pending = 0
93
- @workers = 0
94
-
95
- all_done = proc{
96
- after.call if after and @ended and @pending == 0
97
- }
98
-
99
- @process_next = proc{
100
- # p [:process_next, :pending=, @pending, :workers=, @workers, :ended=, @ended, :concurrency=, @concurrency, :list=, @list]
101
- unless @ended or @workers > @concurrency
102
- if @list.empty?
103
- @ended = true
104
- @workers -= 1
105
- all_done.call
106
- else
107
- item = @list.shift
108
- @pending += 1
109
-
110
- is_done = false
111
- on_done = proc{
112
- raise RuntimeError, 'already completed this iteration' if is_done
113
- is_done = true
114
-
115
- @pending -= 1
116
-
117
- if @ended
118
- all_done.call
119
- else
120
- EM.next_tick(@process_next)
121
- end
122
- }
123
- class << on_done
124
- alias :next :call
125
- end
126
-
127
- foreach.call(item, on_done)
128
- end
129
- else
130
- @workers -= 1
131
- end
132
- }
133
-
134
- spawn_workers
135
-
136
- self
137
- end
138
-
139
- # Collect the results of an asynchronous iteration into an array.
140
- #
141
- # EM::Iterator.new(%w[ pwd uptime uname date ], 2).map(proc{ |cmd,iter|
142
- # EM.system(cmd){ |output,status|
143
- # iter.return(output)
144
- # }
145
- # }, proc{ |results|
146
- # p results
147
- # })
148
- #
149
- def map(foreach, after)
150
- index = 0
151
-
152
- inject([], proc{ |results,item,iter|
153
- i = index
154
- index += 1
155
-
156
- is_done = false
157
- on_done = proc{ |res|
158
- raise RuntimeError, 'already returned a value for this iteration' if is_done
159
- is_done = true
160
-
161
- results[i] = res
162
- iter.return(results)
163
- }
164
- class << on_done
165
- alias :return :call
166
- def next
167
- raise NoMethodError, 'must call #return on a map iterator'
168
- end
169
- end
170
-
171
- foreach.call(item, on_done)
172
- }, proc{ |results|
173
- after.call(results)
174
- })
175
- end
176
-
177
- # Inject the results of an asynchronous iteration onto a given object.
178
- #
179
- # EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
180
- # EM.system(cmd){ |output,status|
181
- # hash[cmd] = status.exitstatus == 0 ? output.strip : nil
182
- # iter.return(hash)
183
- # }
184
- # }, proc{ |results|
185
- # p results
186
- # })
187
- #
188
- def inject(obj, foreach, after)
189
- each(proc{ |item,iter|
190
- is_done = false
191
- on_done = proc{ |res|
192
- raise RuntimeError, 'already returned a value for this iteration' if is_done
193
- is_done = true
194
-
195
- obj = res
196
- iter.next
197
- }
198
- class << on_done
199
- alias :return :call
200
- def next
201
- raise NoMethodError, 'must call #return on an inject iterator'
202
- end
203
- end
204
-
205
- foreach.call(obj, item, on_done)
206
- }, proc{
207
- after.call(obj)
208
- })
209
- end
210
-
211
- private
212
-
213
- # Spawn workers to consume items from the iterator's enumerator based on the current concurrency level.
214
- #
215
- def spawn_workers
216
- EM.next_tick(start_worker = proc{
217
- if @workers < @concurrency and !@ended
218
- # p [:spawning_worker, :workers=, @workers, :concurrency=, @concurrency, :ended=, @ended]
219
- @workers += 1
220
- @process_next.call
221
- EM.next_tick(start_worker)
222
- end
223
- })
224
- nil
225
- end
226
- end
227
- end
228
- end
229
-