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
@@ -0,0 +1,330 @@
1
+ #ifndef ZKRB_WRAPPER_H
2
+ #define ZKRB_WRAPPER_H
3
+ #if 0
4
+
5
+ AUTOGENERATED BY generate_gvl_code.rb
6
+
7
+ #endif
8
+
9
+ #include "ruby.h"
10
+ #include "c-client-src/zookeeper.h"
11
+ #include "zkrb_wrapper_compat.h"
12
+ #include "dbg.h"
13
+
14
+ #define ZKRB_FAIL -1
15
+
16
+ typedef struct {
17
+ zhandle_t *zh;
18
+ int rc;
19
+ } zkrb_zoo_recv_timeout_args_t;
20
+
21
+ typedef struct {
22
+ zhandle_t *zh;
23
+ int rc;
24
+ } zkrb_zoo_state_args_t;
25
+
26
+ typedef struct {
27
+ zhandle_t *zh;
28
+ const char *path;
29
+ const char *value;
30
+ int valuelen;
31
+ const struct ACL_vector *acl;
32
+ int flags;
33
+ string_completion_t completion;
34
+ const void *data;
35
+ int rc;
36
+ } zkrb_zoo_acreate_args_t;
37
+
38
+ typedef struct {
39
+ zhandle_t *zh;
40
+ const char *path;
41
+ int version;
42
+ void_completion_t completion;
43
+ const void *data;
44
+ int rc;
45
+ } zkrb_zoo_adelete_args_t;
46
+
47
+ typedef struct {
48
+ zhandle_t *zh;
49
+ const char *path;
50
+ int watch;
51
+ stat_completion_t completion;
52
+ const void *data;
53
+ int rc;
54
+ } zkrb_zoo_aexists_args_t;
55
+
56
+ typedef struct {
57
+ zhandle_t *zh;
58
+ const char *path;
59
+ watcher_fn watcher;
60
+ void* watcherCtx;
61
+ stat_completion_t completion;
62
+ const void *data;
63
+ int rc;
64
+ } zkrb_zoo_awexists_args_t;
65
+
66
+ typedef struct {
67
+ zhandle_t *zh;
68
+ const char *path;
69
+ int watch;
70
+ data_completion_t completion;
71
+ const void *data;
72
+ int rc;
73
+ } zkrb_zoo_aget_args_t;
74
+
75
+ typedef struct {
76
+ zhandle_t *zh;
77
+ const char *path;
78
+ watcher_fn watcher;
79
+ void* watcherCtx;
80
+ data_completion_t completion;
81
+ const void *data;
82
+ int rc;
83
+ } zkrb_zoo_awget_args_t;
84
+
85
+ typedef struct {
86
+ zhandle_t *zh;
87
+ const char *path;
88
+ const char *buffer;
89
+ int buflen;
90
+ int version;
91
+ stat_completion_t completion;
92
+ const void *data;
93
+ int rc;
94
+ } zkrb_zoo_aset_args_t;
95
+
96
+ typedef struct {
97
+ zhandle_t *zh;
98
+ const char *path;
99
+ int watch;
100
+ strings_completion_t completion;
101
+ const void *data;
102
+ int rc;
103
+ } zkrb_zoo_aget_children_args_t;
104
+
105
+ typedef struct {
106
+ zhandle_t *zh;
107
+ const char *path;
108
+ watcher_fn watcher;
109
+ void* watcherCtx;
110
+ strings_completion_t completion;
111
+ const void *data;
112
+ int rc;
113
+ } zkrb_zoo_awget_children_args_t;
114
+
115
+ typedef struct {
116
+ zhandle_t *zh;
117
+ const char *path;
118
+ int watch;
119
+ strings_stat_completion_t completion;
120
+ const void *data;
121
+ int rc;
122
+ } zkrb_zoo_aget_children2_args_t;
123
+
124
+ typedef struct {
125
+ zhandle_t *zh;
126
+ const char *path;
127
+ watcher_fn watcher;
128
+ void* watcherCtx;
129
+ strings_stat_completion_t completion;
130
+ const void *data;
131
+ int rc;
132
+ } zkrb_zoo_awget_children2_args_t;
133
+
134
+ typedef struct {
135
+ zhandle_t *zh;
136
+ const char *path;
137
+ string_completion_t completion;
138
+ const void *data;
139
+ int rc;
140
+ } zkrb_zoo_async_args_t;
141
+
142
+ typedef struct {
143
+ zhandle_t *zh;
144
+ const char *path;
145
+ acl_completion_t completion;
146
+ const void *data;
147
+ int rc;
148
+ } zkrb_zoo_aget_acl_args_t;
149
+
150
+ typedef struct {
151
+ zhandle_t *zh;
152
+ const char *path;
153
+ int version;
154
+ struct ACL_vector *acl;
155
+ void_completion_t completion;
156
+ const void *data;
157
+ int rc;
158
+ } zkrb_zoo_aset_acl_args_t;
159
+
160
+ typedef struct {
161
+ zhandle_t *zh;
162
+ const char* scheme;
163
+ const char* cert;
164
+ int certLen;
165
+ void_completion_t completion;
166
+ const void *data;
167
+ int rc;
168
+ } zkrb_zoo_add_auth_args_t;
169
+
170
+ typedef struct {
171
+ zhandle_t *zh;
172
+ const char *path;
173
+ const char *value;
174
+ int valuelen;
175
+ const struct ACL_vector *acl;
176
+ int flags;
177
+ char *path_buffer;
178
+ int path_buffer_len;
179
+ int rc;
180
+ } zkrb_zoo_create_args_t;
181
+
182
+ typedef struct {
183
+ zhandle_t *zh;
184
+ const char *path;
185
+ int version;
186
+ int rc;
187
+ } zkrb_zoo_delete_args_t;
188
+
189
+ typedef struct {
190
+ zhandle_t *zh;
191
+ const char *path;
192
+ int watch;
193
+ struct Stat *stat;
194
+ int rc;
195
+ } zkrb_zoo_exists_args_t;
196
+
197
+ typedef struct {
198
+ zhandle_t *zh;
199
+ const char *path;
200
+ watcher_fn watcher;
201
+ void* watcherCtx;
202
+ struct Stat *stat;
203
+ int rc;
204
+ } zkrb_zoo_wexists_args_t;
205
+
206
+ typedef struct {
207
+ zhandle_t *zh;
208
+ const char *path;
209
+ int watch;
210
+ char *buffer;
211
+ int* buffer_len;
212
+ struct Stat *stat;
213
+ int rc;
214
+ } zkrb_zoo_get_args_t;
215
+
216
+ typedef struct {
217
+ zhandle_t *zh;
218
+ const char *path;
219
+ watcher_fn watcher;
220
+ void* watcherCtx;
221
+ char *buffer;
222
+ int* buffer_len;
223
+ struct Stat *stat;
224
+ int rc;
225
+ } zkrb_zoo_wget_args_t;
226
+
227
+ typedef struct {
228
+ zhandle_t *zh;
229
+ const char *path;
230
+ const char *buffer;
231
+ int buflen;
232
+ int version;
233
+ int rc;
234
+ } zkrb_zoo_set_args_t;
235
+
236
+ typedef struct {
237
+ zhandle_t *zh;
238
+ const char *path;
239
+ const char *buffer;
240
+ int buflen;
241
+ int version;
242
+ struct Stat *stat;
243
+ int rc;
244
+ } zkrb_zoo_set2_args_t;
245
+
246
+ typedef struct {
247
+ zhandle_t *zh;
248
+ const char *path;
249
+ int watch;
250
+ struct String_vector *strings;
251
+ int rc;
252
+ } zkrb_zoo_get_children_args_t;
253
+
254
+ typedef struct {
255
+ zhandle_t *zh;
256
+ const char *path;
257
+ watcher_fn watcher;
258
+ void* watcherCtx;
259
+ struct String_vector *strings;
260
+ int rc;
261
+ } zkrb_zoo_wget_children_args_t;
262
+
263
+ typedef struct {
264
+ zhandle_t *zh;
265
+ const char *path;
266
+ int watch;
267
+ struct String_vector *strings;
268
+ struct Stat *stat;
269
+ int rc;
270
+ } zkrb_zoo_get_children2_args_t;
271
+
272
+ typedef struct {
273
+ zhandle_t *zh;
274
+ const char *path;
275
+ watcher_fn watcher;
276
+ void* watcherCtx;
277
+ struct String_vector *strings;
278
+ struct Stat *stat;
279
+ int rc;
280
+ } zkrb_zoo_wget_children2_args_t;
281
+
282
+ typedef struct {
283
+ zhandle_t *zh;
284
+ const char *path;
285
+ struct ACL_vector *acl;
286
+ struct Stat *stat;
287
+ int rc;
288
+ } zkrb_zoo_get_acl_args_t;
289
+
290
+ typedef struct {
291
+ zhandle_t *zh;
292
+ const char *path;
293
+ int version;
294
+ const struct ACL_vector *acl;
295
+ int rc;
296
+ } zkrb_zoo_set_acl_args_t;
297
+
298
+ int zkrb_call_zoo_recv_timeout(zhandle_t *zh);
299
+ int zkrb_call_zoo_state(zhandle_t *zh);
300
+ int zkrb_call_zoo_acreate(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, string_completion_t completion, const void *data);
301
+ int zkrb_call_zoo_adelete(zhandle_t *zh, const char *path, int version, void_completion_t completion, const void *data);
302
+ int zkrb_call_zoo_aexists(zhandle_t *zh, const char *path, int watch, stat_completion_t completion, const void *data);
303
+ int zkrb_call_zoo_awexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, stat_completion_t completion, const void *data);
304
+ int zkrb_call_zoo_aget(zhandle_t *zh, const char *path, int watch, data_completion_t completion, const void *data);
305
+ int zkrb_call_zoo_awget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, data_completion_t completion, const void *data);
306
+ int zkrb_call_zoo_aset(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, stat_completion_t completion, const void *data);
307
+ int zkrb_call_zoo_aget_children(zhandle_t *zh, const char *path, int watch, strings_completion_t completion, const void *data);
308
+ int zkrb_call_zoo_awget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_completion_t completion, const void *data);
309
+ int zkrb_call_zoo_aget_children2(zhandle_t *zh, const char *path, int watch, strings_stat_completion_t completion, const void *data);
310
+ int zkrb_call_zoo_awget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, strings_stat_completion_t completion, const void *data);
311
+ int zkrb_call_zoo_async(zhandle_t *zh, const char *path, string_completion_t completion, const void *data);
312
+ int zkrb_call_zoo_aget_acl(zhandle_t *zh, const char *path, acl_completion_t completion, const void *data);
313
+ int zkrb_call_zoo_aset_acl(zhandle_t *zh, const char *path, int version, struct ACL_vector *acl, void_completion_t completion, const void *data);
314
+ int zkrb_call_zoo_add_auth(zhandle_t *zh, const char* scheme, const char* cert, int certLen, void_completion_t completion, const void *data);
315
+ int zkrb_call_zoo_create(zhandle_t *zh, const char *path, const char *value, int valuelen, const struct ACL_vector *acl, int flags, char *path_buffer, int path_buffer_len);
316
+ int zkrb_call_zoo_delete(zhandle_t *zh, const char *path, int version);
317
+ int zkrb_call_zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat);
318
+ int zkrb_call_zoo_wexists(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct Stat *stat);
319
+ int zkrb_call_zoo_get(zhandle_t *zh, const char *path, int watch, char *buffer, int* buffer_len, struct Stat *stat);
320
+ int zkrb_call_zoo_wget(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, char *buffer, int* buffer_len, struct Stat *stat);
321
+ int zkrb_call_zoo_set(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version);
322
+ int zkrb_call_zoo_set2(zhandle_t *zh, const char *path, const char *buffer, int buflen, int version, struct Stat *stat);
323
+ int zkrb_call_zoo_get_children(zhandle_t *zh, const char *path, int watch, struct String_vector *strings);
324
+ int zkrb_call_zoo_wget_children(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings);
325
+ int zkrb_call_zoo_get_children2(zhandle_t *zh, const char *path, int watch, struct String_vector *strings, struct Stat *stat);
326
+ int zkrb_call_zoo_wget_children2(zhandle_t *zh, const char *path, watcher_fn watcher, void* watcherCtx, struct String_vector *strings, struct Stat *stat);
327
+ int zkrb_call_zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl, struct Stat *stat);
328
+ int zkrb_call_zoo_set_acl(zhandle_t *zh, const char *path, int version, const struct ACL_vector *acl);
329
+
330
+ #endif /* ZKRB_WRAPPER_H */
@@ -0,0 +1,15 @@
1
+ #include "ruby.h"
2
+ #include "zkrb_wrapper_compat.h"
3
+
4
+
5
+ VALUE zkrb_thread_blocking_region(zkrb_blocking_function_t *func, void *data1) {
6
+
7
+ #ifdef ZKRB_RUBY_187
8
+ return func(data1);
9
+ #else
10
+ return rb_thread_blocking_region((rb_blocking_function_t *)func, data1, RUBY_UBF_IO, 0);
11
+ #endif
12
+
13
+ }
14
+
15
+ // vim:sts=2:sw=2:et
@@ -0,0 +1,11 @@
1
+ #ifndef ZKRB_WRAPPER_COMPAT_H
2
+ #define ZKRB_WRAPPER_COMPAT_H
3
+
4
+ typedef VALUE zkrb_blocking_function_t(void *);
5
+ typedef void zkrb_unblock_function_t(void *);
6
+
7
+ // delegates to rb_thread_blocking_region on 1.9.x, always uses UBF_IO
8
+ VALUE zkrb_thread_blocking_region(zkrb_blocking_function_t *func, void *data1);
9
+
10
+
11
+ #endif /* ZKRB_WRAPPER_COMPAT_H */
@@ -0,0 +1,211 @@
1
+ require File.expand_path('../c_zookeeper', __FILE__)
2
+ require 'forwardable'
3
+
4
+ # The low-level wrapper-specific methods for the C lib
5
+ # subclassed by the top-level Zookeeper class
6
+ class ZookeeperBase
7
+ extend Forwardable
8
+ include ZookeeperCommon
9
+ include ZookeeperCallbacks
10
+ include ZookeeperConstants
11
+ include ZookeeperExceptions
12
+ include ZookeeperACLs
13
+ include ZookeeperStat
14
+
15
+ # @private
16
+ class ClientShutdownException < StandardError; end
17
+
18
+ # @private
19
+ KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
20
+
21
+ ZKRB_GLOBAL_CB_REQ = -1
22
+
23
+ # debug levels
24
+ ZOO_LOG_LEVEL_ERROR = 1
25
+ ZOO_LOG_LEVEL_WARN = 2
26
+ ZOO_LOG_LEVEL_INFO = 3
27
+ ZOO_LOG_LEVEL_DEBUG = 4
28
+
29
+ def_delegators :czk,
30
+ :get_children, :exists, :delete, :get, :set, :set_acl, :get_acl, :client_id, :sync, :selectable_io
31
+
32
+ # some state methods need to be more paranoid about locking to ensure the correct
33
+ # state is returned
34
+ #
35
+ def self.threadsafe_inquisitor(*syms)
36
+ syms.each do |sym|
37
+ class_eval(<<-EOM, __FILE__, __LINE__+1)
38
+ def #{sym}
39
+ false|@mutex.synchronize { @czk and @czk.#{sym} }
40
+ end
41
+ EOM
42
+ end
43
+ end
44
+
45
+ threadsafe_inquisitor :connected?, :connecting?, :associating?, :running?
46
+
47
+ attr_reader :event_queue
48
+
49
+ def reopen(timeout = 10, watcher=nil)
50
+ if watcher and (watcher != @default_watcher)
51
+ raise "You cannot set the watcher to a different value this way anymore!"
52
+ end
53
+
54
+ @mutex.synchronize do
55
+ # flushes all outstanding watcher reqs.
56
+ @watcher_reqs.clear
57
+ set_default_global_watcher
58
+
59
+ orig_czk, @czk = @czk, CZookeeper.new(@host, @event_queue)
60
+
61
+ orig_czk.close if orig_czk
62
+
63
+ @czk.wait_until_connected(timeout)
64
+ end
65
+
66
+ setup_dispatch_thread!
67
+ state
68
+ end
69
+
70
+ def initialize(host, timeout = 10, watcher=nil)
71
+ @watcher_reqs = {}
72
+ @completion_reqs = {}
73
+
74
+ @mutex = Monitor.new
75
+ @dispatch_shutdown_cond = @mutex.new_cond
76
+
77
+ @current_req_id = 0
78
+ @event_queue = QueueWithPipe.new
79
+ @czk = nil
80
+
81
+ # approximate the java behavior of raising java.lang.IllegalArgumentException if the host
82
+ # argument ends with '/'
83
+ raise ArgumentError, "Host argument #{host.inspect} may not end with /" if host.end_with?('/')
84
+
85
+ @host = host
86
+
87
+ @default_watcher = (watcher or get_default_global_watcher)
88
+
89
+ yield self if block_given?
90
+
91
+ reopen(timeout)
92
+ end
93
+
94
+ # synchronized accessor to the @czk instance
95
+ # @private
96
+ def czk
97
+ @mutex.synchronize { @czk }
98
+ end
99
+
100
+ # if either of these happen, the user will need to renegotiate a connection via reopen
101
+ def assert_open
102
+ raise ZookeeperException::SessionExpired if state == ZOO_EXPIRED_SESSION_STATE
103
+ raise ZookeeperException::NotConnected unless connected?
104
+ end
105
+
106
+ def close
107
+ shutdown_thread = Thread.new do
108
+ @mutex.synchronize do
109
+ stop_dispatch_thread!
110
+ @czk.close
111
+ end
112
+ end
113
+
114
+ shutdown_thread.join unless event_dispatch_thread?
115
+ end
116
+
117
+ # the C lib doesn't strip the chroot path off of returned path values, which
118
+ # is pretty damn annoying. this is used to clean things up.
119
+ def create(*args)
120
+ # since we don't care about the inputs, just glob args
121
+ rc, new_path = czk.create(*args)
122
+ [rc, strip_chroot_from(new_path)]
123
+ end
124
+
125
+ def set_debug_level(int)
126
+ warn "DEPRECATION WARNING: #{self.class.name}#set_debug_level, it has moved to the class level and will be removed in a future release"
127
+ self.class.set_debug_level(int)
128
+ end
129
+
130
+ # set the watcher object/proc that will receive all global events (such as session/state events)
131
+ def set_default_global_watcher
132
+ warn "DEPRECATION WARNING: #{self.class}#set_default_global_watcher ignores block" if block_given?
133
+
134
+ @mutex.synchronize do
135
+ # @default_watcher = block # save this here for reopen() to use
136
+ @watcher_reqs[ZKRB_GLOBAL_CB_REQ] = { :watcher => @default_watcher, :watcher_context => nil }
137
+ end
138
+ end
139
+
140
+ def state
141
+ return ZOO_CLOSED_STATE if closed?
142
+ czk.state
143
+ end
144
+
145
+ def session_id
146
+ cid = client_id and cid.session_id
147
+ end
148
+
149
+ def session_passwd
150
+ cid = client_id and cid.passwd
151
+ end
152
+
153
+ # we are closed if there is no @czk instance or @czk.closed?
154
+ def closed?
155
+ @mutex.synchronize { !@czk or @czk.closed? }
156
+ end
157
+
158
+ protected
159
+ # this is a hack: to provide consistency between the C and Java drivers when
160
+ # using a chrooted connection, we wrap the callback in a block that will
161
+ # strip the chroot path from the returned path (important in an async create
162
+ # sequential call). This is the only place where we can hook *just* the C
163
+ # version. The non-async manipulation is handled in ZookeeperBase#create.
164
+ #
165
+ def setup_completion(req_id, meth_name, call_opts)
166
+ if (meth_name == :create) and cb = call_opts[:callback]
167
+ call_opts[:callback] = lambda do |hash|
168
+ # in this case the string will be the absolute zookeeper path (i.e.
169
+ # with the chroot still prepended to the path). Here's where we strip it off
170
+ hash[:string] = strip_chroot_from(hash[:string])
171
+
172
+ # call the original callback
173
+ cb.call(hash)
174
+ end
175
+ end
176
+
177
+ # pass this along to the ZookeeperCommon implementation
178
+ super(req_id, meth_name, call_opts)
179
+ end
180
+
181
+ # if we're chrooted, this method will strip the chroot prefix from +path+
182
+ def strip_chroot_from(path)
183
+ return path unless (chrooted? and path and path.start_with?(chroot_path))
184
+ path[chroot_path.length..-1]
185
+ end
186
+
187
+ def get_default_global_watcher
188
+ Proc.new { |args|
189
+ logger.debug { "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}" }
190
+ true
191
+ }
192
+ end
193
+
194
+ def chrooted?
195
+ !chroot_path.empty?
196
+ end
197
+
198
+ def chroot_path
199
+ if @chroot_path.nil?
200
+ @chroot_path =
201
+ if idx = @host.index('/')
202
+ @host.slice(idx, @host.length)
203
+ else
204
+ ''
205
+ end
206
+ end
207
+
208
+ @chroot_path
209
+ end
210
+ end
211
+