zookeeper 0.9.3-java

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 (53) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +119 -0
  3. data/Gemfile +17 -0
  4. data/LICENSE +23 -0
  5. data/Manifest +29 -0
  6. data/README.markdown +59 -0
  7. data/Rakefile +139 -0
  8. data/examples/cloud_config.rb +125 -0
  9. data/ext/.gitignore +6 -0
  10. data/ext/Rakefile +51 -0
  11. data/ext/c_zookeeper.rb +212 -0
  12. data/ext/dbg.h +53 -0
  13. data/ext/depend +5 -0
  14. data/ext/extconf.rb +85 -0
  15. data/ext/generate_gvl_code.rb +316 -0
  16. data/ext/zkc-3.3.5.tar.gz +0 -0
  17. data/ext/zkrb_wrapper.c +731 -0
  18. data/ext/zkrb_wrapper.h +330 -0
  19. data/ext/zkrb_wrapper_compat.c +15 -0
  20. data/ext/zkrb_wrapper_compat.h +11 -0
  21. data/ext/zookeeper_base.rb +211 -0
  22. data/ext/zookeeper_c.c +725 -0
  23. data/ext/zookeeper_lib.c +677 -0
  24. data/ext/zookeeper_lib.h +172 -0
  25. data/java/zookeeper_base.rb +477 -0
  26. data/lib/zookeeper.rb +297 -0
  27. data/lib/zookeeper/acls.rb +40 -0
  28. data/lib/zookeeper/callbacks.rb +91 -0
  29. data/lib/zookeeper/common.rb +174 -0
  30. data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
  31. data/lib/zookeeper/constants.rb +57 -0
  32. data/lib/zookeeper/em_client.rb +55 -0
  33. data/lib/zookeeper/exceptions.rb +100 -0
  34. data/lib/zookeeper/stat.rb +21 -0
  35. data/lib/zookeeper/version.rb +6 -0
  36. data/notes.txt +14 -0
  37. data/spec/c_zookeeper_spec.rb +50 -0
  38. data/spec/chrooted_connection_spec.rb +81 -0
  39. data/spec/default_watcher_spec.rb +41 -0
  40. data/spec/em_spec.rb +51 -0
  41. data/spec/log4j.properties +17 -0
  42. data/spec/shared/all_success_return_values.rb +10 -0
  43. data/spec/shared/connection_examples.rb +1018 -0
  44. data/spec/spec_helper.rb +119 -0
  45. data/spec/support/progress_formatter.rb +15 -0
  46. data/spec/zookeeper_spec.rb +24 -0
  47. data/test/test_basic.rb +37 -0
  48. data/test/test_callback1.rb +36 -0
  49. data/test/test_close.rb +16 -0
  50. data/test/test_esoteric.rb +7 -0
  51. data/test/test_watcher1.rb +56 -0
  52. data/test/test_watcher2.rb +52 -0
  53. metadata +181 -0
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *.gem
2
+ *.o
3
+ *.so
4
+ *~
5
+ *.log
6
+ Makefile
7
+ pkg
8
+ zookeeper.gemspec
9
+ Gemfile.*
10
+ tmp/
data/CHANGELOG ADDED
@@ -0,0 +1,119 @@
1
+ v0.9.3 Event thread shutdown fix, Windows compatibility fix
2
+
3
+ * Use a 'shutdown thread' to coordinate cleanup if close is called from the
4
+ event thread (prevents deadlock)
5
+
6
+ * Default Logger now uses $stderr instead of opening /dev/null [#16]
7
+
8
+ * Gemfile/gemspec/Rakefile refactoring.
9
+
10
+ v0.9.2 More efficient and simpler wrappers for GIL release
11
+
12
+ * After a code review by Andrew Wason (rectalogic), use a much simpler
13
+ technique for creating the arg structs and passing them to the
14
+ zkrb_gvl_* functions. No malloc(), no free(), no problem.
15
+
16
+ v0.9.1 see v0.8.4 notes, same patch
17
+
18
+ v0.9.0 RELEASE THE KRAK..er, GIL!!
19
+
20
+ * In >= 1.9.2 the ruby interpreter allows you to release the GIL when
21
+ calling into native code, sounds like a good idea.
22
+
23
+ This release makes use of that code by parsing the zookeeper.h header file
24
+ and extracting the method signatures of all relevant zoo_* functions, then
25
+ generating boilerplate that allows us to call those functions via the
26
+ rb_thread_blocking_region function.
27
+
28
+ 1.8.7 compatibility is maintained by stubbing out that functionality if built
29
+ under 1.8.7.
30
+
31
+ * 1.8.7 is deprecated! I will continue to support 1.8.7 for the near future
32
+ but sometime soon, you're gonna have to upgrade.
33
+
34
+ v0.8.4 fix NameError, require 'forwardable'
35
+
36
+ * Really not sure why this didn't come up in tests
37
+
38
+ * issue here https://github.com/slyphon/zk/issues/22
39
+
40
+ v0.8.3 fix NonLocalJump exception in event delivery thread shutdown code
41
+
42
+ * hit a corner case where we're waiting for the zkc handle setup
43
+ and the user decides to shutdown, but before we've had a chance
44
+ to enter the delivery loop.
45
+
46
+ * Cleaned up some nasty code in ZookeeperConstants
47
+
48
+ * removed ZookeeperConstants#print_events and ZookeeperConstants#print_states
49
+
50
+ * changed EVENT_TYPE_NAMES and EVENT_STATE_NAMES in ZookeeperConstants
51
+ to use string values instead of symbols
52
+
53
+ v0.8.2 fix close after a fork()
54
+
55
+ * The dispatch thread will be dead in this situation, so we need to
56
+ check to see if it's already dead before waiting on it to exit.
57
+
58
+ v0.8.1 Java client fix, silence warnings
59
+
60
+ v0.8.0 Refactor C implementaion, EventMachine client
61
+
62
+ * separated CZookeeper and ZookeeperBase implementation
63
+
64
+ This solves issues with reopen not working properly, makes for a much
65
+ cleaner event delivery implementation. ZookeeperBase controls the lifecycle
66
+ of the event dispatch thread now, rather than it being tied to CZookeeper.
67
+
68
+ * added support for the 'sync' API call
69
+
70
+ * Refactored zookeeper_c.c and zookeeper_lib.c
71
+
72
+ More error checking in zookeeper_lib.c and restructure some things to make
73
+ logic easier to follow
74
+
75
+ Fix bug in method_get_next_event that made the shutdown case so complicated
76
+
77
+ * Massively simplified EMClient implementation
78
+
79
+ Rather than trying to hook the IO used by zookeeper_lib to notify zookeeper_c
80
+ about event availabiltiy directly into EventMachine, use the same event delivery
81
+ thread, but wrap the dispatch call in EM.schedule.
82
+
83
+ * Improve implementation of spin-lock-esque code that waits for the connection to be
84
+ established before returning.
85
+
86
+ This cut the test runtime down from 1m 20s to 2s.
87
+
88
+ * Java client refactoring, similar correctness changes
89
+
90
+ * Change ZookeeperException base class to StandardError instead of Exception
91
+
92
+
93
+ v0.4.5 Upgrade to ZooKeeper 3.3.3
94
+
95
+ v0.4.4 Fix race condition on close, possible data corruption on async get.
96
+
97
+ v0.4.3 Fix a handful of memory-related bugs, fix SIGSEGV on master change, reduce latency of event handling, fix compilation on OSX.
98
+
99
+ v0.4.2 Add options to Zookeeper#initialize, silence most Zookeeper logs.
100
+
101
+ v0.4.1 Upgrade to ZooKeeper 3.3.2
102
+
103
+ v0.4.0. More attr-readers (StarvingMarvin) and 1.9 compatibility (tsuraan)
104
+
105
+ v0.3.2. Handle close, closed connections and expired sessions a little more gracefully.
106
+
107
+ v0.3.1. ACL bugfix.
108
+
109
+ v0.3.0. Wickman's rewrite, breaks dependencies from myelin/emaland port.
110
+
111
+ v0.2.2. Fix compatibility with stock Leopard fat-binary Ruby.
112
+
113
+ v0.2.1. No more camelcase classname.
114
+
115
+ v0.2. Bundle C dependencies, like memcached.gem.
116
+
117
+ v0.1. First release.
118
+
119
+ # vim:ft=text:ts=2:sw=2:et
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "rspec", "~> 2.8.0"
7
+ gem 'flexmock', '~> 0.8.11'
8
+ gem 'eventmachine', '1.0.0.beta.4'
9
+ gem 'evented-spec', '~> 0.9.0'
10
+ end
11
+
12
+ group :development do
13
+ gem 'rake', '~> 0.9.0'
14
+ gem 'pry'
15
+ end
16
+
17
+ # vim:ft=ruby
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ (The MIT License)
2
+
3
+ Copyright (C) 2008 Phillip Pearson
4
+ Copyright (C) 2010 Twitter, Inc.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ 'Software'), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,29 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README
5
+ Rakefile
6
+ examples/cloud_config.rb
7
+ ext/extconf.rb
8
+ ext/zkc-3.3.4.tar.gz
9
+ ext/zookeeper_base.rb
10
+ ext/zookeeper_c.c
11
+ ext/zookeeper_lib.c
12
+ ext/zookeeper_lib.h
13
+ java/zookeeper_base.rb
14
+ lib/zookeeper.rb
15
+ lib/zookeeper/acls.rb
16
+ lib/zookeeper/callbacks.rb
17
+ lib/zookeeper/common.rb
18
+ lib/zookeeper/constants.rb
19
+ lib/zookeeper/exceptions.rb
20
+ lib/zookeeper/stat.rb
21
+ spec/log4j.properties
22
+ spec/spec_helper.rb
23
+ spec/zookeeper_spec.rb
24
+ test/test_basic.rb
25
+ test/test_callback1.rb
26
+ test/test_close.rb
27
+ test/test_esoteric.rb
28
+ test/test_watcher1.rb
29
+ test/test_watcher2.rb
data/README.markdown ADDED
@@ -0,0 +1,59 @@
1
+ # zookeeper #
2
+
3
+ An interface to the Zookeeper cluster coordination server.
4
+
5
+ For a higher-level interface with a more convenient API and features such as locks, have a look at [ZK](https://github.com/slyphon/zk) (also available is [ZK-EventMachine](https://github.com/slyphon/zk-eventmachine) for those who prefer async).
6
+
7
+ ## Big Plans for 1.0 ##
8
+
9
+ The 1.0 release will feature a reorganization of the heirarchy. There will be a single top-level `Zookeeper` namespace (as opposed to the current layout, with 5-6 different top-level constants), and for the next several releases, there will be a backwards compatible require for users that still need to use the old names.
10
+
11
+ ## License
12
+
13
+ Copyright 2008 Phillip Pearson, and 2010 Twitter, Inc.
14
+ Licensed under the MIT License. See the included LICENSE file.
15
+
16
+ Portions copyright 2008-2010 the Apache Software Foundation, licensed under the
17
+ Apache 2 license, and used with permission.
18
+
19
+ Portions contributed to the open source community by HPDC, L.P.
20
+
21
+ ## Install
22
+
23
+ sudo gem install zookeeper
24
+
25
+ ## Usage
26
+
27
+ Connect to a server:
28
+
29
+ require 'rubygems'
30
+ require 'zookeeper'
31
+ z = Zookeeper.new("localhost:2181")
32
+ z.get_children(:path => "/")
33
+
34
+ ## Idioms
35
+
36
+ The following methods are initially supported:
37
+ * get
38
+ * set
39
+ * get\_children
40
+ * stat
41
+ * create
42
+ * delete
43
+ * get\_acl
44
+ * set\_acl
45
+
46
+ All support async callbacks. get, get\_children and stat support both watchers and callbacks.
47
+
48
+ Calls take a dictionary of parameters. With the exception of set\_acl, the only required parameter is :path. Each call returns a dictionary with at minimum two keys :req\_id and :rc.
49
+
50
+ ### A Bit about this repository ###
51
+
52
+ Twitter's open source office was kind enough to transfer this repository to facilitate development and administration of this repository. The `zookeeper` gem's last three releases were recorded in branches `v0.4.2`, `v0.4.3` and `v0.4.4`. Releases of the `slyphon-zookeeper` gem were cut off of the fork, and unfortunately (due to an oversight on my part) were tagged with unrelated versions. Those were tagged with names `release/0.9.2`.
53
+
54
+ The plan is to keep the `slyphon-zookeeper` tags, and to tag the `zookeeper` releases `twitter/release/0.4.x`.
55
+
56
+ Further work will be carried out on this repository. The `0.9.3` release of the zookeeper gem will be released under the 'zookeeper' name, and will bring the two divergent (conceptual) branches of development together.
57
+
58
+
59
+
data/Rakefile ADDED
@@ -0,0 +1,139 @@
1
+ # def gemset_name
2
+ # ENV.fetch('GEM_HOME').split('@').last
3
+ # end
4
+
5
+ GEM_FILES = FileList['slyphon-zookeeper-*.gem']
6
+
7
+ namespace :mb do
8
+ namespace :gems do
9
+ task :build do
10
+ sh "rvm 1.8.7 do gem build zookeeper.gemspec"
11
+ ENV['JAVA_GEM'] = '1'
12
+ sh "rvm 1.8.7 do gem build zookeeper.gemspec"
13
+ end
14
+
15
+ task :push do
16
+ GEM_FILES.each do |gem|
17
+ sh "gem push #{gem}"
18
+ end
19
+ end
20
+
21
+ task :clean do
22
+ rm_rf GEM_FILES
23
+ end
24
+
25
+ task :all => [:build, :push, :clean]
26
+ end
27
+ end
28
+
29
+ gemset_name = 'zookeeper'
30
+
31
+ # this nonsense w/ tmp and the Gemfile is a bundler optimization
32
+
33
+ %w[1.8.7 1.9.2 jruby rbx 1.9.3].each do |ns_name|
34
+ rvm_ruby = (ns_name == 'rbx') ? "rbx-2.0.testing" : ns_name
35
+
36
+ ruby_with_gemset = "#{rvm_ruby}@#{gemset_name}"
37
+
38
+ create_gemset_name = "mb:#{ns_name}:create_gemset"
39
+ clobber_task_name = "mb:#{ns_name}:clobber"
40
+ clean_task_name = "mb:#{ns_name}:clean"
41
+ build_task_name = "mb:#{ns_name}:build"
42
+ bundle_task_name = "mb:#{ns_name}:bundle_install"
43
+ rspec_task_name = "mb:#{ns_name}:run_rspec"
44
+
45
+ phony_gemfile_link_name = "Gemfile.#{ns_name}"
46
+ phony_gemfile_lock_name = "#{phony_gemfile_link_name}.lock"
47
+
48
+ file phony_gemfile_link_name do
49
+ # apparently, rake doesn't deal with symlinks intelligently :P
50
+ ln_s('Gemfile', phony_gemfile_link_name) unless File.symlink?(phony_gemfile_link_name)
51
+ end
52
+
53
+ task :clean do
54
+ rm_rf [phony_gemfile_lock_name, phony_gemfile_lock_name]
55
+ end
56
+
57
+ task create_gemset_name do
58
+ sh "rvm #{rvm_ruby} do rvm gemset create #{gemset_name}"
59
+ end
60
+
61
+ task clobber_task_name do
62
+ unless rvm_ruby == 'jruby'
63
+ cd 'ext' do
64
+ sh "rake clobber"
65
+ end
66
+ end
67
+ end
68
+
69
+ task clean_task_name do
70
+ unless rvm_ruby == 'jruby'
71
+ cd 'ext' do
72
+ sh "rake clean"
73
+ end
74
+ end
75
+ end
76
+
77
+ task build_task_name => [create_gemset_name, clean_task_name] do
78
+ unless rvm_ruby == 'jruby'
79
+ cd 'ext' do
80
+ sh "rvm #{ruby_with_gemset} do rake build"
81
+ end
82
+ end
83
+ end
84
+
85
+ task bundle_task_name => [phony_gemfile_link_name, build_task_name] do
86
+ sh "rvm #{ruby_with_gemset} do bundle install --gemfile #{phony_gemfile_link_name}"
87
+ end
88
+
89
+ task rspec_task_name => bundle_task_name do
90
+ sh "rvm #{ruby_with_gemset} do env BUNDLE_GEMFILE=#{phony_gemfile_link_name} bundle exec rspec spec --fail-fast"
91
+ end
92
+
93
+ task "mb:#{ns_name}" => rspec_task_name
94
+
95
+ task "mb:test_all_rubies" => rspec_task_name
96
+ end
97
+
98
+ task "mb:test_all" do
99
+ require 'benchmark'
100
+ t = Benchmark.realtime do
101
+ Rake::Task['mb:test_all_rubies'].invoke
102
+ end
103
+
104
+ $stderr.puts "Test run took: #{t} s"
105
+ end
106
+
107
+ task :default => 'mb:1.9.3'
108
+
109
+ task :clobber do
110
+ rm_rf 'tmp'
111
+ end
112
+
113
+ # cargo culted from http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
114
+ VALGRIND_BASIC_OPTS = '--num-callers=50 --error-limit=no --partial-loads-ok=yes --undef-value-errors=no'
115
+
116
+ task 'valgrind' do
117
+ cd 'ext' do
118
+ sh "rake clean build"
119
+ end
120
+
121
+ sh "valgrind #{VALGRIND_BASIC_OPTS} bundle exec rspec spec"
122
+ end
123
+
124
+ namespace :build do
125
+ task :clean do
126
+ cd 'ext' do
127
+ sh 'rake clean'
128
+ end
129
+
130
+ Rake::Task['build'].invoke
131
+ end
132
+ end
133
+
134
+ task :build do
135
+ cd 'ext' do
136
+ sh "rake"
137
+ end
138
+ end
139
+
@@ -0,0 +1,125 @@
1
+ require "rubygems"
2
+ require "zookeeper"
3
+
4
+ # A basic cloud-based YAML config library. Ruby Zookeeper client example.
5
+ #
6
+ # If you pass in a file as 'zk:/foo.yml/blah' it will go out to zookeeper.
7
+ # Otherwise the file is assumed to be local. The yml file will get parsed
8
+ # and cached locally, and keys after the .yml get interpreted as keys into
9
+ # the YAML.
10
+ #
11
+ # e.g. get(zk:/config/service.yml/key1/key2/key3..) =>
12
+ # zk.get(:path => /config/service.yml)
13
+ # yaml <= YAML.parse(data)
14
+ # yaml[key1][key2][key3]...
15
+ #
16
+ # If keys are unspecified, it returns the parsed YAML as one big object
17
+ #
18
+ # TODO if staleness is set to 0, read in YAML immediately before next
19
+ # get(...)
20
+
21
+ class CloudConfig
22
+ class NodeNotFound < StandardError; end
23
+ class BadPathError < StandardError; end
24
+
25
+ DEFAULT_SERVERS = "localhost:2181"
26
+
27
+ def initialize(zkservers = DEFAULT_SERVERS, staleness = 15) # maximum allowed staleness in seconds
28
+ @staleness = staleness
29
+ @lock = Mutex.new
30
+ @zkservers = DEFAULT_SERVERS
31
+
32
+ # cache
33
+ @data = {}
34
+ @zkcb = Zookeeper::WatcherCallback.new { dirty_callback(@zkcb.context) }
35
+ @zk = nil
36
+ end
37
+
38
+ def get(node)
39
+ filename, keys = extract_filename(node)
40
+
41
+ # read(filename) is potentially a zk call, so do not hold the lock during the read
42
+ if @lock.synchronize { !@data.has_key?(filename) }
43
+ d = YAML.load(read(filename))
44
+ @lock.synchronize { @data[filename] = d }
45
+ end
46
+
47
+ # synchronized b/c we potentially have a background thread updating data nodes from zk
48
+ # if keys is empty, return the whole file, otherwise roll up the keys
49
+ @lock.synchronize {
50
+ keys.empty? ? @data[filename] : keys.inject(@data[filename]) { |hash, key| hash[key] }
51
+ }
52
+ end
53
+
54
+ # todo:
55
+ # factor get-and-watch into a different subsystem (so you can have
56
+ # polling stat() ops on local filesystem.)
57
+ def read(yaml)
58
+ # read yaml file and register watcher. if watcher fires, set up
59
+ # background thread to do read and update data.
60
+ if yaml.match(/^zk:/)
61
+ @zk ||= init_zk
62
+ yaml = yaml['zk:'.length..-1] # strip off zk: from zk:/config/path.yml
63
+ resp = get_and_register(yaml)
64
+
65
+ if resp[:rc] != Zookeeper::ZOK
66
+ @zk.unregister_watcher(resp[:req_id])
67
+ raise NodeNotFound
68
+ end
69
+
70
+ resp[:data]
71
+ else
72
+ raise NodeNotFound unless File.exists?(yaml)
73
+ File.read(yaml)
74
+ end
75
+ end
76
+
77
+ def extract_filename(node)
78
+ path_elements = node.split("/")
79
+
80
+ yamlindex = path_elements.map{ |x| x.match("\.yml$") != nil }.index(true)
81
+ raise BadPathError unless yamlindex
82
+
83
+ yamlname = path_elements[0..yamlindex].join '/'
84
+ yamlkeys = path_elements[(yamlindex+1)..-1]
85
+
86
+ return yamlname, yamlkeys
87
+ end
88
+
89
+ private
90
+ def init_zk
91
+ Zookeeper.new(@zkservers)
92
+ end
93
+
94
+ def get_and_register(znode)
95
+ @zk.get(:path => znode, :watcher => @zkcb,
96
+ :watcher_context => { :path => znode,
97
+ :wait => rand(@staleness) })
98
+ end
99
+
100
+ def dirty_callback(context)
101
+ path = context[:path]
102
+ wait = context[:wait]
103
+
104
+ # Fire off a background update that waits a randomized period of time up
105
+ # to @staleness seconds.
106
+ Thread.new do
107
+ sleep wait
108
+ background_update(path)
109
+ end
110
+ end
111
+
112
+ def background_update(zkpath)
113
+ # do a synchronous get/register a new watcher
114
+ resp = get_and_register(zkpath)
115
+ if resp[:rc] != Zookeeper::ZOK
116
+ # puts "Unable to read #{zkpath} from Zookeeper!" @logger.error
117
+ zk.unregister_watcher(resp[:req_id])
118
+ else
119
+ # puts "Updating data."
120
+ d = YAML.load(resp[:data])
121
+ @lock.synchronize { @data["zk:#{zkpath}"] = d }
122
+ end
123
+ end
124
+ end
125
+