1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.client;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.conf.Configuration;
25 import org.apache.hadoop.hbase.ClusterStatus;
26 import org.apache.hadoop.hbase.HBaseConfiguration;
27 import org.apache.hadoop.hbase.HColumnDescriptor;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.HRegionInfo;
30 import org.apache.hadoop.hbase.HRegionLocation;
31 import org.apache.hadoop.hbase.HTableDescriptor;
32 import org.apache.hadoop.hbase.MasterNotRunningException;
33 import org.apache.hadoop.hbase.RegionException;
34 import org.apache.hadoop.hbase.RemoteExceptionHandler;
35 import org.apache.hadoop.hbase.TableExistsException;
36 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
37 import org.apache.hadoop.hbase.ipc.HMasterInterface;
38 import org.apache.hadoop.hbase.ipc.HRegionInterface;
39 import org.apache.hadoop.hbase.util.Bytes;
40 import org.apache.hadoop.hbase.util.MetaUtils;
41 import org.apache.hadoop.hbase.util.Writables;
42 import org.apache.hadoop.io.BooleanWritable;
43 import org.apache.hadoop.io.Writable;
44 import org.apache.hadoop.ipc.RemoteException;
45
46 import java.io.IOException;
47 import java.util.Arrays;
48 import java.util.Map;
49 import java.util.NavigableMap;
50
51
52
53
54
55
56
57
58 public class HBaseAdmin {
59 private final Log LOG = LogFactory.getLog(this.getClass().getName());
60
61 final HConnection connection;
62 private volatile Configuration conf;
63 private final long pause;
64 private final int numRetries;
65 private volatile HMasterInterface master;
66
67
68
69
70
71
72
73 public HBaseAdmin(Configuration conf) throws MasterNotRunningException {
74 this.connection = HConnectionManager.getConnection(conf);
75 this.conf = conf;
76 this.pause = conf.getLong("hbase.client.pause", 30 * 1000);
77 this.numRetries = conf.getInt("hbase.client.retries.number", 5);
78 this.master = connection.getMaster();
79 }
80
81
82 public HConnection getConnection() {
83 return connection;
84 }
85
86
87
88
89
90 public HMasterInterface getMaster() throws MasterNotRunningException{
91 return this.connection.getMaster();
92 }
93
94
95 public boolean isMasterRunning() {
96 return this.connection.isMasterRunning();
97 }
98
99
100
101
102
103
104 public boolean tableExists(final String tableName)
105 throws MasterNotRunningException {
106 return tableExists(Bytes.toBytes(tableName));
107 }
108
109
110
111
112
113
114 public boolean tableExists(final byte [] tableName)
115 throws MasterNotRunningException {
116 if (this.master == null) {
117 throw new MasterNotRunningException("master has been shut down");
118 }
119 return connection.tableExists(tableName);
120 }
121
122
123
124
125
126
127
128
129
130
131
132 public HTableDescriptor[] listTables() throws IOException {
133 return this.connection.listTables();
134 }
135
136
137
138
139
140
141
142
143 public HTableDescriptor getTableDescriptor(final byte [] tableName)
144 throws IOException {
145 return this.connection.getHTableDescriptor(tableName);
146 }
147
148 private long getPauseTime(int tries) {
149 int triesCount = tries;
150 if (triesCount >= HConstants.RETRY_BACKOFF.length)
151 triesCount = HConstants.RETRY_BACKOFF.length - 1;
152 return this.pause * HConstants.RETRY_BACKOFF[triesCount];
153 }
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 public void createTable(HTableDescriptor desc)
169 throws IOException {
170 createTable(desc, null);
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 public void createTable(HTableDescriptor desc, byte [] startKey,
198 byte [] endKey, int numRegions)
199 throws IOException {
200 HTableDescriptor.isLegalTableName(desc.getName());
201 if(numRegions < 3) {
202 throw new IllegalArgumentException("Must create at least three regions");
203 } else if(Bytes.compareTo(startKey, endKey) >= 0) {
204 throw new IllegalArgumentException("Start key must be smaller than end key");
205 }
206 byte [][] splitKeys = Bytes.split(startKey, endKey, numRegions - 3);
207 if(splitKeys == null || splitKeys.length != numRegions - 1) {
208 throw new IllegalArgumentException("Unable to split key range into enough regions");
209 }
210 createTable(desc, splitKeys);
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 public void createTable(HTableDescriptor desc, byte [][] splitKeys)
231 throws IOException {
232 HTableDescriptor.isLegalTableName(desc.getName());
233 if(splitKeys != null && splitKeys.length > 1) {
234 Arrays.sort(splitKeys, Bytes.BYTES_COMPARATOR);
235
236 byte [] lastKey = null;
237 for(byte [] splitKey : splitKeys) {
238 if(lastKey != null && Bytes.equals(splitKey, lastKey)) {
239 throw new IllegalArgumentException("All split keys must be unique, found duplicate");
240 }
241 lastKey = splitKey;
242 }
243 }
244 createTableAsync(desc, splitKeys);
245 for (int tries = 0; tries < numRetries; tries++) {
246 try {
247
248 connection.locateRegion(desc.getName(), HConstants.EMPTY_START_ROW);
249 break;
250
251 } catch (RegionException e) {
252 if (tries == numRetries - 1) {
253
254 throw e;
255 }
256 }
257 try {
258 Thread.sleep(getPauseTime(tries));
259 } catch (InterruptedException e) {
260
261 }
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public void createTableAsync(HTableDescriptor desc, byte [][] splitKeys)
279 throws IOException {
280 if (this.master == null) {
281 throw new MasterNotRunningException("master has been shut down");
282 }
283 HTableDescriptor.isLegalTableName(desc.getName());
284 try {
285 this.master.createTable(desc, splitKeys);
286 } catch (RemoteException e) {
287 throw RemoteExceptionHandler.decodeRemoteException(e);
288 }
289 }
290
291
292
293
294
295
296
297
298 public void deleteTable(final String tableName) throws IOException {
299 deleteTable(Bytes.toBytes(tableName));
300 }
301
302
303
304
305
306
307
308
309 public void deleteTable(final byte [] tableName) throws IOException {
310 if (this.master == null) {
311 throw new MasterNotRunningException("master has been shut down");
312 }
313 HTableDescriptor.isLegalTableName(tableName);
314 HRegionLocation firstMetaServer = getFirstMetaServerForTable(tableName);
315 try {
316 this.master.deleteTable(tableName);
317 } catch (RemoteException e) {
318 throw RemoteExceptionHandler.decodeRemoteException(e);
319 }
320 final int batchCount = this.conf.getInt("hbase.admin.scanner.caching", 10);
321
322 HRegionInterface server =
323 connection.getHRegionConnection(firstMetaServer.getServerAddress());
324 HRegionInfo info = new HRegionInfo();
325 for (int tries = 0; tries < numRetries; tries++) {
326 long scannerId = -1L;
327 try {
328 Scan scan = new Scan().addColumn(HConstants.CATALOG_FAMILY,
329 HConstants.REGIONINFO_QUALIFIER);
330 scannerId = server.openScanner(
331 firstMetaServer.getRegionInfo().getRegionName(), scan);
332
333 Result [] values = server.next(scannerId, batchCount);
334 if (values == null || values.length == 0) {
335 break;
336 }
337 boolean found = false;
338 for (Result r : values) {
339 NavigableMap<byte[], byte[]> infoValues =
340 r.getFamilyMap(HConstants.CATALOG_FAMILY);
341 for (Map.Entry<byte[], byte[]> e : infoValues.entrySet()) {
342 if (Bytes.equals(e.getKey(), HConstants.REGIONINFO_QUALIFIER)) {
343 info = (HRegionInfo) Writables.getWritable(e.getValue(), info);
344 if (Bytes.equals(info.getTableDesc().getName(), tableName)) {
345 found = true;
346 } else {
347 found = false;
348 break;
349 }
350 }
351 }
352 }
353 if (!found) {
354 break;
355 }
356 } catch (IOException ex) {
357 if(tries == numRetries - 1) {
358 if (ex instanceof RemoteException) {
359 ex = RemoteExceptionHandler.decodeRemoteException((RemoteException) ex);
360 }
361 throw ex;
362 }
363 } finally {
364 if (scannerId != -1L) {
365 try {
366 server.close(scannerId);
367 } catch (Exception ex) {
368 LOG.warn(ex);
369 }
370 }
371 }
372 try {
373 Thread.sleep(getPauseTime(tries));
374 } catch (InterruptedException e) {
375
376 }
377 }
378
379 HConnectionManager.deleteConnectionInfo(conf, false);
380 LOG.info("Deleted " + Bytes.toString(tableName));
381 }
382
383
384
385
386
387
388
389
390
391
392 public void enableTable(final String tableName) throws IOException {
393 enableTable(Bytes.toBytes(tableName));
394 }
395
396
397
398
399
400
401
402
403 public void enableTable(final byte [] tableName) throws IOException {
404 if (this.master == null) {
405 throw new MasterNotRunningException("master has been shut down");
406 }
407
408
409 boolean enabled = false;
410 for (int tries = 0; tries < this.numRetries; tries++) {
411
412 try {
413 this.master.enableTable(tableName);
414 } catch (RemoteException e) {
415 throw RemoteExceptionHandler.decodeRemoteException(e);
416 }
417 enabled = isTableEnabled(tableName);
418 if (enabled) break;
419 long sleep = getPauseTime(tries);
420 if (LOG.isDebugEnabled()) {
421 LOG.debug("Sleeping= " + sleep + "ms, waiting for all regions to be " +
422 "enabled in " + Bytes.toString(tableName));
423 }
424 try {
425 Thread.sleep(sleep);
426 } catch (InterruptedException e) {
427
428 }
429 if (LOG.isDebugEnabled()) {
430 LOG.debug("Wake. Waiting for all regions to be enabled from " +
431 Bytes.toString(tableName));
432 }
433 }
434 if (!enabled)
435 throw new IOException("Unable to enable table " +
436 Bytes.toString(tableName));
437 LOG.info("Enabled table " + Bytes.toString(tableName));
438 }
439
440
441
442
443
444
445
446
447
448 public void disableTable(final String tableName) throws IOException {
449 disableTable(Bytes.toBytes(tableName));
450 }
451
452
453
454
455
456
457
458
459
460 public void disableTable(final byte [] tableName) throws IOException {
461 if (this.master == null) {
462 throw new MasterNotRunningException("master has been shut down");
463 }
464
465
466 boolean disabled = false;
467 for (int tries = 0; tries < this.numRetries; tries++) {
468 try {
469 this.master.disableTable(tableName);
470 } catch (RemoteException e) {
471 throw RemoteExceptionHandler.decodeRemoteException(e);
472 }
473 disabled = isTableDisabled(tableName);
474 if (disabled) break;
475 if (LOG.isDebugEnabled()) {
476 LOG.debug("Sleep. Waiting for all regions to be disabled from " +
477 Bytes.toString(tableName));
478 }
479 try {
480 Thread.sleep(getPauseTime(tries));
481 } catch (InterruptedException e) {
482
483 }
484 if (LOG.isDebugEnabled()) {
485 LOG.debug("Wake. Waiting for all regions to be disabled from " +
486 Bytes.toString(tableName));
487 }
488 }
489 if (!disabled) {
490 throw new RegionException("Retries exhausted, it took too long to wait"+
491 " for the table " + Bytes.toString(tableName) + " to be disabled.");
492 }
493 LOG.info("Disabled " + Bytes.toString(tableName));
494 }
495
496
497
498
499
500
501 public boolean isTableEnabled(String tableName) throws IOException {
502 return isTableEnabled(Bytes.toBytes(tableName));
503 }
504
505
506
507
508
509 public boolean isTableEnabled(byte[] tableName) throws IOException {
510 return connection.isTableEnabled(tableName);
511 }
512
513
514
515
516
517
518 public boolean isTableDisabled(byte[] tableName) throws IOException {
519 return connection.isTableDisabled(tableName);
520 }
521
522
523
524
525
526
527 public boolean isTableAvailable(byte[] tableName) throws IOException {
528 return connection.isTableAvailable(tableName);
529 }
530
531
532
533
534
535
536 public boolean isTableAvailable(String tableName) throws IOException {
537 return connection.isTableAvailable(Bytes.toBytes(tableName));
538 }
539
540
541
542
543
544
545
546
547
548 public void addColumn(final String tableName, HColumnDescriptor column)
549 throws IOException {
550 addColumn(Bytes.toBytes(tableName), column);
551 }
552
553
554
555
556
557
558
559
560
561 public void addColumn(final byte [] tableName, HColumnDescriptor column)
562 throws IOException {
563 if (this.master == null) {
564 throw new MasterNotRunningException("master has been shut down");
565 }
566 HTableDescriptor.isLegalTableName(tableName);
567 try {
568 this.master.addColumn(tableName, column);
569 } catch (RemoteException e) {
570 throw RemoteExceptionHandler.decodeRemoteException(e);
571 }
572 }
573
574
575
576
577
578
579
580
581
582 public void deleteColumn(final String tableName, final String columnName)
583 throws IOException {
584 deleteColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName));
585 }
586
587
588
589
590
591
592
593
594
595 public void deleteColumn(final byte [] tableName, final byte [] columnName)
596 throws IOException {
597 if (this.master == null) {
598 throw new MasterNotRunningException("master has been shut down");
599 }
600 HTableDescriptor.isLegalTableName(tableName);
601 try {
602 this.master.deleteColumn(tableName, columnName);
603 } catch (RemoteException e) {
604 throw RemoteExceptionHandler.decodeRemoteException(e);
605 }
606 }
607
608
609
610
611
612
613
614
615
616
617 public void modifyColumn(final String tableName, final String columnName,
618 HColumnDescriptor descriptor)
619 throws IOException {
620 modifyColumn(Bytes.toBytes(tableName), Bytes.toBytes(columnName),
621 descriptor);
622 }
623
624
625
626
627
628
629
630
631
632
633 public void modifyColumn(final byte [] tableName, final byte [] columnName,
634 HColumnDescriptor descriptor)
635 throws IOException {
636 if (this.master == null) {
637 throw new MasterNotRunningException("master has been shut down");
638 }
639 HTableDescriptor.isLegalTableName(tableName);
640 try {
641 this.master.modifyColumn(tableName, columnName, descriptor);
642 } catch (RemoteException e) {
643 throw RemoteExceptionHandler.decodeRemoteException(e);
644 }
645 }
646
647
648
649
650
651
652
653
654
655
656 public void closeRegion(final String regionname, final Object... args)
657 throws IOException {
658 closeRegion(Bytes.toBytes(regionname), args);
659 }
660
661
662
663
664
665
666
667
668
669
670 public void closeRegion(final byte [] regionname, final Object... args)
671 throws IOException {
672
673 int len = (args == null)? 0: args.length;
674 int xtraArgsCount = 1;
675 Object [] newargs = new Object[len + xtraArgsCount];
676 newargs[0] = regionname;
677 if(args != null) {
678 System.arraycopy(args, 0, newargs, xtraArgsCount, len);
679 }
680 modifyTable(HConstants.META_TABLE_NAME, HConstants.Modify.CLOSE_REGION,
681 newargs);
682 }
683
684
685
686
687
688
689
690
691 public void flush(final String tableNameOrRegionName) throws IOException {
692 flush(Bytes.toBytes(tableNameOrRegionName));
693 }
694
695
696
697
698
699
700
701
702 public void flush(final byte [] tableNameOrRegionName) throws IOException {
703 modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_FLUSH);
704 }
705
706
707
708
709
710
711
712
713 public void compact(final String tableNameOrRegionName) throws IOException {
714 compact(Bytes.toBytes(tableNameOrRegionName));
715 }
716
717
718
719
720
721
722
723
724 public void compact(final byte [] tableNameOrRegionName) throws IOException {
725 modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_COMPACT);
726 }
727
728
729
730
731
732
733
734
735 public void majorCompact(final String tableNameOrRegionName)
736 throws IOException {
737 majorCompact(Bytes.toBytes(tableNameOrRegionName));
738 }
739
740
741
742
743
744
745
746
747 public void majorCompact(final byte [] tableNameOrRegionName)
748 throws IOException {
749 modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_MAJOR_COMPACT);
750 }
751
752
753
754
755
756
757
758
759 public void split(final String tableNameOrRegionName) throws IOException {
760 split(Bytes.toBytes(tableNameOrRegionName));
761 }
762
763
764
765
766
767
768
769
770 public void split(final byte [] tableNameOrRegionName) throws IOException {
771 modifyTable(tableNameOrRegionName, HConstants.Modify.TABLE_SPLIT);
772 }
773
774
775
776
777
778
779
780
781 private void modifyTable(final byte [] tableNameOrRegionName,
782 final HConstants.Modify op)
783 throws IOException {
784 if (tableNameOrRegionName == null) {
785 throw new IllegalArgumentException("Pass a table name or region name");
786 }
787 byte [] tableName = tableExists(tableNameOrRegionName)?
788 tableNameOrRegionName: null;
789 byte [] regionName = tableName == null? tableNameOrRegionName: null;
790 Object [] args = regionName == null? null: new byte [][] {regionName};
791 modifyTable(tableName == null? null: tableName, op, args);
792 }
793
794
795
796
797
798
799
800
801
802 public void modifyTable(final byte [] tableName, HTableDescriptor htd)
803 throws IOException {
804 modifyTable(tableName, HConstants.Modify.TABLE_SET_HTD, htd);
805 }
806
807
808
809
810
811
812
813
814
815
816
817 public void modifyTable(final byte [] tableName, HConstants.Modify op,
818 Object... args)
819 throws IOException {
820 if (this.master == null) {
821 throw new MasterNotRunningException("master has been shut down");
822 }
823
824 if (tableName != null && !MetaUtils.isMetaTableName(tableName)) {
825
826 HTableDescriptor.isLegalTableName(tableName);
827 }
828 Writable[] arr = null;
829 try {
830 switch (op) {
831 case TABLE_SET_HTD:
832 if (args == null || args.length < 1 ||
833 !(args[0] instanceof HTableDescriptor)) {
834 throw new IllegalArgumentException("SET_HTD requires a HTableDescriptor");
835 }
836 arr = new Writable[1];
837 arr[0] = (HTableDescriptor)args[0];
838 this.master.modifyTable(tableName, op, arr);
839 break;
840
841 case TABLE_COMPACT:
842 case TABLE_SPLIT:
843 case TABLE_MAJOR_COMPACT:
844 case TABLE_FLUSH:
845 if (args != null && args.length > 0) {
846 arr = new Writable[1];
847 if (args[0] instanceof byte[]) {
848 arr[0] = new ImmutableBytesWritable((byte[])args[0]);
849 } else if (args[0] instanceof ImmutableBytesWritable) {
850 arr[0] = (ImmutableBytesWritable)args[0];
851 } else if (args[0] instanceof String) {
852 arr[0] = new ImmutableBytesWritable(Bytes.toBytes((String)args[0]));
853 } else {
854 throw new IllegalArgumentException("Requires byte[], String, or" +
855 "ImmutableBytesWritable");
856 }
857 }
858 this.master.modifyTable(tableName, op, arr);
859 break;
860
861 case CLOSE_REGION:
862 if (args == null || args.length < 1) {
863 throw new IllegalArgumentException("Requires at least a region name");
864 }
865 arr = new Writable[args.length];
866 for (int i = 0; i < args.length; i++) {
867 if (args[i] instanceof byte[]) {
868 arr[i] = new ImmutableBytesWritable((byte[])args[i]);
869 } else if (args[i] instanceof ImmutableBytesWritable) {
870 arr[i] = (ImmutableBytesWritable)args[i];
871 } else if (args[i] instanceof String) {
872 arr[i] = new ImmutableBytesWritable(Bytes.toBytes((String)args[i]));
873 } else if (args[i] instanceof Boolean) {
874 arr[i] = new BooleanWritable((Boolean) args[i]);
875 } else {
876 throw new IllegalArgumentException("Requires byte [] or " +
877 "ImmutableBytesWritable, not " + args[i]);
878 }
879 }
880 this.master.modifyTable(tableName, op, arr);
881 break;
882
883 default:
884 throw new IOException("unknown modifyTable op " + op);
885 }
886 } catch (RemoteException e) {
887 throw RemoteExceptionHandler.decodeRemoteException(e);
888 }
889 }
890
891
892
893
894
895 public synchronized void shutdown() throws IOException {
896 if (this.master == null) {
897 throw new MasterNotRunningException("master has been shut down");
898 }
899 try {
900 this.master.shutdown();
901 } catch (RemoteException e) {
902 throw RemoteExceptionHandler.decodeRemoteException(e);
903 } finally {
904 this.master = null;
905 }
906 }
907
908
909
910
911
912 public ClusterStatus getClusterStatus() throws IOException {
913 if (this.master == null) {
914 throw new MasterNotRunningException("master has been shut down");
915 }
916 return this.master.getClusterStatus();
917 }
918
919 private HRegionLocation getFirstMetaServerForTable(final byte [] tableName)
920 throws IOException {
921 return connection.locateRegion(HConstants.META_TABLE_NAME,
922 HRegionInfo.createRegionName(tableName, null, HConstants.NINES, false));
923 }
924
925
926
927
928
929
930
931 public static void checkHBaseAvailable(Configuration conf)
932 throws MasterNotRunningException {
933 Configuration copyOfConf = HBaseConfiguration.create(conf);
934 copyOfConf.setInt("hbase.client.retries.number", 1);
935 new HBaseAdmin(copyOfConf);
936 }
937 }