zkruby 3.4.3
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.tar.gz.sig +0 -0
 - data/.gemtest +0 -0
 - data/History.txt +18 -0
 - data/Manifest.txt +39 -0
 - data/README.rdoc +119 -0
 - data/Rakefile +39 -0
 - data/jute/jute.citrus +105 -0
 - data/jute/lib/hoe/jute.rb +56 -0
 - data/jute/lib/jute.rb +120 -0
 - data/lib/em_zkruby.rb +4 -0
 - data/lib/jute/zookeeper.rb +203 -0
 - data/lib/zkruby.rb +4 -0
 - data/lib/zkruby/bindata.rb +45 -0
 - data/lib/zkruby/client.rb +608 -0
 - data/lib/zkruby/enum.rb +108 -0
 - data/lib/zkruby/eventmachine.rb +186 -0
 - data/lib/zkruby/multi.rb +47 -0
 - data/lib/zkruby/protocol.rb +182 -0
 - data/lib/zkruby/rubyio.rb +310 -0
 - data/lib/zkruby/session.rb +445 -0
 - data/lib/zkruby/util.rb +141 -0
 - data/lib/zkruby/zkruby.rb +27 -0
 - data/spec/bindata_spec.rb +51 -0
 - data/spec/enum_spec.rb +84 -0
 - data/spec/eventmachine_spec.rb +50 -0
 - data/spec/multi_spec.rb +93 -0
 - data/spec/protocol_spec.rb +72 -0
 - data/spec/recipe_helper.rb +68 -0
 - data/spec/rubyio_spec.rb +8 -0
 - data/spec/sequences_spec.rb +19 -0
 - data/spec/server_helper.rb +45 -0
 - data/spec/shared/auth.rb +40 -0
 - data/spec/shared/basic.rb +180 -0
 - data/spec/shared/binding.rb +33 -0
 - data/spec/shared/chroot.rb +61 -0
 - data/spec/shared/multi.rb +38 -0
 - data/spec/shared/util.rb +56 -0
 - data/spec/shared/watch.rb +49 -0
 - data/spec/spec_helper.rb +12 -0
 - data/src/jute/zookeeper.jute +288 -0
 - data/yard_ext/enum_handler.rb +16 -0
 - metadata +243 -0
 - metadata.gz.sig +0 -0
 
    
        data/lib/zkruby/enum.rb
    ADDED
    
    | 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            # Including in a class and us the "enum" DSL method to create class instances
         
     | 
| 
      
 3 
     | 
    
         
            +
            # As a special case, if the including class is descendant from StandardError, the enumerated
         
     | 
| 
      
 4 
     | 
    
         
            +
            # instances will be classes descendent from the including class (eg like Errno)
         
     | 
| 
      
 5 
     | 
    
         
            +
            module Enumeration
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def self.included(base)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    #  In the normal case we just include our methods in the base class
         
     | 
| 
      
 10 
     | 
    
         
            +
                    #  but for Errors we need to include them on each instance
         
     | 
| 
      
 11 
     | 
    
         
            +
                    base.send :include,InstanceMethods unless base < StandardError
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                module InstanceMethods
         
     | 
| 
      
 15 
     | 
    
         
            +
                    def === (other)
         
     | 
| 
      
 16 
     | 
    
         
            +
                        case other
         
     | 
| 
      
 17 
     | 
    
         
            +
                        when Symbol
         
     | 
| 
      
 18 
     | 
    
         
            +
                            to_sym == other
         
     | 
| 
      
 19 
     | 
    
         
            +
                        when Fixnum
         
     | 
| 
      
 20 
     | 
    
         
            +
                            to_int == other
         
     | 
| 
      
 21 
     | 
    
         
            +
                        else
         
     | 
| 
      
 22 
     | 
    
         
            +
                            super
         
     | 
| 
      
 23 
     | 
    
         
            +
                        end
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    def to_i
         
     | 
| 
      
 27 
     | 
    
         
            +
                        to_int
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    def to_int
         
     | 
| 
      
 31 
     | 
    
         
            +
                        @index
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    def |(num)
         
     | 
| 
      
 35 
     | 
    
         
            +
                        to_int | num
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    def &(num)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        to_int & num
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    def to_sym
         
     | 
| 
      
 43 
     | 
    
         
            +
                        @name
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def to_s
         
     | 
| 
      
 47 
     | 
    
         
            +
                        "#{super} (:#{@name} [#{@index}])"
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 52 
     | 
    
         
            +
                  
         
     | 
| 
      
 53 
     | 
    
         
            +
                    # @param [] ref Symbol, Fixnum or Enumeration
         
     | 
| 
      
 54 
     | 
    
         
            +
                    # @return [Enumeration] instance representing ref or nil if not found
         
     | 
| 
      
 55 
     | 
    
         
            +
                    def get(ref)
         
     | 
| 
      
 56 
     | 
    
         
            +
                        @enums[ref]
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    # @param [] ref Symbol, Fixnum 
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # @raise [KeyError] if ref not found
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # @return [Enumeration] 
         
     | 
| 
      
 62 
     | 
    
         
            +
                    def fetch(ref)
         
     | 
| 
      
 63 
     | 
    
         
            +
                        @enums.fetch(ref)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    # Will dynamically create a new enum instance if ref is not found
         
     | 
| 
      
 67 
     | 
    
         
            +
                    def lookup(ref)
         
     | 
| 
      
 68 
     | 
    
         
            +
                        case ref
         
     | 
| 
      
 69 
     | 
    
         
            +
                        when Enumeration,Class 
         
     | 
| 
      
 70 
     | 
    
         
            +
                            ref
         
     | 
| 
      
 71 
     | 
    
         
            +
                        when Symbol
         
     | 
| 
      
 72 
     | 
    
         
            +
                            get(ref) || enum(ref,nil)
         
     | 
| 
      
 73 
     | 
    
         
            +
                        when Fixnum
         
     | 
| 
      
 74 
     | 
    
         
            +
                            get(ref) || enum(nil,ref)
         
     | 
| 
      
 75 
     | 
    
         
            +
                        else
         
     | 
| 
      
 76 
     | 
    
         
            +
                            nil
         
     | 
| 
      
 77 
     | 
    
         
            +
                        end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    def enum(name,index,*args)
         
     | 
| 
      
 81 
     | 
    
         
            +
                        @enums ||= {}
         
     | 
| 
      
 82 
     | 
    
         
            +
                        
         
     | 
| 
      
 83 
     | 
    
         
            +
                        instance = if (self < StandardError) then Class.new(self) else self.new(*args) end
         
     | 
| 
      
 84 
     | 
    
         
            +
                        
         
     | 
| 
      
 85 
     | 
    
         
            +
                        instance.extend(InstanceMethods) if (self < StandardError)
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                        const_name = if name.nil?
         
     | 
| 
      
 88 
     | 
    
         
            +
                                         "ENUM" + index.to_s.sub("-","_")
         
     | 
| 
      
 89 
     | 
    
         
            +
                                     else
         
     | 
| 
      
 90 
     | 
    
         
            +
                                         name.to_s.upcase
         
     | 
| 
      
 91 
     | 
    
         
            +
                                     end
         
     | 
| 
      
 92 
     | 
    
         
            +
                                        
         
     | 
| 
      
 93 
     | 
    
         
            +
                        self.const_set(const_name.to_s.upcase,instance)
         
     | 
| 
      
 94 
     | 
    
         
            +
                        
         
     | 
| 
      
 95 
     | 
    
         
            +
                        @enums[instance] = instance
         
     | 
| 
      
 96 
     | 
    
         
            +
                        @enums[name] = instance if name
         
     | 
| 
      
 97 
     | 
    
         
            +
                        @enums[index] = instance if index
         
     | 
| 
      
 98 
     | 
    
         
            +
                        instance.instance_variable_set(:@name,name)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        instance.instance_variable_set(:@index,index)
         
     | 
| 
      
 100 
     | 
    
         
            +
                        instance.freeze
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    def method_missing(method,*args)
         
     | 
| 
      
 104 
     | 
    
         
            +
                        @enums[method.downcase] || super
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,186 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'eventmachine'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            if defined?(JRUBY_VERSION) && JRUBY_VERSION =~ /1\.6\.5.*/
         
     | 
| 
      
 4 
     | 
    
         
            +
                raise "Fibers are broken in JRuby 1.6.5 (See JRUBY-6170)"
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'strand'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module ZooKeeper
         
     | 
| 
      
 10 
     | 
    
         
            +
                module EventMachine
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    class ClientConn < ::EM::Connection
         
     | 
| 
      
 13 
     | 
    
         
            +
                        include Protocol
         
     | 
| 
      
 14 
     | 
    
         
            +
                        include Slf4r::Logger        
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                        unless EventMachine.methods.include?(:set_pending_connect_timeout)
         
     | 
| 
      
 17 
     | 
    
         
            +
                            def set_pending_connect_timeout(timeout)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                            end
         
     | 
| 
      
 20 
     | 
    
         
            +
                        end  
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                        def initialize(session,connect_timeout)
         
     | 
| 
      
 23 
     | 
    
         
            +
                            @session = session
         
     | 
| 
      
 24 
     | 
    
         
            +
                            @connect_timeout = connect_timeout
         
     | 
| 
      
 25 
     | 
    
         
            +
                            set_pending_connect_timeout(connect_timeout)
         
     | 
| 
      
 26 
     | 
    
         
            +
                        rescue Exception => ex
         
     | 
| 
      
 27 
     | 
    
         
            +
                            logger.warn("Exception in initialize",ex)
         
     | 
| 
      
 28 
     | 
    
         
            +
                        end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                        def post_init()
         
     | 
| 
      
 31 
     | 
    
         
            +
                        rescue Exception => ex
         
     | 
| 
      
 32 
     | 
    
         
            +
                            logger.warn("Exception in post_init",ex)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                        def connection_completed()
         
     | 
| 
      
 36 
     | 
    
         
            +
                            @session.prime_connection(self)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                            # Make sure we connect within the timeout period
         
     | 
| 
      
 39 
     | 
    
         
            +
                            # TODO this should really be the amount of connect timeout left over
         
     | 
| 
      
 40 
     | 
    
         
            +
                            @timer = EM.add_timer(@connect_timeout) do
         
     | 
| 
      
 41 
     | 
    
         
            +
                                if @session.connected?
         
     | 
| 
      
 42 
     | 
    
         
            +
                                    # Start the ping timer 
         
     | 
| 
      
 43 
     | 
    
         
            +
                                    ping = @session.ping_interval 
         
     | 
| 
      
 44 
     | 
    
         
            +
                                    @timer = EM.add_periodic_timer ( ping ) do
         
     | 
| 
      
 45 
     | 
    
         
            +
                                        case @ping
         
     | 
| 
      
 46 
     | 
    
         
            +
                                        when 1 then @session.ping()
         
     | 
| 
      
 47 
     | 
    
         
            +
                                        when 2 then close_connection()
         
     | 
| 
      
 48 
     | 
    
         
            +
                                        end
         
     | 
| 
      
 49 
     | 
    
         
            +
                                        @ping += 1
         
     | 
| 
      
 50 
     | 
    
         
            +
                                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                                else
         
     | 
| 
      
 52 
     | 
    
         
            +
                                    close_connection()
         
     | 
| 
      
 53 
     | 
    
         
            +
                                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                            end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                        rescue Exception => ex
         
     | 
| 
      
 57 
     | 
    
         
            +
                            logger.warn("Exception in connection_completed",ex)
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                        def receive_records(packet_io)
         
     | 
| 
      
 61 
     | 
    
         
            +
                            @ping = 0
         
     | 
| 
      
 62 
     | 
    
         
            +
                            @session.receive_records(packet_io)
         
     | 
| 
      
 63 
     | 
    
         
            +
                        end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                        def disconnect()
         
     | 
| 
      
 66 
     | 
    
         
            +
                            close_connection()
         
     | 
| 
      
 67 
     | 
    
         
            +
                        end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                        def unbind
         
     | 
| 
      
 70 
     | 
    
         
            +
                            EM.cancel_timer(@timer) if @timer
         
     | 
| 
      
 71 
     | 
    
         
            +
                            @session.disconnected()
         
     | 
| 
      
 72 
     | 
    
         
            +
                        rescue Exception => ex
         
     | 
| 
      
 73 
     | 
    
         
            +
                            logger.warn("Exception in unbind",ex)
         
     | 
| 
      
 74 
     | 
    
         
            +
                        end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    # The EventMachine binding is very simple because there is only one thread!
         
     | 
| 
      
 80 
     | 
    
         
            +
                    # and we have good stuff like timers provided for us
         
     | 
| 
      
 81 
     | 
    
         
            +
                    class Binding
         
     | 
| 
      
 82 
     | 
    
         
            +
                        include Slf4r::Logger        
         
     | 
| 
      
 83 
     | 
    
         
            +
                        # We can use this binding if we are running in the reactor thread
         
     | 
| 
      
 84 
     | 
    
         
            +
                        def self.available?()
         
     | 
| 
      
 85 
     | 
    
         
            +
                            EM.reactor_running? && EM.reactor_thread?
         
     | 
| 
      
 86 
     | 
    
         
            +
                        end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                        def self.context(&context_block)
         
     | 
| 
      
 89 
     | 
    
         
            +
                            s = Strand.new() do
         
     | 
| 
      
 90 
     | 
    
         
            +
                                context_block.call(Strand)
         
     | 
| 
      
 91 
     | 
    
         
            +
                            end
         
     | 
| 
      
 92 
     | 
    
         
            +
                            s.join
         
     | 
| 
      
 93 
     | 
    
         
            +
                        end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                        attr_reader :client, :session
         
     | 
| 
      
 96 
     | 
    
         
            +
                        def start(client,session)
         
     | 
| 
      
 97 
     | 
    
         
            +
                            @client = client
         
     | 
| 
      
 98 
     | 
    
         
            +
                            @session = session
         
     | 
| 
      
 99 
     | 
    
         
            +
                            @session.start()
         
     | 
| 
      
 100 
     | 
    
         
            +
                        end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                        def connect(host,port,delay,timeout)
         
     | 
| 
      
 103 
     | 
    
         
            +
                            EM.add_timer(delay) do
         
     | 
| 
      
 104 
     | 
    
         
            +
                                EM.connect(host,port,ZooKeeper::EventMachine::ClientConn,@session,timeout)
         
     | 
| 
      
 105 
     | 
    
         
            +
                            end
         
     | 
| 
      
 106 
     | 
    
         
            +
                        end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                        # You are working in event machine it is up to you to ensure your callbacks do not block
         
     | 
| 
      
 109 
     | 
    
         
            +
                        def invoke(callback,*args)
         
     | 
| 
      
 110 
     | 
    
         
            +
                            callback.call(*args)
         
     | 
| 
      
 111 
     | 
    
         
            +
                        end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                        def queue_request(*args,&callback)
         
     | 
| 
      
 114 
     | 
    
         
            +
                            op = AsyncOp.new(self,&callback)
         
     | 
| 
      
 115 
     | 
    
         
            +
                            begin
         
     | 
| 
      
 116 
     | 
    
         
            +
                                @session.queue_request(*args) do |error,response|
         
     | 
| 
      
 117 
     | 
    
         
            +
                                    op.resume(error,response)
         
     | 
| 
      
 118 
     | 
    
         
            +
                                end
         
     | 
| 
      
 119 
     | 
    
         
            +
                            rescue ZooKeeper::Error => ex
         
     | 
| 
      
 120 
     | 
    
         
            +
                                op.resume(ex,nil)
         
     | 
| 
      
 121 
     | 
    
         
            +
                            end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                            op
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                        def close(&callback)
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                            op = AsyncOp.new(self,&callback)
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                            begin
         
     | 
| 
      
 131 
     | 
    
         
            +
                                @session.close() do |error,response|
         
     | 
| 
      
 132 
     | 
    
         
            +
                                    op.resume(error,response) 
         
     | 
| 
      
 133 
     | 
    
         
            +
                                end
         
     | 
| 
      
 134 
     | 
    
         
            +
                            rescue ZooKeeper::Error => ex
         
     | 
| 
      
 135 
     | 
    
         
            +
                                op.resume(ex,nil)
         
     | 
| 
      
 136 
     | 
    
         
            +
                            end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                            op
         
     | 
| 
      
 139 
     | 
    
         
            +
                        end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    end #class Binding
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                    class AsyncOp < ZooKeeper::AsyncOp
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                        def initialize(binding,&callback)
         
     | 
| 
      
 146 
     | 
    
         
            +
                            @em_binding = binding
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                            # Wrap the callback in its own Strand
         
     | 
| 
      
 149 
     | 
    
         
            +
                            @op_strand = Strand.new do
         
     | 
| 
      
 150 
     | 
    
         
            +
                                #immediately pause
         
     | 
| 
      
 151 
     | 
    
         
            +
                                error, response = Strand.yield
         
     | 
| 
      
 152 
     | 
    
         
            +
                                Strand.current[ZooKeeper::CURRENT] =  [ @em_binding.client ] 
         
     | 
| 
      
 153 
     | 
    
         
            +
                                raise error if error
         
     | 
| 
      
 154 
     | 
    
         
            +
                                callback.call(response)
         
     | 
| 
      
 155 
     | 
    
         
            +
                            end
         
     | 
| 
      
 156 
     | 
    
         
            +
                        end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                        def resume(error,response)
         
     | 
| 
      
 159 
     | 
    
         
            +
                            #TODO - raise issue in strand for resume to take arguments
         
     | 
| 
      
 160 
     | 
    
         
            +
                            op_strand.fiber.resume(error,response)
         
     | 
| 
      
 161 
     | 
    
         
            +
                        end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                        private
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                        attr_reader :op_strand,:err_strand
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                        def set_error_handler(errcallback)
         
     | 
| 
      
 168 
     | 
    
         
            +
                            @err_strand = Strand.new() do
         
     | 
| 
      
 169 
     | 
    
         
            +
                                begin
         
     | 
| 
      
 170 
     | 
    
         
            +
                                    op_strand.value()
         
     | 
| 
      
 171 
     | 
    
         
            +
                                rescue StandardError => ex
         
     | 
| 
      
 172 
     | 
    
         
            +
                                    Strand.current[ZooKeeper::CURRENT] =  [ @em_binding.client ] 
         
     | 
| 
      
 173 
     | 
    
         
            +
                                    errcallback.call(ex)   
         
     | 
| 
      
 174 
     | 
    
         
            +
                                end
         
     | 
| 
      
 175 
     | 
    
         
            +
                            end
         
     | 
| 
      
 176 
     | 
    
         
            +
                        end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                        def wait_value()
         
     | 
| 
      
 179 
     | 
    
         
            +
                            err_strand ? err_strand.value : op_strand.value 
         
     | 
| 
      
 180 
     | 
    
         
            +
                        end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                    end #class AsyncOp
         
     | 
| 
      
 183 
     | 
    
         
            +
                end #module EventMachine
         
     | 
| 
      
 184 
     | 
    
         
            +
            end #module ZooKeeper
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
            ZooKeeper.add_binding(ZooKeeper::EventMachine::Binding)
         
     | 
    
        data/lib/zkruby/multi.rb
    ADDED
    
    | 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ZooKeeper
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
                module Proto
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                    #MultiTransactionRecord and MultiResponse in java
         
     | 
| 
      
 6 
     | 
    
         
            +
                    #are not able to be compiled from Jute because jute doesn't support
         
     | 
| 
      
 7 
     | 
    
         
            +
                    #discriminators
         
     | 
| 
      
 8 
     | 
    
         
            +
                    class MultiRequest < BinData::Record
         
     | 
| 
      
 9 
     | 
    
         
            +
                        array :requests, :read_until => lambda { element.header._type < 0 } do
         
     | 
| 
      
 10 
     | 
    
         
            +
                            multi_header :header
         
     | 
| 
      
 11 
     | 
    
         
            +
                            choice :request, :selection => lambda { header._type },
         
     | 
| 
      
 12 
     | 
    
         
            +
                                :onlyif => lambda { header._type > 0 } do
         
     | 
| 
      
 13 
     | 
    
         
            +
                                create_request 1
         
     | 
| 
      
 14 
     | 
    
         
            +
                                delete_request 2
         
     | 
| 
      
 15 
     | 
    
         
            +
                                set_data_request 5
         
     | 
| 
      
 16 
     | 
    
         
            +
                                check_version_request 13
         
     | 
| 
      
 17 
     | 
    
         
            +
                                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                        end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    class MultiResponseItem < BinData::Record
         
     | 
| 
      
 23 
     | 
    
         
            +
                        multi_header :header
         
     | 
| 
      
 24 
     | 
    
         
            +
                        choice :response, :selection => lambda { header._type },
         
     | 
| 
      
 25 
     | 
    
         
            +
                            :onlyif => lambda { has_response? } do
         
     | 
| 
      
 26 
     | 
    
         
            +
                            error_response -1
         
     | 
| 
      
 27 
     | 
    
         
            +
                            create_response 1
         
     | 
| 
      
 28 
     | 
    
         
            +
                            set_data_response 5
         
     | 
| 
      
 29 
     | 
    
         
            +
                            end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                        def has_response?
         
     | 
| 
      
 32 
     | 
    
         
            +
                            !done? && [ -1, 1, 5 ] .include?(header._type)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                        def done?
         
     | 
| 
      
 36 
     | 
    
         
            +
                            # Boolean's don't actually work properly in bindata
         
     | 
| 
      
 37 
     | 
    
         
            +
                            header.done == true
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    class MultiResponse < BinData::Record
         
     | 
| 
      
 43 
     | 
    
         
            +
                        array :responses, :type => :multi_response_item, :read_until => lambda { element.done? }
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,182 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'stringio'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module ZooKeeper
         
     | 
| 
      
 4 
     | 
    
         
            +
                # Represents a problem communicating with the ZK cluster
         
     | 
| 
      
 5 
     | 
    
         
            +
                # client's shouldn't see this
         
     | 
| 
      
 6 
     | 
    
         
            +
                class ProtocolError < IOError;end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                 # Raw object protocol, very similar to EM's native ObjectProtocol
         
     | 
| 
      
 9 
     | 
    
         
            +
                 # Expects:
         
     | 
| 
      
 10 
     | 
    
         
            +
                 #   #receive_data and #send_records to be invoked
         
     | 
| 
      
 11 
     | 
    
         
            +
                 #   #receive_records and #send_data to be implemented
         
     | 
| 
      
 12 
     | 
    
         
            +
                 module Protocol
         
     | 
| 
      
 13 
     | 
    
         
            +
                    MIN_PACKET = 5 #TODO Work out what the min packet size really is
         
     | 
| 
      
 14 
     | 
    
         
            +
                    include Slf4r::Logger
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def receive_data data # :nodoc:
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                      @buffer ||= StringIO.new()
         
     | 
| 
      
 19 
     | 
    
         
            +
                      @buffer.seek(0, IO::SEEK_END)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      @buffer << data
         
     | 
| 
      
 21 
     | 
    
         
            +
                      @buffer.rewind
         
     | 
| 
      
 22 
     | 
    
         
            +
                      logger.debug { "Received #{data.length} bytes: buffer length = #{@buffer.length} pos = #{@buffer.pos}" }
         
     | 
| 
      
 23 
     | 
    
         
            +
                      loop do
         
     | 
| 
      
 24 
     | 
    
         
            +
                        if @buffer.length - @buffer.pos > MIN_PACKET 
         
     | 
| 
      
 25 
     | 
    
         
            +
                            packet_size = @buffer.read(4).unpack("N").first
         
     | 
| 
      
 26 
     | 
    
         
            +
                            if (@buffer.length - @buffer.pos >= packet_size)
         
     | 
| 
      
 27 
     | 
    
         
            +
                                expected_pos = @buffer.pos + packet_size
         
     | 
| 
      
 28 
     | 
    
         
            +
                                # We just pass the buffer around and expect packet_size to be consumed
         
     | 
| 
      
 29 
     | 
    
         
            +
                                receive_records(@buffer)
         
     | 
| 
      
 30 
     | 
    
         
            +
                                if (@buffer.pos != expected_pos)
         
     | 
| 
      
 31 
     | 
    
         
            +
                                    #this can happen during disconnection with left over packets
         
     | 
| 
      
 32 
     | 
    
         
            +
                                    #the connection is dying anyway
         
     | 
| 
      
 33 
     | 
    
         
            +
                                    leftover = @buffer.read(packet_size).unpack("H*")[0]
         
     | 
| 
      
 34 
     | 
    
         
            +
                                    raise ProtocolError, "Records not consumed #{leftover}"
         
     | 
| 
      
 35 
     | 
    
         
            +
                                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                                logger.debug { "Consumed packet #{packet_size}. Buffer pos=#{@buffer.pos}, length=#{@buffer.length}" }
         
     | 
| 
      
 37 
     | 
    
         
            +
                                next
         
     | 
| 
      
 38 
     | 
    
         
            +
                            else
         
     | 
| 
      
 39 
     | 
    
         
            +
                                # found the last partial packet
         
     | 
| 
      
 40 
     | 
    
         
            +
                                @buffer.seek(-4, IO::SEEK_CUR)
         
     | 
| 
      
 41 
     | 
    
         
            +
                                logger.debug { "Buffer contains #{@buffer.length} of #{packet_size} packet" }
         
     | 
| 
      
 42 
     | 
    
         
            +
                            end
         
     | 
| 
      
 43 
     | 
    
         
            +
                        end
         
     | 
| 
      
 44 
     | 
    
         
            +
                        break
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                      # reset the buffer
         
     | 
| 
      
 47 
     | 
    
         
            +
                      @buffer = StringIO.new(@buffer.read()) if @buffer.pos > 0
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def receive_records(packet_io)
         
     | 
| 
      
 51 
     | 
    
         
            +
                        #stub
         
     | 
| 
      
 52 
     | 
    
         
            +
                        #we don't unpack records here because we don't know what kind of records they are!
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    def send_records(*records)
         
     | 
| 
      
 56 
     | 
    
         
            +
                        length = 0
         
     | 
| 
      
 57 
     | 
    
         
            +
                        bindata = records.collect { |r| s = r.to_binary_s; length += s.length; s }
         
     | 
| 
      
 58 
     | 
    
         
            +
                        send_data([length].pack("N"))
         
     | 
| 
      
 59 
     | 
    
         
            +
                        bindata.each { |b| send_data(b) }
         
     | 
| 
      
 60 
     | 
    
         
            +
                        logger.debug { "Sent #{length} byte packet containing  #{records.length} records" }
         
     | 
| 
      
 61 
     | 
    
         
            +
                    end
         
     | 
| 
      
 62 
     | 
    
         
            +
                 end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                class Operation
         
     | 
| 
      
 65 
     | 
    
         
            +
                    attr_reader :op, :opcode, :request, :response, :callback
         
     | 
| 
      
 66 
     | 
    
         
            +
                    def initialize(op,opcode,request,response,callback)
         
     | 
| 
      
 67 
     | 
    
         
            +
                        @op=op;@opcode=opcode
         
     | 
| 
      
 68 
     | 
    
         
            +
                        @request=request;@response=response
         
     | 
| 
      
 69 
     | 
    
         
            +
                        @callback=callback
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                    
         
     | 
| 
      
 72 
     | 
    
         
            +
                    def path
         
     | 
| 
      
 73 
     | 
    
         
            +
                        #Every request has a path!
         
     | 
| 
      
 74 
     | 
    
         
            +
                        #TODO - path may be chrooted!
         
     | 
| 
      
 75 
     | 
    
         
            +
                        request.path if request.respond_to?(:path)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                class Packet < Operation
         
     | 
| 
      
 80 
     | 
    
         
            +
                    attr_reader :xid, :watch_type, :watcher
         
     | 
| 
      
 81 
     | 
    
         
            +
                   
         
     | 
| 
      
 82 
     | 
    
         
            +
                    def initialize(xid,op,opcode,request,response,watch_type,watcher,callback)
         
     | 
| 
      
 83 
     | 
    
         
            +
                        super(op,opcode,request,response,callback)
         
     | 
| 
      
 84 
     | 
    
         
            +
                        @xid=xid;
         
     | 
| 
      
 85 
     | 
    
         
            +
                        @watch_type = watch_type; @watcher = watcher
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    
         
     | 
| 
      
 89 
     | 
    
         
            +
                    def error(reason)
         
     | 
| 
      
 90 
     | 
    
         
            +
                        result(reason)[0..2] # don't need the watch
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    def result(rc)
         
     | 
| 
      
 94 
     | 
    
         
            +
                        error = nil
         
     | 
| 
      
 95 
     | 
    
         
            +
                        unless (Error::NONE === rc) then 
         
     | 
| 
      
 96 
     | 
    
         
            +
                            error = Error.lookup(rc) 
         
     | 
| 
      
 97 
     | 
    
         
            +
                            error = error.exception("ZooKeeper error for #{@op}(#{path}) ")
         
     | 
| 
      
 98 
     | 
    
         
            +
                        end
         
     | 
| 
      
 99 
     | 
    
         
            +
                        [ callback, error ,response, watch_type ] 
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                # NoNode error is expected for exists
         
     | 
| 
      
 104 
     | 
    
         
            +
                class ExistsPacket < Packet
         
     | 
| 
      
 105 
     | 
    
         
            +
                    def result(rc)
         
     | 
| 
      
 106 
     | 
    
         
            +
                        Error::NO_NODE === rc ? [ callback, nil, nil, :exists ] : super(rc)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                # In the normal case the close packet will be last and will get
         
     | 
| 
      
 111 
     | 
    
         
            +
                # cleared via disconnected() and :session_expired
         
     | 
| 
      
 112 
     | 
    
         
            +
                class ClosePacket < Packet
         
     | 
| 
      
 113 
     | 
    
         
            +
                    def result(rc)
         
     | 
| 
      
 114 
     | 
    
         
            +
                        Error::SESSION_EXPIRED == rc ? [ callback, nil, nil, nil ] : super(rc)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                
         
     | 
| 
      
 119 
     | 
    
         
            +
                # Returned by asynchronous calls
         
     | 
| 
      
 120 
     | 
    
         
            +
                # 
         
     | 
| 
      
 121 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 122 
     | 
    
         
            +
                #    op = zk.stat("\apath") { |stat| something_with_stat() }
         
     | 
| 
      
 123 
     | 
    
         
            +
                #
         
     | 
| 
      
 124 
     | 
    
         
            +
                #    op.on_error do |err|
         
     | 
| 
      
 125 
     | 
    
         
            +
                #      case err
         
     | 
| 
      
 126 
     | 
    
         
            +
                #      when ZK::Error::SESSION_EXPIRED 
         
     | 
| 
      
 127 
     | 
    
         
            +
                #           puts "Ignoring session expired"
         
     | 
| 
      
 128 
     | 
    
         
            +
                #      else
         
     | 
| 
      
 129 
     | 
    
         
            +
                #           raise err
         
     | 
| 
      
 130 
     | 
    
         
            +
                #      end
         
     | 
| 
      
 131 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 132 
     | 
    
         
            +
                #
         
     | 
| 
      
 133 
     | 
    
         
            +
                #    begin
         
     | 
| 
      
 134 
     | 
    
         
            +
                #       result_of_somthing_with_stat = op.value
         
     | 
| 
      
 135 
     | 
    
         
            +
                #    rescue StandardError => ex
         
     | 
| 
      
 136 
     | 
    
         
            +
                #       puts "Oops, my error handler raised an exception"
         
     | 
| 
      
 137 
     | 
    
         
            +
                #    end
         
     | 
| 
      
 138 
     | 
    
         
            +
                #
         
     | 
| 
      
 139 
     | 
    
         
            +
                #
         
     | 
| 
      
 140 
     | 
    
         
            +
                class AsyncOp
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                    attr_accessor :backtrace
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    # Provide an error callback. 
         
     | 
| 
      
 145 
     | 
    
         
            +
                    # @param block the error callback as a block
         
     | 
| 
      
 146 
     | 
    
         
            +
                    # @yieldparam [StandardError] the error raised by the zookeeper operation OR by its callback
         
     | 
| 
      
 147 
     | 
    
         
            +
                    def errback(&block)
         
     | 
| 
      
 148 
     | 
    
         
            +
                        set_error_handler(block)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                    # @param block the error callback as a Proc
         
     | 
| 
      
 152 
     | 
    
         
            +
                    def errback=(block)
         
     | 
| 
      
 153 
     | 
    
         
            +
                        set_error_handler(block)
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                    alias :on_error :errback
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                    # Wait for the async op to finish and returns its value
         
     | 
| 
      
 159 
     | 
    
         
            +
                    # will raise an exception if 
         
     | 
| 
      
 160 
     | 
    
         
            +
                    #    the operation itself fails and there is no error handler
         
     | 
| 
      
 161 
     | 
    
         
            +
                    #    the callback raises a StandardError and there is no error handler
         
     | 
| 
      
 162 
     | 
    
         
            +
                    #    the error handler raises StandardError
         
     | 
| 
      
 163 
     | 
    
         
            +
                    def value();
         
     | 
| 
      
 164 
     | 
    
         
            +
                        wait_value()
         
     | 
| 
      
 165 
     | 
    
         
            +
                        rescue ZooKeeper::Error => ex
         
     | 
| 
      
 166 
     | 
    
         
            +
                           # Set the backtrace to the original caller, rather than the ZK event loop
         
     | 
| 
      
 167 
     | 
    
         
            +
                           ex.set_backtrace(@backtrace) if @backtrace
         
     | 
| 
      
 168 
     | 
    
         
            +
                           raise ex
         
     | 
| 
      
 169 
     | 
    
         
            +
                    end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                    private
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                    def set_error_handler(blk)
         
     | 
| 
      
 174 
     | 
    
         
            +
                        raise NotImplementedError, ":wait_result to be privately implemented by binding"
         
     | 
| 
      
 175 
     | 
    
         
            +
                    end
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                    def wait_value();
         
     | 
| 
      
 178 
     | 
    
         
            +
                        raise NotImplementedError, ":wait_result to be privately implemented by binding"
         
     | 
| 
      
 179 
     | 
    
         
            +
                    end
         
     | 
| 
      
 180 
     | 
    
         
            +
                end
         
     | 
| 
      
 181 
     | 
    
         
            +
            end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     |