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.
- 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/ext/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
task :clean do
|
3
|
+
if File.exists?('Makefile')
|
4
|
+
sh 'make clean'
|
5
|
+
else
|
6
|
+
$stderr.puts "nothing to clean, no Makefile"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
GENERATE_GVL_CODE_RB = 'generate_gvl_code.rb'
|
11
|
+
|
12
|
+
file 'c' do
|
13
|
+
if tarball = Dir['zkc-*.tar.gz'].first
|
14
|
+
sh "tar -zxf #{tarball}"
|
15
|
+
else
|
16
|
+
raise "couldn't find the tarball! wtf?!"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
file GENERATE_GVL_CODE_RB => 'c'
|
21
|
+
|
22
|
+
file 'zkrb_wrapper.c' => GENERATE_GVL_CODE_RB do
|
23
|
+
sh "ruby generate_gvl_code.rb code"
|
24
|
+
end
|
25
|
+
|
26
|
+
file 'zkrb_wrapper.h' => GENERATE_GVL_CODE_RB do
|
27
|
+
sh "ruby generate_gvl_code.rb headers"
|
28
|
+
end
|
29
|
+
|
30
|
+
ZKRB_WRAPPER = %w[zkrb_wrapper.c zkrb_wrapper.h]
|
31
|
+
|
32
|
+
|
33
|
+
task :wrappers => ZKRB_WRAPPER
|
34
|
+
|
35
|
+
|
36
|
+
task :clobber => :clean do
|
37
|
+
rm_rf %w[Makefile c lib bin include]
|
38
|
+
end
|
39
|
+
|
40
|
+
task :build_zkc do
|
41
|
+
sh 'ruby extconf.rb'
|
42
|
+
end
|
43
|
+
|
44
|
+
file 'Makefile' => :build_zkc
|
45
|
+
|
46
|
+
task :build => [ZKRB_WRAPPER, 'Makefile'].flatten do
|
47
|
+
sh 'make'
|
48
|
+
end
|
49
|
+
|
50
|
+
task :default => :build
|
51
|
+
|
data/ext/c_zookeeper.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'zookeeper/constants'
|
2
|
+
require File.expand_path('../zookeeper_c', __FILE__)
|
3
|
+
|
4
|
+
# TODO: see if we can get the destructor to handle thread/event queue teardown
|
5
|
+
# when we're garbage collected
|
6
|
+
class CZookeeper
|
7
|
+
include ZookeeperCommon
|
8
|
+
include ZookeeperConstants
|
9
|
+
include ZookeeperExceptions
|
10
|
+
|
11
|
+
DEFAULT_SESSION_TIMEOUT_MSEC = 10000
|
12
|
+
|
13
|
+
class GotNilEventException < StandardError; end
|
14
|
+
|
15
|
+
# assume we're at debug level
|
16
|
+
def self.get_debug_level
|
17
|
+
@debug_level ||= ZOO_LOG_LEVEL_INFO
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_debug_level(value)
|
21
|
+
@debug_level = value
|
22
|
+
set_zkrb_debug_level(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(host, event_queue, opts={})
|
26
|
+
@host = host
|
27
|
+
@event_queue = event_queue
|
28
|
+
|
29
|
+
# used by the C layer. CZookeeper sets this to true when the init method
|
30
|
+
# has completed. once this is set to true, it stays true.
|
31
|
+
#
|
32
|
+
# you should grab the @start_stop_mutex before messing with this flag
|
33
|
+
@_running = nil
|
34
|
+
|
35
|
+
# This is set to true after destroy_zkrb_instance has been called and all
|
36
|
+
# CZookeeper state has been cleaned up
|
37
|
+
@_closed = false # also used by the C layer
|
38
|
+
|
39
|
+
# set by the ruby side to indicate we are in shutdown mode used by method_get_next_event
|
40
|
+
@_shutting_down = false
|
41
|
+
|
42
|
+
# the actual C data is stashed in this ivar. never *ever* touch this
|
43
|
+
@_data = nil
|
44
|
+
|
45
|
+
@_session_timeout_msec = DEFAULT_SESSION_TIMEOUT_MSEC
|
46
|
+
|
47
|
+
@start_stop_mutex = Monitor.new
|
48
|
+
|
49
|
+
# used to signal that we're running
|
50
|
+
@running_cond = @start_stop_mutex.new_cond
|
51
|
+
|
52
|
+
@event_thread = nil
|
53
|
+
|
54
|
+
setup_event_thread!
|
55
|
+
|
56
|
+
zkrb_init(@host)
|
57
|
+
|
58
|
+
logger.debug { "init returned!" }
|
59
|
+
end
|
60
|
+
|
61
|
+
def closed?
|
62
|
+
@start_stop_mutex.synchronize { !!@_closed }
|
63
|
+
end
|
64
|
+
|
65
|
+
def running?
|
66
|
+
@start_stop_mutex.synchronize { !!@_running }
|
67
|
+
end
|
68
|
+
|
69
|
+
def shutting_down?
|
70
|
+
@start_stop_mutex.synchronize { !!@_shutting_down }
|
71
|
+
end
|
72
|
+
|
73
|
+
def connected?
|
74
|
+
state == ZOO_CONNECTED_STATE
|
75
|
+
end
|
76
|
+
|
77
|
+
def connecting?
|
78
|
+
state == ZOO_CONNECTING_STATE
|
79
|
+
end
|
80
|
+
|
81
|
+
def associating?
|
82
|
+
state == ZOO_ASSOCIATING_STATE
|
83
|
+
end
|
84
|
+
|
85
|
+
def close
|
86
|
+
return if closed?
|
87
|
+
|
88
|
+
shut_down!
|
89
|
+
stop_event_thread!
|
90
|
+
|
91
|
+
@start_stop_mutex.synchronize do
|
92
|
+
if !@_closed and @_data
|
93
|
+
close_handle
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def state
|
101
|
+
return ZOO_CLOSED_STATE if closed?
|
102
|
+
zkrb_state
|
103
|
+
end
|
104
|
+
|
105
|
+
# this implementation is gross, but i don't really see another way of doing it
|
106
|
+
# without more grossness
|
107
|
+
#
|
108
|
+
# returns true if we're connected, false if we're not
|
109
|
+
#
|
110
|
+
# if timeout is nil, we never time out, and wait forever for CONNECTED state
|
111
|
+
#
|
112
|
+
def wait_until_connected(timeout=10)
|
113
|
+
return false unless wait_until_running(timeout)
|
114
|
+
|
115
|
+
time_to_stop = timeout ? (Time.now + timeout) : nil
|
116
|
+
|
117
|
+
until connected? or (time_to_stop and Time.now > time_to_stop)
|
118
|
+
Thread.pass
|
119
|
+
end
|
120
|
+
|
121
|
+
connected?
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
# will wait until the client has entered the running? state
|
126
|
+
# or until timeout seconds have passed.
|
127
|
+
#
|
128
|
+
# returns true if we're running, false if we timed out
|
129
|
+
def wait_until_running(timeout=5)
|
130
|
+
@start_stop_mutex.synchronize do
|
131
|
+
return true if @_running
|
132
|
+
@running_cond.wait(timeout)
|
133
|
+
!!@_running
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def setup_event_thread!
|
138
|
+
@event_thread ||= Thread.new(&method(:_event_thread_body))
|
139
|
+
end
|
140
|
+
|
141
|
+
def _event_thread_body
|
142
|
+
logger.debug { "event_thread waiting until running: #{@_running}" }
|
143
|
+
|
144
|
+
@start_stop_mutex.synchronize do
|
145
|
+
@running_cond.wait_until { @_running }
|
146
|
+
|
147
|
+
if @_shutting_down
|
148
|
+
logger.error { "event thread saw @_shutting_down, bailing without entering loop" }
|
149
|
+
return
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
logger.debug { "event_thread running: #{@_running}" }
|
154
|
+
|
155
|
+
while true
|
156
|
+
begin
|
157
|
+
_iterate_event_delivery
|
158
|
+
rescue GotNilEventException
|
159
|
+
logger.debug { "#{self.class}##{__method__}: event delivery thread is exiting" }
|
160
|
+
break
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def _iterate_event_delivery
|
166
|
+
get_next_event(true).tap do |hash|
|
167
|
+
raise GotNilEventException if hash.nil?
|
168
|
+
@event_queue.push(hash)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# use this method to set the @_shutting_down flag to true
|
173
|
+
def shut_down!
|
174
|
+
logger.debug { "#{self.class}##{__method__}" }
|
175
|
+
|
176
|
+
@start_stop_mutex.synchronize do
|
177
|
+
@_shutting_down = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# this method is part of the reopen/close code, and is responsible for
|
182
|
+
# shutting down the dispatch thread.
|
183
|
+
#
|
184
|
+
# @dispatch will be nil when this method exits
|
185
|
+
#
|
186
|
+
def stop_event_thread!
|
187
|
+
logger.debug { "#{self.class}##{__method__}" }
|
188
|
+
|
189
|
+
if @event_thread
|
190
|
+
unless @_closed
|
191
|
+
wake_event_loop! # this is a C method
|
192
|
+
end
|
193
|
+
@event_thread.join
|
194
|
+
@event_thread = nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def logger
|
199
|
+
Zookeeper.logger
|
200
|
+
end
|
201
|
+
|
202
|
+
# called by underlying C code to signal we're running
|
203
|
+
def zkc_set_running_and_notify!
|
204
|
+
logger.debug { "#{self.class}##{__method__}" }
|
205
|
+
|
206
|
+
@start_stop_mutex.synchronize do
|
207
|
+
@_running = true
|
208
|
+
@running_cond.broadcast
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
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", 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
|
+
|
data/ext/depend
ADDED
data/ext/extconf.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
require 'mkmf'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
HERE = File.expand_path(File.dirname(__FILE__))
|
6
|
+
BUNDLE = Dir.glob("zkc-*.tar.gz").first
|
7
|
+
BUNDLE_PATH = "c"
|
8
|
+
|
9
|
+
$EXTRA_CONF = ''
|
10
|
+
|
11
|
+
# CLANG!!!! jeez, if apple would only *stop* "thinking different"
|
12
|
+
if cc = RbConfig::CONFIG['CC'] && cc =~ /^gcc/
|
13
|
+
$CC = cc
|
14
|
+
$EXTRA_CONF = "#{$EXTRA_CONF} CC=#{$CC}"
|
15
|
+
end
|
16
|
+
|
17
|
+
$CFLAGS = "#{$CFLAGS}".gsub("$(cflags)", "").gsub("-arch ppc", "")
|
18
|
+
$LDFLAGS = "#{$LDFLAGS}".gsub("$(ldflags)", "").gsub("-arch ppc", "")
|
19
|
+
$CXXFLAGS = " -std=gnu++98 #{$CFLAGS}"
|
20
|
+
$CPPFLAGS = $ARCH_FLAG = $DLDFLAGS = ""
|
21
|
+
|
22
|
+
if RUBY_VERSION == '1.8.7'
|
23
|
+
$CFLAGS << ' -DZKRB_RUBY_187'
|
24
|
+
end
|
25
|
+
|
26
|
+
ZK_DEBUG = (ENV['DEBUG'] or ARGV.any? { |arg| arg == '--debug' })
|
27
|
+
DEBUG_CFLAGS = " -O0 -ggdb3 -DHAVE_DEBUG"
|
28
|
+
|
29
|
+
if ZK_DEBUG
|
30
|
+
$stderr.puts "*** Setting debug flags. ***"
|
31
|
+
$EXTRA_CONF = "#{$EXTRA_CONF} --enable-debug"
|
32
|
+
$CFLAGS.gsub!(/ -O[^0] /, ' ')
|
33
|
+
$CFLAGS << DEBUG_CFLAGS
|
34
|
+
end
|
35
|
+
|
36
|
+
$includes = " -I#{HERE}/include"
|
37
|
+
$libraries = " -L#{HERE}/lib -L#{RbConfig::CONFIG['libdir']}"
|
38
|
+
$CFLAGS = "#{$includes} #{$libraries} #{$CFLAGS}"
|
39
|
+
$LDFLAGS = "#{$libraries} #{$LDFLAGS}"
|
40
|
+
$LIBPATH = ["#{HERE}/lib"]
|
41
|
+
$DEFLIBPATH = []
|
42
|
+
|
43
|
+
def safe_sh(cmd)
|
44
|
+
puts cmd
|
45
|
+
system(cmd)
|
46
|
+
unless $?.exited? and $?.success?
|
47
|
+
raise "command failed! #{cmd}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Dir.chdir(HERE) do
|
52
|
+
if File.exist?("lib")
|
53
|
+
puts "Zkc already built; run 'rake clobber' in ext/ first if you need to rebuild."
|
54
|
+
else
|
55
|
+
puts "Building zkc."
|
56
|
+
|
57
|
+
unless File.exists?('c')
|
58
|
+
puts(cmd = "tar xzf #{BUNDLE} 2>&1")
|
59
|
+
raise "'#{cmd}' failed" unless system(cmd)
|
60
|
+
end
|
61
|
+
|
62
|
+
Dir.chdir(BUNDLE_PATH) do
|
63
|
+
configure = "./configure --prefix=#{HERE} --with-pic --without-cppunit --disable-dependency-tracking #{$EXTRA_CONF} 2>&1"
|
64
|
+
|
65
|
+
configure = "env CFLAGS='#{DEBUG_CFLAGS}' #{configure}" if ZK_DEBUG
|
66
|
+
|
67
|
+
safe_sh(configure)
|
68
|
+
safe_sh("make 2>&1")
|
69
|
+
safe_sh("make install 2>&1")
|
70
|
+
end
|
71
|
+
|
72
|
+
system("rm -rf #{BUNDLE_PATH}") unless ENV['DEBUG'] or ENV['DEV']
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Absolutely prevent the linker from picking up any other zookeeper_mt
|
77
|
+
Dir.chdir("#{HERE}/lib") do
|
78
|
+
system("cp -f libzookeeper_mt.a libzookeeper_mt_gem.a")
|
79
|
+
system("cp -f libzookeeper_mt.la libzookeeper_mt_gem.la")
|
80
|
+
end
|
81
|
+
$LIBS << " -lzookeeper_mt_gem"
|
82
|
+
|
83
|
+
|
84
|
+
create_makefile 'zookeeper_c'
|
85
|
+
|
@@ -0,0 +1,316 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
=begin
|
4
|
+
the idea here is to take each zoo_* function declaration in the header file, and turn it into
|
5
|
+
a calling arguments struct, a wrapper function and a macro for packing the values.
|
6
|
+
|
7
|
+
so for:
|
8
|
+
|
9
|
+
ZOOAPI int zoo_acreate(zhandle_t *zh, const char *path, const char *value,
|
10
|
+
int valuelen, const struct ACL_vector *acl, int flags,
|
11
|
+
string_completion_t completion, const void *data);
|
12
|
+
|
13
|
+
we want
|
14
|
+
|
15
|
+
typedef struct {
|
16
|
+
zhandle_t *zh;
|
17
|
+
const char *path;
|
18
|
+
const char *value;
|
19
|
+
int valuelen;
|
20
|
+
const struct ACL_vector *acl;
|
21
|
+
int flags;
|
22
|
+
string_completion_t completion;
|
23
|
+
const void *data;
|
24
|
+
} zkrb_zoo_acreate_args_t;
|
25
|
+
|
26
|
+
static VALUE zkrb_gvl_zoo_acreate(void *data) {
|
27
|
+
zkrb_zoo_acreate_args_t *a = (zkrb_zoo_acreate_args_t *)data;
|
28
|
+
|
29
|
+
a->rc = zoo_acreate(a->zh, a->path, a->value, a->valuelen, a->acl, a->flags, a->completion, a->data);
|
30
|
+
|
31
|
+
return Qnil;
|
32
|
+
}
|
33
|
+
|
34
|
+
static int zkrb_call_zoo_acreate(zhandle_t *zh, const char *path, const char *value,
|
35
|
+
int valuelen, const struct ACL_vector *acl, int flags,
|
36
|
+
string_completion_t completion, const void *data) {
|
37
|
+
|
38
|
+
zkrb_zoo_acreate_args_t args = {
|
39
|
+
.rc = ZKRB_FAIL,
|
40
|
+
.zh = zh,
|
41
|
+
.path = path,
|
42
|
+
.value = value,
|
43
|
+
.valuelen = valuelen,
|
44
|
+
.acl = acl,
|
45
|
+
.flags = flags,
|
46
|
+
.completion = completion,
|
47
|
+
.data = data
|
48
|
+
};
|
49
|
+
|
50
|
+
zkrb_thread_blocking_region(zkrb_gvl_zoo_acreate, (void *)&args);
|
51
|
+
|
52
|
+
return args.rc;
|
53
|
+
}
|
54
|
+
|
55
|
+
=end
|
56
|
+
|
57
|
+
REGEXP = /^ZOOAPI int (zoo_[^(]+)\(([^)]+)\);$/m
|
58
|
+
|
59
|
+
require 'forwardable'
|
60
|
+
require 'stringio'
|
61
|
+
|
62
|
+
ZKRB_WRAPPER_H_PATH = File.expand_path('../zkrb_wrapper.h', __FILE__)
|
63
|
+
ZKRB_WRAPPER_C_PATH = File.expand_path('../zkrb_wrapper.c', __FILE__)
|
64
|
+
|
65
|
+
# the struct that holds the call args for zoo_fn_name
|
66
|
+
class CallStruct
|
67
|
+
attr_reader :zoo_fn_name, :typed_args, :name
|
68
|
+
|
69
|
+
def initialize(zoo_fn_name, typed_args)
|
70
|
+
@zoo_fn_name, @typed_args = zoo_fn_name, typed_args
|
71
|
+
@name = "zkrb_#{zoo_fn_name}_args_t"
|
72
|
+
end
|
73
|
+
|
74
|
+
def body
|
75
|
+
@body ||= (
|
76
|
+
lines = ["typedef struct {"]
|
77
|
+
lines += typed_args.map{|n| " #{n};"}
|
78
|
+
lines << " int rc;"
|
79
|
+
lines << "} #{name};"
|
80
|
+
lines.join("\n")
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module MemberNames
|
86
|
+
def member_names
|
87
|
+
@member_names ||= typed_args.map { |n| n.split(/[ *]/).last }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# the zkrb_gvl_zoo_* function
|
92
|
+
class WrapperFunction
|
93
|
+
extend Forwardable
|
94
|
+
include MemberNames
|
95
|
+
|
96
|
+
PREFIX = 'zkrb_gvl'
|
97
|
+
|
98
|
+
def_delegators :struct, :typed_args
|
99
|
+
|
100
|
+
attr_reader :struct, :name, :zoo_fn_name
|
101
|
+
|
102
|
+
def initialize(zoo_fn_name, struct)
|
103
|
+
@zoo_fn_name = zoo_fn_name
|
104
|
+
@struct = struct
|
105
|
+
@name = "#{PREFIX}_#{zoo_fn_name}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def fn_signature
|
109
|
+
@fn_signature ||= "static VALUE #{name}(void *data)"
|
110
|
+
end
|
111
|
+
|
112
|
+
def body
|
113
|
+
@body ||= (
|
114
|
+
lines = ["#{fn_signature} {"]
|
115
|
+
lines << " #{struct.name} *a = (#{struct.name} *)data;"
|
116
|
+
|
117
|
+
funcall = " a->rc = #{zoo_fn_name}("
|
118
|
+
funcall << member_names.map { |m| "a->#{m}" }.join(', ')
|
119
|
+
funcall << ');'
|
120
|
+
|
121
|
+
lines << funcall
|
122
|
+
|
123
|
+
lines << " return Qnil;"
|
124
|
+
lines << "}"
|
125
|
+
lines.join("\n")
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# the zkrb_call_zoo_* function
|
131
|
+
class CallingFunction
|
132
|
+
extend Forwardable
|
133
|
+
include MemberNames
|
134
|
+
|
135
|
+
PREFIX = 'zkrb_call'
|
136
|
+
|
137
|
+
def_delegators :struct, :typed_args
|
138
|
+
|
139
|
+
attr_reader :struct, :wrapper_fn, :zoo_fn_name, :name
|
140
|
+
|
141
|
+
def initialize(zoo_fn_name, struct, wrapper_fn)
|
142
|
+
@zoo_fn_name, @struct, @wrapper_fn = zoo_fn_name, struct, wrapper_fn
|
143
|
+
|
144
|
+
@name = "#{PREFIX}_#{zoo_fn_name}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def fn_signature
|
148
|
+
@fn_signature ||= "int #{name}(#{typed_args.join(', ')})"
|
149
|
+
end
|
150
|
+
|
151
|
+
def initializer_lines
|
152
|
+
@initializer_lines ||= member_names.map { |n| " .#{n} = #{n}" }.join(",\n")
|
153
|
+
end
|
154
|
+
|
155
|
+
def top
|
156
|
+
<<-EOS
|
157
|
+
// wrapper that calls #{zoo_fn_name} via #{wrapper_fn.name} inside rb_thread_blocking_region
|
158
|
+
#{fn_signature} {
|
159
|
+
#{struct.name} args = {
|
160
|
+
.rc = ZKRB_FAIL,
|
161
|
+
#{initializer_lines}
|
162
|
+
};
|
163
|
+
EOS
|
164
|
+
end
|
165
|
+
|
166
|
+
def rb_thread_blocking_region_call
|
167
|
+
" zkrb_thread_blocking_region(#{wrapper_fn.name}, (void *)&args);"
|
168
|
+
end
|
169
|
+
|
170
|
+
def bottom
|
171
|
+
<<-EOS
|
172
|
+
|
173
|
+
return args.rc;
|
174
|
+
}
|
175
|
+
EOS
|
176
|
+
end
|
177
|
+
|
178
|
+
def body
|
179
|
+
@body ||= [top, rb_thread_blocking_region_call, bottom].join("\n")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class GeneratedCode < Struct.new(:structs, :wrapper_fns, :calling_fns)
|
184
|
+
def initialize(*a)
|
185
|
+
super
|
186
|
+
|
187
|
+
self.structs ||= []
|
188
|
+
self.wrapper_fns ||= []
|
189
|
+
self.calling_fns ||= []
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.from_zookeeper_h(text)
|
193
|
+
new.tap do |code|
|
194
|
+
while true
|
195
|
+
break unless text =~ REGEXP
|
196
|
+
text = $~.post_match
|
197
|
+
|
198
|
+
zoo_fn_name, argstr = $1
|
199
|
+
argstr = $2
|
200
|
+
|
201
|
+
typed_args = argstr.split(',').map(&:strip)
|
202
|
+
|
203
|
+
# gah, fix up zoo_aset_acl which has a void_completion_t with no name assigned
|
204
|
+
if zoo_fn_name == 'zoo_aset_acl'
|
205
|
+
if idx = typed_args.index('void_completion_t')
|
206
|
+
typed_args[idx] = 'void_completion_t completion'
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
struct = CallStruct.new(zoo_fn_name, typed_args)
|
211
|
+
wrapper_fn = WrapperFunction.new(zoo_fn_name, struct)
|
212
|
+
calling_fn = CallingFunction.new(zoo_fn_name, struct, wrapper_fn)
|
213
|
+
|
214
|
+
code.structs << struct
|
215
|
+
code.wrapper_fns << wrapper_fn
|
216
|
+
code.calling_fns << calling_fn
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def render_header_file(code)
|
223
|
+
StringIO.new('zkrb_wrapper.h', 'w').tap do |fp|
|
224
|
+
fp.puts <<-EOS
|
225
|
+
#ifndef ZKRB_WRAPPER_H
|
226
|
+
#define ZKRB_WRAPPER_H
|
227
|
+
#if 0
|
228
|
+
|
229
|
+
AUTOGENERATED BY #{File.basename(__FILE__)}
|
230
|
+
|
231
|
+
#endif
|
232
|
+
|
233
|
+
#include "ruby.h"
|
234
|
+
#include "c-client-src/zookeeper.h"
|
235
|
+
#include "zkrb_wrapper_compat.h"
|
236
|
+
#include "dbg.h"
|
237
|
+
|
238
|
+
#define ZKRB_FAIL -1
|
239
|
+
|
240
|
+
EOS
|
241
|
+
|
242
|
+
code.structs.each do |struct|
|
243
|
+
fp.puts(struct.body)
|
244
|
+
fp.puts
|
245
|
+
end
|
246
|
+
|
247
|
+
code.calling_fns.each do |cf|
|
248
|
+
fp.puts "#{cf.fn_signature};"
|
249
|
+
end
|
250
|
+
|
251
|
+
fp.puts <<-EOS
|
252
|
+
|
253
|
+
#endif /* ZKRB_WRAPPER_H */
|
254
|
+
EOS
|
255
|
+
|
256
|
+
end.string
|
257
|
+
end
|
258
|
+
|
259
|
+
def render_c_file(code)
|
260
|
+
StringIO.new('zkrb_wrapper.c', 'w').tap do |fp|
|
261
|
+
fp.puts <<-EOS
|
262
|
+
/*
|
263
|
+
|
264
|
+
Autogenerated boilerplate wrappers around zoo_* function calls necessary for using
|
265
|
+
rb_thread_blocking_region to release the GIL when calling native code.
|
266
|
+
|
267
|
+
generated by ext/#{File.basename(__FILE__)}
|
268
|
+
|
269
|
+
*/
|
270
|
+
|
271
|
+
#include "ruby.h"
|
272
|
+
#include "zkrb_wrapper.h"
|
273
|
+
#include <errno.h>
|
274
|
+
#include <stdio.h>
|
275
|
+
#include <stdlib.h>
|
276
|
+
|
277
|
+
EOS
|
278
|
+
|
279
|
+
code.wrapper_fns.zip(code.calling_fns) do |wrap_fn, call_fn|
|
280
|
+
fp.puts "#{wrap_fn.body}\n\n"
|
281
|
+
fp.puts "#{call_fn.body}\n\n"
|
282
|
+
end
|
283
|
+
|
284
|
+
end.string
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
def help!
|
289
|
+
$stderr.puts "usage: #{File.basename(__FILE__)} {all|headers|code}"
|
290
|
+
exit 1
|
291
|
+
end
|
292
|
+
|
293
|
+
def main
|
294
|
+
help! if ARGV.empty?
|
295
|
+
|
296
|
+
text = File.read('c/include/zookeeper.h')
|
297
|
+
code = GeneratedCode.from_zookeeper_h(text)
|
298
|
+
|
299
|
+
cmd = ARGV.first
|
300
|
+
|
301
|
+
help! unless %w[headers all code].include?(cmd)
|
302
|
+
|
303
|
+
if %w[headers all].include?(cmd)
|
304
|
+
$stderr.puts "writing #{ZKRB_WRAPPER_H_PATH}"
|
305
|
+
File.open(ZKRB_WRAPPER_H_PATH, 'w') { |fp| fp.write(render_header_file(code)) }
|
306
|
+
end
|
307
|
+
|
308
|
+
if %w[code all].include?(cmd)
|
309
|
+
$stderr.puts "writing #{ZKRB_WRAPPER_C_PATH}"
|
310
|
+
File.open(ZKRB_WRAPPER_C_PATH, 'w') { |fp| fp.write(render_c_file(code)) }
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
main
|
316
|
+
|