1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.TreeMap;
34 import java.util.TreeSet;
35 import java.util.regex.Matcher;
36
37 import org.apache.hadoop.classification.InterfaceAudience;
38 import org.apache.hadoop.classification.InterfaceStability;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.exceptions.DeserializationException;
41 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
42 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
43 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BytesBytesPair;
44 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ColumnFamilySchema;
45 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
46 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.TableSchema;
47 import org.apache.hadoop.hbase.security.User;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.Writables;
50 import org.apache.hadoop.io.WritableComparable;
51
52 import com.google.protobuf.ByteString;
53 import com.google.protobuf.InvalidProtocolBufferException;
54
55
56
57
58
59
60
61 @InterfaceAudience.Public
62 @InterfaceStability.Evolving
63 public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
64
65
66
67
68
69
70
71
72
73 private static final byte TABLE_DESCRIPTOR_VERSION = 7;
74
75 private byte [] name = HConstants.EMPTY_BYTE_ARRAY;
76
77 private String nameAsString = "";
78
79
80
81
82
83
84 private final Map<ImmutableBytesWritable, ImmutableBytesWritable> values =
85 new HashMap<ImmutableBytesWritable, ImmutableBytesWritable>();
86
87
88
89
90
91
92 private final Map<String, String> configuration = new HashMap<String, String>();
93
94 public static final String SPLIT_POLICY = "SPLIT_POLICY";
95
96
97
98
99
100
101
102
103 public static final String MAX_FILESIZE = "MAX_FILESIZE";
104 private static final ImmutableBytesWritable MAX_FILESIZE_KEY =
105 new ImmutableBytesWritable(Bytes.toBytes(MAX_FILESIZE));
106
107 public static final String OWNER = "OWNER";
108 public static final ImmutableBytesWritable OWNER_KEY =
109 new ImmutableBytesWritable(Bytes.toBytes(OWNER));
110
111
112
113
114
115
116
117 public static final String READONLY = "READONLY";
118 private static final ImmutableBytesWritable READONLY_KEY =
119 new ImmutableBytesWritable(Bytes.toBytes(READONLY));
120
121
122
123
124
125
126
127
128 public static final String MEMSTORE_FLUSHSIZE = "MEMSTORE_FLUSHSIZE";
129 private static final ImmutableBytesWritable MEMSTORE_FLUSHSIZE_KEY =
130 new ImmutableBytesWritable(Bytes.toBytes(MEMSTORE_FLUSHSIZE));
131
132
133
134
135
136
137
138 public static final String IS_ROOT = "IS_ROOT";
139 private static final ImmutableBytesWritable IS_ROOT_KEY =
140 new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT));
141
142
143
144
145
146
147
148
149 public static final String IS_META = "IS_META";
150 private static final ImmutableBytesWritable IS_META_KEY =
151 new ImmutableBytesWritable(Bytes.toBytes(IS_META));
152
153
154
155
156
157 public static final String DEFERRED_LOG_FLUSH = "DEFERRED_LOG_FLUSH";
158 private static final ImmutableBytesWritable DEFERRED_LOG_FLUSH_KEY =
159 new ImmutableBytesWritable(Bytes.toBytes(DEFERRED_LOG_FLUSH));
160
161
162
163
164
165
166 private static final ImmutableBytesWritable FALSE =
167 new ImmutableBytesWritable(Bytes.toBytes(Boolean.FALSE.toString()));
168
169 private static final ImmutableBytesWritable TRUE =
170 new ImmutableBytesWritable(Bytes.toBytes(Boolean.TRUE.toString()));
171
172 private static final boolean DEFAULT_DEFERRED_LOG_FLUSH = false;
173
174
175
176
177 public static final boolean DEFAULT_READONLY = false;
178
179
180
181
182
183 public static final long DEFAULT_MEMSTORE_FLUSH_SIZE = 1024*1024*128L;
184
185 private final static Map<String, String> DEFAULT_VALUES
186 = new HashMap<String, String>();
187 private final static Set<ImmutableBytesWritable> RESERVED_KEYWORDS
188 = new HashSet<ImmutableBytesWritable>();
189 static {
190 DEFAULT_VALUES.put(MAX_FILESIZE,
191 String.valueOf(HConstants.DEFAULT_MAX_FILE_SIZE));
192 DEFAULT_VALUES.put(READONLY, String.valueOf(DEFAULT_READONLY));
193 DEFAULT_VALUES.put(MEMSTORE_FLUSHSIZE,
194 String.valueOf(DEFAULT_MEMSTORE_FLUSH_SIZE));
195 DEFAULT_VALUES.put(DEFERRED_LOG_FLUSH,
196 String.valueOf(DEFAULT_DEFERRED_LOG_FLUSH));
197 for (String s : DEFAULT_VALUES.keySet()) {
198 RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(s)));
199 }
200 RESERVED_KEYWORDS.add(IS_ROOT_KEY);
201 RESERVED_KEYWORDS.add(IS_META_KEY);
202 }
203
204
205
206
207 private volatile Boolean meta = null;
208
209
210
211 private volatile Boolean root = null;
212
213
214
215 private Boolean deferredLog = null;
216
217
218
219
220 private final Map<byte [], HColumnDescriptor> families =
221 new TreeMap<byte [], HColumnDescriptor>(Bytes.BYTES_RAWCOMPARATOR);
222
223
224
225
226
227 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families) {
228 this.name = name.clone();
229 this.nameAsString = Bytes.toString(this.name);
230 setMetaFlags(name);
231 for(HColumnDescriptor descriptor : families) {
232 this.families.put(descriptor.getName(), descriptor);
233 }
234 }
235
236
237
238
239
240 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families,
241 Map<ImmutableBytesWritable,ImmutableBytesWritable> values) {
242 this.name = name.clone();
243 this.nameAsString = Bytes.toString(this.name);
244 setMetaFlags(name);
245 for(HColumnDescriptor descriptor : families) {
246 this.families.put(descriptor.getName(), descriptor);
247 }
248 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry:
249 values.entrySet()) {
250 setValue(entry.getKey(), entry.getValue());
251 }
252 }
253
254
255
256
257
258
259
260 @Deprecated
261 public HTableDescriptor() {
262 super();
263 }
264
265
266
267
268
269
270
271
272
273 public HTableDescriptor(final String name) {
274 this(Bytes.toBytes(name));
275 }
276
277
278
279
280
281
282
283
284
285 public HTableDescriptor(final byte [] name) {
286 super();
287 setMetaFlags(this.name);
288 this.name = this.isMetaRegion()? name: isLegalTableName(name);
289 this.nameAsString = Bytes.toString(this.name);
290 }
291
292
293
294
295
296
297
298
299 public HTableDescriptor(final HTableDescriptor desc) {
300 super();
301 this.name = desc.name.clone();
302 this.nameAsString = Bytes.toString(this.name);
303 setMetaFlags(this.name);
304 for (HColumnDescriptor c: desc.families.values()) {
305 this.families.put(c.getName(), new HColumnDescriptor(c));
306 }
307 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
308 desc.values.entrySet()) {
309 setValue(e.getKey(), e.getValue());
310 }
311 for (Map.Entry<String, String> e : desc.configuration.entrySet()) {
312 this.configuration.put(e.getKey(), e.getValue());
313 }
314 }
315
316
317
318
319
320
321
322
323 private void setMetaFlags(final byte [] name) {
324 setRootRegion(Bytes.equals(name, HConstants.ROOT_TABLE_NAME));
325 setMetaRegion(isRootRegion() ||
326 Bytes.equals(name, HConstants.META_TABLE_NAME));
327 }
328
329
330
331
332
333
334 public boolean isRootRegion() {
335 if (this.root == null) {
336 this.root = isSomething(IS_ROOT_KEY, false)? Boolean.TRUE: Boolean.FALSE;
337 }
338 return this.root.booleanValue();
339 }
340
341
342
343
344
345
346
347
348 protected void setRootRegion(boolean isRoot) {
349
350 setValue(IS_ROOT_KEY, isRoot? TRUE: FALSE);
351 }
352
353
354
355
356
357
358
359
360 public boolean isMetaRegion() {
361 if (this.meta == null) {
362 this.meta = calculateIsMetaRegion();
363 }
364 return this.meta.booleanValue();
365 }
366
367 private synchronized Boolean calculateIsMetaRegion() {
368 byte [] value = getValue(IS_META_KEY);
369 return (value != null)? Boolean.valueOf(Bytes.toString(value)): Boolean.FALSE;
370 }
371
372 private boolean isSomething(final ImmutableBytesWritable key,
373 final boolean valueIfNull) {
374 byte [] value = getValue(key);
375 if (value != null) {
376
377 return Boolean.valueOf(Bytes.toString(value));
378 }
379 return valueIfNull;
380 }
381
382
383
384
385
386
387
388
389
390 protected void setMetaRegion(boolean isMeta) {
391 setValue(IS_META_KEY, isMeta? TRUE: FALSE);
392 }
393
394
395
396
397
398
399 public boolean isMetaTable() {
400 return isMetaRegion() && !isRootRegion();
401 }
402
403
404
405
406
407
408
409
410 public static boolean isMetaTable(final byte [] tableName) {
411 return Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME) ||
412 Bytes.equals(tableName, HConstants.META_TABLE_NAME);
413 }
414
415
416 public static final String VALID_USER_TABLE_REGEX = "(?:[a-zA-Z_0-9][a-zA-Z_0-9.-]*)";
417
418
419
420
421
422
423
424
425
426 public static byte [] isLegalTableName(final byte [] tableName) {
427 if (tableName == null || tableName.length <= 0) {
428 throw new IllegalArgumentException("Name is null or empty");
429 }
430 if (tableName[0] == '.' || tableName[0] == '-') {
431 throw new IllegalArgumentException("Illegal first character <" + tableName[0] +
432 "> at 0. User-space table names can only start with 'word " +
433 "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(tableName));
434 }
435 if (HConstants.CLUSTER_ID_FILE_NAME.equalsIgnoreCase(Bytes
436 .toString(tableName))
437 || HConstants.SPLIT_LOGDIR_NAME.equalsIgnoreCase(Bytes
438 .toString(tableName))
439 || HConstants.VERSION_FILE_NAME.equalsIgnoreCase(Bytes
440 .toString(tableName))) {
441 throw new IllegalArgumentException(Bytes.toString(tableName)
442 + " conflicted with system reserved words");
443 }
444 for (int i = 0; i < tableName.length; i++) {
445 if (Character.isLetterOrDigit(tableName[i]) || tableName[i] == '_' ||
446 tableName[i] == '-' || tableName[i] == '.') {
447 continue;
448 }
449 throw new IllegalArgumentException("Illegal character <" + tableName[i] +
450 "> at " + i + ". User-space table names can only contain " +
451 "'word characters': i.e. [a-zA-Z_0-9-.]: " + Bytes.toString(tableName));
452 }
453 return tableName;
454 }
455
456
457
458
459
460
461
462
463 public byte[] getValue(byte[] key) {
464 return getValue(new ImmutableBytesWritable(key));
465 }
466
467 private byte[] getValue(final ImmutableBytesWritable key) {
468 ImmutableBytesWritable ibw = values.get(key);
469 if (ibw == null)
470 return null;
471 return ibw.get();
472 }
473
474
475
476
477
478
479
480
481 public String getValue(String key) {
482 byte[] value = getValue(Bytes.toBytes(key));
483 if (value == null)
484 return null;
485 return Bytes.toString(value);
486 }
487
488
489
490
491
492
493
494 public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
495
496 return Collections.unmodifiableMap(values);
497 }
498
499
500
501
502
503
504
505
506 public void setValue(byte[] key, byte[] value) {
507 setValue(new ImmutableBytesWritable(key), new ImmutableBytesWritable(value));
508 }
509
510
511
512
513
514 private void setValue(final ImmutableBytesWritable key,
515 final String value) {
516 setValue(key, new ImmutableBytesWritable(Bytes.toBytes(value)));
517 }
518
519
520
521
522
523 private void setValue(final ImmutableBytesWritable key,
524 final ImmutableBytesWritable value) {
525 values.put(key, value);
526 }
527
528
529
530
531
532
533
534
535 public void setValue(String key, String value) {
536 if (value == null) {
537 remove(key);
538 } else {
539 setValue(Bytes.toBytes(key), Bytes.toBytes(value));
540 }
541 }
542
543
544
545
546
547
548
549 public void remove(final String key) {
550 remove(new ImmutableBytesWritable(Bytes.toBytes(key)));
551 }
552
553
554
555
556
557
558
559 public void remove(ImmutableBytesWritable key) {
560 values.remove(key);
561 }
562
563
564
565
566
567
568
569 public boolean isReadOnly() {
570 return isSomething(READONLY_KEY, DEFAULT_READONLY);
571 }
572
573
574
575
576
577
578
579
580
581 public void setReadOnly(final boolean readOnly) {
582 setValue(READONLY_KEY, readOnly? TRUE: FALSE);
583 }
584
585
586
587
588
589
590
591
592 public synchronized boolean isDeferredLogFlush() {
593 if(this.deferredLog == null) {
594 this.deferredLog =
595 isSomething(DEFERRED_LOG_FLUSH_KEY, DEFAULT_DEFERRED_LOG_FLUSH);
596 }
597 return this.deferredLog;
598 }
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614 public synchronized void setDeferredLogFlush(final boolean isDeferredLogFlush) {
615 setValue(DEFERRED_LOG_FLUSH_KEY, isDeferredLogFlush? TRUE: FALSE);
616 this.deferredLog = isDeferredLogFlush;
617 }
618
619
620
621
622
623
624 public byte [] getName() {
625 return name;
626 }
627
628
629
630
631
632
633 public String getNameAsString() {
634 return this.nameAsString;
635 }
636
637
638
639
640
641
642
643
644
645 public String getRegionSplitPolicyClassName() {
646 return getValue(SPLIT_POLICY);
647 }
648
649
650
651
652
653
654 public void setName(byte[] name) {
655 this.name = name;
656 this.nameAsString = Bytes.toString(this.name);
657 setMetaFlags(this.name);
658 }
659
660
661
662
663
664
665
666
667
668
669 public long getMaxFileSize() {
670 byte [] value = getValue(MAX_FILESIZE_KEY);
671 if (value != null) {
672 return Long.parseLong(Bytes.toString(value));
673 }
674 return -1;
675 }
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692 public void setMaxFileSize(long maxFileSize) {
693 setValue(MAX_FILESIZE_KEY, Long.toString(maxFileSize));
694 }
695
696
697
698
699
700
701
702
703 public long getMemStoreFlushSize() {
704 byte [] value = getValue(MEMSTORE_FLUSHSIZE_KEY);
705 if (value != null) {
706 return Long.parseLong(Bytes.toString(value));
707 }
708 return -1;
709 }
710
711
712
713
714
715
716
717 public void setMemStoreFlushSize(long memstoreFlushSize) {
718 setValue(MEMSTORE_FLUSHSIZE_KEY, Long.toString(memstoreFlushSize));
719 }
720
721
722
723
724
725 public void addFamily(final HColumnDescriptor family) {
726 if (family.getName() == null || family.getName().length <= 0) {
727 throw new NullPointerException("Family name cannot be null or empty");
728 }
729 this.families.put(family.getName(), family);
730 }
731
732
733
734
735
736
737 public boolean hasFamily(final byte [] familyName) {
738 return families.containsKey(familyName);
739 }
740
741
742
743
744
745
746 @Override
747 public String toString() {
748 StringBuilder s = new StringBuilder();
749 s.append('\'').append(Bytes.toString(name)).append('\'');
750 s.append(getValues(true));
751 for (HColumnDescriptor f : families.values()) {
752 s.append(", ").append(f);
753 }
754 return s.toString();
755 }
756
757
758
759
760
761 public String toStringCustomizedValues() {
762 StringBuilder s = new StringBuilder();
763 s.append('\'').append(Bytes.toString(name)).append('\'');
764 s.append(getValues(false));
765 for(HColumnDescriptor hcd : families.values()) {
766 s.append(", ").append(hcd.toStringCustomizedValues());
767 }
768 return s.toString();
769 }
770
771 private StringBuilder getValues(boolean printDefaults) {
772 StringBuilder s = new StringBuilder();
773
774
775 Set<ImmutableBytesWritable> reservedKeys = new TreeSet<ImmutableBytesWritable>();
776 Set<ImmutableBytesWritable> userKeys = new TreeSet<ImmutableBytesWritable>();
777 for (ImmutableBytesWritable k : values.keySet()) {
778 if (k == null || k.get() == null) continue;
779 String key = Bytes.toString(k.get());
780
781 if (!RESERVED_KEYWORDS.contains(k) && !key.startsWith("coprocessor$")) {
782 userKeys.add(k);
783 continue;
784 }
785
786 String value = Bytes.toString(values.get(k).get());
787 if (key.equalsIgnoreCase(IS_ROOT) || key.equalsIgnoreCase(IS_META)) {
788 if (Boolean.valueOf(value) == false) continue;
789 }
790
791 if (printDefaults
792 || !DEFAULT_VALUES.containsKey(key)
793 || !DEFAULT_VALUES.get(key).equalsIgnoreCase(value)) {
794 reservedKeys.add(k);
795 }
796 }
797
798
799 boolean hasAttributes = !reservedKeys.isEmpty() || !userKeys.isEmpty();
800 if (!hasAttributes && configuration.isEmpty()) return s;
801
802 s.append(", {");
803
804 if (hasAttributes) {
805 s.append("TABLE_ATTRIBUTES => {");
806
807
808 boolean printCommaForAttr = false;
809 for (ImmutableBytesWritable k : reservedKeys) {
810 String key = Bytes.toString(k.get());
811 String value = Bytes.toString(values.get(k).get());
812 if (printCommaForAttr) s.append(", ");
813 printCommaForAttr = true;
814 s.append(key);
815 s.append(" => ");
816 s.append('\'').append(value).append('\'');
817 }
818
819 if (!userKeys.isEmpty()) {
820
821 if (printCommaForAttr) s.append(", ");
822 printCommaForAttr = true;
823 s.append(HConstants.METADATA).append(" => ");
824 s.append("{");
825 boolean printCommaForCfg = false;
826 for (ImmutableBytesWritable k : userKeys) {
827 String key = Bytes.toString(k.get());
828 String value = Bytes.toString(values.get(k).get());
829 if (printCommaForCfg) s.append(", ");
830 printCommaForCfg = true;
831 s.append('\'').append(key).append('\'');
832 s.append(" => ");
833 s.append('\'').append(value).append('\'');
834 }
835 s.append("}");
836 }
837 }
838
839
840 if (!configuration.isEmpty()) {
841 if (hasAttributes) {
842 s.append(", ");
843 }
844 s.append(HConstants.CONFIGURATION).append(" => ");
845 s.append('{');
846 boolean printCommaForConfig = false;
847 for (Map.Entry<String, String> e : configuration.entrySet()) {
848 if (printCommaForConfig) s.append(", ");
849 printCommaForConfig = true;
850 s.append('\'').append(e.getKey()).append('\'');
851 s.append(" => ");
852 s.append('\'').append(e.getValue()).append('\'');
853 }
854 s.append("}");
855 }
856 s.append("}");
857 return s;
858 }
859
860
861
862
863
864
865
866
867
868
869 @Override
870 public boolean equals(Object obj) {
871 if (this == obj) {
872 return true;
873 }
874 if (obj == null) {
875 return false;
876 }
877 if (!(obj instanceof HTableDescriptor)) {
878 return false;
879 }
880 return compareTo((HTableDescriptor)obj) == 0;
881 }
882
883
884
885
886 @Override
887 public int hashCode() {
888 int result = Bytes.hashCode(this.name);
889 result ^= Byte.valueOf(TABLE_DESCRIPTOR_VERSION).hashCode();
890 if (this.families != null && this.families.size() > 0) {
891 for (HColumnDescriptor e: this.families.values()) {
892 result ^= e.hashCode();
893 }
894 }
895 result ^= values.hashCode();
896 result ^= configuration.hashCode();
897 return result;
898 }
899
900
901
902
903
904
905 @Deprecated
906 @Override
907 public void readFields(DataInput in) throws IOException {
908 int version = in.readInt();
909 if (version < 3)
910 throw new IOException("versions < 3 are not supported (and never existed!?)");
911
912 name = Bytes.readByteArray(in);
913 nameAsString = Bytes.toString(this.name);
914 setRootRegion(in.readBoolean());
915 setMetaRegion(in.readBoolean());
916 values.clear();
917 configuration.clear();
918 int numVals = in.readInt();
919 for (int i = 0; i < numVals; i++) {
920 ImmutableBytesWritable key = new ImmutableBytesWritable();
921 ImmutableBytesWritable value = new ImmutableBytesWritable();
922 key.readFields(in);
923 value.readFields(in);
924 setValue(key, value);
925 }
926 families.clear();
927 int numFamilies = in.readInt();
928 for (int i = 0; i < numFamilies; i++) {
929 HColumnDescriptor c = new HColumnDescriptor();
930 c.readFields(in);
931 families.put(c.getName(), c);
932 }
933 if (version >= 7) {
934 int numConfigs = in.readInt();
935 for (int i = 0; i < numConfigs; i++) {
936 ImmutableBytesWritable key = new ImmutableBytesWritable();
937 ImmutableBytesWritable value = new ImmutableBytesWritable();
938 key.readFields(in);
939 value.readFields(in);
940 configuration.put(
941 Bytes.toString(key.get(), key.getOffset(), key.getLength()),
942 Bytes.toString(value.get(), value.getOffset(), value.getLength()));
943 }
944 }
945 }
946
947
948
949
950
951
952
953 @Deprecated
954 @Override
955 public void write(DataOutput out) throws IOException {
956 out.writeInt(TABLE_DESCRIPTOR_VERSION);
957 Bytes.writeByteArray(out, name);
958 out.writeBoolean(isRootRegion());
959 out.writeBoolean(isMetaRegion());
960 out.writeInt(values.size());
961 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
962 values.entrySet()) {
963 e.getKey().write(out);
964 e.getValue().write(out);
965 }
966 out.writeInt(families.size());
967 for(Iterator<HColumnDescriptor> it = families.values().iterator();
968 it.hasNext(); ) {
969 HColumnDescriptor family = it.next();
970 family.write(out);
971 }
972 out.writeInt(configuration.size());
973 for (Map.Entry<String, String> e : configuration.entrySet()) {
974 new ImmutableBytesWritable(Bytes.toBytes(e.getKey())).write(out);
975 new ImmutableBytesWritable(Bytes.toBytes(e.getValue())).write(out);
976 }
977 }
978
979
980
981
982
983
984
985
986
987
988 @Override
989 public int compareTo(final HTableDescriptor other) {
990 int result = Bytes.compareTo(this.name, other.name);
991 if (result == 0) {
992 result = families.size() - other.families.size();
993 }
994 if (result == 0 && families.size() != other.families.size()) {
995 result = Integer.valueOf(families.size()).compareTo(
996 Integer.valueOf(other.families.size()));
997 }
998 if (result == 0) {
999 for (Iterator<HColumnDescriptor> it = families.values().iterator(),
1000 it2 = other.families.values().iterator(); it.hasNext(); ) {
1001 result = it.next().compareTo(it2.next());
1002 if (result != 0) {
1003 break;
1004 }
1005 }
1006 }
1007 if (result == 0) {
1008
1009 result = this.values.hashCode() - other.values.hashCode();
1010 if (result < 0)
1011 result = -1;
1012 else if (result > 0)
1013 result = 1;
1014 }
1015 if (result == 0) {
1016 result = this.configuration.hashCode() - other.configuration.hashCode();
1017 if (result < 0)
1018 result = -1;
1019 else if (result > 0)
1020 result = 1;
1021 }
1022 return result;
1023 }
1024
1025
1026
1027
1028
1029
1030
1031
1032 public Collection<HColumnDescriptor> getFamilies() {
1033 return Collections.unmodifiableCollection(this.families.values());
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044 public Set<byte[]> getFamiliesKeys() {
1045 return Collections.unmodifiableSet(this.families.keySet());
1046 }
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056 public HColumnDescriptor[] getColumnFamilies() {
1057 Collection<HColumnDescriptor> hColumnDescriptors = getFamilies();
1058 return hColumnDescriptors.toArray(new HColumnDescriptor[hColumnDescriptors.size()]);
1059 }
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070 public HColumnDescriptor getFamily(final byte [] column) {
1071 return this.families.get(column);
1072 }
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 public HColumnDescriptor removeFamily(final byte [] column) {
1084 return this.families.remove(column);
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098 public void addCoprocessor(String className) throws IOException {
1099 addCoprocessor(className, null, Coprocessor.PRIORITY_USER, null);
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 public void addCoprocessor(String className, Path jarFilePath,
1118 int priority, final Map<String, String> kvs)
1119 throws IOException {
1120 if (hasCoprocessor(className)) {
1121 throw new IOException("Coprocessor " + className + " already exists.");
1122 }
1123
1124 StringBuilder kvString = new StringBuilder();
1125 if (kvs != null) {
1126 for (Map.Entry<String, String> e: kvs.entrySet()) {
1127 if (!e.getKey().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN)) {
1128 throw new IOException("Illegal parameter key = " + e.getKey());
1129 }
1130 if (!e.getValue().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN)) {
1131 throw new IOException("Illegal parameter (" + e.getKey() +
1132 ") value = " + e.getValue());
1133 }
1134 if (kvString.length() != 0) {
1135 kvString.append(',');
1136 }
1137 kvString.append(e.getKey());
1138 kvString.append('=');
1139 kvString.append(e.getValue());
1140 }
1141 }
1142
1143
1144 int maxCoprocessorNumber = 0;
1145 Matcher keyMatcher;
1146 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
1147 this.values.entrySet()) {
1148 keyMatcher =
1149 HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(
1150 Bytes.toString(e.getKey().get()));
1151 if (!keyMatcher.matches()) {
1152 continue;
1153 }
1154 maxCoprocessorNumber = Math.max(Integer.parseInt(keyMatcher.group(1)),
1155 maxCoprocessorNumber);
1156 }
1157 maxCoprocessorNumber++;
1158
1159 String key = "coprocessor$" + Integer.toString(maxCoprocessorNumber);
1160 String value = ((jarFilePath == null)? "" : jarFilePath.toString()) +
1161 "|" + className + "|" + Integer.toString(priority) + "|" +
1162 kvString.toString();
1163 setValue(key, value);
1164 }
1165
1166
1167
1168
1169
1170
1171
1172
1173 public boolean hasCoprocessor(String className) {
1174 Matcher keyMatcher;
1175 Matcher valueMatcher;
1176 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
1177 this.values.entrySet()) {
1178 keyMatcher =
1179 HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(
1180 Bytes.toString(e.getKey().get()));
1181 if (!keyMatcher.matches()) {
1182 continue;
1183 }
1184 valueMatcher =
1185 HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(
1186 Bytes.toString(e.getValue().get()));
1187 if (!valueMatcher.matches()) {
1188 continue;
1189 }
1190
1191 String clazz = valueMatcher.group(2).trim();
1192 if (clazz.equals(className.trim())) {
1193 return true;
1194 }
1195 }
1196 return false;
1197 }
1198
1199
1200
1201
1202
1203
1204 public List<String> getCoprocessors() {
1205 List<String> result = new ArrayList<String>();
1206 Matcher keyMatcher;
1207 Matcher valueMatcher;
1208 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e : this.values.entrySet()) {
1209 keyMatcher = HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e.getKey().get()));
1210 if (!keyMatcher.matches()) {
1211 continue;
1212 }
1213 valueMatcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
1214 .toString(e.getValue().get()));
1215 if (!valueMatcher.matches()) {
1216 continue;
1217 }
1218 result.add(valueMatcher.group(2).trim());
1219 }
1220 return result;
1221 }
1222
1223
1224
1225
1226
1227 public void removeCoprocessor(String className) {
1228 ImmutableBytesWritable match = null;
1229 Matcher keyMatcher;
1230 Matcher valueMatcher;
1231 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e : this.values
1232 .entrySet()) {
1233 keyMatcher = HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e
1234 .getKey().get()));
1235 if (!keyMatcher.matches()) {
1236 continue;
1237 }
1238 valueMatcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
1239 .toString(e.getValue().get()));
1240 if (!valueMatcher.matches()) {
1241 continue;
1242 }
1243
1244 String clazz = valueMatcher.group(2).trim();
1245
1246 if (clazz.equals(className.trim())) {
1247 match = e.getKey();
1248 break;
1249 }
1250 }
1251
1252 if (match != null)
1253 remove(match);
1254 }
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264 public static Path getTableDir(Path rootdir, final byte [] tableName) {
1265 return new Path(rootdir, Bytes.toString(tableName));
1266 }
1267
1268
1269 public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor(
1270 HConstants.ROOT_TABLE_NAME,
1271 new HColumnDescriptor[] {
1272 new HColumnDescriptor(HConstants.CATALOG_FAMILY)
1273
1274 .setMaxVersions(10)
1275 .setInMemory(true)
1276 .setBlocksize(8 * 1024)
1277 .setTimeToLive(HConstants.FOREVER)
1278 .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
1279 });
1280
1281
1282 public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor(
1283 HConstants.META_TABLE_NAME, new HColumnDescriptor[] {
1284 new HColumnDescriptor(HConstants.CATALOG_FAMILY)
1285
1286 .setMaxVersions(10)
1287 .setInMemory(true)
1288 .setBlocksize(8 * 1024)
1289 .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
1290 });
1291
1292 static {
1293 try {
1294 META_TABLEDESC.addCoprocessor(
1295 "org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint",
1296 null, Coprocessor.PRIORITY_SYSTEM, null);
1297 } catch (IOException ex) {
1298
1299 throw new RuntimeException(ex);
1300 }
1301 }
1302
1303
1304 @Deprecated
1305 public void setOwner(User owner) {
1306 setOwnerString(owner != null ? owner.getShortName() : null);
1307 }
1308
1309
1310 @Deprecated
1311 public void setOwnerString(String ownerString) {
1312 if (ownerString != null) {
1313 setValue(OWNER_KEY, ownerString);
1314 } else {
1315 remove(OWNER_KEY);
1316 }
1317 }
1318
1319 @Deprecated
1320 public String getOwnerString() {
1321 if (getValue(OWNER_KEY) != null) {
1322 return Bytes.toString(getValue(OWNER_KEY));
1323 }
1324
1325
1326
1327 return null;
1328 }
1329
1330
1331
1332
1333
1334 public byte [] toByteArray() {
1335 return ProtobufUtil.prependPBMagic(convert().toByteArray());
1336 }
1337
1338
1339
1340
1341
1342
1343
1344
1345 public static HTableDescriptor parseFrom(final byte [] bytes)
1346 throws DeserializationException, IOException {
1347 if (!ProtobufUtil.isPBMagicPrefix(bytes)) {
1348 return (HTableDescriptor)Writables.getWritable(bytes, new HTableDescriptor());
1349 }
1350 int pblen = ProtobufUtil.lengthOfPBMagic();
1351 TableSchema.Builder builder = TableSchema.newBuilder();
1352 TableSchema ts;
1353 try {
1354 ts = builder.mergeFrom(bytes, pblen, bytes.length - pblen).build();
1355 } catch (InvalidProtocolBufferException e) {
1356 throw new DeserializationException(e);
1357 }
1358 return convert(ts);
1359 }
1360
1361
1362
1363
1364 public TableSchema convert() {
1365 TableSchema.Builder builder = TableSchema.newBuilder();
1366 builder.setName(ByteString.copyFrom(getName()));
1367 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e: this.values.entrySet()) {
1368 BytesBytesPair.Builder aBuilder = BytesBytesPair.newBuilder();
1369 aBuilder.setFirst(ByteString.copyFrom(e.getKey().get()));
1370 aBuilder.setSecond(ByteString.copyFrom(e.getValue().get()));
1371 builder.addAttributes(aBuilder.build());
1372 }
1373 for (HColumnDescriptor hcd: getColumnFamilies()) {
1374 builder.addColumnFamilies(hcd.convert());
1375 }
1376 for (Map.Entry<String, String> e : this.configuration.entrySet()) {
1377 NameStringPair.Builder aBuilder = NameStringPair.newBuilder();
1378 aBuilder.setName(e.getKey());
1379 aBuilder.setValue(e.getValue());
1380 builder.addConfiguration(aBuilder.build());
1381 }
1382 return builder.build();
1383 }
1384
1385
1386
1387
1388
1389 public static HTableDescriptor convert(final TableSchema ts) {
1390 List<ColumnFamilySchema> list = ts.getColumnFamiliesList();
1391 HColumnDescriptor [] hcds = new HColumnDescriptor[list.size()];
1392 int index = 0;
1393 for (ColumnFamilySchema cfs: list) {
1394 hcds[index++] = HColumnDescriptor.convert(cfs);
1395 }
1396 HTableDescriptor htd = new HTableDescriptor(ts.getName().toByteArray(), hcds);
1397 for (BytesBytesPair a: ts.getAttributesList()) {
1398 htd.setValue(a.getFirst().toByteArray(), a.getSecond().toByteArray());
1399 }
1400 for (NameStringPair a: ts.getConfigurationList()) {
1401 htd.setConfiguration(a.getName(), a.getValue());
1402 }
1403 return htd;
1404 }
1405
1406
1407
1408
1409 public String getConfigurationValue(String key) {
1410 return configuration.get(key);
1411 }
1412
1413
1414
1415
1416 public Map<String, String> getConfiguration() {
1417
1418 return Collections.unmodifiableMap(configuration);
1419 }
1420
1421
1422
1423
1424
1425
1426 public void setConfiguration(String key, String value) {
1427 if (value == null) {
1428 removeConfiguration(key);
1429 } else {
1430 configuration.put(key, value);
1431 }
1432 }
1433
1434
1435
1436
1437 public void removeConfiguration(final String key) {
1438 configuration.remove(key);
1439 }
1440 }