zk-eventmachine 0.1.13 → 0.2.0.beta.1

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.
data/.gitignore CHANGED
@@ -7,4 +7,3 @@ pkg/*
7
7
  .rspec
8
8
  *.log
9
9
  .yardoc
10
- doc
data/Gemfile CHANGED
@@ -1,7 +1,9 @@
1
- source ENV['MBOX_BUNDLER_SOURCE'] if ENV['MBOX_BUNDLER_SOURCE']
1
+ source 'http://localhost:50000'
2
2
  source "http://rubygems.org"
3
3
 
4
+
4
5
  # Specify your gem's dependencies in zk-em.gemspec
5
6
  gemspec
6
7
 
8
+
7
9
  # vim:ft=ruby
data/Rakefile CHANGED
@@ -1,37 +1,2 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
-
4
- task :yard do
5
- Bundler.setup
6
- require 'yard'
7
-
8
- YARD::Rake::YardocTask.new(:run_yardoc) do |t|
9
- t.files = ['lib/**/*.rb']
10
- end
11
-
12
- Rake::Task[:run_yardoc].invoke
13
- end
14
-
15
- %w[1.8.7 1.9.2 1.9.3 jruby].each do |rvm_ruby|
16
- gemset_name = 'zk-em'
17
- ruby_with_gemset = "#{rvm_ruby}@#{gemset_name}"
18
- create_gemset_name = "mb:#{rvm_ruby}:create_gemset"
19
- bundle_task_name = "mb:#{rvm_ruby}:bundle_install"
20
- rspec_task_name = "mb:#{rvm_ruby}:run_rspec"
21
-
22
- task create_gemset_name do
23
- sh "rvm #{rvm_ruby} do rvm gemset create #{gemset_name}"
24
- end
25
-
26
- task bundle_task_name => create_gemset_name do
27
- rm_f 'Gemfile.lock'
28
- sh "rvm #{ruby_with_gemset} do bundle install"
29
- end
30
-
31
- task rspec_task_name => bundle_task_name do
32
- sh "rvm #{ruby_with_gemset} do bundle exec rspec spec --fail-fast"
33
- end
34
-
35
- task 'mb:test_all' => rspec_task_name
36
- end
37
-
@@ -70,7 +70,7 @@ module ZK
70
70
  #
71
71
  # @param [Hash] hash the result of the async call
72
72
  #
73
- # @return [true, false] for success, failure
73
+ # @returns [true, false] for success, failure
74
74
  def success?(hash)
75
75
  hash[:rc] == Zookeeper::ZOK
76
76
  end
@@ -1,63 +1,26 @@
1
1
  module ZK
2
2
  module ZKEventMachine
3
3
  class Client < ZK::Client::Base
4
- include Deferred::Accessors
5
4
  include ZK::Logging
6
5
  include Unixisms
7
6
 
8
7
  DEFAULT_TIMEOUT = 10
9
8
 
10
- # If we get a ZK::Exceptions::ConnectionLoss exeption back from any call,
11
- # or a EXPIRED_SESSION_STATE event, we will call back any handlers registered
12
- # here with the exception instance as the argument.
13
- #
14
- # once this deferred has been fired, it will be replaced with a new
15
- # deferred, so callbacks must be re-registered, and *should* be
16
- # re-registered *within* the callback to avoid missing events
17
- #
18
- # @method on_connection_lost
19
- # @return [Deferred::Default]
20
- deferred_event :connection_lost
21
-
22
-
23
- # Registers a one-shot callback for the ZOO_CONNECTED_STATE event.
24
- #
25
- # @note this is experimental currently. This may or may not fire for the *initial* connection.
26
- # it's purpose is to warn an already-existing client with watches that a connection has been
27
- # re-established (with session information saved). From the ZooKeeper Programmers' Guide:
28
- #
29
- # If you are using watches, you must look for the connected watch event.
30
- # When a ZooKeeper client disconnects from a server, you will not receive
31
- # notification of changes until reconnected. If you are watching for a
32
- # znode to come into existance, you will miss the event if the znode is
33
- # created and deleted while you are disconnected.
34
- #
35
- # once this deferred has been fired, it will be replaced with a new
36
- # deferred, so callbacks must be re-registered, and *should* be
37
- # re-registered *within* the callback to avoid missing events
38
- #
39
- # @method on_connected
40
- # @return [Deferred::Default]
41
- deferred_event :connected
42
-
43
- # Registers a one-shot callback for the ZOO_CONNECTING_STATE event
44
- #
45
- # This event is triggered when we have become disconnected from the
46
- # cluster and are in the process of reconnecting.
47
- deferred_event :connecting
48
-
49
- # called back once the connection has been closed.
50
- #
51
- # @method on_close
52
- # @return [Deferred::Default]
53
- deferred_event :close
9
+ # allows the synchrony client to muck with this
10
+ # @private
11
+ attr_writer :event_handler
54
12
 
55
13
  # Takes same options as ZK::Client::Base
56
14
  def initialize(host, opts={})
57
15
  @host = host
58
- @event_handler = EventHandlerEM.new(self)
59
- @closing = false
60
- register_default_event_handlers!
16
+ @close_deferred = Deferred::Default.new
17
+ @connection_lost_deferred = Deferred::Default.new
18
+ @event_handler = EventHandlerEM.new(self)
19
+ end
20
+
21
+ def on_close(&blk)
22
+ @close_deferred.callback(&blk) if blk
23
+ @close_deferred
61
24
  end
62
25
 
63
26
  # open a ZK connection, attach it to the reactor.
@@ -65,21 +28,34 @@ module ZK
65
28
  # ready for use
66
29
  def connect(&blk)
67
30
  # XXX: maybe move this into initialize, need to figure out how to schedule it properly
68
- @cnx ||= (
69
- ZookeeperEM::Client.new(@host, DEFAULT_TIMEOUT, event_handler.get_default_watcher_block)
70
- )
31
+ @cnx ||= ZookeeperEM::Client.new(@host, DEFAULT_TIMEOUT, event_handler.get_default_watcher_block)
71
32
  @cnx.on_attached(&blk)
72
33
  end
73
34
 
74
35
  # @private
36
+ # XXX: move this down into ZK::Client::Base
37
+ def connected?
38
+ @cnx and @cnx.connected?
39
+ end
40
+
41
+ # If we get a ZK::Exceptions::ConnectionLoss exeption back from any call,
42
+ # we will call back any handlers registered here with the exception
43
+ # instance as the argument
44
+ #
45
+ # once this deferred has been fired, it will be replaced with a new
46
+ # deferred, so callbacks must be re-registered
47
+ #
48
+ def on_connection_lost(&blk)
49
+ @connection_lost_deferred.callback(&blk) if blk
50
+ @connection_lost_deferred
51
+ end
52
+
75
53
  def reopen(*a)
76
54
  raise NotImplementedError, "reoopen is not implemented for the eventmachine version of the client"
77
55
  end
78
56
 
79
57
  def close!(&blk)
80
58
  on_close(&blk)
81
- return on_close if @closing
82
- @closing = true
83
59
 
84
60
  if @cnx
85
61
  logger.debug { "#{self.class.name}: in close! clearing event_handler" }
@@ -101,7 +77,7 @@ module ZK
101
77
 
102
78
  # get data at path, optionally enabling a watch on the node
103
79
  #
104
- # @return [Callback] returns a Callback which is an EM::Deferred (so you
80
+ # @returns [Callback] returns a Callback which is an EM::Deferred (so you
105
81
  # can assign callbacks/errbacks) see Callback::Base for discussion
106
82
  #
107
83
  def get(path, opts={}, &block)
@@ -168,47 +144,11 @@ module ZK
168
144
  end
169
145
  end
170
146
 
171
- # @return [Fixnum] The underlying connection's session_id
172
- def session_id
173
- return nil unless @cnx
174
- @cnx.session_id
175
- end
176
-
177
- # @return [String] The underlying connection's session passwd (an opaque value)
178
- def session_passwd
179
- return nil unless @cnx
180
- @cnx.session_passwd
181
- end
182
-
183
147
  protected
184
- # @private
185
- def register_default_event_handlers!
186
- @event_handler.register_state_handler(Zookeeper::ZOO_EXPIRED_SESSION_STATE, &method(:handle_expired_session_state_event!))
187
- @event_handler.register_state_handler(Zookeeper::ZOO_CONNECTED_STATE, &method(:handle_connected_state_event!))
188
- @event_handler.register_state_handler(Zookeeper::ZOO_CONNECTING_STATE, &method(:handle_connecting_state_event!))
189
- end
190
-
191
- # @private
192
- def handle_connected_state_event!(event)
193
- reset_connected_event.succeed(event)
194
- end
195
-
196
- # @private
197
- def handle_connecting_state_event!(event)
198
- reset_connecting_event.succeed(event)
199
- end
200
-
201
- # @private
202
- def handle_expired_session_state_event!(event)
203
- exc = ZK::Exceptions::ConnectionLoss.new("Received EXPIRED_SESSION_STATE event: #{event.inspect}")
204
- exc.set_backtrace(caller)
205
- connection_lost_hook(exc)
206
- end
207
-
208
- # @private
209
148
  def connection_lost_hook(exc)
210
149
  if exc and exc.kind_of?(ZK::Exceptions::ConnectionLoss)
211
- reset_connection_lost_event.succeed(exc)
150
+ dfr, @connection_lost_deferred = @connection_lost_deferred, Deferred::Default.new
151
+ dfr.succeed(exc)
212
152
  end
213
153
  end
214
154
  end
@@ -0,0 +1,39 @@
1
+ module ZK
2
+ module ZKEventMachine
3
+ module Deferred
4
+ include EM::Deferrable
5
+
6
+ # slight modification to EM::Deferrable,
7
+ #
8
+ # @returns [self] to allow for chaining
9
+ #
10
+ def callback(&block)
11
+ super(&block)
12
+ self
13
+ end
14
+
15
+ # @see #callback
16
+ def errback(&block)
17
+ super(&block)
18
+ self
19
+ end
20
+
21
+ # adds the block to both the callback and errback chains
22
+ def ensure_that(&block)
23
+ callback(&block)
24
+ errback(&block)
25
+ end
26
+
27
+ def chain_to(other_dfr, opts={})
28
+ other_dfr.callback { |*a| self.succeed(*a) }
29
+ other_dfr.errback { |*a| self.fail(*a) } unless opts[:ignore_errors]
30
+ self
31
+ end
32
+
33
+ class Default
34
+ include ZK::ZKEventMachine::Deferred
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,111 @@
1
+ module ZK
2
+ module ZKEventMachine
3
+ class SynchronyEventHandlerWrapper
4
+ include ZK::Logging
5
+
6
+ def initialize(event_handler)
7
+ @event_handler = event_handler
8
+ end
9
+
10
+ # registers a block to be called back within a fiber context
11
+ def register(path, &block)
12
+ new_block = proc do |*a|
13
+ Fiber.new { block.call(*a) }.resume
14
+ end
15
+
16
+ @event_handler.register(path, &new_block)
17
+ end
18
+
19
+ private
20
+ def method_missing(meth, *a, &b)
21
+ @event_handler.__send__(meth, *a, &b)
22
+ end
23
+ end
24
+
25
+ # This class is an EM::Synchrony wrapper around a ZK::ZKEventMachine::Client
26
+ #
27
+ # It should behave exactly like a ZK::Client instance (when called in a
28
+ # synchronous fashion), and one should look there for documentation about
29
+ # the various methods
30
+ #
31
+ # @note this class is implemented as a wrapper instead of a subclass of Client
32
+ # so that it can support the unixisms like rm_rf and mkdir_p. The
33
+ # synchrony pattern of aliasing the base class methods and specializing for
34
+ # synchrony didn't work in this case.
35
+ #
36
+ class SynchronyClient
37
+ include ZK::Logging
38
+
39
+ attr_reader :event_handler, :client
40
+
41
+ # @overload new(client_instance)
42
+ # Wrap an existing ZK::ZKEventMachine::Client instance in an
43
+ # EM::Synchrony compatible way
44
+ # @param [ZK::ZKEventMachine::Client] client_instance an instance of Client to wrap
45
+ # @overload new(host, opts={})
46
+ # Creates a new ZK::ZKEventMachine::Client instance to manage
47
+ # takes the same arguments as ZK::Client::Base
48
+ def initialize(host, opts={})
49
+ case host
50
+ when Client
51
+ @client = host
52
+ when String
53
+ @client = Client.new(host, opts)
54
+ else
55
+ raise ArgumentError, "argument must be either a ZK::ZKEventMachine::Client instance or a hostname:port string"
56
+ end
57
+
58
+ @event_handler = SynchronyEventHandlerWrapper.new(@client.event_handler)
59
+ end
60
+
61
+ %w[connect close close! get set create stat delete children get_acl set_acl mkdir_p rm_rf].each do |meth|
62
+ class_eval(<<-EOMETH, __FILE__, __LINE__ + 1)
63
+ def #{meth}(*args,&blk)
64
+ sync!(@client.#{meth}(*args, &blk))
65
+ end
66
+ EOMETH
67
+ end
68
+
69
+ # @deprecated for backwards compatibility only
70
+ def watcher
71
+ event_handler
72
+ end
73
+
74
+ def exists?(path, opts={})
75
+ stat(path, opts={}).exists?
76
+ end
77
+
78
+ protected
79
+ # a modification of EM::Synchrony.sync to handle multiple callback arguments properly
80
+ def sync(df)
81
+ f = Fiber.current
82
+
83
+ xback = proc do |*args|
84
+ if f == Fiber.current
85
+ return *args
86
+ else
87
+ f.resume(*args)
88
+ end
89
+ end
90
+
91
+ df.callback(&xback)
92
+ df.errback(&xback)
93
+
94
+ Fiber.yield
95
+ end
96
+
97
+ # like sync, but if the deferred returns an exception instance, re-raises
98
+ def sync!(deferred)
99
+ rval = sync(deferred)
100
+ raise rval if rval.kind_of?(Exception)
101
+ rval
102
+ end
103
+
104
+ private
105
+ def method_missing(meth, *a, &b)
106
+ @client.__send__(meth, *a, &b)
107
+ end
108
+ end
109
+ end
110
+ end
111
+
@@ -31,18 +31,15 @@ module ZK
31
31
  _handle_calling_convention(dfr, &blk)
32
32
  end
33
33
 
34
- # @private
35
34
  def find(*paths, &block)
36
35
  raise NotImplementedError, "Coming soon"
37
36
  end
38
37
 
39
- # @private
40
38
  def block_until_node_deleted(abs_node_path)
41
39
  raise NotImplementedError, "blocking does not make sense in EventMachine-land"
42
40
  end
43
41
 
44
42
  protected
45
- # @private
46
43
  def _handle_calling_convention(dfr, &blk)
47
44
  return dfr unless blk
48
45
  dfr.callback { |*a| blk.call(nil, *a) }
@@ -50,7 +47,6 @@ module ZK
50
47
  dfr
51
48
  end
52
49
 
53
- # @private
54
50
  def _rm_rf_dfr(path)
55
51
  Deferred::Default.new.tap do |my_dfr|
56
52
  delete(path) do |exc|
@@ -89,7 +85,6 @@ module ZK
89
85
  end
90
86
  end
91
87
 
92
- # @private
93
88
  def _mkdir_p_dfr(path)
94
89
  Deferred::Default.new.tap do |my_dfr|
95
90
  d = create(path, '')
@@ -1,5 +1,5 @@
1
1
  module ZK
2
2
  module ZKEventMachine
3
- VERSION = "0.1.13"
3
+ VERSION = "0.2.0.beta.1"
4
4
  end
5
5
  end
@@ -1,10 +1,11 @@
1
1
  require 'eventmachine'
2
+ require 'em-synchrony'
2
3
 
3
4
  require 'zookeeper'
4
5
  require 'zookeeper/em_client'
5
6
 
6
7
  require 'zk'
7
- require 'deferred'
8
+
8
9
 
9
10
  module ZK
10
11
  module ZKEventMachine
@@ -15,9 +16,11 @@ end
15
16
  $LOAD_PATH.unshift(File.expand_path('../..', __FILE__)).uniq!
16
17
 
17
18
  require 'z_k/z_k_event_machine/iterator'
19
+ require 'z_k/z_k_event_machine/deferred'
18
20
  require 'z_k/z_k_event_machine/callback'
19
21
  require 'z_k/z_k_event_machine/event_handler_e_m'
20
22
  require 'z_k/z_k_event_machine/unixisms'
21
23
  require 'z_k/z_k_event_machine/client'
24
+ require 'z_k/z_k_event_machine/synchrony_client'
22
25
 
23
26
 
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,8 @@ require 'evented-spec'
10
10
  # in spec/support/ and its subdirectories.
11
11
  Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
12
12
 
13
+ $stderr.sync = true
14
+
13
15
  case `uname -s`.chomp
14
16
  when 'Linux'
15
17
  $stderr.puts "WARN: setting EM.epoll = true for tests"
@@ -19,25 +21,6 @@ when 'Darwin'
19
21
  EM.kqueue = true
20
22
  end
21
23
 
22
- # method to wait until block passed returns true or timeout (default is 2 seconds) is reached
23
- def wait_until(timeout=2)
24
- time_to_stop = Time.now + timeout
25
-
26
- until yield
27
- break if Time.now > time_to_stop
28
- Thread.pass
29
- end
30
- end
31
-
32
- def wait_while(timeout=2)
33
- time_to_stop = Time.now + timeout
34
-
35
- while yield
36
- break if Time.now > time_to_stop
37
- Thread.pass
38
- end
39
- end
40
-
41
24
  RSpec.configure do |config|
42
25
  config.mock_with :flexmock
43
26
  end
@@ -1,19 +1,14 @@
1
1
  require 'logger'
2
2
 
3
- log_file = File.open(File.expand_path('../../../test.log', __FILE__), 'a').tap { |f| f.sync = true }
3
+ logger = Logger.new(File.expand_path('../../../test.log', __FILE__)).tap {|l| l.level = Logger::DEBUG}
4
4
 
5
- Logger.new(log_file).tap do |log|
6
- log.level = Logger::DEBUG
7
- ZK.logger = log
8
- Zookeeper.logger = log
9
- end
10
-
11
- # for debugging along with C output uncomment the following
12
- #
13
- # $stderr.sync = true
14
5
  # logger = Logger.new($stderr).tap { |l| l.level = Logger::DEBUG }
15
6
  # Zookeeper.set_debug_level(4)
16
7
 
8
+ ZK.logger = logger
9
+ Zookeeper.logger = ZK.logger
10
+
11
+
17
12
  def logger
18
13
  ZK.logger
19
14
  end