zookeeper 0.9.3-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/CHANGELOG +119 -0
- data/Gemfile +17 -0
- data/LICENSE +23 -0
- data/Manifest +29 -0
- data/README.markdown +59 -0
- data/Rakefile +139 -0
- data/examples/cloud_config.rb +125 -0
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +51 -0
- data/ext/c_zookeeper.rb +212 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/extconf.rb +85 -0
- data/ext/generate_gvl_code.rb +316 -0
- data/ext/zkc-3.3.5.tar.gz +0 -0
- data/ext/zkrb_wrapper.c +731 -0
- data/ext/zkrb_wrapper.h +330 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +211 -0
- data/ext/zookeeper_c.c +725 -0
- data/ext/zookeeper_lib.c +677 -0
- data/ext/zookeeper_lib.h +172 -0
- data/java/zookeeper_base.rb +477 -0
- data/lib/zookeeper.rb +297 -0
- data/lib/zookeeper/acls.rb +40 -0
- data/lib/zookeeper/callbacks.rb +91 -0
- data/lib/zookeeper/common.rb +174 -0
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/constants.rb +57 -0
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +100 -0
- data/lib/zookeeper/stat.rb +21 -0
- data/lib/zookeeper/version.rb +6 -0
- data/notes.txt +14 -0
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +81 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1018 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/test/test_basic.rb +37 -0
- data/test/test_callback1.rb +36 -0
- data/test/test_close.rb +16 -0
- data/test/test_esoteric.rb +7 -0
- data/test/test_watcher1.rb +56 -0
- data/test/test_watcher2.rb +52 -0
- metadata +181 -0
data/.gitignore
ADDED
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
|
+
|