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;
21
22 import java.io.DataInput;
23 import java.io.DataOutput;
24 import java.io.IOException;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
30 import org.apache.hadoop.hbase.io.hfile.Compression;
31 import org.apache.hadoop.hbase.io.hfile.HFile;
32 import org.apache.hadoop.hbase.regionserver.StoreFile;
33 import org.apache.hadoop.hbase.regionserver.StoreFile.BloomType;
34 import org.apache.hadoop.hbase.util.Bytes;
35 import org.apache.hadoop.io.Text;
36 import org.apache.hadoop.io.WritableComparable;
37
38
39
40
41
42
43
44
45
46
47 public class HColumnDescriptor implements WritableComparable<HColumnDescriptor> {
48
49
50
51
52
53
54
55
56 private static final byte COLUMN_DESCRIPTOR_VERSION = (byte)8;
57
58
59
60
61
62
63
64 @Deprecated
65 public static enum CompressionType {
66
67 NONE,
68
69 RECORD,
70
71 BLOCK
72 }
73
74 public static final String COMPRESSION = "COMPRESSION";
75 public static final String BLOCKCACHE = "BLOCKCACHE";
76 public static final String BLOCKSIZE = "BLOCKSIZE";
77 public static final String LENGTH = "LENGTH";
78 public static final String TTL = "TTL";
79 public static final String BLOOMFILTER = "BLOOMFILTER";
80 public static final String FOREVER = "FOREVER";
81 public static final String REPLICATION_SCOPE = "REPLICATION_SCOPE";
82
83
84
85
86 public static final String DEFAULT_COMPRESSION =
87 Compression.Algorithm.NONE.getName();
88
89
90
91
92 public static final int DEFAULT_VERSIONS = 3;
93
94
95
96
97
98 private volatile Integer blocksize = null;
99
100
101
102
103 public static final boolean DEFAULT_IN_MEMORY = false;
104
105
106
107
108 public static final boolean DEFAULT_BLOCKCACHE = true;
109
110
111
112
113
114 public static final int DEFAULT_BLOCKSIZE = HFile.DEFAULT_BLOCKSIZE;
115
116
117
118
119 public static final String DEFAULT_BLOOMFILTER = StoreFile.BloomType.NONE.toString();
120
121
122
123
124 public static final int DEFAULT_TTL = HConstants.FOREVER;
125
126
127
128
129 public static final int DEFAULT_REPLICATION_SCOPE = HConstants.REPLICATION_SCOPE_LOCAL;
130
131
132 private byte [] name;
133
134
135 protected Map<ImmutableBytesWritable,ImmutableBytesWritable> values =
136 new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
137
138
139
140
141 private int cachedMaxVersions = -1;
142
143
144
145
146 public HColumnDescriptor() {
147 this.name = null;
148 }
149
150
151
152
153
154
155
156
157 public HColumnDescriptor(final String familyName) {
158 this(Bytes.toBytes(familyName));
159 }
160
161
162
163
164
165
166
167
168 public HColumnDescriptor(final byte [] familyName) {
169 this (familyName == null || familyName.length <= 0?
170 HConstants.EMPTY_BYTE_ARRAY: familyName, DEFAULT_VERSIONS,
171 DEFAULT_COMPRESSION, DEFAULT_IN_MEMORY, DEFAULT_BLOCKCACHE,
172 DEFAULT_TTL, DEFAULT_BLOOMFILTER);
173 }
174
175
176
177
178
179
180
181 public HColumnDescriptor(HColumnDescriptor desc) {
182 super();
183 this.name = desc.name.clone();
184 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
185 desc.values.entrySet()) {
186 this.values.put(e.getKey(), e.getValue());
187 }
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 public HColumnDescriptor(final byte [] familyName, final int maxVersions,
209 final String compression, final boolean inMemory,
210 final boolean blockCacheEnabled,
211 final int timeToLive, final String bloomFilter) {
212 this(familyName, maxVersions, compression, inMemory, blockCacheEnabled,
213 DEFAULT_BLOCKSIZE, timeToLive, bloomFilter, DEFAULT_REPLICATION_SCOPE);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236 public HColumnDescriptor(final byte [] familyName, final int maxVersions,
237 final String compression, final boolean inMemory,
238 final boolean blockCacheEnabled, final int blocksize,
239 final int timeToLive, final String bloomFilter, final int scope) {
240 isLegalFamilyName(familyName);
241 this.name = familyName;
242
243 if (maxVersions <= 0) {
244
245
246 throw new IllegalArgumentException("Maximum versions must be positive");
247 }
248 setMaxVersions(maxVersions);
249 setInMemory(inMemory);
250 setBlockCacheEnabled(blockCacheEnabled);
251 setTimeToLive(timeToLive);
252 setCompressionType(Compression.Algorithm.
253 valueOf(compression.toUpperCase()));
254 setBloomFilterType(StoreFile.BloomType.
255 valueOf(bloomFilter.toUpperCase()));
256 setBlocksize(blocksize);
257 setScope(scope);
258 }
259
260
261
262
263
264
265
266
267
268 public static byte [] isLegalFamilyName(final byte [] b) {
269 if (b == null) {
270 return b;
271 }
272 if (b[0] == '.') {
273 throw new IllegalArgumentException("Family names cannot start with a " +
274 "period: " + Bytes.toString(b));
275 }
276 for (int i = 0; i < b.length; i++) {
277 if (Character.isISOControl(b[i]) || b[i] == ':') {
278 throw new IllegalArgumentException("Illegal character <" + b[i] +
279 ">. Family names cannot contain control characters or colons: " +
280 Bytes.toString(b));
281 }
282 }
283 return b;
284 }
285
286
287
288
289 public byte [] getName() {
290 return name;
291 }
292
293
294
295
296 public String getNameAsString() {
297 return Bytes.toString(this.name);
298 }
299
300
301
302
303
304 public byte[] getValue(byte[] key) {
305 ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key));
306 if (ibw == null)
307 return null;
308 return ibw.get();
309 }
310
311
312
313
314
315 public String getValue(String key) {
316 byte[] value = getValue(Bytes.toBytes(key));
317 if (value == null)
318 return null;
319 return Bytes.toString(value);
320 }
321
322
323
324
325 public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
326 return Collections.unmodifiableMap(values);
327 }
328
329
330
331
332
333 public void setValue(byte[] key, byte[] value) {
334 values.put(new ImmutableBytesWritable(key),
335 new ImmutableBytesWritable(value));
336 }
337
338
339
340
341 public void remove(final byte [] key) {
342 values.remove(new ImmutableBytesWritable(key));
343 }
344
345
346
347
348
349 public void setValue(String key, String value) {
350 setValue(Bytes.toBytes(key), Bytes.toBytes(value));
351 }
352
353
354 public Compression.Algorithm getCompression() {
355 String n = getValue(COMPRESSION);
356 return Compression.Algorithm.valueOf(n.toUpperCase());
357 }
358
359
360 public synchronized int getMaxVersions() {
361 if (this.cachedMaxVersions == -1) {
362 String value = getValue(HConstants.VERSIONS);
363 this.cachedMaxVersions = (value != null)?
364 Integer.valueOf(value).intValue(): DEFAULT_VERSIONS;
365 }
366 return this.cachedMaxVersions;
367 }
368
369
370
371
372 public void setMaxVersions(int maxVersions) {
373 setValue(HConstants.VERSIONS, Integer.toString(maxVersions));
374 }
375
376
377
378
379 public synchronized int getBlocksize() {
380 if (this.blocksize == null) {
381 String value = getValue(BLOCKSIZE);
382 this.blocksize = (value != null)?
383 Integer.decode(value): Integer.valueOf(DEFAULT_BLOCKSIZE);
384 }
385 return this.blocksize.intValue();
386 }
387
388
389
390
391 public void setBlocksize(int s) {
392 setValue(BLOCKSIZE, Integer.toString(s));
393 this.blocksize = null;
394 }
395
396
397
398
399 public Compression.Algorithm getCompressionType() {
400 return getCompression();
401 }
402
403
404
405
406
407
408
409
410 public void setCompressionType(Compression.Algorithm type) {
411 String compressionType;
412 switch (type) {
413 case LZO: compressionType = "LZO"; break;
414 case GZ: compressionType = "GZ"; break;
415 default: compressionType = "NONE"; break;
416 }
417 setValue(COMPRESSION, compressionType);
418 }
419
420
421
422
423 public boolean isInMemory() {
424 String value = getValue(HConstants.IN_MEMORY);
425 if (value != null)
426 return Boolean.valueOf(value).booleanValue();
427 return DEFAULT_IN_MEMORY;
428 }
429
430
431
432
433
434 public void setInMemory(boolean inMemory) {
435 setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory));
436 }
437
438
439
440
441 public int getTimeToLive() {
442 String value = getValue(TTL);
443 return (value != null)? Integer.valueOf(value).intValue(): DEFAULT_TTL;
444 }
445
446
447
448
449 public void setTimeToLive(int timeToLive) {
450 setValue(TTL, Integer.toString(timeToLive));
451 }
452
453
454
455
456 public boolean isBlockCacheEnabled() {
457 String value = getValue(BLOCKCACHE);
458 if (value != null)
459 return Boolean.valueOf(value).booleanValue();
460 return DEFAULT_BLOCKCACHE;
461 }
462
463
464
465
466 public void setBlockCacheEnabled(boolean blockCacheEnabled) {
467 setValue(BLOCKCACHE, Boolean.toString(blockCacheEnabled));
468 }
469
470
471
472
473 public StoreFile.BloomType getBloomFilterType() {
474 String n = getValue(BLOOMFILTER);
475 if (n == null) {
476 n = DEFAULT_BLOOMFILTER;
477 }
478 return StoreFile.BloomType.valueOf(n.toUpperCase());
479 }
480
481
482
483
484 public void setBloomFilterType(final StoreFile.BloomType bt) {
485 setValue(BLOOMFILTER, bt.toString());
486 }
487
488
489
490
491 public int getScope() {
492 String value = getValue(REPLICATION_SCOPE);
493 if (value != null) {
494 return Integer.valueOf(value).intValue();
495 }
496 return DEFAULT_REPLICATION_SCOPE;
497 }
498
499
500
501
502 public void setScope(int scope) {
503 setValue(REPLICATION_SCOPE, Integer.toString(scope));
504 }
505
506
507
508
509 @Override
510 public String toString() {
511 StringBuilder s = new StringBuilder();
512 s.append('{');
513 s.append(HConstants.NAME);
514 s.append(" => '");
515 s.append(Bytes.toString(name));
516 s.append("'");
517 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
518 values.entrySet()) {
519 String key = Bytes.toString(e.getKey().get());
520 String value = Bytes.toString(e.getValue().get());
521 s.append(", ");
522 s.append(key);
523 s.append(" => '");
524 s.append(value);
525 s.append("'");
526 }
527 s.append('}');
528 return s.toString();
529 }
530
531
532
533
534 @Override
535 public boolean equals(Object obj) {
536 if (this == obj) {
537 return true;
538 }
539 if (obj == null) {
540 return false;
541 }
542 if (!(obj instanceof HColumnDescriptor)) {
543 return false;
544 }
545 return compareTo((HColumnDescriptor)obj) == 0;
546 }
547
548
549
550
551 @Override
552 public int hashCode() {
553 int result = Bytes.hashCode(this.name);
554 result ^= Byte.valueOf(COLUMN_DESCRIPTOR_VERSION).hashCode();
555 result ^= values.hashCode();
556 return result;
557 }
558
559
560
561 public void readFields(DataInput in) throws IOException {
562 int version = in.readByte();
563 if (version < 6) {
564 if (version <= 2) {
565 Text t = new Text();
566 t.readFields(in);
567 this.name = t.getBytes();
568
569
570
571
572 } else {
573 this.name = Bytes.readByteArray(in);
574 }
575 this.values.clear();
576 setMaxVersions(in.readInt());
577 int ordinal = in.readInt();
578 setCompressionType(Compression.Algorithm.values()[ordinal]);
579 setInMemory(in.readBoolean());
580 setBloomFilterType(in.readBoolean() ? BloomType.ROW : BloomType.NONE);
581 if (getBloomFilterType() != BloomType.NONE && version < 5) {
582
583
584
585
586 throw new UnsupportedClassVersionError(this.getClass().getName() +
587 " does not support backward compatibility with versions older " +
588 "than version 5");
589 }
590 if (version > 1) {
591 setBlockCacheEnabled(in.readBoolean());
592 }
593 if (version > 2) {
594 setTimeToLive(in.readInt());
595 }
596 } else {
597
598 this.name = Bytes.readByteArray(in);
599 this.values.clear();
600 int numValues = in.readInt();
601 for (int i = 0; i < numValues; i++) {
602 ImmutableBytesWritable key = new ImmutableBytesWritable();
603 ImmutableBytesWritable value = new ImmutableBytesWritable();
604 key.readFields(in);
605 value.readFields(in);
606
607
608 if (version < 8 && Bytes.toString(key.get()).equals(BLOOMFILTER)) {
609 value.set(Bytes.toBytes(
610 Boolean.getBoolean(Bytes.toString(value.get()))
611 ? BloomType.ROW.toString()
612 : BloomType.NONE.toString()));
613 }
614
615 values.put(key, value);
616 }
617 if (version == 6) {
618
619 setValue(COMPRESSION, Compression.Algorithm.NONE.getName());
620 }
621 }
622 }
623
624 public void write(DataOutput out) throws IOException {
625 out.writeByte(COLUMN_DESCRIPTOR_VERSION);
626 Bytes.writeByteArray(out, this.name);
627 out.writeInt(values.size());
628 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
629 values.entrySet()) {
630 e.getKey().write(out);
631 e.getValue().write(out);
632 }
633 }
634
635
636
637 public int compareTo(HColumnDescriptor o) {
638 int result = Bytes.compareTo(this.name, o.getName());
639 if (result == 0) {
640
641 result = this.values.hashCode() - o.values.hashCode();
642 if (result < 0)
643 result = -1;
644 else if (result > 0)
645 result = 1;
646 }
647 return result;
648 }
649 }