zookeeper 0.9.3-java

Sign up to get free protection for your applications and to get access to all the features.
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
+