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,398 @@
1
+ Zookeeper.require_lib(
2
+ 'zookeeper/logger',
3
+ 'zookeeper/common',
4
+ 'zookeeper/constants',
5
+ 'zookeeper/exceptions' # zookeeper_c depends on exceptions defined in here
6
+ )
7
+
8
+ Zookeeper.require_root 'ext/zookeeper_c'
9
+
10
+ # require File.expand_path('../zookeeper_c', __FILE__)
11
+
12
+ module Zookeeper
13
+ # NOTE: this class extending (opening) the class defined in zkrb.c
14
+ class CZookeeper
15
+ include Forked
16
+ include Constants
17
+ include Exceptions
18
+ include Logger
19
+
20
+ DEFAULT_RECEIVE_TIMEOUT_MSEC = 10000
21
+
22
+ class GotNilEventException < StandardError; end
23
+
24
+ attr_accessor :original_pid
25
+
26
+ # assume we're at debug level
27
+ def self.get_debug_level
28
+ @debug_level ||= ZOO_LOG_LEVEL_INFO
29
+ end
30
+
31
+ def self.set_debug_level(value)
32
+ @debug_level = value
33
+ set_zkrb_debug_level(value)
34
+ end
35
+
36
+ # wrap these calls in our sync->async special sauce
37
+ %w[get set exists create delete get_acl set_acl get_children add_auth].each do |sym|
38
+ class_eval(<<-EOS, __FILE__, __LINE__+1)
39
+ def #{sym}(*args)
40
+ submit_and_block(:#{sym}, *args)
41
+ end
42
+ EOS
43
+ end
44
+
45
+ def initialize(host, event_queue, opts={})
46
+ @host = host
47
+ @event_queue = event_queue
48
+
49
+ # keep track of the pid that created us
50
+ update_pid!
51
+
52
+ # used by the C layer. CZookeeper sets this to true when the init method
53
+ # has completed. once this is set to true, it stays true.
54
+ #
55
+ # you should grab the @mutex before messing with this flag
56
+ @_running = nil
57
+
58
+ # This is set to true after destroy_zkrb_instance has been called and all
59
+ # CZookeeper state has been cleaned up
60
+ @_closed = false # also used by the C layer
61
+
62
+ # set by the ruby side to indicate we are in shutdown mode used by method_get_next_event
63
+ @_shutting_down = false
64
+
65
+ # the actual C data is stashed in this ivar. never *ever* touch this
66
+ @_data = nil
67
+
68
+ @_receive_timeout_msec = opts[:receive_timeout_msec] || DEFAULT_RECEIVE_TIMEOUT_MSEC
69
+
70
+ @mutex = Monitor.new
71
+
72
+ # used to signal that we're running
73
+ @running_cond = @mutex.new_cond
74
+
75
+ # used to signal we've received the connected event
76
+ @state_mutex = Monitor.new
77
+ @state_cond = @state_mutex.new_cond
78
+
79
+ # the current state of the connection
80
+ @state = ZOO_CLOSED_STATE
81
+
82
+ @pipe_read, @pipe_write = IO.pipe
83
+
84
+ @event_thread = nil
85
+
86
+ # hash of in-flight Continuation instances
87
+ @reg = Continuation::Registry.new
88
+
89
+ log_level = ENV['ZKC_DEBUG'] ? ZOO_LOG_LEVEL_DEBUG : ZOO_LOG_LEVEL_ERROR
90
+
91
+ logger.info { "initiating connection to #{@host}" }
92
+
93
+ zkrb_init(@host, opts)#, :zkc_log_level => log_level)
94
+
95
+ start_event_thread
96
+
97
+ logger.debug { "init returned!" }
98
+ end
99
+
100
+ def closed?
101
+ @mutex.synchronize { !!@_closed }
102
+ end
103
+
104
+ def running?
105
+ @mutex.synchronize { !!@_running }
106
+ end
107
+
108
+ def shutting_down?
109
+ @mutex.synchronize { !!@_shutting_down }
110
+ end
111
+
112
+ def connected?
113
+ state == ZOO_CONNECTED_STATE
114
+ end
115
+
116
+ def connecting?
117
+ state == ZOO_CONNECTING_STATE
118
+ end
119
+
120
+ def associating?
121
+ state == ZOO_ASSOCIATING_STATE
122
+ end
123
+
124
+ def close
125
+ return if closed?
126
+
127
+ fn_close = proc do
128
+ if !@_closed and @_data
129
+ logger.debug { "CALLING CLOSE HANDLE!!" }
130
+ close_handle
131
+ end
132
+ end
133
+
134
+ if forked?
135
+ fn_close.call
136
+ else
137
+ stop_event_thread
138
+ @mutex.synchronize(&fn_close)
139
+ end
140
+
141
+ [@pipe_read, @pipe_write].each { |io| io.close unless io.closed? }
142
+
143
+ nil
144
+ end
145
+
146
+ # call this to stop the event loop, you can resume with the
147
+ # resume method
148
+ #
149
+ # requests may still be added during this time, but they will not be
150
+ # processed until you call resume
151
+ def pause_before_fork_in_parent
152
+ logger.debug { "##{__method__}" }
153
+ @mutex.synchronize { stop_event_thread }
154
+ end
155
+
156
+ # call this if 'pause' was previously called to start the event loop again
157
+ def resume_after_fork_in_parent
158
+ logger.debug { "##{__method__}" }
159
+
160
+ @mutex.synchronize do
161
+ @_shutting_down = nil
162
+ start_event_thread
163
+ end
164
+ end
165
+
166
+ def state
167
+ return ZOO_CLOSED_STATE if closed?
168
+ @state_mutex.synchronize { @state }
169
+ end
170
+
171
+ # this implementation is gross, but i don't really see another way of doing it
172
+ # without more grossness
173
+ #
174
+ # returns true if we're connected, false if we're not
175
+ #
176
+ # if timeout is nil, we never time out, and wait forever for CONNECTED state
177
+ #
178
+ def wait_until_connected(timeout=10)
179
+ time_to_stop = timeout ? Time.now + timeout : nil
180
+
181
+ return false unless wait_until_running(timeout)
182
+
183
+ @state_mutex.synchronize do
184
+ while true
185
+ if timeout
186
+ now = Time.now
187
+ break if (@state == ZOO_CONNECTED_STATE) || unhealthy? || (now > time_to_stop)
188
+ delay = time_to_stop.to_f - now.to_f
189
+ @state_cond.wait(delay)
190
+ else
191
+ break if (@state == ZOO_CONNECTED_STATE) || unhealthy?
192
+ @state_cond.wait
193
+ end
194
+ end
195
+ end
196
+
197
+ connected?
198
+ end
199
+
200
+ private
201
+ # This method is NOT SYNCHRONIZED!
202
+ #
203
+ # you must hold the @mutex lock while calling this method
204
+ def unhealthy?
205
+ @_closed || @_shutting_down || is_unrecoverable
206
+ end
207
+
208
+ # This method is NOT SYNCHRONIZED!
209
+ #
210
+ # you must hold the @mutex lock while calling this method
211
+ def healthy?
212
+ !unhealthy?
213
+ end
214
+
215
+ # submits a job for processing
216
+ # blocks the caller until result has returned
217
+ def submit_and_block(meth, *args)
218
+ @mutex.synchronize do
219
+ raise Exceptions::NotConnected if unhealthy?
220
+ end
221
+
222
+ cnt = Continuation.new(meth, *args)
223
+ @reg.synchronize do |r|
224
+ if meth == :state
225
+ r.state_check << cnt
226
+ else
227
+ r.pending << cnt
228
+ end
229
+ end
230
+ wake_event_loop!
231
+ cnt.value
232
+ end
233
+
234
+ # this method is part of the reopen/close code, and is responsible for
235
+ # shutting down the dispatch thread.
236
+ #
237
+ # this method must be EXTERNALLY SYNCHRONIZED!
238
+ #
239
+ # @event_thread will be nil when this method exits
240
+ #
241
+ def stop_event_thread
242
+ if @event_thread
243
+ logger.debug { "##{__method__}" }
244
+ shut_down!
245
+ wake_event_loop!
246
+ @event_thread.join
247
+ @event_thread = nil
248
+ end
249
+ end
250
+
251
+ # starts the event thread running if not already started
252
+ # returns false if already running
253
+ def start_event_thread
254
+ return false if @event_thread
255
+ @event_thread = Thread.new(&method(:event_thread_body))
256
+ end
257
+
258
+ # will wait until the client has entered the running? state
259
+ # or until timeout seconds have passed.
260
+ #
261
+ # returns true if we're running, false if we timed out
262
+ def wait_until_running(timeout=5)
263
+ @mutex.synchronize do
264
+ return true if @_running
265
+ @running_cond.wait(timeout)
266
+ !!@_running
267
+ end
268
+ end
269
+
270
+ def event_thread_body
271
+ Thread.current.abort_on_exception = true
272
+ logger.debug { "##{__method__} starting event thread" }
273
+
274
+ event_thread_await_running
275
+
276
+ # this is the main loop
277
+ while healthy?
278
+ if @reg.anything_to_do? && connected?
279
+ submit_pending_calls
280
+ end
281
+
282
+ zkrb_iterate_event_loop
283
+ iterate_event_delivery
284
+ end
285
+
286
+ # ok, if we're exiting the event loop, and we still have a valid connection
287
+ # and there's still completions we're waiting to hear about, then we
288
+ # should pump the handle before leaving this loop
289
+ if @_shutting_down and not (@_closed or is_unrecoverable)
290
+ logger.debug { "we're in shutting down state, there are #{@reg.in_flight.length} in_flight completions" }
291
+
292
+ until @reg.in_flight.empty? or @_closed or is_unrecoverable
293
+ zkrb_iterate_event_loop
294
+ iterate_event_delivery
295
+ logger.debug { "there are #{@reg.in_flight} in_flight completions left" }
296
+ end
297
+
298
+ logger.debug { "finished completions" }
299
+ end
300
+
301
+ # anything left over after all that gets the finger
302
+ remaining = @reg.next_batch + @reg.in_flight.values
303
+
304
+ logger.debug { "there are #{remaining.length} completions to awaken" }
305
+
306
+ @reg.in_flight.clear
307
+
308
+ while cb = remaining.shift
309
+ cb.shutdown!
310
+ end
311
+ rescue ShuttingDownException
312
+ logger.error { "event thread saw @_shutting_down, bailing without entering loop" }
313
+ ensure
314
+ logger.debug { "##{__method__} exiting" }
315
+ end
316
+
317
+ def submit_pending_calls
318
+ calls = @reg.next_batch()
319
+
320
+ return if calls.empty?
321
+
322
+ while cntn = calls.shift
323
+ cntn.submit(self) # this delivers state check results (and does other stuff)
324
+ if req_id = cntn.req_id # state checks will not have a req_id
325
+ @reg.in_flight[req_id] = cntn # in_flight is only ever touched by us
326
+ end
327
+ end
328
+ end
329
+
330
+ def wake_event_loop!
331
+ @pipe_write && @pipe_write.write('1')
332
+ end
333
+
334
+ def iterate_event_delivery
335
+ while hash = zkrb_get_next_event_st()
336
+ logger.debug { "##{__method__} got #{hash.inspect} " }
337
+
338
+ if (hash[:req_id] == ZKRB_GLOBAL_CB_REQ) && (hash[:type] == -1)
339
+ ev_state = hash[:state]
340
+
341
+ @state_mutex.synchronize do
342
+ if @state != ev_state
343
+ @state = ev_state
344
+ @state_cond.broadcast
345
+ end
346
+ end
347
+ end
348
+
349
+ cntn = @reg.in_flight.delete(hash[:req_id])
350
+
351
+ if cntn and not cntn.user_callback? # this is one of "our" continuations
352
+ cntn.call(hash) # so we handle delivering it
353
+ next # and skip handing it to the dispatcher
354
+ end
355
+
356
+ # otherwise, the event was a session event (ZKRB_GLOBAL_CB_REQ)
357
+ # or a user-provided callback
358
+ @event_queue.push(hash)
359
+ end
360
+ end
361
+
362
+ def event_thread_await_running
363
+ logger.debug { "event_thread waiting until running: #{@_running}" }
364
+
365
+ @mutex.synchronize do
366
+ @running_cond.wait_until { @_running or @_shutting_down }
367
+ logger.debug { "event_thread running: #{@_running}" }
368
+
369
+ raise ShuttingDownException if @_shutting_down
370
+ end
371
+ end
372
+
373
+ # use this method to set the @_shutting_down flag to true
374
+ def shut_down!
375
+ logger.debug { "##{__method__}" }
376
+
377
+ @mutex.synchronize do
378
+ @_shutting_down = true
379
+ # ollie ollie oxen all home free!
380
+ @running_cond.broadcast
381
+ end
382
+
383
+ @state_mutex.synchronize do
384
+ @state_cond.broadcast
385
+ end
386
+ end
387
+
388
+ # called by underlying C code to signal we're running
389
+ def zkc_set_running_and_notify!
390
+ logger.debug { "##{__method__}" }
391
+
392
+ @mutex.synchronize do
393
+ @_running = true
394
+ @running_cond.broadcast
395
+ end
396
+ end
397
+ end
398
+ end
data/ext/common.h ADDED
@@ -0,0 +1,17 @@
1
+ #ifndef ZKRB_COMMON_H
2
+ #define ZKRB_COMMON_H
3
+
4
+ #include "ruby.h"
5
+
6
+ //#define THREADED
7
+ #undef THREADED // we are linking against the zookeeper_st lib, this is crucial
8
+
9
+ #ifndef RB_GC_GUARD_PTR
10
+ #define RB_GC_GUARD_PTR(V) (V);
11
+ #endif
12
+ #ifndef RB_GC_GUARD
13
+ #define RB_GC_GUARD(V) (V);
14
+ #endif
15
+
16
+
17
+ #endif /* ZKRB_COMMON_H */
data/ext/dbg.h ADDED
@@ -0,0 +1,53 @@
1
+ #ifndef __dbg_h__
2
+ #define __dbg_h__
3
+
4
+ // ALL GLORY TO THE Zed A. Shaw
5
+ // http://c.learncodethehardway.org/book/learn-c-the-hard-waych21.html#x26-10500021
6
+
7
+ #include <stdio.h>
8
+ #include <errno.h>
9
+ #include <string.h>
10
+
11
+ #ifdef NDEBUG
12
+ #define debug(M, ...)
13
+ #else
14
+ #define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
15
+ #endif
16
+
17
+ #define clean_errno() (errno == 0 ? "None" : strerror(errno))
18
+
19
+ #define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
20
+
21
+ #define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
22
+
23
+ #define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
24
+
25
+ // acts to assert that A is true
26
+ #define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
27
+
28
+ // like check, but provide an explicit goto label name
29
+ #define check_goto(A, L, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto L; }
30
+
31
+ // like check, but implicit jump to 'unlock' label
32
+ #define check_unlock(A, M, ...) check_goto(A, unlock, M, ##__VA_ARGS__)
33
+
34
+ #define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
35
+
36
+ #define check_mem(A) check((A), "Out of memory.")
37
+
38
+ // checks the condition A, if not true, logs the message M given using zkrb_debug
39
+ // then does a goto to the label L
40
+ #define check_debug_goto(A, L, M, ...) if(!(A)) { zkrb_debug(M, ##__VA_ARGS__); errno=0; goto L; }
41
+
42
+ // check_debug_goto with implicit 'unlock' label
43
+ #define check_debug_unlock(A, M, ...) check_debug_goto(A, unlock, M, ##__VA_ARGS__)
44
+
45
+ // like check_debug_goto, but the label is implicitly 'error'
46
+ #define check_debug(A, M, ...) check_debug_goto(A, error, M, ##__VA_ARGS__)
47
+
48
+ #define zkrb_debug(M, ...) if (ZKRBDebugging) fprintf(stderr, "DEBUG %p:%s:%d: " M "\n", (void *)pthread_self(), __FILE__, __LINE__, ##__VA_ARGS__)
49
+ #define zkrb_debug_inst(O, M, ...) zkrb_debug("obj_id: %lx, " M, FIX2LONG(rb_obj_id(O)), ##__VA_ARGS__)
50
+
51
+ // __dbg_h__
52
+ #endif
53
+