001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import java.io.IOException; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.HashSet; 024import java.util.Map; 025import java.util.Set; 026import java.util.function.Function; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.KeepDeletedCells; 029import org.apache.hadoop.hbase.MemoryCompactionPolicy; 030import org.apache.hadoop.hbase.exceptions.DeserializationException; 031import org.apache.hadoop.hbase.exceptions.HBaseException; 032import org.apache.hadoop.hbase.io.compress.Compression; 033import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 034import org.apache.hadoop.hbase.regionserver.BloomType; 035import org.apache.hadoop.hbase.util.Bytes; 036import org.apache.hadoop.hbase.util.PrettyPrinter; 037import org.apache.hadoop.hbase.util.PrettyPrinter.Unit; 038import org.apache.yetus.audience.InterfaceAudience; 039 040import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 041 042import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 043import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ColumnFamilySchema; 044 045/** 046 * @since 2.0.0 047 */ 048@InterfaceAudience.Public 049public class ColumnFamilyDescriptorBuilder { 050 // For future backward compatibility 051 052 // Version 3 was when column names become byte arrays and when we picked up 053 // Time-to-live feature. Version 4 was when we moved to byte arrays, HBASE-82. 054 // Version 5 was when bloom filter descriptors were removed. 055 // Version 6 adds metadata as a map where keys and values are byte[]. 056 // Version 7 -- add new compression and hfile blocksize to HColumnDescriptor (HBASE-1217) 057 // Version 8 -- reintroduction of bloom filters, changed from boolean to enum 058 // Version 9 -- add data block encoding 059 // Version 10 -- change metadata to standard type. 060 // Version 11 -- add column family level configuration. 061 private static final byte COLUMN_DESCRIPTOR_VERSION = (byte) 11; 062 063 @InterfaceAudience.Private 064 public static final String IN_MEMORY_COMPACTION = "IN_MEMORY_COMPACTION"; 065 private static final Bytes IN_MEMORY_COMPACTION_BYTES = 066 new Bytes(Bytes.toBytes(IN_MEMORY_COMPACTION)); 067 068 @InterfaceAudience.Private 069 public static final String IN_MEMORY = HConstants.IN_MEMORY; 070 private static final Bytes IN_MEMORY_BYTES = new Bytes(Bytes.toBytes(IN_MEMORY)); 071 072 // These constants are used as FileInfo keys 073 @InterfaceAudience.Private 074 public static final String COMPRESSION = "COMPRESSION"; 075 private static final Bytes COMPRESSION_BYTES = new Bytes(Bytes.toBytes(COMPRESSION)); 076 @InterfaceAudience.Private 077 public static final String COMPRESSION_COMPACT = "COMPRESSION_COMPACT"; 078 private static final Bytes COMPRESSION_COMPACT_BYTES = 079 new Bytes(Bytes.toBytes(COMPRESSION_COMPACT)); 080 @InterfaceAudience.Private 081 public static final String DATA_BLOCK_ENCODING = "DATA_BLOCK_ENCODING"; 082 private static final Bytes DATA_BLOCK_ENCODING_BYTES = 083 new Bytes(Bytes.toBytes(DATA_BLOCK_ENCODING)); 084 /** 085 * Key for the BLOCKCACHE attribute. A more exact name would be CACHE_DATA_ON_READ because this 086 * flag sets whether or not we cache DATA blocks. We always cache INDEX and BLOOM blocks; caching 087 * these blocks cannot be disabled. 088 */ 089 @InterfaceAudience.Private 090 public static final String BLOCKCACHE = "BLOCKCACHE"; 091 private static final Bytes BLOCKCACHE_BYTES = new Bytes(Bytes.toBytes(BLOCKCACHE)); 092 @InterfaceAudience.Private 093 public static final String CACHE_DATA_ON_WRITE = "CACHE_DATA_ON_WRITE"; 094 private static final Bytes CACHE_DATA_ON_WRITE_BYTES = 095 new Bytes(Bytes.toBytes(CACHE_DATA_ON_WRITE)); 096 @InterfaceAudience.Private 097 public static final String CACHE_INDEX_ON_WRITE = "CACHE_INDEX_ON_WRITE"; 098 private static final Bytes CACHE_INDEX_ON_WRITE_BYTES = 099 new Bytes(Bytes.toBytes(CACHE_INDEX_ON_WRITE)); 100 @InterfaceAudience.Private 101 public static final String CACHE_BLOOMS_ON_WRITE = "CACHE_BLOOMS_ON_WRITE"; 102 private static final Bytes CACHE_BLOOMS_ON_WRITE_BYTES = 103 new Bytes(Bytes.toBytes(CACHE_BLOOMS_ON_WRITE)); 104 @InterfaceAudience.Private 105 public static final String EVICT_BLOCKS_ON_CLOSE = "EVICT_BLOCKS_ON_CLOSE"; 106 private static final Bytes EVICT_BLOCKS_ON_CLOSE_BYTES = 107 new Bytes(Bytes.toBytes(EVICT_BLOCKS_ON_CLOSE)); 108 109 /** 110 * Key for the PREFETCH_BLOCKS_ON_OPEN attribute. If set, all INDEX, BLOOM, and DATA blocks of 111 * HFiles belonging to this family will be loaded into the cache as soon as the file is opened. 112 * These loads will not count as cache misses. 113 */ 114 @InterfaceAudience.Private 115 public static final String PREFETCH_BLOCKS_ON_OPEN = "PREFETCH_BLOCKS_ON_OPEN"; 116 private static final Bytes PREFETCH_BLOCKS_ON_OPEN_BYTES = 117 new Bytes(Bytes.toBytes(PREFETCH_BLOCKS_ON_OPEN)); 118 119 /** 120 * Size of storefile/hfile 'blocks'. Default is {@link #DEFAULT_BLOCKSIZE}. Use smaller block 121 * sizes for faster random-access at expense of larger indices (more memory consumption). Note 122 * that this is a soft limit and that blocks have overhead (metadata, CRCs) so blocks will tend to 123 * be the size specified here and then some; i.e. don't expect that setting BLOCKSIZE=4k means 124 * hbase data will align with an SSDs 4k page accesses (TODO). 125 */ 126 @InterfaceAudience.Private 127 public static final String BLOCKSIZE = "BLOCKSIZE"; 128 private static final Bytes BLOCKSIZE_BYTES = new Bytes(Bytes.toBytes(BLOCKSIZE)); 129 130 @InterfaceAudience.Private 131 public static final String TTL = "TTL"; 132 private static final Bytes TTL_BYTES = new Bytes(Bytes.toBytes(TTL)); 133 @InterfaceAudience.Private 134 public static final String BLOOMFILTER = "BLOOMFILTER"; 135 private static final Bytes BLOOMFILTER_BYTES = new Bytes(Bytes.toBytes(BLOOMFILTER)); 136 @InterfaceAudience.Private 137 public static final String REPLICATION_SCOPE = "REPLICATION_SCOPE"; 138 @InterfaceAudience.Private 139 public static final String MAX_VERSIONS = HConstants.VERSIONS; 140 private static final Bytes MAX_VERSIONS_BYTES = new Bytes(Bytes.toBytes(MAX_VERSIONS)); 141 @InterfaceAudience.Private 142 public static final String MIN_VERSIONS = "MIN_VERSIONS"; 143 private static final Bytes MIN_VERSIONS_BYTES = new Bytes(Bytes.toBytes(MIN_VERSIONS)); 144 /** 145 * Retain all cells across flushes and compactions even if they fall behind a delete tombstone. To 146 * see all retained cells, do a 'raw' scan; see Scan#setRaw or pass RAW => true attribute in 147 * the shell. 148 */ 149 @InterfaceAudience.Private 150 public static final String KEEP_DELETED_CELLS = "KEEP_DELETED_CELLS"; 151 private static final Bytes KEEP_DELETED_CELLS_BYTES = 152 new Bytes(Bytes.toBytes(KEEP_DELETED_CELLS)); 153 @InterfaceAudience.Private 154 public static final String COMPRESS_TAGS = "COMPRESS_TAGS"; 155 private static final Bytes COMPRESS_TAGS_BYTES = new Bytes(Bytes.toBytes(COMPRESS_TAGS)); 156 @InterfaceAudience.Private 157 public static final String ENCRYPTION = "ENCRYPTION"; 158 private static final Bytes ENCRYPTION_BYTES = new Bytes(Bytes.toBytes(ENCRYPTION)); 159 @InterfaceAudience.Private 160 public static final String ENCRYPTION_KEY = "ENCRYPTION_KEY"; 161 private static final Bytes ENCRYPTION_KEY_BYTES = new Bytes(Bytes.toBytes(ENCRYPTION_KEY)); 162 163 private static final boolean DEFAULT_MOB = false; 164 @InterfaceAudience.Private 165 public static final String IS_MOB = "IS_MOB"; 166 private static final Bytes IS_MOB_BYTES = new Bytes(Bytes.toBytes(IS_MOB)); 167 @InterfaceAudience.Private 168 public static final String MOB_THRESHOLD = "MOB_THRESHOLD"; 169 private static final Bytes MOB_THRESHOLD_BYTES = new Bytes(Bytes.toBytes(MOB_THRESHOLD)); 170 public static final long DEFAULT_MOB_THRESHOLD = 100 * 1024; // 100k 171 @InterfaceAudience.Private 172 public static final String MOB_COMPACT_PARTITION_POLICY = "MOB_COMPACT_PARTITION_POLICY"; 173 private static final Bytes MOB_COMPACT_PARTITION_POLICY_BYTES = 174 new Bytes(Bytes.toBytes(MOB_COMPACT_PARTITION_POLICY)); 175 public static final MobCompactPartitionPolicy DEFAULT_MOB_COMPACT_PARTITION_POLICY = 176 MobCompactPartitionPolicy.DAILY; 177 @InterfaceAudience.Private 178 public static final String DFS_REPLICATION = "DFS_REPLICATION"; 179 private static final Bytes DFS_REPLICATION_BYTES = new Bytes(Bytes.toBytes(DFS_REPLICATION)); 180 public static final short DEFAULT_DFS_REPLICATION = 0; 181 @InterfaceAudience.Private 182 public static final String STORAGE_POLICY = "STORAGE_POLICY"; 183 private static final Bytes STORAGE_POLICY_BYTES = new Bytes(Bytes.toBytes(STORAGE_POLICY)); 184 185 public static final String NEW_VERSION_BEHAVIOR = "NEW_VERSION_BEHAVIOR"; 186 private static final Bytes NEW_VERSION_BEHAVIOR_BYTES = 187 new Bytes(Bytes.toBytes(NEW_VERSION_BEHAVIOR)); 188 public static final boolean DEFAULT_NEW_VERSION_BEHAVIOR = false; 189 /** 190 * Default compression type. 191 */ 192 public static final Compression.Algorithm DEFAULT_COMPRESSION = Compression.Algorithm.NONE; 193 194 /** 195 * Default data block encoding algorithm. 196 */ 197 public static final DataBlockEncoding DEFAULT_DATA_BLOCK_ENCODING = DataBlockEncoding.NONE; 198 199 /** 200 * Default number of versions of a record to keep. 201 */ 202 public static final int DEFAULT_MAX_VERSIONS = 1; 203 204 /** 205 * Default is not to keep a minimum of versions. 206 */ 207 public static final int DEFAULT_MIN_VERSIONS = 0; 208 209 /** 210 * Default setting for whether to try and serve this column family from memory or not. 211 */ 212 public static final boolean DEFAULT_IN_MEMORY = false; 213 214 /** 215 * Default setting for preventing deleted from being collected immediately. 216 */ 217 public static final KeepDeletedCells DEFAULT_KEEP_DELETED = KeepDeletedCells.FALSE; 218 219 /** 220 * Default setting for whether to use a block cache or not. 221 */ 222 public static final boolean DEFAULT_BLOCKCACHE = true; 223 224 /** 225 * Default setting for whether to cache data blocks on write if block caching is enabled. 226 */ 227 public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false; 228 229 /** 230 * Default setting for whether to cache index blocks on write if block caching is enabled. 231 */ 232 public static final boolean DEFAULT_CACHE_INDEX_ON_WRITE = false; 233 234 /** 235 * Default size of blocks in files stored to the filesytem (hfiles). 236 */ 237 public static final int DEFAULT_BLOCKSIZE = HConstants.DEFAULT_BLOCKSIZE; 238 239 /** 240 * Default setting for whether or not to use bloomfilters. 241 */ 242 public static final BloomType DEFAULT_BLOOMFILTER = BloomType.ROW; 243 244 /** 245 * Default setting for whether to cache bloom filter blocks on write if block caching is enabled. 246 */ 247 public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false; 248 249 /** 250 * Default time to live of cell contents. 251 */ 252 public static final int DEFAULT_TTL = HConstants.FOREVER; 253 254 /** 255 * Default scope. 256 */ 257 public static final int DEFAULT_REPLICATION_SCOPE = HConstants.REPLICATION_SCOPE_LOCAL; 258 259 /** 260 * Default setting for whether to evict cached blocks from the blockcache on close. 261 */ 262 public static final boolean DEFAULT_EVICT_BLOCKS_ON_CLOSE = false; 263 264 /** 265 * Default compress tags along with any type of DataBlockEncoding. 266 */ 267 public static final boolean DEFAULT_COMPRESS_TAGS = true; 268 269 /* 270 * Default setting for whether to prefetch blocks into the blockcache on open. 271 */ 272 public static final boolean DEFAULT_PREFETCH_BLOCKS_ON_OPEN = false; 273 274 private final static Map<String, String> DEFAULT_VALUES = new HashMap<>(); 275 276 private static Map<Bytes, Bytes> getDefaultValuesBytes() { 277 Map<Bytes, Bytes> values = new HashMap<>(); 278 DEFAULT_VALUES 279 .forEach((k, v) -> values.put(new Bytes(Bytes.toBytes(k)), new Bytes(Bytes.toBytes(v)))); 280 return values; 281 } 282 283 public static Map<String, String> getDefaultValues() { 284 return Collections.unmodifiableMap(DEFAULT_VALUES); 285 } 286 287 private final static Set<Bytes> RESERVED_KEYWORDS = new HashSet<>(); 288 289 static { 290 DEFAULT_VALUES.put(BLOOMFILTER, DEFAULT_BLOOMFILTER.name()); 291 DEFAULT_VALUES.put(REPLICATION_SCOPE, String.valueOf(DEFAULT_REPLICATION_SCOPE)); 292 DEFAULT_VALUES.put(MAX_VERSIONS, String.valueOf(DEFAULT_MAX_VERSIONS)); 293 DEFAULT_VALUES.put(MIN_VERSIONS, String.valueOf(DEFAULT_MIN_VERSIONS)); 294 DEFAULT_VALUES.put(COMPRESSION, DEFAULT_COMPRESSION.name()); 295 DEFAULT_VALUES.put(TTL, String.valueOf(DEFAULT_TTL)); 296 DEFAULT_VALUES.put(BLOCKSIZE, String.valueOf(DEFAULT_BLOCKSIZE)); 297 DEFAULT_VALUES.put(IN_MEMORY, String.valueOf(DEFAULT_IN_MEMORY)); 298 DEFAULT_VALUES.put(BLOCKCACHE, String.valueOf(DEFAULT_BLOCKCACHE)); 299 DEFAULT_VALUES.put(KEEP_DELETED_CELLS, String.valueOf(DEFAULT_KEEP_DELETED)); 300 DEFAULT_VALUES.put(DATA_BLOCK_ENCODING, String.valueOf(DEFAULT_DATA_BLOCK_ENCODING)); 301 // Do NOT add this key/value by default. NEW_VERSION_BEHAVIOR is NOT defined in hbase1 so 302 // it is not possible to make an hbase1 HCD the same as an hbase2 HCD and so the replication 303 // compare of schemas will fail. It is OK not adding the below to the initial map because of 304 // fetch of this value, we will check for null and if null will return the default. 305 // DEFAULT_VALUES.put(NEW_VERSION_BEHAVIOR, String.valueOf(DEFAULT_NEW_VERSION_BEHAVIOR)); 306 DEFAULT_VALUES.keySet().forEach(s -> RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(s)))); 307 RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(ENCRYPTION))); 308 RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(ENCRYPTION_KEY))); 309 RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(IS_MOB))); 310 RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(MOB_THRESHOLD))); 311 RESERVED_KEYWORDS.add(new Bytes(Bytes.toBytes(MOB_COMPACT_PARTITION_POLICY))); 312 } 313 314 public static Unit getUnit(String key) { 315 /* TTL for now, we can add more as we need */ 316 switch (key) { 317 case TTL: 318 return Unit.TIME_INTERVAL; 319 default: 320 return Unit.NONE; 321 } 322 } 323 324 /** 325 * @param b Family name. 326 * @return <code>b</code> 327 * @throws IllegalArgumentException If not null and not a legitimate family name: i.e. 'printable' 328 * and ends in a ':' (Null passes are allowed because 329 * <code>b</code> can be null when deserializing). Cannot start 330 * with a '.' either. Also Family can not be an empty value or 331 * equal "recovered.edits". 332 */ 333 public static byte[] isLegalColumnFamilyName(final byte[] b) { 334 if (b == null) { 335 return null; 336 } 337 Preconditions.checkArgument(b.length != 0, "Column Family name can not be empty"); 338 if (b[0] == '.') { 339 throw new IllegalArgumentException( 340 "Column Family names cannot start with a " + "period: " + Bytes.toString(b)); 341 } 342 for (int i = 0; i < b.length; i++) { 343 if (Character.isISOControl(b[i]) || b[i] == ':' || b[i] == '\\' || b[i] == '/') { 344 throw new IllegalArgumentException("Illegal character <" + b[i] 345 + ">. Column Family names cannot contain control characters or colons: " 346 + Bytes.toString(b)); 347 } 348 } 349 byte[] recoveredEdit = Bytes.toBytes(HConstants.RECOVERED_EDITS_DIR); 350 if (Bytes.equals(recoveredEdit, b)) { 351 throw new IllegalArgumentException( 352 "Column Family name cannot be: " + HConstants.RECOVERED_EDITS_DIR); 353 } 354 return b; 355 } 356 357 private final ModifyableColumnFamilyDescriptor desc; 358 359 public static ColumnFamilyDescriptor parseFrom(final byte[] pbBytes) 360 throws DeserializationException { 361 return ModifyableColumnFamilyDescriptor.parseFrom(pbBytes); 362 } 363 364 public static ColumnFamilyDescriptorBuilder newBuilder(final byte[] name) { 365 return new ColumnFamilyDescriptorBuilder(name); 366 } 367 368 public static ColumnFamilyDescriptorBuilder newBuilder(final ColumnFamilyDescriptor desc) { 369 return new ColumnFamilyDescriptorBuilder(desc); 370 } 371 372 public static ColumnFamilyDescriptor copy(ColumnFamilyDescriptor desc) { 373 return new ModifyableColumnFamilyDescriptor(desc); 374 } 375 376 public static ColumnFamilyDescriptor of(String name) { 377 return of(Bytes.toBytes(name)); 378 } 379 380 public static ColumnFamilyDescriptor of(byte[] name) { 381 return newBuilder(name).build(); 382 } 383 384 private ColumnFamilyDescriptorBuilder(final byte[] name) { 385 this.desc = new ModifyableColumnFamilyDescriptor(name); 386 } 387 388 private ColumnFamilyDescriptorBuilder(final ColumnFamilyDescriptor desc) { 389 this.desc = new ModifyableColumnFamilyDescriptor(desc); 390 } 391 392 /** 393 * @param desc The table descriptor to serialize 394 * @return This instance serialized with pb with pb magic prefix 395 */ 396 public static byte[] toByteArray(ColumnFamilyDescriptor desc) { 397 if (desc instanceof ModifyableColumnFamilyDescriptor) { 398 return ((ModifyableColumnFamilyDescriptor) desc).toByteArray(); 399 } 400 return new ModifyableColumnFamilyDescriptor(desc).toByteArray(); 401 } 402 403 public ColumnFamilyDescriptor build() { 404 return new ModifyableColumnFamilyDescriptor(desc); 405 } 406 407 public ColumnFamilyDescriptorBuilder removeConfiguration(String key) { 408 desc.removeConfiguration(key); 409 return this; 410 } 411 412 public String getNameAsString() { 413 return desc.getNameAsString(); 414 } 415 416 public ColumnFamilyDescriptorBuilder setBlockCacheEnabled(boolean value) { 417 desc.setBlockCacheEnabled(value); 418 return this; 419 } 420 421 public ColumnFamilyDescriptorBuilder setBlocksize(int value) { 422 desc.setBlocksize(value); 423 return this; 424 } 425 426 public ColumnFamilyDescriptorBuilder setBloomFilterType(final BloomType value) { 427 desc.setBloomFilterType(value); 428 return this; 429 } 430 431 public ColumnFamilyDescriptorBuilder setCacheBloomsOnWrite(boolean value) { 432 desc.setCacheBloomsOnWrite(value); 433 return this; 434 } 435 436 public ColumnFamilyDescriptorBuilder setCacheDataOnWrite(boolean value) { 437 desc.setCacheDataOnWrite(value); 438 return this; 439 } 440 441 public ColumnFamilyDescriptorBuilder setCacheIndexesOnWrite(final boolean value) { 442 desc.setCacheIndexesOnWrite(value); 443 return this; 444 } 445 446 public ColumnFamilyDescriptorBuilder setCompactionCompressionType(Compression.Algorithm value) { 447 desc.setCompactionCompressionType(value); 448 return this; 449 } 450 451 public ColumnFamilyDescriptorBuilder setCompressTags(boolean value) { 452 desc.setCompressTags(value); 453 return this; 454 } 455 456 public ColumnFamilyDescriptorBuilder setCompressionType(Compression.Algorithm value) { 457 desc.setCompressionType(value); 458 return this; 459 } 460 461 public Compression.Algorithm getCompressionType() { 462 return desc.getCompressionType(); 463 } 464 465 public ColumnFamilyDescriptorBuilder setConfiguration(final String key, final String value) { 466 desc.setConfiguration(key, value); 467 return this; 468 } 469 470 public ColumnFamilyDescriptorBuilder setDFSReplication(short value) { 471 desc.setDFSReplication(value); 472 return this; 473 } 474 475 public ColumnFamilyDescriptorBuilder setDataBlockEncoding(DataBlockEncoding value) { 476 desc.setDataBlockEncoding(value); 477 return this; 478 } 479 480 public ColumnFamilyDescriptorBuilder setEncryptionKey(final byte[] value) { 481 desc.setEncryptionKey(value); 482 return this; 483 } 484 485 public ColumnFamilyDescriptorBuilder setEncryptionType(String value) { 486 desc.setEncryptionType(value); 487 return this; 488 } 489 490 public ColumnFamilyDescriptorBuilder setEvictBlocksOnClose(boolean value) { 491 desc.setEvictBlocksOnClose(value); 492 return this; 493 } 494 495 public ColumnFamilyDescriptorBuilder setInMemory(final boolean value) { 496 desc.setInMemory(value); 497 return this; 498 } 499 500 public ColumnFamilyDescriptorBuilder setInMemoryCompaction(final MemoryCompactionPolicy value) { 501 desc.setInMemoryCompaction(value); 502 return this; 503 } 504 505 public ColumnFamilyDescriptorBuilder setKeepDeletedCells(KeepDeletedCells value) { 506 desc.setKeepDeletedCells(value); 507 return this; 508 } 509 510 public ColumnFamilyDescriptorBuilder setMaxVersions(final int value) { 511 desc.setMaxVersions(value); 512 return this; 513 } 514 515 public ColumnFamilyDescriptorBuilder setMinVersions(final int value) { 516 desc.setMinVersions(value); 517 return this; 518 } 519 520 public ColumnFamilyDescriptorBuilder 521 setMobCompactPartitionPolicy(final MobCompactPartitionPolicy value) { 522 desc.setMobCompactPartitionPolicy(value); 523 return this; 524 } 525 526 public ColumnFamilyDescriptorBuilder setMobEnabled(final boolean value) { 527 desc.setMobEnabled(value); 528 return this; 529 } 530 531 public ColumnFamilyDescriptorBuilder setMobThreshold(final long value) { 532 desc.setMobThreshold(value); 533 return this; 534 } 535 536 public ColumnFamilyDescriptorBuilder setPrefetchBlocksOnOpen(final boolean value) { 537 desc.setPrefetchBlocksOnOpen(value); 538 return this; 539 } 540 541 public ColumnFamilyDescriptorBuilder setScope(final int value) { 542 desc.setScope(value); 543 return this; 544 } 545 546 public ColumnFamilyDescriptorBuilder setStoragePolicy(final String value) { 547 desc.setStoragePolicy(value); 548 return this; 549 } 550 551 public ColumnFamilyDescriptorBuilder setTimeToLive(final int value) { 552 desc.setTimeToLive(value); 553 return this; 554 } 555 556 public ColumnFamilyDescriptorBuilder setTimeToLive(final String value) throws HBaseException { 557 desc.setTimeToLive(value); 558 return this; 559 } 560 561 public ColumnFamilyDescriptorBuilder setNewVersionBehavior(final boolean value) { 562 desc.setNewVersionBehavior(value); 563 return this; 564 } 565 566 public ColumnFamilyDescriptorBuilder setValue(final Bytes key, final Bytes value) { 567 desc.setValue(key, value); 568 return this; 569 } 570 571 public ColumnFamilyDescriptorBuilder setValue(final byte[] key, final byte[] value) { 572 desc.setValue(key, value); 573 return this; 574 } 575 576 public ColumnFamilyDescriptorBuilder setValue(final String key, final String value) { 577 desc.setValue(key, value); 578 return this; 579 } 580 581 public ColumnFamilyDescriptorBuilder setVersionsWithTimeToLive(final int retentionInterval, 582 final int versionAfterInterval) { 583 desc.setVersionsWithTimeToLive(retentionInterval, versionAfterInterval); 584 return this; 585 } 586 587 /** 588 * An ModifyableFamilyDescriptor contains information about a column family such as the number of 589 * versions, compression settings, etc. It is used as input when creating a table or adding a 590 * column. TODO: make this package-private after removing the HColumnDescriptor 591 */ 592 @InterfaceAudience.Private 593 public static class ModifyableColumnFamilyDescriptor 594 implements ColumnFamilyDescriptor, Comparable<ModifyableColumnFamilyDescriptor> { 595 596 // Column family name 597 private final byte[] name; 598 599 // Column metadata 600 private final Map<Bytes, Bytes> values = new HashMap<>(); 601 602 /** 603 * A map which holds the configuration specific to the column family. The keys of the map have 604 * the same names as config keys and override the defaults with cf-specific settings. Example 605 * usage may be for compactions, etc. 606 */ 607 private final Map<String, String> configuration = new HashMap<>(); 608 609 /** 610 * Construct a column descriptor specifying only the family name The other attributes are 611 * defaulted. 612 * @param name Column family name. Must be 'printable' -- digit or letter -- and may not contain 613 * a <code>:</code> TODO: make this private after the HCD is removed. 614 */ 615 @InterfaceAudience.Private 616 public ModifyableColumnFamilyDescriptor(final byte[] name) { 617 this(isLegalColumnFamilyName(name), getDefaultValuesBytes(), Collections.emptyMap()); 618 } 619 620 /** 621 * Constructor. Makes a deep copy of the supplied descriptor. TODO: make this private after the 622 * HCD is removed. 623 * @param desc The descriptor. 624 */ 625 @InterfaceAudience.Private 626 public ModifyableColumnFamilyDescriptor(ColumnFamilyDescriptor desc) { 627 this(desc.getName(), desc.getValues(), desc.getConfiguration()); 628 } 629 630 private ModifyableColumnFamilyDescriptor(byte[] name, Map<Bytes, Bytes> values, 631 Map<String, String> config) { 632 this.name = name; 633 this.values.putAll(values); 634 this.configuration.putAll(config); 635 } 636 637 @Override 638 public byte[] getName() { 639 return Bytes.copy(name); 640 } 641 642 @Override 643 public String getNameAsString() { 644 return Bytes.toString(name); 645 } 646 647 @Override 648 public Bytes getValue(Bytes key) { 649 return values.get(key); 650 } 651 652 @Override 653 public byte[] getValue(byte[] key) { 654 Bytes value = values.get(new Bytes(key)); 655 return value == null ? null : value.get(); 656 } 657 658 @Override 659 public Map<Bytes, Bytes> getValues() { 660 return Collections.unmodifiableMap(values); 661 } 662 663 /** 664 * @param key The key. 665 * @param value The value. 666 * @return this (for chained invocation) 667 */ 668 public ModifyableColumnFamilyDescriptor setValue(byte[] key, byte[] value) { 669 return setValue(toBytesOrNull(key, Function.identity()), 670 toBytesOrNull(value, Function.identity())); 671 } 672 673 public ModifyableColumnFamilyDescriptor setValue(String key, String value) { 674 return setValue(toBytesOrNull(key, Bytes::toBytes), toBytesOrNull(value, Bytes::toBytes)); 675 } 676 677 private ModifyableColumnFamilyDescriptor setValue(Bytes key, String value) { 678 return setValue(key, toBytesOrNull(value, Bytes::toBytes)); 679 } 680 681 /** 682 * @param key The key. 683 * @param value The value. 684 * @return this (for chained invocation) 685 */ 686 private ModifyableColumnFamilyDescriptor setValue(Bytes key, Bytes value) { 687 if (value == null || value.getLength() == 0) { 688 values.remove(key); 689 } else { 690 values.put(key, value); 691 } 692 return this; 693 } 694 695 /** 696 * @param key Key whose key and value we're to remove from HCD parameters. 697 * @return this (for chained invocation) 698 */ 699 public ModifyableColumnFamilyDescriptor removeValue(final Bytes key) { 700 return setValue(key, (Bytes) null); 701 } 702 703 private static <T> Bytes toBytesOrNull(T t, Function<T, byte[]> f) { 704 if (t == null) { 705 return null; 706 } else { 707 return new Bytes(f.apply(t)); 708 } 709 } 710 711 private <T> T getStringOrDefault(Bytes key, Function<String, T> function, T defaultValue) { 712 return getOrDefault(key, b -> function.apply(Bytes.toString(b)), defaultValue); 713 } 714 715 private <T> T getOrDefault(Bytes key, Function<byte[], T> function, T defaultValue) { 716 Bytes value = values.get(key); 717 if (value == null) { 718 return defaultValue; 719 } else { 720 return function.apply(value.get()); 721 } 722 } 723 724 @Override 725 public int getMaxVersions() { 726 return getStringOrDefault(MAX_VERSIONS_BYTES, Integer::parseInt, DEFAULT_MAX_VERSIONS); 727 } 728 729 /** 730 * @param maxVersions maximum number of versions 731 * @return this (for chained invocation) 732 */ 733 public ModifyableColumnFamilyDescriptor setMaxVersions(int maxVersions) { 734 if (maxVersions <= 0) { 735 // TODO: Allow maxVersion of 0 to be the way you say "Keep all versions". 736 // Until there is support, consider 0 or < 0 -- a configuration error. 737 throw new IllegalArgumentException("Maximum versions must be positive"); 738 } 739 if (maxVersions < this.getMinVersions()) { 740 throw new IllegalArgumentException( 741 "Set MaxVersion to " + maxVersions + " while minVersion is " + this.getMinVersions() 742 + ". Maximum versions must be >= minimum versions "); 743 } 744 setValue(MAX_VERSIONS_BYTES, Integer.toString(maxVersions)); 745 return this; 746 } 747 748 /** 749 * Set minimum and maximum versions to keep 750 * @param minVersions minimal number of versions 751 * @param maxVersions maximum number of versions 752 * @return this (for chained invocation) 753 */ 754 public ModifyableColumnFamilyDescriptor setVersions(int minVersions, int maxVersions) { 755 if (minVersions <= 0) { 756 // TODO: Allow minVersion and maxVersion of 0 to be the way you say "Keep all versions". 757 // Until there is support, consider 0 or < 0 -- a configuration error. 758 throw new IllegalArgumentException("Minimum versions must be positive"); 759 } 760 761 if (maxVersions < minVersions) { 762 throw new IllegalArgumentException( 763 "Unable to set MaxVersion to " + maxVersions + " and set MinVersion to " + minVersions 764 + ", as maximum versions must be >= minimum versions."); 765 } 766 setMinVersions(minVersions); 767 setMaxVersions(maxVersions); 768 return this; 769 } 770 771 @Override 772 public int getBlocksize() { 773 return getStringOrDefault(BLOCKSIZE_BYTES, Integer::valueOf, DEFAULT_BLOCKSIZE); 774 } 775 776 /** 777 * @param s Blocksize to use when writing out storefiles/hfiles on this column family. 778 * @return this (for chained invocation) 779 */ 780 public ModifyableColumnFamilyDescriptor setBlocksize(int s) { 781 return setValue(BLOCKSIZE_BYTES, Integer.toString(s)); 782 } 783 784 @Override 785 public Compression.Algorithm getCompressionType() { 786 return getStringOrDefault(COMPRESSION_BYTES, 787 n -> Compression.Algorithm.valueOf(n.toUpperCase()), DEFAULT_COMPRESSION); 788 } 789 790 /** 791 * Compression types supported in hbase. LZO is not bundled as part of the hbase distribution. 792 * See <a href="http://wiki.apache.org/hadoop/UsingLzoCompression">LZO Compression</a> for how 793 * to enable it. 794 * @param type Compression type setting. 795 * @return this (for chained invocation) 796 */ 797 public ModifyableColumnFamilyDescriptor setCompressionType(Compression.Algorithm type) { 798 return setValue(COMPRESSION_BYTES, type.name()); 799 } 800 801 @Override 802 public DataBlockEncoding getDataBlockEncoding() { 803 return getStringOrDefault(DATA_BLOCK_ENCODING_BYTES, 804 n -> DataBlockEncoding.valueOf(n.toUpperCase()), DataBlockEncoding.NONE); 805 } 806 807 /** 808 * Set data block encoding algorithm used in block cache. 809 * @param type What kind of data block encoding will be used. 810 * @return this (for chained invocation) 811 */ 812 public ModifyableColumnFamilyDescriptor setDataBlockEncoding(DataBlockEncoding type) { 813 return setValue(DATA_BLOCK_ENCODING_BYTES, 814 type == null ? DataBlockEncoding.NONE.name() : type.name()); 815 } 816 817 /** 818 * Set whether the tags should be compressed along with DataBlockEncoding. When no 819 * DataBlockEncoding is been used, this is having no effect. 820 * @return this (for chained invocation) 821 */ 822 public ModifyableColumnFamilyDescriptor setCompressTags(boolean compressTags) { 823 return setValue(COMPRESS_TAGS_BYTES, String.valueOf(compressTags)); 824 } 825 826 @Override 827 public boolean isCompressTags() { 828 return getStringOrDefault(COMPRESS_TAGS_BYTES, Boolean::valueOf, DEFAULT_COMPRESS_TAGS); 829 } 830 831 @Override 832 public Compression.Algorithm getCompactionCompressionType() { 833 return getStringOrDefault(COMPRESSION_COMPACT_BYTES, 834 n -> Compression.Algorithm.valueOf(n.toUpperCase()), getCompressionType()); 835 } 836 837 /** 838 * Compression types supported in hbase. LZO is not bundled as part of the hbase distribution. 839 * See <a href="http://wiki.apache.org/hadoop/UsingLzoCompression">LZO Compression</a> for how 840 * to enable it. 841 * @param type Compression type setting. 842 * @return this (for chained invocation) 843 */ 844 public ModifyableColumnFamilyDescriptor 845 setCompactionCompressionType(Compression.Algorithm type) { 846 return setValue(COMPRESSION_COMPACT_BYTES, type.name()); 847 } 848 849 @Override 850 public boolean isInMemory() { 851 return getStringOrDefault(IN_MEMORY_BYTES, Boolean::valueOf, DEFAULT_IN_MEMORY); 852 } 853 854 /** 855 * @param inMemory True if we are to favor keeping all values for this column family in the 856 * HRegionServer cache 857 * @return this (for chained invocation) 858 */ 859 public ModifyableColumnFamilyDescriptor setInMemory(boolean inMemory) { 860 return setValue(IN_MEMORY_BYTES, Boolean.toString(inMemory)); 861 } 862 863 @Override 864 public MemoryCompactionPolicy getInMemoryCompaction() { 865 return getStringOrDefault(IN_MEMORY_COMPACTION_BYTES, 866 n -> MemoryCompactionPolicy.valueOf(n.toUpperCase()), null); 867 } 868 869 /** 870 * @param inMemoryCompaction the prefered in-memory compaction policy for this column family 871 * @return this (for chained invocation) 872 */ 873 public ModifyableColumnFamilyDescriptor 874 setInMemoryCompaction(MemoryCompactionPolicy inMemoryCompaction) { 875 return setValue(IN_MEMORY_COMPACTION_BYTES, inMemoryCompaction.name()); 876 } 877 878 @Override 879 public KeepDeletedCells getKeepDeletedCells() { 880 return getStringOrDefault(KEEP_DELETED_CELLS_BYTES, KeepDeletedCells::getValue, 881 DEFAULT_KEEP_DELETED); 882 } 883 884 /** 885 * @param keepDeletedCells True if deleted rows should not be collected immediately. 886 * @return this (for chained invocation) 887 */ 888 public ModifyableColumnFamilyDescriptor setKeepDeletedCells(KeepDeletedCells keepDeletedCells) { 889 return setValue(KEEP_DELETED_CELLS_BYTES, keepDeletedCells.name()); 890 } 891 892 /** 893 * By default, HBase only consider timestamp in versions. So a previous Delete with higher ts 894 * will mask a later Put with lower ts. Set this to true to enable new semantics of versions. We 895 * will also consider mvcc in versions. See HBASE-15968 for details. 896 */ 897 @Override 898 public boolean isNewVersionBehavior() { 899 return getStringOrDefault(NEW_VERSION_BEHAVIOR_BYTES, Boolean::parseBoolean, 900 DEFAULT_NEW_VERSION_BEHAVIOR); 901 } 902 903 public ModifyableColumnFamilyDescriptor setNewVersionBehavior(boolean newVersionBehavior) { 904 return setValue(NEW_VERSION_BEHAVIOR_BYTES, Boolean.toString(newVersionBehavior)); 905 } 906 907 @Override 908 public int getTimeToLive() { 909 return getStringOrDefault(TTL_BYTES, Integer::parseInt, DEFAULT_TTL); 910 } 911 912 /** 913 * @param timeToLive Time-to-live of cell contents, in seconds. 914 * @return this (for chained invocation) 915 */ 916 public ModifyableColumnFamilyDescriptor setTimeToLive(int timeToLive) { 917 return setValue(TTL_BYTES, Integer.toString(timeToLive)); 918 } 919 920 /** 921 * @param timeToLive Time-to-live of cell contents, in seconds. 922 * @return this (for chained invocation) 923 * @throws org.apache.hadoop.hbase.exceptions.HBaseException 924 */ 925 public ModifyableColumnFamilyDescriptor setTimeToLive(String timeToLive) throws HBaseException { 926 return setTimeToLive(Integer.parseInt(PrettyPrinter.valueOf(timeToLive, Unit.TIME_INTERVAL))); 927 } 928 929 @Override 930 public int getMinVersions() { 931 return getStringOrDefault(MIN_VERSIONS_BYTES, Integer::valueOf, DEFAULT_MIN_VERSIONS); 932 } 933 934 /** 935 * @param minVersions The minimum number of versions to keep. (used when timeToLive is set) 936 * @return this (for chained invocation) 937 */ 938 public ModifyableColumnFamilyDescriptor setMinVersions(int minVersions) { 939 return setValue(MIN_VERSIONS_BYTES, Integer.toString(minVersions)); 940 } 941 942 /** 943 * Retain all versions for a given TTL(retentionInterval), and then only a specific number of 944 * versions(versionAfterInterval) after that interval elapses. 945 * @param retentionInterval Retain all versions for this interval 946 * @param versionAfterInterval Retain no of versions to retain after retentionInterval 947 * @return this (for chained invocation) 948 */ 949 public ModifyableColumnFamilyDescriptor setVersionsWithTimeToLive(final int retentionInterval, 950 final int versionAfterInterval) { 951 ModifyableColumnFamilyDescriptor modifyableColumnFamilyDescriptor = 952 setVersions(versionAfterInterval, Integer.MAX_VALUE); 953 modifyableColumnFamilyDescriptor.setTimeToLive(retentionInterval); 954 modifyableColumnFamilyDescriptor.setKeepDeletedCells(KeepDeletedCells.TTL); 955 return modifyableColumnFamilyDescriptor; 956 } 957 958 @Override 959 public boolean isBlockCacheEnabled() { 960 return getStringOrDefault(BLOCKCACHE_BYTES, Boolean::valueOf, DEFAULT_BLOCKCACHE); 961 } 962 963 /** 964 * @param blockCacheEnabled True if hfile DATA type blocks should be cached (We always cache 965 * INDEX and BLOOM blocks; you cannot turn this off). 966 * @return this (for chained invocation) 967 */ 968 public ModifyableColumnFamilyDescriptor setBlockCacheEnabled(boolean blockCacheEnabled) { 969 return setValue(BLOCKCACHE_BYTES, Boolean.toString(blockCacheEnabled)); 970 } 971 972 @Override 973 public BloomType getBloomFilterType() { 974 return getStringOrDefault(BLOOMFILTER_BYTES, n -> BloomType.valueOf(n.toUpperCase()), 975 DEFAULT_BLOOMFILTER); 976 } 977 978 public ModifyableColumnFamilyDescriptor setBloomFilterType(final BloomType bt) { 979 return setValue(BLOOMFILTER_BYTES, bt.name()); 980 } 981 982 @Override 983 public int getScope() { 984 return getStringOrDefault(REPLICATION_SCOPE_BYTES, Integer::valueOf, 985 DEFAULT_REPLICATION_SCOPE); 986 } 987 988 /** 989 * @param scope the scope tag 990 * @return this (for chained invocation) 991 */ 992 public ModifyableColumnFamilyDescriptor setScope(int scope) { 993 return setValue(REPLICATION_SCOPE_BYTES, Integer.toString(scope)); 994 } 995 996 @Override 997 public boolean isCacheDataOnWrite() { 998 return getStringOrDefault(CACHE_DATA_ON_WRITE_BYTES, Boolean::valueOf, 999 DEFAULT_CACHE_DATA_ON_WRITE); 1000 } 1001 1002 /** 1003 * @param value true if we should cache data blocks on write 1004 * @return this (for chained invocation) 1005 */ 1006 public ModifyableColumnFamilyDescriptor setCacheDataOnWrite(boolean value) { 1007 return setValue(CACHE_DATA_ON_WRITE_BYTES, Boolean.toString(value)); 1008 } 1009 1010 @Override 1011 public boolean isCacheIndexesOnWrite() { 1012 return getStringOrDefault(CACHE_INDEX_ON_WRITE_BYTES, Boolean::valueOf, 1013 DEFAULT_CACHE_INDEX_ON_WRITE); 1014 } 1015 1016 /** 1017 * @param value true if we should cache index blocks on write 1018 * @return this (for chained invocation) 1019 */ 1020 public ModifyableColumnFamilyDescriptor setCacheIndexesOnWrite(boolean value) { 1021 return setValue(CACHE_INDEX_ON_WRITE_BYTES, Boolean.toString(value)); 1022 } 1023 1024 @Override 1025 public boolean isCacheBloomsOnWrite() { 1026 return getStringOrDefault(CACHE_BLOOMS_ON_WRITE_BYTES, Boolean::valueOf, 1027 DEFAULT_CACHE_BLOOMS_ON_WRITE); 1028 } 1029 1030 /** 1031 * @param value true if we should cache bloomfilter blocks on write 1032 * @return this (for chained invocation) 1033 */ 1034 public ModifyableColumnFamilyDescriptor setCacheBloomsOnWrite(boolean value) { 1035 return setValue(CACHE_BLOOMS_ON_WRITE_BYTES, Boolean.toString(value)); 1036 } 1037 1038 @Override 1039 public boolean isEvictBlocksOnClose() { 1040 return getStringOrDefault(EVICT_BLOCKS_ON_CLOSE_BYTES, Boolean::valueOf, 1041 DEFAULT_EVICT_BLOCKS_ON_CLOSE); 1042 } 1043 1044 /** 1045 * @param value true if we should evict cached blocks from the blockcache on close 1046 * @return this (for chained invocation) 1047 */ 1048 public ModifyableColumnFamilyDescriptor setEvictBlocksOnClose(boolean value) { 1049 return setValue(EVICT_BLOCKS_ON_CLOSE_BYTES, Boolean.toString(value)); 1050 } 1051 1052 @Override 1053 public boolean isPrefetchBlocksOnOpen() { 1054 return getStringOrDefault(PREFETCH_BLOCKS_ON_OPEN_BYTES, Boolean::valueOf, 1055 DEFAULT_PREFETCH_BLOCKS_ON_OPEN); 1056 } 1057 1058 /** 1059 * @param value true if we should prefetch blocks into the blockcache on open 1060 * @return this (for chained invocation) 1061 */ 1062 public ModifyableColumnFamilyDescriptor setPrefetchBlocksOnOpen(boolean value) { 1063 return setValue(PREFETCH_BLOCKS_ON_OPEN_BYTES, Boolean.toString(value)); 1064 } 1065 1066 @Override 1067 public String toString() { 1068 StringBuilder s = new StringBuilder(); 1069 s.append('{'); 1070 s.append(HConstants.NAME); 1071 s.append(" => '"); 1072 s.append(getNameAsString()); 1073 s.append("'"); 1074 s.append(getValues(true)); 1075 s.append('}'); 1076 return s.toString(); 1077 } 1078 1079 @Override 1080 public String toStringCustomizedValues() { 1081 StringBuilder s = new StringBuilder(); 1082 s.append('{'); 1083 s.append(HConstants.NAME); 1084 s.append(" => '"); 1085 s.append(getNameAsString()); 1086 s.append("'"); 1087 s.append(getValues(false)); 1088 s.append('}'); 1089 return s.toString(); 1090 } 1091 1092 private StringBuilder getValues(boolean printDefaults) { 1093 StringBuilder s = new StringBuilder(); 1094 1095 boolean hasConfigKeys = false; 1096 1097 // print all reserved keys first 1098 for (Map.Entry<Bytes, Bytes> entry : values.entrySet()) { 1099 if (!RESERVED_KEYWORDS.contains(entry.getKey())) { 1100 hasConfigKeys = true; 1101 continue; 1102 } 1103 String key = Bytes.toString(entry.getKey().get()); 1104 String value = Bytes.toStringBinary(entry.getValue().get()); 1105 if ( 1106 printDefaults || !DEFAULT_VALUES.containsKey(key) 1107 || !DEFAULT_VALUES.get(key).equalsIgnoreCase(value) 1108 ) { 1109 s.append(", "); 1110 s.append(key); 1111 s.append(" => "); 1112 s.append('\'').append(PrettyPrinter.format(value, getUnit(key))).append('\''); 1113 } 1114 } 1115 1116 // print all non-reserved, advanced config keys as a separate subset 1117 if (hasConfigKeys) { 1118 s.append(", "); 1119 s.append(HConstants.METADATA).append(" => "); 1120 s.append('{'); 1121 boolean printComma = false; 1122 for (Map.Entry<Bytes, Bytes> entry : values.entrySet()) { 1123 Bytes k = entry.getKey(); 1124 if (RESERVED_KEYWORDS.contains(k)) { 1125 continue; 1126 } 1127 String key = Bytes.toString(k.get()); 1128 String value = Bytes.toStringBinary(entry.getValue().get()); 1129 if (printComma) { 1130 s.append(", "); 1131 } 1132 printComma = true; 1133 s.append('\'').append(key).append('\''); 1134 s.append(" => "); 1135 s.append('\'').append(PrettyPrinter.format(value, getUnit(key))).append('\''); 1136 } 1137 s.append('}'); 1138 } 1139 1140 if (!configuration.isEmpty()) { 1141 s.append(", "); 1142 s.append(HConstants.CONFIGURATION).append(" => "); 1143 s.append('{'); 1144 boolean printCommaForConfiguration = false; 1145 for (Map.Entry<String, String> e : configuration.entrySet()) { 1146 if (printCommaForConfiguration) { 1147 s.append(", "); 1148 } 1149 printCommaForConfiguration = true; 1150 s.append('\'').append(e.getKey()).append('\''); 1151 s.append(" => "); 1152 s.append('\'').append(PrettyPrinter.format(e.getValue(), getUnit(e.getKey()))) 1153 .append('\''); 1154 } 1155 s.append("}"); 1156 } 1157 return s; 1158 } 1159 1160 @Override 1161 public boolean equals(Object obj) { 1162 if (this == obj) { 1163 return true; 1164 } 1165 if (obj instanceof ModifyableColumnFamilyDescriptor) { 1166 return ColumnFamilyDescriptor.COMPARATOR.compare(this, 1167 (ModifyableColumnFamilyDescriptor) obj) == 0; 1168 } 1169 return false; 1170 } 1171 1172 @Override 1173 public int hashCode() { 1174 int result = Bytes.hashCode(name); 1175 result ^= (int) COLUMN_DESCRIPTOR_VERSION; 1176 result ^= values.hashCode(); 1177 result ^= configuration.hashCode(); 1178 return result; 1179 } 1180 1181 @Override 1182 public int compareTo(ModifyableColumnFamilyDescriptor other) { 1183 return COMPARATOR.compare(this, other); 1184 } 1185 1186 /** 1187 * @return This instance serialized with pb with pb magic prefix 1188 * @see #parseFrom(byte[]) 1189 */ 1190 private byte[] toByteArray() { 1191 return ProtobufUtil.prependPBMagic(ProtobufUtil.toColumnFamilySchema(this).toByteArray()); 1192 } 1193 1194 /** 1195 * @param bytes A pb serialized {@link ModifyableColumnFamilyDescriptor} instance with pb magic 1196 * prefix 1197 * @return An instance of {@link ModifyableColumnFamilyDescriptor} made from <code>bytes</code> 1198 * @see #toByteArray() 1199 */ 1200 private static ColumnFamilyDescriptor parseFrom(final byte[] bytes) 1201 throws DeserializationException { 1202 if (!ProtobufUtil.isPBMagicPrefix(bytes)) { 1203 throw new DeserializationException("No magic"); 1204 } 1205 int pblen = ProtobufUtil.lengthOfPBMagic(); 1206 ColumnFamilySchema.Builder builder = ColumnFamilySchema.newBuilder(); 1207 ColumnFamilySchema cfs = null; 1208 try { 1209 ProtobufUtil.mergeFrom(builder, bytes, pblen, bytes.length - pblen); 1210 cfs = builder.build(); 1211 } catch (IOException e) { 1212 throw new DeserializationException(e); 1213 } 1214 return ProtobufUtil.toColumnFamilyDescriptor(cfs); 1215 } 1216 1217 @Override 1218 public String getConfigurationValue(String key) { 1219 return configuration.get(key); 1220 } 1221 1222 @Override 1223 public Map<String, String> getConfiguration() { 1224 // shallow pointer copy 1225 return Collections.unmodifiableMap(configuration); 1226 } 1227 1228 /** 1229 * Setter for storing a configuration setting in {@link #configuration} map. 1230 * @param key Config key. Same as XML config key e.g. hbase.something.or.other. 1231 * @param value String value. If null, removes the configuration. 1232 * @return this (for chained invocation) 1233 */ 1234 public ModifyableColumnFamilyDescriptor setConfiguration(String key, String value) { 1235 if (value == null || value.length() == 0) { 1236 configuration.remove(key); 1237 } else { 1238 configuration.put(key, value); 1239 } 1240 return this; 1241 } 1242 1243 /** 1244 * Remove a configuration setting represented by the key from the {@link #configuration} map. 1245 * @return this (for chained invocation) 1246 */ 1247 public ModifyableColumnFamilyDescriptor removeConfiguration(final String key) { 1248 return setConfiguration(key, null); 1249 } 1250 1251 @Override 1252 public String getEncryptionType() { 1253 return getStringOrDefault(ENCRYPTION_BYTES, Function.identity(), null); 1254 } 1255 1256 /** 1257 * Set the encryption algorithm for use with this family 1258 * @return this (for chained invocation) 1259 */ 1260 public ModifyableColumnFamilyDescriptor setEncryptionType(String algorithm) { 1261 return setValue(ENCRYPTION_BYTES, algorithm); 1262 } 1263 1264 @Override 1265 public byte[] getEncryptionKey() { 1266 return getOrDefault(ENCRYPTION_KEY_BYTES, Bytes::copy, null); 1267 } 1268 1269 /** 1270 * Set the raw crypto key attribute for the family 1271 * @return this (for chained invocation) 1272 */ 1273 public ModifyableColumnFamilyDescriptor setEncryptionKey(byte[] keyBytes) { 1274 return setValue(ENCRYPTION_KEY_BYTES, new Bytes(keyBytes)); 1275 } 1276 1277 @Override 1278 public long getMobThreshold() { 1279 return getStringOrDefault(MOB_THRESHOLD_BYTES, Long::valueOf, DEFAULT_MOB_THRESHOLD); 1280 } 1281 1282 /** 1283 * Sets the mob threshold of the family. 1284 * @param threshold The mob threshold. 1285 * @return this (for chained invocation) 1286 */ 1287 public ModifyableColumnFamilyDescriptor setMobThreshold(long threshold) { 1288 return setValue(MOB_THRESHOLD_BYTES, String.valueOf(threshold)); 1289 } 1290 1291 @Override 1292 public boolean isMobEnabled() { 1293 return getStringOrDefault(IS_MOB_BYTES, Boolean::valueOf, DEFAULT_MOB); 1294 } 1295 1296 /** 1297 * Enables the mob for the family. 1298 * @param isMobEnabled Whether to enable the mob for the family. 1299 * @return this (for chained invocation) 1300 */ 1301 public ModifyableColumnFamilyDescriptor setMobEnabled(boolean isMobEnabled) { 1302 return setValue(IS_MOB_BYTES, String.valueOf(isMobEnabled)); 1303 } 1304 1305 @Override 1306 public MobCompactPartitionPolicy getMobCompactPartitionPolicy() { 1307 return getStringOrDefault(MOB_COMPACT_PARTITION_POLICY_BYTES, 1308 n -> MobCompactPartitionPolicy.valueOf(n.toUpperCase()), 1309 DEFAULT_MOB_COMPACT_PARTITION_POLICY); 1310 } 1311 1312 /** 1313 * Set the mob compact partition policy for the family. 1314 * @param policy policy type 1315 * @return this (for chained invocation) 1316 */ 1317 public ModifyableColumnFamilyDescriptor 1318 setMobCompactPartitionPolicy(MobCompactPartitionPolicy policy) { 1319 return setValue(MOB_COMPACT_PARTITION_POLICY_BYTES, policy.name()); 1320 } 1321 1322 @Override 1323 public short getDFSReplication() { 1324 return getStringOrDefault(DFS_REPLICATION_BYTES, Short::valueOf, DEFAULT_DFS_REPLICATION); 1325 } 1326 1327 /** 1328 * Set the replication factor to hfile(s) belonging to this family 1329 * @param replication number of replicas the blocks(s) belonging to this CF should have, or 1330 * {@link #DEFAULT_DFS_REPLICATION} for the default replication factor set in 1331 * the filesystem 1332 * @return this (for chained invocation) 1333 */ 1334 public ModifyableColumnFamilyDescriptor setDFSReplication(short replication) { 1335 if (replication < 1 && replication != DEFAULT_DFS_REPLICATION) { 1336 throw new IllegalArgumentException( 1337 "DFS replication factor cannot be less than 1 if explicitly set."); 1338 } 1339 return setValue(DFS_REPLICATION_BYTES, Short.toString(replication)); 1340 } 1341 1342 @Override 1343 public String getStoragePolicy() { 1344 return getStringOrDefault(STORAGE_POLICY_BYTES, Function.identity(), null); 1345 } 1346 1347 /** 1348 * Set the storage policy for use with this family 1349 * @param policy the policy to set, valid setting includes: <i>"LAZY_PERSIST"</i>, 1350 * <i>"ALL_SSD"</i>, <i>"ONE_SSD"</i>, <i>"HOT"</i>, <i>"WARM"</i>, <i>"COLD"</i> 1351 * @return this (for chained invocation) 1352 */ 1353 public ModifyableColumnFamilyDescriptor setStoragePolicy(String policy) { 1354 return setValue(STORAGE_POLICY_BYTES, policy); 1355 } 1356 1357 } 1358}