zookeeper-ng 1.5

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.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags_paths +1 -0
  3. data/.dotfiles/ruby-gemset +1 -0
  4. data/.dotfiles/ruby-version +1 -0
  5. data/.dotfiles/rvmrc +2 -0
  6. data/.gitignore +19 -0
  7. data/.gitmodules +3 -0
  8. data/.travis.yml +25 -0
  9. data/CHANGELOG +395 -0
  10. data/Gemfile +30 -0
  11. data/Guardfile +8 -0
  12. data/LICENSE +23 -0
  13. data/Manifest +29 -0
  14. data/README.markdown +85 -0
  15. data/Rakefile +121 -0
  16. data/cause-abort.rb +117 -0
  17. data/ext/.gitignore +6 -0
  18. data/ext/Rakefile +41 -0
  19. data/ext/c_zookeeper.rb +398 -0
  20. data/ext/common.h +17 -0
  21. data/ext/dbg.h +53 -0
  22. data/ext/depend +5 -0
  23. data/ext/event_lib.c +740 -0
  24. data/ext/event_lib.h +175 -0
  25. data/ext/extconf.rb +103 -0
  26. data/ext/generate_gvl_code.rb +321 -0
  27. data/ext/patches/zkc-3.3.5-network.patch +24 -0
  28. data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
  29. data/ext/patches/zkc-3.4.5-logging.patch +41 -0
  30. data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
  31. data/ext/patches/zkc-3.4.5-overflow.patch +11 -0
  32. data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
  33. data/ext/zkc-3.4.5.tar.gz +0 -0
  34. data/ext/zkrb.c +1075 -0
  35. data/ext/zkrb_wrapper.c +775 -0
  36. data/ext/zkrb_wrapper.h +350 -0
  37. data/ext/zkrb_wrapper_compat.c +15 -0
  38. data/ext/zkrb_wrapper_compat.h +11 -0
  39. data/ext/zookeeper_base.rb +256 -0
  40. data/java/java_base.rb +503 -0
  41. data/lib/zookeeper.rb +115 -0
  42. data/lib/zookeeper/acls.rb +44 -0
  43. data/lib/zookeeper/callbacks.rb +108 -0
  44. data/lib/zookeeper/client.rb +30 -0
  45. data/lib/zookeeper/client_methods.rb +282 -0
  46. data/lib/zookeeper/common.rb +122 -0
  47. data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
  48. data/lib/zookeeper/compatibility.rb +138 -0
  49. data/lib/zookeeper/constants.rb +97 -0
  50. data/lib/zookeeper/continuation.rb +223 -0
  51. data/lib/zookeeper/core_ext.rb +58 -0
  52. data/lib/zookeeper/em_client.rb +55 -0
  53. data/lib/zookeeper/exceptions.rb +135 -0
  54. data/lib/zookeeper/forked.rb +19 -0
  55. data/lib/zookeeper/latch.rb +34 -0
  56. data/lib/zookeeper/logger.rb +39 -0
  57. data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
  58. data/lib/zookeeper/monitor.rb +19 -0
  59. data/lib/zookeeper/rake_tasks.rb +165 -0
  60. data/lib/zookeeper/request_registry.rb +153 -0
  61. data/lib/zookeeper/stat.rb +21 -0
  62. data/lib/zookeeper/version.rb +4 -0
  63. data/notes.txt +14 -0
  64. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  65. data/spec/c_zookeeper_spec.rb +51 -0
  66. data/spec/chrooted_connection_spec.rb +83 -0
  67. data/spec/compatibilty_spec.rb +8 -0
  68. data/spec/default_watcher_spec.rb +41 -0
  69. data/spec/em_spec.rb +51 -0
  70. data/spec/ext/zookeeper_base_spec.rb +19 -0
  71. data/spec/forked_connection_spec.rb +124 -0
  72. data/spec/latch_spec.rb +24 -0
  73. data/spec/log4j.properties +17 -0
  74. data/spec/shared/all_success_return_values.rb +10 -0
  75. data/spec/shared/connection_examples.rb +1077 -0
  76. data/spec/spec_helper.rb +61 -0
  77. data/spec/support/00_logging.rb +38 -0
  78. data/spec/support/10_spawn_zookeeper.rb +24 -0
  79. data/spec/support/progress_formatter.rb +15 -0
  80. data/spec/support/zookeeper_spec_helpers.rb +96 -0
  81. data/spec/zookeeper_spec.rb +24 -0
  82. data/zookeeper.gemspec +38 -0
  83. data/zoomonkey/duplicates +3 -0
  84. data/zoomonkey/zoomonkey.rb +194 -0
  85. metadata +157 -0
@@ -0,0 +1,19 @@
1
+ module Zookeeper
2
+ module Forked
3
+ # the includer provides an 'original_pid' method, which is set
4
+ # when the original 'owning' process creates the object.
5
+ #
6
+ # @return [true] if the current PID differs from the original_pid value
7
+ # @return [false] if the current PID matches the original_pid value
8
+ #
9
+ def forked?
10
+ Process.pid != original_pid
11
+ end
12
+
13
+ # sets the `original_pid` to the current value
14
+ def update_pid!
15
+ self.original_pid = Process.pid
16
+ end
17
+ end # Forked
18
+ end # Zookeeper
19
+
@@ -0,0 +1,34 @@
1
+ module Zookeeper
2
+ # a cross-thread gate of sorts.
3
+ class Latch
4
+ def initialize(count = 1)
5
+ @count = count
6
+ @mutex = Monitor.new
7
+ @cond = @mutex.new_cond
8
+ end
9
+
10
+ def release
11
+ @mutex.synchronize {
12
+ @count -= 1 if @count > 0
13
+ @cond.broadcast if @count.zero?
14
+ }
15
+ end
16
+
17
+ def await(timeout=nil)
18
+ @mutex.synchronize do
19
+ if timeout
20
+ time_to_stop = Time.now + timeout
21
+
22
+ while @count > 0
23
+ @cond.wait(timeout)
24
+
25
+ break if (Time.now > time_to_stop)
26
+ end
27
+ else
28
+ @cond.wait_while { @count > 0 }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,39 @@
1
+ module Zookeeper
2
+ module Logger
3
+ def self.wrapped_logger
4
+ if defined?(@@wrapped_logger)
5
+ @@wrapped_logger
6
+ else
7
+ @@wrapped_logger = ::Logger.new(STDERR).tap { |l| l.level = ::Logger::FATAL }
8
+ end
9
+ end
10
+
11
+ def self.wrapped_logger=(log)
12
+ @@wrapped_logger = log
13
+ end
14
+
15
+ # @private
16
+ module ClassMethods
17
+ def logger
18
+ ::Zookeeper.logger || ForwardingLogger.for(::Zookeeper::Logger.wrapped_logger, _zk_logger_name)
19
+ end
20
+ end
21
+
22
+ def self.included(base)
23
+ # return false if base < self # avoid infinite recursion
24
+ base.extend(ClassMethods)
25
+ end
26
+
27
+ private
28
+ def log_realtime(what)
29
+ logger.debug do
30
+ t = Benchmark.realtime { yield }
31
+ "#{what} took #{t} sec"
32
+ end
33
+ end
34
+
35
+ def logger
36
+ @logger ||= (::Zookeeper.logger || self.class.logger)
37
+ end
38
+ end # Logger
39
+ end # Zookeeper
@@ -0,0 +1,84 @@
1
+ module Zookeeper
2
+ module Logger
3
+ # h/t _eric and Papertrail
4
+ # @private
5
+ class ForwardingLogger
6
+ attr_accessor :level, :formatter
7
+
8
+ @@mutex = Monitor.new unless defined?(@@mutex)
9
+ @@loggers = {} unless defined?(@@loggers)
10
+
11
+ def self.for(logger, name)
12
+ @@mutex.synchronize do
13
+ @@loggers.fetch(name) do |k|
14
+ @@loggers[k] = new(logger, :formatter => lambda { |m| "%25.25s: %s" % [k, m] })
15
+ end
16
+ end
17
+ end
18
+
19
+ def initialize(logger, options = {})
20
+ @level = ::Logger::DEBUG
21
+ @logger = logger
22
+ @formatter = options[:formatter]
23
+ end
24
+
25
+ def add(severity, message = nil, progname = nil, &block)
26
+ severity ||= ::Logger::UNKNOWN
27
+ if !@logger || severity < @level
28
+ return true
29
+ end
30
+
31
+ message = (message || (block && block.call) || progname).to_s
32
+
33
+ if @formatter && @formatter.respond_to?(:call)
34
+ message = @formatter.call(message)
35
+ end
36
+
37
+ # If a newline is necessary then create a new message ending with a newline.
38
+ # Ensures that the original message is not mutated.
39
+ # message = "#{message}\n" unless message[-1] == ?\n
40
+
41
+ @logger.add(severity, message)
42
+ end
43
+
44
+ def <<(msg); @logger << msg; end
45
+ def write(msg); @logger.write(msg); end
46
+
47
+ def debug(progname = nil, &block)
48
+ add(::Logger::DEBUG, nil, progname, &block)
49
+ end
50
+
51
+ def info(progname = nil, &block)
52
+ add(::Logger::INFO, nil, progname, &block)
53
+ end
54
+
55
+ def warn(progname = nil, &block)
56
+ add(::Logger::WARN, nil, progname, &block)
57
+ end
58
+
59
+ def error(progname = nil, &block)
60
+ add(::Logger::ERROR, nil, progname, &block)
61
+ end
62
+
63
+ def fatal(progname = nil, &block)
64
+ add(::Logger::FATAL, nil, progname, &block)
65
+ end
66
+
67
+ def unknown(progname = nil, &block)
68
+ add(::Logger::UNKNOWN, nil, progname, &block)
69
+ end
70
+
71
+ def debug?; @level <= DEBUG; end
72
+
73
+ def info?; @level <= INFO; end
74
+
75
+ def warn?; @level <= WARN; end
76
+
77
+ def error?; @level <= ERROR; end
78
+
79
+ def fatal?; @level <= FATAL; end
80
+ end # ForwardingLogger
81
+ end # Logger
82
+ end # Zookeeper
83
+
84
+
@@ -0,0 +1,19 @@
1
+ module Zookeeper
2
+ # just like stdlib Monitor but provides the SAME API AS MUTEX, FFS!
3
+ class Monitor
4
+ include MonitorMixin
5
+
6
+ alias try_enter try_mon_enter
7
+ alias enter mon_enter
8
+ alias exit mon_exit
9
+
10
+ # here, HERE!
11
+ # *here* are the methods that are the same
12
+ # god *dammit*
13
+
14
+ alias lock mon_enter
15
+ alias unlock mon_exit
16
+ alias try_lock try_mon_enter
17
+ end
18
+ end
19
+
@@ -0,0 +1,165 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module Zookeeper
5
+ # @private
6
+ module RakeTasks
7
+ def self.define_test_tasks_for(*rubies)
8
+ rubies.each do |r|
9
+
10
+ TestOneRuby.new(:name => r) do |tor|
11
+ yield tor if block_given?
12
+ end
13
+ end
14
+ end
15
+
16
+ class TestOneRuby < ::Rake::TaskLib
17
+ include ::Rake::DSL if defined?(::Rake::DSL)
18
+
19
+ DEFAULT_RVM_RUBY_NAME = '1.9.3'
20
+
21
+ # defaults to 'zk', test tasks will be built under this
22
+ attr_accessor :namespace
23
+
24
+ # the name of the task
25
+ # (tasks will be 'zk:1.9.3:run_rspec')
26
+ #
27
+ # this is mainly here so that the rvm ruby name rbx-2.0.testing
28
+ # will have its tasks defined as 'zk:rbx'
29
+ attr_accessor :name
30
+
31
+ # what is the rvm name we should use for testing? (i.e. could be an alias)
32
+ # defaults to {#name}
33
+ attr_accessor :rvm_ruby_name
34
+
35
+ # any extra environment variables?
36
+ attr_accessor :env
37
+
38
+ # gemset name to use, deafults to the name of the gemspec in the top of the
39
+ # project directory (minus the .gempsec)
40
+ attr_accessor :gemset_name
41
+
42
+ # @private
43
+ attr_reader :ruby_with_gemset,
44
+ :create_gemset_name,
45
+ :clobber_task_name,
46
+ :clean_task_name,
47
+ :build_task_name,
48
+ :bundle_task_name,
49
+ :rspec_task_name,
50
+ :phony_gemfile_link_name,
51
+ :phony_gemfile_lock_name
52
+
53
+
54
+ def self.default_gemset_name
55
+ ary = Dir['*.gemspec']
56
+ raise 'No gemspec found' if ary.empty?
57
+ ary.first[/(.+)\.gemspec\Z/, 1]
58
+ end
59
+
60
+ def initialize(opts={})
61
+ @namespace = 'zk'
62
+ @name = nil
63
+ @env = {}
64
+ @rvm_ruby_name = nil
65
+ @gemset_name = nil
66
+
67
+ opts.each { |k,v| __send__(:"#{k}=", v) }
68
+
69
+ yield self if block_given?
70
+
71
+ @gemset_name ||= self.class.default_gemset_name
72
+
73
+ # XXX: add an exception just for me in here (yes, i know this is naughty)
74
+ # or else i'd have to do this in every zk variant i want to test
75
+ # (like i have to now)
76
+
77
+ unless @rvm_ruby_name
78
+ @rvm_ruby_name = 'rbx-2.0.testing' if @name == 'rbx'
79
+ end
80
+
81
+ @rvm_ruby_name ||= name
82
+
83
+ @ruby_with_gemset = "#{@rvm_ruby_name}@#{@gemset_name}"
84
+ @create_gemset_name = "#{namespace}:#{name}:create_gemset"
85
+ @clobber_task_name = "#{namespace}:#{name}:clobber"
86
+ @clean_task_name = "#{namespace}:#{name}:clean"
87
+ @build_task_name = "#{namespace}:#{name}:build"
88
+ @bundle_task_name = "#{namespace}:#{name}:bundle_install"
89
+ @rspec_task_name = "#{namespace}:#{name}:run_rspec"
90
+ @phony_gemfile_link_name = "Gemfile.#{name}"
91
+ @phony_gemfile_lock_name = "#{phony_gemfile_link_name}.lock"
92
+
93
+ define_tasks
94
+ end
95
+
96
+ private
97
+ def need_ext_build?
98
+ name != 'jruby' && File.directory?('./ext')
99
+ end
100
+
101
+ def define_tasks
102
+ file phony_gemfile_link_name do
103
+ # apparently, rake doesn't deal with symlinks intelligently :P
104
+ ln_s('Gemfile', phony_gemfile_link_name) unless File.symlink?(phony_gemfile_link_name)
105
+ end
106
+
107
+ task :clean do
108
+ rm_rf [phony_gemfile_lock_name, phony_gemfile_lock_name]
109
+ end
110
+
111
+ task create_gemset_name do
112
+ sh "rvm #{rvm_ruby_name} do rvm gemset create #{gemset_name}"
113
+ end
114
+
115
+ task clobber_task_name do
116
+ if need_ext_build?
117
+ cd 'ext' do
118
+ sh "rake clobber"
119
+ end
120
+ end
121
+ end
122
+
123
+ task clean_task_name do
124
+ if need_ext_build?
125
+ cd 'ext' do
126
+ sh "rake clean"
127
+ end
128
+ end
129
+ end
130
+
131
+ task build_task_name => [create_gemset_name, clean_task_name] do
132
+ if need_ext_build?
133
+ cd 'ext' do
134
+ sh "rvm #{ruby_with_gemset} do rake build"
135
+ end
136
+ end
137
+ end
138
+
139
+ task bundle_task_name => [phony_gemfile_link_name, build_task_name] do
140
+ sh "rvm #{ruby_with_gemset} do bundle install --gemfile #{phony_gemfile_link_name}"
141
+ end
142
+
143
+ task rspec_task_name => bundle_task_name do
144
+ sh "rvm #{ruby_with_gemset} do env BUNDLE_GEMFILE=#{phony_gemfile_link_name} bundle exec rspec spec --fail-fast"
145
+ end
146
+
147
+ task "#{namespace}:#{name}" => rspec_task_name
148
+
149
+ task "#{namespace}:test_all_rubies" => rspec_task_name
150
+
151
+ unless Rake::Task.task_defined?("#{namespace}:test_all")
152
+ task "#{namespace}:test_all" do
153
+ require 'benchmark'
154
+ t = Benchmark.realtime do
155
+ Rake::Task["#{namespace}:test_all_rubies"].invoke
156
+ end
157
+
158
+ $stderr.puts "Test run took: #{t} s"
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
165
+
@@ -0,0 +1,153 @@
1
+ module Zookeeper
2
+ class RequestRegistry
3
+ include Constants
4
+ include Logger
5
+
6
+ # @param [Hash] opts
7
+ # @option opts [String] :chroot_path (nil) if given, will be used to
8
+ # correct a discrepancy between the C and Java clients when using a
9
+ # chrooted connection. If given, the chroot path will be stripped from
10
+ # the string returned by a `create`. It should be an absolute path.
11
+ #
12
+ def initialize(watcher, opts={})
13
+ @mutex = Monitor.new
14
+
15
+ @default_watcher = watcher
16
+
17
+ @current_req_id = 0
18
+ @watcher_reqs = {}
19
+ @completion_reqs = {}
20
+
21
+ @chroot_path = opts[:chroot_path]
22
+ end
23
+
24
+ def default_watcher
25
+ @mutex.synchronize { @default_watcher }
26
+ end
27
+
28
+ def default_watcher=(blk)
29
+ @mutex.synchronize { @default_watcher = blk }
30
+ end
31
+
32
+ def setup_call(meth_name, opts)
33
+ req_id = nil
34
+ @mutex.synchronize {
35
+ req_id = @current_req_id
36
+ @current_req_id += 1
37
+ setup_completion(req_id, meth_name, opts) if opts[:callback]
38
+ setup_watcher(req_id, opts) if opts[:watcher]
39
+ }
40
+ req_id
41
+ end
42
+
43
+ def get_context_for(hash)
44
+ return nil unless hash
45
+
46
+ is_session_event = (hash[:type] == ZOO_SESSION_EVENT)
47
+
48
+ req_id = hash.fetch(:req_id)
49
+
50
+ if hash.has_key?(:rc)
51
+ get_completion(req_id, :keep => is_session_event)
52
+ else
53
+ get_watcher(req_id, :keep => is_session_event)
54
+ end
55
+ end
56
+
57
+ def clear_watchers!
58
+ @mutex.synchronize { @watcher_reqs.clear }
59
+ end
60
+
61
+ # if we're chrooted, this method will strip the chroot prefix from +path+
62
+ def strip_chroot_from(path)
63
+ return path unless (chrooted? and path and path.start_with?(@chroot_path))
64
+ path[@chroot_path.length..-1]
65
+ end
66
+
67
+ private
68
+ def get_completion(req_id, opts={})
69
+ @mutex.synchronize do
70
+ if opts[:keep]
71
+ @completion_reqs[req_id]
72
+ else
73
+ @completion_reqs.delete(req_id)
74
+ end
75
+ end
76
+ end
77
+
78
+ # Return the watcher hash associated with the req_id. If the req_id
79
+ # is the ZKRB_GLOBAL_CB_REQ, then does not clear the req from the internal
80
+ # store, otherwise the req_id is removed.
81
+ #
82
+ def get_watcher(req_id, opts={})
83
+ @mutex.synchronize do
84
+ if Constants::ZKRB_GLOBAL_CB_REQ == req_id
85
+ { :watcher => @default_watcher, :watcher_context => nil }
86
+ elsif opts[:keep]
87
+ @watcher_reqs[req_id]
88
+ else
89
+ @watcher_reqs.delete(req_id)
90
+ end
91
+ end
92
+ end
93
+
94
+
95
+ def setup_watcher(req_id, call_opts)
96
+ @mutex.synchronize do
97
+ @watcher_reqs[req_id] = {
98
+ :watcher => call_opts[:watcher],
99
+ :context => call_opts[:watcher_context]
100
+ }
101
+ end
102
+ end
103
+
104
+ # as a hack, to provide consistency between the java implementation and the C
105
+ # implementation when dealing w/ chrooted connections, we override this in
106
+ # ext/zookeeper_base.rb to wrap the callback in a chroot-path-stripping block.
107
+ #
108
+ # we don't use meth_name here, but we need it in the C implementation
109
+ #
110
+ def setup_completion(req_id, meth_name, call_opts)
111
+ @mutex.synchronize do
112
+ @completion_reqs[req_id] = {
113
+ :callback => maybe_wrap_callback(meth_name, call_opts[:callback]),
114
+ :context => call_opts[:callback_context]
115
+ }
116
+ end
117
+ end
118
+
119
+ # this is a hack: to provide consistency between the C and Java drivers when
120
+ # using a chrooted connection, we wrap the callback in a block that will
121
+ # strip the chroot path from the returned path (important in an async create
122
+ # sequential call). This is the only place where we can hook *just* the C
123
+ # version. The non-async manipulation is handled in ZookeeperBase#create.
124
+ #
125
+ # TODO: need to move the continuation setup into here, so that it can get
126
+ # added to the callback hash
127
+ #
128
+ def maybe_wrap_callback(meth_name, cb)
129
+ return cb unless cb and chrooted? and (meth_name == :create)
130
+
131
+ lambda do |hash|
132
+ # in this case the string will be the absolute zookeeper path (i.e.
133
+ # with the chroot still prepended to the path). Here's where we strip it off
134
+ hash[:string] = strip_chroot_from(hash[:string])
135
+
136
+ # call the original callback
137
+ cb.call(hash)
138
+ end
139
+ end
140
+
141
+ def chrooted?
142
+ @chroot_path && !@chroot_path.empty?
143
+ end
144
+
145
+ def default_watcher_proc
146
+ Proc.new { |args|
147
+ logger.debug { "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}" }
148
+ true
149
+ }
150
+ end
151
+ end
152
+ end
153
+