hbase-jruby 0.1.6-java → 0.2.0-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.
@@ -8,6 +8,30 @@ class HBase
8
8
 
9
9
  include Admin
10
10
 
11
+ # @overload HBase.log4j=(filename)
12
+ # Configure Log4j logging with the given file
13
+ # @param [String] filename Path to log4j.properties file
14
+ # @return [nil]
15
+ # @overload HBase.log4j=(hash)
16
+ # Configure Log4j logging with the given Hash
17
+ # @param [Hash] hash Log4j properties in Ruby Hash
18
+ # @return [nil]
19
+ # @overload HBase.log4j=(props)
20
+ # Configure Log4j logging with the given Properties
21
+ # @param [java.util.Properties] props Properties object
22
+ # @return [nil]
23
+ def self.log4j= arg
24
+ if arg.is_a?(Hash)
25
+ props = java.util.Properties.new
26
+ arg.each do |k, v|
27
+ props.setProperty k.to_s, v.to_s
28
+ end
29
+ arg = props
30
+ end
31
+
32
+ org.apache.log4j.PropertyConfigurator.configure arg
33
+ end
34
+
11
35
  # Connects to HBase
12
36
  # @param [Hash] config A key-value pairs to build HBaseConfiguration from
13
37
  def initialize config = {}
@@ -30,12 +54,15 @@ class HBase
30
54
  end
31
55
  end
32
56
  @htable_pool = HTablePool.new @config, java.lang.Integer::MAX_VALUE
57
+ @closed = false
33
58
  end
34
59
 
35
60
  # Returns an HBaseAdmin object for administration
36
- # @yield [org.apache.hadoop.hbase.client.HBaseAdmin]
61
+ # @yield [admin] An HBaseAdmin object
62
+ # @yieldparam [org.apache.hadoop.hbase.client.HBaseAdmin] admin
37
63
  # @return [org.apache.hadoop.hbase.client.HBaseAdmin]
38
64
  def admin
65
+ check_closed
39
66
  if block_given?
40
67
  with_admin { |admin| yield admin }
41
68
  else
@@ -46,37 +73,53 @@ class HBase
46
73
  # Closes HTablePool and connection
47
74
  # @return [nil]
48
75
  def close
49
- @htable_pool.close
50
- HConnectionManager.deleteConnection(@config, true)
76
+ unless @closed
77
+ @htable_pool.close
78
+ HConnectionManager.deleteConnection(@config, true)
79
+ @closed = true
80
+ end
81
+ end
82
+
83
+ # Returns whether if the connection is closed
84
+ # @return [Boolean]
85
+ def closed?
86
+ @closed
51
87
  end
52
88
 
53
89
  # Returns the list of HBase::Table instances
54
90
  # @return [Array<HBase::Table>]
55
91
  def tables
92
+ check_closed
56
93
  table_names.map { |tn| table(tn) }
57
94
  end
58
95
 
59
96
  # Returns the list of table names
60
97
  # @return [Array<String>]
61
98
  def table_names
99
+ check_closed
62
100
  with_admin { |admin| admin.list_tables.map(&:name_as_string) }
63
101
  end
102
+ alias list table_names
64
103
 
65
- # Creates HBase::Table instance for the specified name
104
+ # Creates an HBase::Table instance for the specified name
66
105
  # @param [#to_s] table_name The name of the table
67
106
  # @return [HBase::Table]
68
107
  def table table_name
69
- ht = HBase::Table.send :new, @config, @htable_pool, table_name
108
+ check_closed
109
+
110
+ ht = HBase::Table.send :new, self, @config, @htable_pool, table_name
70
111
 
71
112
  if block_given?
72
- begin
73
- yield ht
74
- ensure
75
- ht.close
76
- end
113
+ yield ht
77
114
  else
78
115
  ht
79
116
  end
80
117
  end
118
+ alias [] table
119
+
120
+ private
121
+ def check_closed
122
+ raise RuntimeError, "Connection already closed" if closed?
123
+ end
81
124
  end
82
125
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  <groupId>hbase-jruby</groupId>
6
6
  <artifactId>hbase-project</artifactId>
7
- <version>0.1.6</version>
7
+ <version>0.2</version>
8
8
  <packaging>jar</packaging>
9
9
 
10
10
  <name>hbase-jruby</name>
@@ -6,6 +6,7 @@ class HBase
6
6
  class Scoped
7
7
  include Enumerable
8
8
  include Scoped::Aggregation
9
+ include HBase::Util
9
10
 
10
11
  attr_reader :table
11
12
 
@@ -59,7 +60,8 @@ class Scoped
59
60
  end
60
61
 
61
62
  # Iterate through the scope.
62
- # @yield [HBase::Result] Yields each row in the scope
63
+ # @yield [row] Yields each row in the scope
64
+ # @yieldparam [HBase::Result] row
63
65
  def each
64
66
  if block_given?
65
67
  begin
@@ -158,6 +160,21 @@ class Scoped
158
160
  spawn :@limit, rows
159
161
  end
160
162
 
163
+ # Returns an HBase::Scoped object with the specified time range
164
+ # @param [Fixnum|Time] min Minimum timestamp (inclusive)
165
+ # @param [Fixnum|Time] max Maximum timestamp (exclusive)
166
+ # @return [HBase::Scoped] HBase::Scoped object with the specified time range
167
+ def time_range min, max
168
+ spawn :@trange, [min, max].map { |e| time_to_long e }
169
+ end
170
+
171
+ # Returns an HBase::Scoped object with the specified timestamp
172
+ # @param [Fixnum|Time] ts Timestamp
173
+ # @return [HBase::Scoped] HBase::Scoped object with the specified timestamp
174
+ def at ts
175
+ spawn :@trange, time_to_long(ts)
176
+ end
177
+
161
178
  # Returns an HBase::Scoped object with the specified projection
162
179
  # @param [Array<String>] columns Array of column expressions
163
180
  # @return [HBase::Scoped] HBase::Scoped object with the specified projection
@@ -212,6 +229,7 @@ private
212
229
  @batch = nil
213
230
  @caching = nil
214
231
  @limit = nil
232
+ @trange = nil
215
233
  end
216
234
 
217
235
  def spawn *args
@@ -339,6 +357,14 @@ private
339
357
  filters += @filters
340
358
 
341
359
  get.setFilter FilterList.new(filters) unless filters.empty?
360
+
361
+ # Timerange / Timestamp
362
+ case @trange
363
+ when Array
364
+ get.setTimeRange *@trange
365
+ when Time, Fixnum
366
+ get.setTimeStamp @trange
367
+ end
342
368
  }
343
369
  end
344
370
 
@@ -412,6 +438,7 @@ private
412
438
 
413
439
  def filtered_scan
414
440
  Scan.new.tap { |scan|
441
+ # Range
415
442
  range = @range || range_for_prefix
416
443
  case range
417
444
  when Range
@@ -430,15 +457,17 @@ private
430
457
  raise ArgumentError, "Invalid range"
431
458
  end if range
432
459
 
460
+ # Caching
433
461
  scan.caching = @caching if @caching
434
462
 
435
- # Filters
463
+ # Filters (with projection)
436
464
  prefix_filter = [*build_prefix_filter].compact
437
465
  filters = prefix_filter + @filters
438
466
  filters += process_projection!(scan)
439
467
 
440
468
  scan.setFilter FilterList.new(filters) unless filters.empty?
441
469
 
470
+ # Limit
442
471
  if @limit
443
472
  # setMaxResultSize not implemented in 0.92
444
473
  if scan.respond_to?(:setMaxResultSize)
@@ -448,12 +477,21 @@ private
448
477
  end
449
478
  end
450
479
 
480
+ # Versions
451
481
  if @versions
452
482
  scan.setMaxVersions @versions
453
483
  else
454
484
  scan.setMaxVersions
455
485
  end
456
486
 
487
+ # Timerange / Timestamp
488
+ case @trange
489
+ when Array
490
+ scan.setTimeRange *@trange
491
+ when Time, Fixnum
492
+ scan.setTimeStamp @trange
493
+ end
494
+
457
495
  # Batch
458
496
  scan.setBatch @batch if @batch
459
497
  }
@@ -0,0 +1,442 @@
1
+ class HBase
2
+ class Table
3
+ # Checks if the table of the name exists
4
+ # @return [true, false] Whether table exists
5
+ def exists?
6
+ with_admin { |admin| admin.tableExists @name }
7
+ end
8
+
9
+ # Checks if the table is enabled
10
+ # @return [true, false] Whether table is enabled
11
+ def enabled?
12
+ with_admin { |admin| admin.isTableEnabled(@name) }
13
+ end
14
+
15
+ # Checks if the table is disabled
16
+ # @return [true, false] Whether table is disabled
17
+ def disabled?
18
+ !enabled?
19
+ end
20
+
21
+ # Creates the table
22
+ # @overload create!(column_family_name, props = {})
23
+ # Create the table with one column family of the given name
24
+ # @param [#to_s] The name of the column family
25
+ # @param [Hash] props Table properties
26
+ # @return [nil]
27
+ # @overload create!(column_family_hash, props = {})
28
+ # Create the table with the specified column families
29
+ # @param [Hash] Column family properties
30
+ # @param [Hash] props Table properties
31
+ # @return [nil]
32
+ # @example
33
+ # table.create!(
34
+ # # Column family with default options
35
+ # :cf1 => {},
36
+ # # Another column family with custom properties
37
+ # :cf2 => {
38
+ # :blockcache => true,
39
+ # :blocksize => 128 * 1024,
40
+ # :bloomfilter => :row,
41
+ # :compression => :snappy,
42
+ # :in_memory => true,
43
+ # :keep_deleted_cells => true,
44
+ # :min_versions => 2,
45
+ # :replication_scope => 0,
46
+ # :ttl => 100,
47
+ # :versions => 5
48
+ # }
49
+ # )
50
+ # @overload create!(table_descriptor)
51
+ # Create the table with the given HTableDescriptor
52
+ # @param [org.apache.hadoop.hbase.HTableDescriptor] Table descriptor
53
+ # @return [nil]
54
+ def create! desc, props = {}
55
+ splits =
56
+ if props[:splits]
57
+ raise ArgumentError, ":splits property must be an Array" if !props[:splits].is_a?(Array)
58
+ props[:splits].map { |e| Util.to_bytes(e).to_a }.to_java(Java::byte[])
59
+ end
60
+
61
+ todo = nil
62
+ with_admin do |admin|
63
+ raise RuntimeError, 'Table already exists' if admin.tableExists(@name)
64
+
65
+ case desc
66
+ when HTableDescriptor
67
+ patch_table_descriptor! desc, props
68
+ admin.createTable *[desc, splits].compact
69
+ when Symbol, String
70
+ todo = lambda { create!({desc => {}}, props) }
71
+ when Hash
72
+ htd = HTableDescriptor.new(@name.to_java_bytes)
73
+ patch_table_descriptor! htd, props
74
+ desc.each do |name, opts|
75
+ htd.addFamily hcd(name, opts)
76
+ end
77
+
78
+ admin.createTable *[htd, splits].compact
79
+ else
80
+ raise ArgumentError, 'Invalid table description'
81
+ end
82
+ end
83
+ todo.call if todo # Avoids mutex relocking
84
+ end
85
+
86
+ # Alters the table (synchronous)
87
+ # @param [Hash] props Table properties
88
+ # @return [nil]
89
+ # @yield [progress, total]
90
+ # @yieldparam [Fixnum] progress Number of regions updated
91
+ # @yieldparam [Fixnum] total Total number of regions
92
+ # @example
93
+ # table.alter!(
94
+ # :max_filesize => 512 * 1024 ** 2,
95
+ # :memstore_flushsize => 64 * 1024 ** 2,
96
+ # :readonly => false,
97
+ # :deferred_log_flush => true
98
+ # )
99
+ def alter! props, &block
100
+ _alter props, true, &block
101
+ end
102
+
103
+ # Alters the table (asynchronous)
104
+ # @see HBase::Table#alter!
105
+ def alter props
106
+ _alter props, false
107
+ end
108
+
109
+ # Adds the column family (synchronous)
110
+ # @param [#to_s] name The name of the column family
111
+ # @param [Hash] opts Column family properties
112
+ # @return [nil]
113
+ # @yield [progress, total]
114
+ # @yieldparam [Fixnum] progress Number of regions updated
115
+ # @yieldparam [Fixnum] total Total number of regions
116
+ def add_family! name, opts, &block
117
+ _add_family name, opts, true, &block
118
+ end
119
+
120
+ # Adds the column family (asynchronous)
121
+ # @see HBase::Table#add_family!
122
+ def add_family name, opts
123
+ _add_family name, opts, false
124
+ end
125
+
126
+ # Alters the column family
127
+ # @param [#to_s] name The name of the column family
128
+ # @param [Hash] opts Column family properties
129
+ # @return [nil]
130
+ # @yield [progress, total]
131
+ # @yieldparam [Fixnum] progress Number of regions updated
132
+ # @yieldparam [Fixnum] total Total number of regions
133
+ def alter_family! name, opts, &block
134
+ _alter_family name, opts, true, &block
135
+ end
136
+
137
+ # Alters the column family (asynchronous)
138
+ # @see HBase::Table#alter_family!
139
+ def alter_family name, opts
140
+ _alter_family name, opts, false
141
+ end
142
+
143
+ # Removes the column family
144
+ # @param [#to_s] name The name of the column family
145
+ # @return [nil]
146
+ # @yield [progress, total]
147
+ # @yieldparam [Fixnum] progress Number of regions updated
148
+ # @yieldparam [Fixnum] total Total number of regions
149
+ def delete_family! name, &block
150
+ _delete_family name, true, &block
151
+ end
152
+
153
+ # Removes the column family (asynchronous)
154
+ # @see HBase::Table#delete_family!
155
+ def delete_family name
156
+ _delete_family name, false
157
+ end
158
+
159
+ # Adds the table coprocessor to the table
160
+ # @param [String] class_name Full class name of the coprocessor
161
+ # @param [Hash] props Coprocessor properties
162
+ # @option props [String] path The path of the JAR file
163
+ # @option props [Fixnum] priority Coprocessor priority
164
+ # @option props [Hash<#to_s, #to_s>] params Arbitrary key-value parameter pairs passed into the coprocessor
165
+ # @yield [progress, total]
166
+ # @yieldparam [Fixnum] progress Number of regions updated
167
+ # @yieldparam [Fixnum] total Total number of regions
168
+ def add_coprocessor! class_name, props = {}, &block
169
+ _add_coprocessor class_name, props, true, &block
170
+ end
171
+
172
+ # Adds the table coprocessor to the table (asynchronous)
173
+ def add_coprocessor class_name, props = {}
174
+ _add_coprocessor class_name, props, false
175
+ end
176
+
177
+ # Removes the coprocessor from the table.
178
+ # @param [String] class_name Full class name of the coprocessor
179
+ # @return [nil]
180
+ # @yield [progress, total]
181
+ # @yieldparam [Fixnum] progress Number of regions updated
182
+ # @yieldparam [Fixnum] total Total number of regions
183
+ def remove_coprocessor! class_name, &block
184
+ _remove_coprocessor class_name, true, &block
185
+ end
186
+
187
+ # Removes the coprocessor from the table (asynchronous)
188
+ # @see HBase::Table#remove_coprocessor!
189
+ def remove_coprocessor class_name
190
+ _remove_coprocessor class_name, false
191
+ end
192
+
193
+ # Return if the table has the coprocessor of the given class name
194
+ # @param [String] class_name Full class name of the coprocessor
195
+ # @return [true, false]
196
+ def has_coprocessor? class_name
197
+ descriptor.hasCoprocessor(class_name)
198
+ end
199
+
200
+ # Splits the table region on the given split point (asynchronous)
201
+ # @param [*Object] split_keys
202
+ # @return [nil]
203
+ def split! *split_keys
204
+ _split split_keys, false
205
+ end
206
+
207
+ # Enables the table
208
+ # @return [nil]
209
+ def enable!
210
+ with_admin do |admin|
211
+ admin.enableTable @name unless admin.isTableEnabled(@name)
212
+ end
213
+ end
214
+
215
+ # Disables the table
216
+ # @return [nil]
217
+ def disable!
218
+ with_admin do |admin|
219
+ admin.disableTable @name if admin.isTableEnabled(@name)
220
+ end
221
+ end
222
+
223
+ # Truncates the table by dropping it and recreating it.
224
+ # @return [nil]
225
+ def truncate!
226
+ htd = htable.get_table_descriptor
227
+ drop!
228
+ create! htd
229
+ end
230
+
231
+ # Drops the table
232
+ # @return [nil]
233
+ def drop!
234
+ with_admin do |admin|
235
+ raise RuntimeError, 'Table does not exist' unless admin.tableExists @name
236
+
237
+ admin.disableTable @name if admin.isTableEnabled(@name)
238
+ admin.deleteTable @name
239
+ close
240
+ end
241
+ end
242
+
243
+ private
244
+ COLUMN_PROPERTIES = {
245
+ :blockcache => { :set => :setBlockCacheEnabled, :get => :isBlockCacheEnabled },
246
+ :blocksize => { :set => :setBlocksize, :get => :getBlocksize },
247
+ :bloomfilter => { :set => :setBloomFilterType, :get => :getBloomFilterType },
248
+ :cache_blooms_on_write => { :set => :setCacheBloomsOnWrite, :get => :shouldCacheBloomsOnWrite },
249
+ :cache_data_on_write => { :set => :setCacheDataOnWrite, :get => :shouldCacheDataOnWrite },
250
+ :cache_index_on_write => { :set => :setCacheIndexesOnWrite, :get => :shouldCacheIndexesOnWrite },
251
+ :compression => { :set => :setCompressionType, :get => :getCompressionType },
252
+ :compression_compact => { :set => :setCompactionCompressionType, :get => :getCompactionCompression },
253
+ :data_block_encoding => { :set => :setDataBlockEncoding, :get => :getDataBlockEncoding },
254
+ :encode_on_disk => { :set => :setEncodeOnDisk, :get => nil },
255
+ :evict_blocks_on_close => { :set => :setEvictBlocksOnClose, :get => :shouldEvictBlocksOnClose },
256
+ :in_memory => { :set => :setInMemory, :get => :isInMemory },
257
+ :keep_deleted_cells => { :set => :setKeepDeletedCells, :get => :getKeepDeletedCells },
258
+ :min_versions => { :set => :setMinVersions, :get => :getMinVersions },
259
+ :replication_scope => { :set => :setScope, :get => :getScope },
260
+ :ttl => { :set => :setTimeToLive, :get => :getTimeToLive },
261
+ :versions => { :set => :setMaxVersions, :get => :getMaxVersions },
262
+ }
263
+
264
+ TABLE_PROPERTIES = {
265
+ :max_filesize => { :get => :getMaxFileSize, :set => :setMaxFileSize },
266
+ :readonly => { :get => :isReadOnly, :set => :setReadOnly },
267
+ :memstore_flushsize => { :get => :getMemStoreFlushSize, :set => :setMemStoreFlushSize },
268
+ :deferred_log_flush => { :get => :isDeferredLogFlush, :set => :setDeferredLogFlush },
269
+ }
270
+
271
+ MAX_SPLIT_WAIT = 30
272
+
273
+ def while_disabled admin
274
+ begin
275
+ admin.disableTable @name if admin.isTableEnabled(@name)
276
+ yield
277
+ ensure
278
+ admin.enableTable @name
279
+ end
280
+ end
281
+
282
+ def hcd name, opts
283
+ HColumnDescriptor.new(name.to_s).tap do |hcd|
284
+ opts.each do |key, val|
285
+ method = COLUMN_PROPERTIES[key] && COLUMN_PROPERTIES[key][:set]
286
+ if method
287
+ hcd.send method,
288
+ ({
289
+ :bloomfilter => proc { |v|
290
+ enum =
291
+ if defined?(org.apache.hadoop.hbase.regionserver.StoreFile::BloomType)
292
+ org.apache.hadoop.hbase.regionserver.StoreFile::BloomType
293
+ else
294
+ # 0.95 or later
295
+ org.apache.hadoop.hbase.regionserver.BloomType
296
+ end
297
+ const_shortcut enum, v, "Invalid bloom filter type"
298
+ },
299
+ :compression => proc { |v|
300
+ const_shortcut Compression::Algorithm, v, "Invalid compression algorithm"
301
+ },
302
+ :compression_compact => proc { |v|
303
+ const_shortcut Compression::Algorithm, v, "Invalid compression algorithm"
304
+ },
305
+ :data_block_encoding => proc { |v|
306
+ const_shortcut org.apache.hadoop.hbase.io.encoding.DataBlockEncoding, v, "Invalid data block encoding algorithm"
307
+ }
308
+ }[key] || proc { |a| a }).call(val)
309
+ elsif key.is_a?(String)
310
+ hcd.setValue key, val.to_s
311
+ else
312
+ raise ArgumentError, "Invalid property: #{key}"
313
+ end
314
+ end#opts
315
+ end
316
+ end
317
+
318
+ def const_shortcut base, v, message
319
+ # Match by constant value
320
+ # - const_get doesn't work with symbols in 1.8 compatibility mode
321
+ if base.constants.map { |c| base.const_get c }.any? { |cv| v == cv }
322
+ v
323
+ # Match by constant name (uppercase)
324
+ elsif (e = base.valueOf(vs = v.to_s.upcase) rescue nil)
325
+ e
326
+ else
327
+ raise ArgumentError, [message, v.to_s].join(': ')
328
+ end
329
+ end
330
+
331
+ def patch_table_descriptor! htd, props
332
+ props.each do |key, value|
333
+ next if key == :splits
334
+
335
+ if method = TABLE_PROPERTIES[key] && TABLE_PROPERTIES[key][:set]
336
+ htd.send method, value
337
+ elsif key.is_a?(String)
338
+ htd.setValue key, value.to_s
339
+ else
340
+ raise ArgumentError, "Invalid table property: #{key}" unless method
341
+ end
342
+ end
343
+ htd
344
+ end
345
+
346
+ def _alter props, bang, &block
347
+ raise ArgumentError, ":split not supported" if props[:splits]
348
+ with_admin do |admin|
349
+ htd = admin.get_table_descriptor(@name.to_java_bytes)
350
+ patch_table_descriptor! htd, props
351
+ while_disabled(admin) do
352
+ admin.modifyTable @name.to_java_bytes, htd
353
+ wait_async_admin(admin, &block) if bang
354
+ end
355
+ end
356
+ end
357
+
358
+ def _add_family name, opts, bang, &block
359
+ with_admin do |admin|
360
+ while_disabled(admin) do
361
+ admin.addColumn @name, hcd(name.to_s, opts)
362
+ wait_async_admin(admin, &block) if bang
363
+ end
364
+ end
365
+ end
366
+
367
+ def _alter_family name, opts, bang, &block
368
+ with_admin do |admin|
369
+ while_disabled(admin) do
370
+ admin.modifyColumn @name, hcd(name.to_s, opts)
371
+ wait_async_admin(admin, &block) if bang
372
+ end
373
+ end
374
+ end
375
+
376
+ def _delete_family name, bang, &block
377
+ with_admin do |admin|
378
+ while_disabled(admin) do
379
+ admin.deleteColumn @name, name.to_s
380
+ wait_async_admin(admin, &block) if bang
381
+ end
382
+ end
383
+ end
384
+
385
+ def _add_coprocessor class_name, props, bang, &block
386
+ with_admin do |admin|
387
+ while_disabled(admin) do
388
+
389
+ htd = admin.get_table_descriptor(@name.to_java_bytes)
390
+ if props.empty?
391
+ htd.addCoprocessor class_name
392
+ else
393
+ path, priority, params = props.values_at :path, :priority, :params
394
+ params = Hash[ params.map { |k, v| [k.to_s, v.to_s] } ]
395
+ htd.addCoprocessor class_name, path, priority || Coprocessor::PRIORITY_USER, params
396
+ end
397
+ admin.modifyTable @name.to_java_bytes, htd
398
+ wait_async_admin(admin, &block) if bang
399
+ end
400
+ end
401
+ end
402
+
403
+ def _remove_coprocessor name, bang, &block
404
+ unless HTableDescriptor.respond_to?(:removeCoprocessor)
405
+ raise NotImplementedError, "org.apache.hadoop.hbase.HTableDescriptor.removeCoprocessor not implemented"
406
+ end
407
+ with_admin do |admin|
408
+ while_disabled(admin) do
409
+ htd = admin.get_table_descriptor(@name.to_java_bytes)
410
+ htd.removeCoprocessor name
411
+ admin.modifyTable @name.to_java_bytes, htd
412
+ wait_async_admin(admin, &block) if bang
413
+ end
414
+ end
415
+ end
416
+
417
+ def _split split_keys, bang, &block
418
+ with_admin do |admin|
419
+ split_keys.each do |sk|
420
+ wait_until_all_regions_online admin
421
+ admin.split(@name.to_java_bytes, Util.to_bytes(sk))
422
+
423
+ if bang
424
+ wait_async_admin(admin, &block)
425
+ wait_until_all_regions_online admin
426
+ end
427
+ end
428
+ end
429
+ end
430
+
431
+ def wait_until_all_regions_online admin
432
+ # FIXME: progress reporting
433
+ cnt = 0
434
+ while !_regions(admin).map { |r| r[:online] }.all? { |e| e }
435
+ raise RuntimeError, "Not all regions are online" if cnt >= MAX_SPLIT_WAIT
436
+ cnt += 1
437
+ sleep 1
438
+ end
439
+ end
440
+ end#Table
441
+ end#HBase
442
+