zookeeper 0.9.4 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.dotfiles/rvmrc +1 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +22 -0
  5. data/CHANGELOG +38 -5
  6. data/Gemfile +18 -1
  7. data/README.markdown +2 -0
  8. data/Rakefile +47 -109
  9. data/ext/c_zookeeper.rb +10 -6
  10. data/ext/zookeeper_base.rb +23 -11
  11. data/ext/zookeeper_c.c +14 -10
  12. data/java/{zookeeper_base.rb → java_base.rb} +13 -12
  13. data/lib/zookeeper.rb +32 -244
  14. data/lib/zookeeper/acls.rb +17 -13
  15. data/lib/zookeeper/callbacks.rb +28 -11
  16. data/lib/zookeeper/client.rb +30 -0
  17. data/lib/zookeeper/client_methods.rb +241 -0
  18. data/lib/zookeeper/common.rb +13 -12
  19. data/lib/zookeeper/common/queue_with_pipe.rb +3 -7
  20. data/lib/zookeeper/compatibility.rb +135 -0
  21. data/lib/zookeeper/constants.rb +35 -1
  22. data/lib/zookeeper/em_client.rb +1 -1
  23. data/lib/zookeeper/exceptions.rb +117 -93
  24. data/lib/zookeeper/rake_tasks.rb +165 -0
  25. data/lib/zookeeper/stat.rb +16 -16
  26. data/lib/zookeeper/version.rb +2 -4
  27. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  28. data/spec/c_zookeeper_spec.rb +10 -9
  29. data/spec/chrooted_connection_spec.rb +2 -2
  30. data/spec/default_watcher_spec.rb +4 -4
  31. data/spec/em_spec.rb +1 -1
  32. data/spec/shared/connection_examples.rb +52 -37
  33. data/spec/spec_helper.rb +22 -84
  34. data/spec/support/00_spawn_zookeeper.rb +20 -0
  35. data/spec/support/zookeeper_spec_helpers.rb +84 -0
  36. data/spec/zookeeper_spec.rb +1 -1
  37. metadata +47 -34
  38. data/examples/cloud_config.rb +0 -125
  39. data/test/test_basic.rb +0 -37
  40. data/test/test_callback1.rb +0 -36
  41. data/test/test_close.rb +0 -16
  42. data/test/test_esoteric.rb +0 -7
  43. data/test/test_watcher1.rb +0 -56
  44. data/test/test_watcher2.rb +0 -52
@@ -4,9 +4,13 @@ $LOAD_PATH.uniq!
4
4
 
5
5
  require 'rubygems'
6
6
 
7
- gem 'flexmock', '~> 0.8.11'
7
+ release_ops_path = File.expand_path('../../releaseops/lib', __FILE__)
8
+
9
+ if File.exists?(release_ops_path)
10
+ require File.join(release_ops_path, 'releaseops')
11
+ ReleaseOps::SimpleCov.maybe_start
12
+ end
8
13
 
9
- require 'flexmock'
10
14
  require 'zookeeper'
11
15
 
12
16
  Dir[File.expand_path('../support/**/*.rb', __FILE__)].sort.each { |f| require(f) }
@@ -26,94 +30,28 @@ if ENV['ZKRB_NOLOG']
26
30
  end
27
31
 
28
32
 
29
- module ZookeeperSpecHeleprs
30
- class TimeoutError < StandardError; end
31
-
32
- def logger
33
- Zookeeper.logger
34
- end
35
-
36
- def ensure_node(zk, path, data)
37
- return if zk.closed?
38
- if zk.stat(:path => path)[:stat].exists?
39
- zk.set(:path => path, :data => data)
40
- else
41
- zk.create(:path => path, :data => data)
42
- end
43
- end
44
-
45
- def with_open_zk(host='localhost:2181')
46
- z = Zookeeper.new(host)
47
- yield z
48
- ensure
49
- if z
50
- unless z.closed?
51
- z.close
33
+ RSpec.configure do |config|
34
+ config.mock_with :rspec
35
+ config.include ZookeeperSpecHeleprs
36
+ config.extend ZookeeperSpecHeleprs
52
37
 
53
- wait_until do
54
- begin
55
- !z.connected?
56
- rescue RuntimeError
57
- true
58
- end
59
- end
60
- end
61
- end
62
- end
38
+ if Zookeeper.spawn_zookeeper?
39
+ require 'zk-server'
63
40
 
64
- # this is not as safe as the one in ZK, just to be used to clean up
65
- # when we're the only one adjusting a particular path
66
- def rm_rf(z, path)
67
- z.get_children(:path => path).tap do |h|
68
- if h[:rc].zero?
69
- h[:children].each do |child|
70
- rm_rf(z, File.join(path, child))
71
- end
72
- elsif h[:rc] == ZookeeperExceptions::ZNONODE
73
- # no-op
74
- else
75
- raise "Oh noes! unexpected return value! #{h.inspect}"
41
+ config.before(:suite) do
42
+ Zookeeper.logger.debug { "Starting zookeeper service" }
43
+ ZK::Server.run do |c|
44
+ c.base_dir = File.expand_path('../../.zkserver', __FILE__)
45
+ c.client_port = Zookeeper.test_port
46
+ c.force_sync = false
47
+ c.snap_count = 1_000_000
76
48
  end
77
49
  end
78
50
 
79
- rv = z.delete(:path => path)
80
-
81
- unless (rv[:rc].zero? or rv[:rc] == ZookeeperExceptions::ZNONODE)
82
- raise "oh noes! failed to delete #{path}"
83
- end
84
-
85
- path
86
- end
87
-
88
-
89
- # method to wait until block passed returns true or timeout (default is 10 seconds) is reached
90
- # raises TiemoutError on timeout
91
- def wait_until(timeout=10)
92
- time_to_stop = Time.now + timeout
93
- while true
94
- rval = yield
95
- return rval if rval
96
- raise TimeoutError, "timeout of #{timeout}s exceeded" if Time.now > time_to_stop
97
- Thread.pass
98
- end
99
- end
100
-
101
- # inverse of wait_until
102
- def wait_while(timeout=10)
103
- time_to_stop = Time.now + timeout
104
- while true
105
- rval = yield
106
- return rval unless rval
107
- raise TimeoutError, "timeout of #{timeout}s exceeded" if Time.now > time_to_stop
108
- Thread.pass
51
+ config.after(:suite) do
52
+ Zookeeper.logger.debug { "stopping zookeeper service" }
53
+ ZK::Server.shutdown
109
54
  end
110
55
  end
111
56
  end
112
57
 
113
- RSpec.configure do |config|
114
- config.mock_with :flexmock
115
- config.include ZookeeperSpecHeleprs
116
- config.extend ZookeeperSpecHeleprs
117
- end
118
-
119
-
@@ -0,0 +1,20 @@
1
+ module Zookeeper
2
+ def self.spawn_zookeeper?
3
+ !!ENV['SPAWN_ZOOKEEPER']
4
+ end
5
+
6
+ def self.travis?
7
+ !!ENV['TRAVIS']
8
+ end
9
+
10
+ @test_port ||= spawn_zookeeper? ? 21811 : 2181
11
+
12
+ class << self
13
+ attr_accessor :test_port
14
+ end
15
+
16
+ def self.default_cnx_str
17
+ "localhost:#{test_port}"
18
+ end
19
+ end
20
+
@@ -0,0 +1,84 @@
1
+ module ZookeeperSpecHeleprs
2
+ class TimeoutError < StandardError; end
3
+
4
+ def logger
5
+ Zookeeper.logger
6
+ end
7
+
8
+ def ensure_node(zk, path, data)
9
+ return if zk.closed?
10
+ if zk.stat(:path => path)[:stat].exists?
11
+ zk.set(:path => path, :data => data)
12
+ else
13
+ zk.create(:path => path, :data => data)
14
+ end
15
+ end
16
+
17
+ def with_open_zk(host=nil)
18
+ z = Zookeeper.new(Zookeeper.default_cnx_str)
19
+ yield z
20
+ ensure
21
+ if z
22
+ unless z.closed?
23
+ z.close
24
+
25
+ wait_until do
26
+ begin
27
+ !z.connected?
28
+ rescue RuntimeError
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # this is not as safe as the one in ZK, just to be used to clean up
37
+ # when we're the only one adjusting a particular path
38
+ def rm_rf(z, path)
39
+ z.get_children(:path => path).tap do |h|
40
+ if h[:rc].zero?
41
+ h[:children].each do |child|
42
+ rm_rf(z, File.join(path, child))
43
+ end
44
+ elsif h[:rc] == Zookeeper::Exceptions::ZNONODE
45
+ # no-op
46
+ else
47
+ raise "Oh noes! unexpected return value! #{h.inspect}"
48
+ end
49
+ end
50
+
51
+ rv = z.delete(:path => path)
52
+
53
+ unless (rv[:rc].zero? or rv[:rc] == Zookeeper::Exceptions::ZNONODE)
54
+ raise "oh noes! failed to delete #{path}"
55
+ end
56
+
57
+ path
58
+ end
59
+
60
+
61
+ # method to wait until block passed returns true or timeout (default is 10 seconds) is reached
62
+ # raises TiemoutError on timeout
63
+ def wait_until(timeout=10)
64
+ time_to_stop = Time.now + timeout
65
+ while true
66
+ rval = yield
67
+ return rval if rval
68
+ raise TimeoutError, "timeout of #{timeout}s exceeded" if Time.now > time_to_stop
69
+ Thread.pass
70
+ end
71
+ end
72
+
73
+ # inverse of wait_until
74
+ def wait_while(timeout=10)
75
+ time_to_stop = Time.now + timeout
76
+ while true
77
+ rval = yield
78
+ return rval unless rval
79
+ raise TimeoutError, "timeout of #{timeout}s exceeded" if Time.now > time_to_stop
80
+ Thread.pass
81
+ end
82
+ end
83
+ end
84
+
@@ -5,7 +5,7 @@ require 'shared/connection_examples'
5
5
  describe 'Zookeeper' do
6
6
  let(:path) { "/_zktest_" }
7
7
  let(:data) { "underpants" }
8
- let(:connection_string) { 'localhost:2181' }
8
+ let(:connection_string) { Zookeeper.default_cnx_str }
9
9
 
10
10
  before do
11
11
  @zk = Zookeeper.new(connection_string)
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zookeeper
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
5
- prerelease:
4
+ hash: 3809227699
5
+ prerelease: 6
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 9
9
- - 4
10
- version: 0.9.4
9
+ - 0
10
+ - beta
11
+ - 1
12
+ version: 1.0.0.beta.1
11
13
  platform: ruby
12
14
  authors:
13
15
  - Phillip Pearson
@@ -21,17 +23,27 @@ bindir: bin
21
23
  cert_chain: []
22
24
 
23
25
  date: 2012-05-07 00:00:00 Z
24
- dependencies: []
25
-
26
+ dependencies:
27
+ - !ruby/object:Gem::Dependency
28
+ name: backports
29
+ prerelease: false
30
+ requirement: &id001 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ hash: 25
36
+ segments:
37
+ - 2
38
+ - 5
39
+ - 1
40
+ version: 2.5.1
41
+ type: :runtime
42
+ version_requirements: *id001
26
43
  description: |+
27
- A low-level multi-Ruby wrapper around the ZooKeeper API bindings.
28
- For a friendlier interface, see http://github.com/slyphon/zk
29
-
30
- Currently supported:
31
-
32
- MRI: 1.8.7, 1.9.2, 1.9.3
33
- JRuby: ~> 1.6.7
34
- Rubinius: 2.0.testing
44
+ A low-level multi-Ruby wrapper around the ZooKeeper API bindings. For a
45
+ friendlier interface, see http://github.com/slyphon/zk. Currently supported:
46
+ MRI: {1.8.7, 1.9.2, 1.9.3}, JRuby: ~> 1.6.7, Rubinius: 2.0.testing, REE 1.8.7.
35
47
 
36
48
  This library uses version 3.3.5 of zookeeper bindings.
37
49
 
@@ -44,14 +56,16 @@ extensions:
44
56
  extra_rdoc_files: []
45
57
 
46
58
  files:
59
+ - .dotfiles/rvmrc
47
60
  - .gitignore
61
+ - .gitmodules
62
+ - .travis.yml
48
63
  - CHANGELOG
49
64
  - Gemfile
50
65
  - LICENSE
51
66
  - Manifest
52
67
  - README.markdown
53
68
  - Rakefile
54
- - examples/cloud_config.rb
55
69
  - ext/.gitignore
56
70
  - ext/Rakefile
57
71
  - ext/c_zookeeper.rb
@@ -68,18 +82,23 @@ files:
68
82
  - ext/zookeeper_c.c
69
83
  - ext/zookeeper_lib.c
70
84
  - ext/zookeeper_lib.h
71
- - java/zookeeper_base.rb
85
+ - java/java_base.rb
72
86
  - lib/zookeeper.rb
73
87
  - lib/zookeeper/acls.rb
74
88
  - lib/zookeeper/callbacks.rb
89
+ - lib/zookeeper/client.rb
90
+ - lib/zookeeper/client_methods.rb
75
91
  - lib/zookeeper/common.rb
76
92
  - lib/zookeeper/common/queue_with_pipe.rb
93
+ - lib/zookeeper/compatibility.rb
77
94
  - lib/zookeeper/constants.rb
78
95
  - lib/zookeeper/em_client.rb
79
96
  - lib/zookeeper/exceptions.rb
97
+ - lib/zookeeper/rake_tasks.rb
80
98
  - lib/zookeeper/stat.rb
81
99
  - lib/zookeeper/version.rb
82
100
  - notes.txt
101
+ - scripts/upgrade-1.0-sed-alike.rb
83
102
  - spec/c_zookeeper_spec.rb
84
103
  - spec/chrooted_connection_spec.rb
85
104
  - spec/default_watcher_spec.rb
@@ -88,14 +107,10 @@ files:
88
107
  - spec/shared/all_success_return_values.rb
89
108
  - spec/shared/connection_examples.rb
90
109
  - spec/spec_helper.rb
110
+ - spec/support/00_spawn_zookeeper.rb
91
111
  - spec/support/progress_formatter.rb
112
+ - spec/support/zookeeper_spec_helpers.rb
92
113
  - spec/zookeeper_spec.rb
93
- - test/test_basic.rb
94
- - test/test_callback1.rb
95
- - test/test_close.rb
96
- - test/test_esoteric.rb
97
- - test/test_watcher1.rb
98
- - test/test_watcher2.rb
99
114
  - zookeeper.gemspec
100
115
  homepage: https://github.com/slyphon/zookeeper
101
116
  licenses: []
@@ -118,19 +133,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
118
133
  required_rubygems_version: !ruby/object:Gem::Requirement
119
134
  none: false
120
135
  requirements:
121
- - - ">="
136
+ - - ">"
122
137
  - !ruby/object:Gem::Version
123
- hash: 3
138
+ hash: 25
124
139
  segments:
125
- - 0
126
- version: "0"
140
+ - 1
141
+ - 3
142
+ - 1
143
+ version: 1.3.1
127
144
  requirements: []
128
145
 
129
146
  rubyforge_project:
130
147
  rubygems_version: 1.8.15
131
148
  signing_key:
132
149
  specification_version: 3
133
- summary: Low level zookeeper client
150
+ summary: Apache ZooKeeper driver for Rubies
134
151
  test_files:
135
152
  - spec/c_zookeeper_spec.rb
136
153
  - spec/chrooted_connection_spec.rb
@@ -140,11 +157,7 @@ test_files:
140
157
  - spec/shared/all_success_return_values.rb
141
158
  - spec/shared/connection_examples.rb
142
159
  - spec/spec_helper.rb
160
+ - spec/support/00_spawn_zookeeper.rb
143
161
  - spec/support/progress_formatter.rb
162
+ - spec/support/zookeeper_spec_helpers.rb
144
163
  - spec/zookeeper_spec.rb
145
- - test/test_basic.rb
146
- - test/test_callback1.rb
147
- - test/test_close.rb
148
- - test/test_esoteric.rb
149
- - test/test_watcher1.rb
150
- - test/test_watcher2.rb
@@ -1,125 +0,0 @@
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
-