From 0696c139f52f53f743947922c68d804181775519 Mon Sep 17 00:00:00 2001 From: Jim Kellerman Date: Mon, 11 Aug 2008 21:24:04 +0000 Subject: [PATCH] HBASE-811 fix whitespaace git-svn-id: https://svn.apache.org/repos/asf/hadoop/hbase/trunk@684937 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop/hbase/HColumnDescriptor.java | 1166 ++++++++--------- .../apache/hadoop/hbase/HTableDescriptor.java | 1146 ++++++++-------- .../client/UnmodifyableHTableDescriptor.java | 208 +-- 3 files changed, 1260 insertions(+), 1260 deletions(-) diff --git a/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java b/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java index d654deb9756..a25877bcf53 100644 --- a/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java +++ b/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java @@ -1,584 +1,584 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.hadoop.hbase; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.hadoop.hbase.io.ImmutableBytesWritable; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.io.Text; -import org.apache.hadoop.io.WritableComparable; - -/** - * An HColumnDescriptor contains information about a column family such as the - * number of versions, compression settings, etc. - * - * It is used as input when creating a table or adding a column. Once set, the - * parameters that specify a column cannot be changed without deleting the - * column and recreating it. If there is data stored in the column, it will be - * deleted when the column is deleted. - */ -public class HColumnDescriptor implements WritableComparable { - // For future backward compatibility - - // Version 3 was when column names become byte arrays and when we picked up - // Time-to-live feature. Version 4 was when we moved to byte arrays, HBASE-82. - // Version 5 was when bloom filter descriptors were removed. - // Version 6 adds metadata as a map where keys and values are byte[]. - private static final byte COLUMN_DESCRIPTOR_VERSION = (byte)6; - - /** - * The type of compression. - * @see org.apache.hadoop.io.SequenceFile.Writer - */ - public static enum CompressionType { - /** Do not compress records. */ - NONE, - /** Compress values only, each separately. */ - RECORD, - /** Compress sequences of records together in blocks. */ - BLOCK - } - - public static final String COMPRESSION = "COMPRESSION"; - public static final String BLOCKCACHE = "BLOCKCACHE"; - public static final String LENGTH = "LENGTH"; - public static final String TTL = "TTL"; - public static final String BLOOMFILTER = "BLOOMFILTER"; - public static final String FOREVER = "FOREVER"; - public static final String MAPFILE_INDEX_INTERVAL = - "MAPFILE_INDEX_INTERVAL"; - - /** - * Default compression type. - */ - public static final CompressionType DEFAULT_COMPRESSION = - CompressionType.NONE; - - /** - * Default number of versions of a record to keep. - */ - public static final int DEFAULT_VERSIONS = 3; - - /** - * Default maximum cell length. - */ - public static final int DEFAULT_LENGTH = Integer.MAX_VALUE; - - /** - * Default setting for whether to serve from memory or not. - */ - public static final boolean DEFAULT_IN_MEMORY = false; - - /** - * Default setting for whether to use a block cache or not. - */ - public static final boolean DEFAULT_BLOCKCACHE = false; - - /** - * Default setting for whether or not to use bloomfilters. - */ - public static final boolean DEFAULT_BLOOMFILTER = false; - - /** - * Default time to live of cell contents. - */ - public static final int DEFAULT_TTL = HConstants.FOREVER; - - // Column family name - private byte [] name; - - /** - * Default mapfile index interval. - */ - public static final int DEFAULT_MAPFILE_INDEX_INTERVAL = 128; - - // Column metadata - protected Map values = - new HashMap(); - - - /** - * Default constructor. Must be present for Writable. - */ - public HColumnDescriptor() { - this.name = null; - } - - /** - * Construct a column descriptor specifying only the family name - * The other attributes are defaulted. - * - * @param columnName - column family name - */ - public HColumnDescriptor(final String columnName) { - this(Bytes.toBytes(columnName)); - } - - /** - * Construct a column descriptor specifying only the family name - * The other attributes are defaulted. - * - * @param columnName - column family name - */ - public HColumnDescriptor(final Text columnName) { - this(columnName.getBytes()); - } - - /** - * Construct a column descriptor specifying only the family name - * The other attributes are defaulted. - * - * @param columnName Column family name. Must have the ':' ending. - */ - public HColumnDescriptor(final byte [] columnName) { - this (columnName == null || columnName.length <= 0? - HConstants.EMPTY_BYTE_ARRAY: columnName, DEFAULT_VERSIONS, - DEFAULT_COMPRESSION, DEFAULT_IN_MEMORY, DEFAULT_BLOCKCACHE, - Integer.MAX_VALUE, DEFAULT_TTL, false); - } - - /** - * Constructor. - * Makes a deep copy of the supplied descriptor. - * Can make a modifiable descriptor from an UnmodifyableHColumnDescriptor. - * @param desc The descriptor. - */ - public HColumnDescriptor(HColumnDescriptor desc) { - super(); - this.name = desc.name.clone(); - for (Map.Entry e: - desc.values.entrySet()) { - this.values.put(e.getKey(), e.getValue()); - } - } - - /** - * Constructor - * @param columnName Column family name. Must have the ':' ending. - * @param maxVersions Maximum number of versions to keep - * @param compression Compression type - * @param inMemory If true, column data should be kept in an HRegionServer's - * cache - * @param blockCacheEnabled If true, MapFile blocks should be cached - * @param maxValueLength Restrict values to <= this value - * @param timeToLive Time-to-live of cell contents, in seconds from last timestamp - * (use HConstants.FOREVER for unlimited TTL) - * @param bloomFilter Enable the specified bloom filter for this column - * - * @throws IllegalArgumentException if passed a family name that is made of - * other than 'word' characters: i.e. [a-zA-Z_0-9] and does not - * end in a : - * @throws IllegalArgumentException if the number of versions is <= 0 - */ - public HColumnDescriptor(final byte [] columnName, final int maxVersions, - final CompressionType compression, final boolean inMemory, - final boolean blockCacheEnabled, final int maxValueLength, - final int timeToLive, final boolean bloomFilter) { - isLegalFamilyName(columnName); - this.name = stripColon(columnName); - if (maxVersions <= 0) { - // TODO: Allow maxVersion of 0 to be the way you say "Keep all versions". - // Until there is support, consider 0 or < 0 -- a configuration error. - throw new IllegalArgumentException("Maximum versions must be positive"); - } - setMaxVersions(maxVersions); - setInMemory(inMemory); - setBlockCacheEnabled(blockCacheEnabled); - setMaxValueLength(maxValueLength); - setTimeToLive(timeToLive); - setCompressionType(compression); - setBloomfilter(bloomFilter); - } - - private static byte [] stripColon(final byte [] n) { - byte [] result = new byte [n.length - 1]; - // Have the stored family name be absent the colon delimiter - System.arraycopy(n, 0, result, 0, n.length - 1); - return result; - } - - /** - * @param b Family name. - * @return b - * @throws IllegalArgumentException If not null and not a legitimate family - * name: i.e. 'printable' and ends in a ':' (Null passes are allowed because - * b can be null when deserializing). - */ - public static byte [] isLegalFamilyName(final byte [] b) { - if (b == null) { - return b; - } - if (b[b.length - 1] != ':') { - throw new IllegalArgumentException("Family names must end in a colon: " + - Bytes.toString(b)); - } - for (int i = 0; i < (b.length - 1); i++) { - if (Character.isLetterOrDigit(b[i]) || b[i] == '_' || b[i] == '.') { - continue; - } - throw new IllegalArgumentException("Illegal character <" + b[i] + - ">. Family names can only contain 'word characters' and must end" + - "with a colon: " + Bytes.toString(b)); - } - return b; - } - - /** - * @return Name of this column family - */ - public byte [] getName() { - return name; - } - - /** - * @return Name of this column family with colon as required by client API - */ - public byte [] getNameWithColon() { - return HStoreKey.addDelimiter(this.name); - } - - /** - * @return Name of this column family - */ - public String getNameAsString() { - return Bytes.toString(this.name); - } - - /** - * @param key The key. - * @return The value. - */ - public byte[] getValue(byte[] key) { - ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key)); - if (ibw == null) - return null; - return ibw.get(); - } - - /** - * @param key The key. - * @return The value as a string. - */ - public String getValue(String key) { - byte[] value = getValue(Bytes.toBytes(key)); - if (value == null) - return null; - return Bytes.toString(value); - } - - /** - * @return All values. - */ - public Map getValues() { - return Collections.unmodifiableMap(values); - } - - /** - * @param key The key. - * @param value The value. - */ - public void setValue(byte[] key, byte[] value) { - values.put(new ImmutableBytesWritable(key), - new ImmutableBytesWritable(value)); - } - - /** - * @param key The key. - * @param value The value. - */ - public void setValue(String key, String value) { - setValue(Bytes.toBytes(key), Bytes.toBytes(value)); - } - - /** @return compression type being used for the column family */ - public CompressionType getCompression() { - String value = getValue(COMPRESSION); - if (value != null) { - if (value.equalsIgnoreCase("BLOCK")) - return CompressionType.BLOCK; - else if (value.equalsIgnoreCase("RECORD")) - return CompressionType.RECORD; - } - return CompressionType.NONE; - } - - /** @return maximum number of versions */ - public int getMaxVersions() { - String value = getValue(HConstants.VERSIONS); - if (value != null) - return Integer.valueOf(value); - return DEFAULT_VERSIONS; - } - - /** - * @param maxVersions maximum number of versions - */ - public void setMaxVersions(int maxVersions) { - setValue(HConstants.VERSIONS, Integer.toString(maxVersions)); - } - - /** - * @return Compression type setting. - */ - public CompressionType getCompressionType() { - return getCompression(); - } - - /** - * @param type Compression type setting. - */ - public void setCompressionType(CompressionType type) { - String compressionType; - switch (type) { - case BLOCK: compressionType = "BLOCK"; break; - case RECORD: compressionType = "RECORD"; break; - default: compressionType = "NONE"; break; - } - setValue(COMPRESSION, compressionType); - } - - /** - * @return True if we are to keep all in use HRegionServer cache. - */ - public boolean isInMemory() { - String value = getValue(HConstants.IN_MEMORY); - if (value != null) - return Boolean.valueOf(value); - return DEFAULT_IN_MEMORY; - } - - /** - * @param inMemory True if we are to keep all values in the HRegionServer - * cache - */ - public void setInMemory(boolean inMemory) { - setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory)); - } - - /** - * @return Maximum value length. - */ - public int getMaxValueLength() { - String value = getValue(LENGTH); - if (value != null) - return Integer.valueOf(value); - return DEFAULT_LENGTH; - } - - /** - * @param maxLength Maximum value length. - */ - public void setMaxValueLength(int maxLength) { - setValue(LENGTH, Integer.toString(maxLength)); - } - - /** - * @return Time to live. - */ - public int getTimeToLive() { - String value = getValue(TTL); - if (value != null) - return Integer.valueOf(value); - return DEFAULT_TTL; - } - - /** - * @param timeToLive - */ - public void setTimeToLive(int timeToLive) { - setValue(TTL, Integer.toString(timeToLive)); - } - - /** - * @return True if MapFile blocks should be cached. - */ - public boolean isBlockCacheEnabled() { - String value = getValue(BLOCKCACHE); - if (value != null) - return Boolean.valueOf(value); - return DEFAULT_BLOCKCACHE; - } - - /** - * @param blockCacheEnabled True if MapFile blocks should be cached. - */ - public void setBlockCacheEnabled(boolean blockCacheEnabled) { - setValue(BLOCKCACHE, Boolean.toString(blockCacheEnabled)); - } - - /** - * @return true if a bloom filter is enabled - */ - public boolean isBloomfilter() { - String value = getValue(BLOOMFILTER); - if (value != null) - return Boolean.valueOf(value); - return DEFAULT_BLOOMFILTER; - } - - /** - * @param onOff Enable/Disable bloom filter - */ - public void setBloomfilter(final boolean onOff) { - setValue(BLOOMFILTER, Boolean.toString(onOff)); - } - - /** - * @return The number of entries that are added to the store MapFile before - * an index entry is added. - */ - public int getMapFileIndexInterval() { - String value = getValue(MAPFILE_INDEX_INTERVAL); - if (value != null) - return Integer.valueOf(value); - return DEFAULT_MAPFILE_INDEX_INTERVAL; - } - - /** - * @param interval The number of entries that are added to the store MapFile before - * an index entry is added. - */ - public void setMapFileIndexInterval(int interval) { - setValue(MAPFILE_INDEX_INTERVAL, Integer.toString(interval)); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer s = new StringBuffer(); - s.append('{'); - s.append(HConstants.NAME); - s.append(" => '"); - s.append(Bytes.toString(name)); - s.append("'"); - for (Map.Entry e: - values.entrySet()) { - s.append(", "); - s.append(Bytes.toString(e.getKey().get())); - s.append(" => '"); - s.append(Bytes.toString(e.getValue().get())); - s.append("'"); - } - s.append('}'); - return s.toString(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return compareTo(obj) == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int result = Bytes.hashCode(this.name); - result ^= Byte.valueOf(COLUMN_DESCRIPTOR_VERSION).hashCode(); - result ^= values.hashCode(); - return result; - } - - // Writable - - /** {@inheritDoc} */ - public void readFields(DataInput in) throws IOException { - int version = in.readByte(); - if (version < 6) { - if (version <= 2) { - Text t = new Text(); - t.readFields(in); - this.name = t.getBytes(); - if (HStoreKey.getFamilyDelimiterIndex(this.name) > 0) { - this.name = stripColon(this.name); - } - } else { - this.name = Bytes.readByteArray(in); - } - this.values.clear(); - setMaxVersions(in.readInt()); - int ordinal = in.readInt(); - setCompressionType(CompressionType.values()[ordinal]); - setInMemory(in.readBoolean()); - setMaxValueLength(in.readInt()); - setBloomfilter(in.readBoolean()); - if (isBloomfilter() && version < 5) { - // If a bloomFilter is enabled and the column descriptor is less than - // version 5, we need to skip over it to read the rest of the column - // descriptor. There are no BloomFilterDescriptors written to disk for - // column descriptors with a version number >= 5 - BloomFilterDescriptor junk = new BloomFilterDescriptor(); - junk.readFields(in); - } - if (version > 1) { - setBlockCacheEnabled(in.readBoolean()); - } - if (version > 2) { - setTimeToLive(in.readInt()); - } - } else { - // version 6+ - this.name = Bytes.readByteArray(in); - this.values.clear(); - int numValues = in.readInt(); - for (int i = 0; i < numValues; i++) { - ImmutableBytesWritable key = new ImmutableBytesWritable(); - ImmutableBytesWritable value = new ImmutableBytesWritable(); - key.readFields(in); - value.readFields(in); - values.put(key, value); - } - } - } - - /** {@inheritDoc} */ - public void write(DataOutput out) throws IOException { - out.writeByte(COLUMN_DESCRIPTOR_VERSION); - Bytes.writeByteArray(out, this.name); - out.writeInt(values.size()); - for (Map.Entry e: - values.entrySet()) { - e.getKey().write(out); - e.getValue().write(out); - } - } - - // Comparable - - /** {@inheritDoc} */ - public int compareTo(Object o) { - HColumnDescriptor other = (HColumnDescriptor)o; - int result = Bytes.compareTo(this.name, other.getName()); - if (result == 0) { - // punt on comparison for ordering, just calculate difference - result = this.values.hashCode() - other.values.hashCode(); - if (result < 0) - result = -1; - else if (result > 0) - result = 1; - } - return result; - } +/** + * Copyright 2007 The Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.WritableComparable; + +/** + * An HColumnDescriptor contains information about a column family such as the + * number of versions, compression settings, etc. + * + * It is used as input when creating a table or adding a column. Once set, the + * parameters that specify a column cannot be changed without deleting the + * column and recreating it. If there is data stored in the column, it will be + * deleted when the column is deleted. + */ +public class HColumnDescriptor implements WritableComparable { + // For future backward compatibility + + // Version 3 was when column names become byte arrays and when we picked up + // Time-to-live feature. Version 4 was when we moved to byte arrays, HBASE-82. + // Version 5 was when bloom filter descriptors were removed. + // Version 6 adds metadata as a map where keys and values are byte[]. + private static final byte COLUMN_DESCRIPTOR_VERSION = (byte)6; + + /** + * The type of compression. + * @see org.apache.hadoop.io.SequenceFile.Writer + */ + public static enum CompressionType { + /** Do not compress records. */ + NONE, + /** Compress values only, each separately. */ + RECORD, + /** Compress sequences of records together in blocks. */ + BLOCK + } + + public static final String COMPRESSION = "COMPRESSION"; + public static final String BLOCKCACHE = "BLOCKCACHE"; + public static final String LENGTH = "LENGTH"; + public static final String TTL = "TTL"; + public static final String BLOOMFILTER = "BLOOMFILTER"; + public static final String FOREVER = "FOREVER"; + public static final String MAPFILE_INDEX_INTERVAL = + "MAPFILE_INDEX_INTERVAL"; + + /** + * Default compression type. + */ + public static final CompressionType DEFAULT_COMPRESSION = + CompressionType.NONE; + + /** + * Default number of versions of a record to keep. + */ + public static final int DEFAULT_VERSIONS = 3; + + /** + * Default maximum cell length. + */ + public static final int DEFAULT_LENGTH = Integer.MAX_VALUE; + + /** + * Default setting for whether to serve from memory or not. + */ + public static final boolean DEFAULT_IN_MEMORY = false; + + /** + * Default setting for whether to use a block cache or not. + */ + public static final boolean DEFAULT_BLOCKCACHE = false; + + /** + * Default setting for whether or not to use bloomfilters. + */ + public static final boolean DEFAULT_BLOOMFILTER = false; + + /** + * Default time to live of cell contents. + */ + public static final int DEFAULT_TTL = HConstants.FOREVER; + + // Column family name + private byte [] name; + + /** + * Default mapfile index interval. + */ + public static final int DEFAULT_MAPFILE_INDEX_INTERVAL = 128; + + // Column metadata + protected Map values = + new HashMap(); + + + /** + * Default constructor. Must be present for Writable. + */ + public HColumnDescriptor() { + this.name = null; + } + + /** + * Construct a column descriptor specifying only the family name + * The other attributes are defaulted. + * + * @param columnName - column family name + */ + public HColumnDescriptor(final String columnName) { + this(Bytes.toBytes(columnName)); + } + + /** + * Construct a column descriptor specifying only the family name + * The other attributes are defaulted. + * + * @param columnName - column family name + */ + public HColumnDescriptor(final Text columnName) { + this(columnName.getBytes()); + } + + /** + * Construct a column descriptor specifying only the family name + * The other attributes are defaulted. + * + * @param columnName Column family name. Must have the ':' ending. + */ + public HColumnDescriptor(final byte [] columnName) { + this (columnName == null || columnName.length <= 0? + HConstants.EMPTY_BYTE_ARRAY: columnName, DEFAULT_VERSIONS, + DEFAULT_COMPRESSION, DEFAULT_IN_MEMORY, DEFAULT_BLOCKCACHE, + Integer.MAX_VALUE, DEFAULT_TTL, false); + } + + /** + * Constructor. + * Makes a deep copy of the supplied descriptor. + * Can make a modifiable descriptor from an UnmodifyableHColumnDescriptor. + * @param desc The descriptor. + */ + public HColumnDescriptor(HColumnDescriptor desc) { + super(); + this.name = desc.name.clone(); + for (Map.Entry e: + desc.values.entrySet()) { + this.values.put(e.getKey(), e.getValue()); + } + } + + /** + * Constructor + * @param columnName Column family name. Must have the ':' ending. + * @param maxVersions Maximum number of versions to keep + * @param compression Compression type + * @param inMemory If true, column data should be kept in an HRegionServer's + * cache + * @param blockCacheEnabled If true, MapFile blocks should be cached + * @param maxValueLength Restrict values to <= this value + * @param timeToLive Time-to-live of cell contents, in seconds from last timestamp + * (use HConstants.FOREVER for unlimited TTL) + * @param bloomFilter Enable the specified bloom filter for this column + * + * @throws IllegalArgumentException if passed a family name that is made of + * other than 'word' characters: i.e. [a-zA-Z_0-9] and does not + * end in a : + * @throws IllegalArgumentException if the number of versions is <= 0 + */ + public HColumnDescriptor(final byte [] columnName, final int maxVersions, + final CompressionType compression, final boolean inMemory, + final boolean blockCacheEnabled, final int maxValueLength, + final int timeToLive, final boolean bloomFilter) { + isLegalFamilyName(columnName); + this.name = stripColon(columnName); + if (maxVersions <= 0) { + // TODO: Allow maxVersion of 0 to be the way you say "Keep all versions". + // Until there is support, consider 0 or < 0 -- a configuration error. + throw new IllegalArgumentException("Maximum versions must be positive"); + } + setMaxVersions(maxVersions); + setInMemory(inMemory); + setBlockCacheEnabled(blockCacheEnabled); + setMaxValueLength(maxValueLength); + setTimeToLive(timeToLive); + setCompressionType(compression); + setBloomfilter(bloomFilter); + } + + private static byte [] stripColon(final byte [] n) { + byte [] result = new byte [n.length - 1]; + // Have the stored family name be absent the colon delimiter + System.arraycopy(n, 0, result, 0, n.length - 1); + return result; + } + + /** + * @param b Family name. + * @return b + * @throws IllegalArgumentException If not null and not a legitimate family + * name: i.e. 'printable' and ends in a ':' (Null passes are allowed because + * b can be null when deserializing). + */ + public static byte [] isLegalFamilyName(final byte [] b) { + if (b == null) { + return b; + } + if (b[b.length - 1] != ':') { + throw new IllegalArgumentException("Family names must end in a colon: " + + Bytes.toString(b)); + } + for (int i = 0; i < (b.length - 1); i++) { + if (Character.isLetterOrDigit(b[i]) || b[i] == '_' || b[i] == '.') { + continue; + } + throw new IllegalArgumentException("Illegal character <" + b[i] + + ">. Family names can only contain 'word characters' and must end" + + "with a colon: " + Bytes.toString(b)); + } + return b; + } + + /** + * @return Name of this column family + */ + public byte [] getName() { + return name; + } + + /** + * @return Name of this column family with colon as required by client API + */ + public byte [] getNameWithColon() { + return HStoreKey.addDelimiter(this.name); + } + + /** + * @return Name of this column family + */ + public String getNameAsString() { + return Bytes.toString(this.name); + } + + /** + * @param key The key. + * @return The value. + */ + public byte[] getValue(byte[] key) { + ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key)); + if (ibw == null) + return null; + return ibw.get(); + } + + /** + * @param key The key. + * @return The value as a string. + */ + public String getValue(String key) { + byte[] value = getValue(Bytes.toBytes(key)); + if (value == null) + return null; + return Bytes.toString(value); + } + + /** + * @return All values. + */ + public Map getValues() { + return Collections.unmodifiableMap(values); + } + + /** + * @param key The key. + * @param value The value. + */ + public void setValue(byte[] key, byte[] value) { + values.put(new ImmutableBytesWritable(key), + new ImmutableBytesWritable(value)); + } + + /** + * @param key The key. + * @param value The value. + */ + public void setValue(String key, String value) { + setValue(Bytes.toBytes(key), Bytes.toBytes(value)); + } + + /** @return compression type being used for the column family */ + public CompressionType getCompression() { + String value = getValue(COMPRESSION); + if (value != null) { + if (value.equalsIgnoreCase("BLOCK")) + return CompressionType.BLOCK; + else if (value.equalsIgnoreCase("RECORD")) + return CompressionType.RECORD; + } + return CompressionType.NONE; + } + + /** @return maximum number of versions */ + public int getMaxVersions() { + String value = getValue(HConstants.VERSIONS); + if (value != null) + return Integer.valueOf(value); + return DEFAULT_VERSIONS; + } + + /** + * @param maxVersions maximum number of versions + */ + public void setMaxVersions(int maxVersions) { + setValue(HConstants.VERSIONS, Integer.toString(maxVersions)); + } + + /** + * @return Compression type setting. + */ + public CompressionType getCompressionType() { + return getCompression(); + } + + /** + * @param type Compression type setting. + */ + public void setCompressionType(CompressionType type) { + String compressionType; + switch (type) { + case BLOCK: compressionType = "BLOCK"; break; + case RECORD: compressionType = "RECORD"; break; + default: compressionType = "NONE"; break; + } + setValue(COMPRESSION, compressionType); + } + + /** + * @return True if we are to keep all in use HRegionServer cache. + */ + public boolean isInMemory() { + String value = getValue(HConstants.IN_MEMORY); + if (value != null) + return Boolean.valueOf(value); + return DEFAULT_IN_MEMORY; + } + + /** + * @param inMemory True if we are to keep all values in the HRegionServer + * cache + */ + public void setInMemory(boolean inMemory) { + setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory)); + } + + /** + * @return Maximum value length. + */ + public int getMaxValueLength() { + String value = getValue(LENGTH); + if (value != null) + return Integer.valueOf(value); + return DEFAULT_LENGTH; + } + + /** + * @param maxLength Maximum value length. + */ + public void setMaxValueLength(int maxLength) { + setValue(LENGTH, Integer.toString(maxLength)); + } + + /** + * @return Time to live. + */ + public int getTimeToLive() { + String value = getValue(TTL); + if (value != null) + return Integer.valueOf(value); + return DEFAULT_TTL; + } + + /** + * @param timeToLive + */ + public void setTimeToLive(int timeToLive) { + setValue(TTL, Integer.toString(timeToLive)); + } + + /** + * @return True if MapFile blocks should be cached. + */ + public boolean isBlockCacheEnabled() { + String value = getValue(BLOCKCACHE); + if (value != null) + return Boolean.valueOf(value); + return DEFAULT_BLOCKCACHE; + } + + /** + * @param blockCacheEnabled True if MapFile blocks should be cached. + */ + public void setBlockCacheEnabled(boolean blockCacheEnabled) { + setValue(BLOCKCACHE, Boolean.toString(blockCacheEnabled)); + } + + /** + * @return true if a bloom filter is enabled + */ + public boolean isBloomfilter() { + String value = getValue(BLOOMFILTER); + if (value != null) + return Boolean.valueOf(value); + return DEFAULT_BLOOMFILTER; + } + + /** + * @param onOff Enable/Disable bloom filter + */ + public void setBloomfilter(final boolean onOff) { + setValue(BLOOMFILTER, Boolean.toString(onOff)); + } + + /** + * @return The number of entries that are added to the store MapFile before + * an index entry is added. + */ + public int getMapFileIndexInterval() { + String value = getValue(MAPFILE_INDEX_INTERVAL); + if (value != null) + return Integer.valueOf(value); + return DEFAULT_MAPFILE_INDEX_INTERVAL; + } + + /** + * @param interval The number of entries that are added to the store MapFile before + * an index entry is added. + */ + public void setMapFileIndexInterval(int interval) { + setValue(MAPFILE_INDEX_INTERVAL, Integer.toString(interval)); + } + + /** {@inheritDoc} */ + @Override + public String toString() { + StringBuffer s = new StringBuffer(); + s.append('{'); + s.append(HConstants.NAME); + s.append(" => '"); + s.append(Bytes.toString(name)); + s.append("'"); + for (Map.Entry e: + values.entrySet()) { + s.append(", "); + s.append(Bytes.toString(e.getKey().get())); + s.append(" => '"); + s.append(Bytes.toString(e.getValue().get())); + s.append("'"); + } + s.append('}'); + return s.toString(); + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return compareTo(obj) == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int result = Bytes.hashCode(this.name); + result ^= Byte.valueOf(COLUMN_DESCRIPTOR_VERSION).hashCode(); + result ^= values.hashCode(); + return result; + } + + // Writable + + /** {@inheritDoc} */ + public void readFields(DataInput in) throws IOException { + int version = in.readByte(); + if (version < 6) { + if (version <= 2) { + Text t = new Text(); + t.readFields(in); + this.name = t.getBytes(); + if (HStoreKey.getFamilyDelimiterIndex(this.name) > 0) { + this.name = stripColon(this.name); + } + } else { + this.name = Bytes.readByteArray(in); + } + this.values.clear(); + setMaxVersions(in.readInt()); + int ordinal = in.readInt(); + setCompressionType(CompressionType.values()[ordinal]); + setInMemory(in.readBoolean()); + setMaxValueLength(in.readInt()); + setBloomfilter(in.readBoolean()); + if (isBloomfilter() && version < 5) { + // If a bloomFilter is enabled and the column descriptor is less than + // version 5, we need to skip over it to read the rest of the column + // descriptor. There are no BloomFilterDescriptors written to disk for + // column descriptors with a version number >= 5 + BloomFilterDescriptor junk = new BloomFilterDescriptor(); + junk.readFields(in); + } + if (version > 1) { + setBlockCacheEnabled(in.readBoolean()); + } + if (version > 2) { + setTimeToLive(in.readInt()); + } + } else { + // version 6+ + this.name = Bytes.readByteArray(in); + this.values.clear(); + int numValues = in.readInt(); + for (int i = 0; i < numValues; i++) { + ImmutableBytesWritable key = new ImmutableBytesWritable(); + ImmutableBytesWritable value = new ImmutableBytesWritable(); + key.readFields(in); + value.readFields(in); + values.put(key, value); + } + } + } + + /** {@inheritDoc} */ + public void write(DataOutput out) throws IOException { + out.writeByte(COLUMN_DESCRIPTOR_VERSION); + Bytes.writeByteArray(out, this.name); + out.writeInt(values.size()); + for (Map.Entry e: + values.entrySet()) { + e.getKey().write(out); + e.getValue().write(out); + } + } + + // Comparable + + /** {@inheritDoc} */ + public int compareTo(Object o) { + HColumnDescriptor other = (HColumnDescriptor)o; + int result = Bytes.compareTo(this.name, other.getName()); + if (result == 0) { + // punt on comparison for ordering, just calculate difference + result = this.values.hashCode() - other.values.hashCode(); + if (result < 0) + result = -1; + else if (result > 0) + result = 1; + } + return result; + } } \ No newline at end of file diff --git a/src/java/org/apache/hadoop/hbase/HTableDescriptor.java b/src/java/org/apache/hadoop/hbase/HTableDescriptor.java index 7df9ccf9542..5a6edbbab76 100644 --- a/src/java/org/apache/hadoop/hbase/HTableDescriptor.java +++ b/src/java/org/apache/hadoop/hbase/HTableDescriptor.java @@ -1,573 +1,573 @@ -/** - * Copyright 2007 The Apache Software Foundation - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.hadoop.hbase; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.apache.hadoop.fs.Path; -import org.apache.hadoop.hbase.io.ImmutableBytesWritable; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.io.WritableComparable; - -/** - * HTableDescriptor contains the name of an HTable, and its - * column families. - */ -public class HTableDescriptor implements WritableComparable { - /** Table descriptor for -ROOT- catalog table */ - public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor( - HConstants.ROOT_TABLE_NAME, - new HColumnDescriptor[] { new HColumnDescriptor(HConstants.COLUMN_FAMILY, - 1, HColumnDescriptor.CompressionType.NONE, false, false, - Integer.MAX_VALUE, HConstants.FOREVER, false) }); - - /** Table descriptor for .META. catalog table */ - public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor( - HConstants.META_TABLE_NAME, new HColumnDescriptor[] { - new HColumnDescriptor(HConstants.COLUMN_FAMILY, 1, - HColumnDescriptor.CompressionType.NONE, false, false, - Integer.MAX_VALUE, HConstants.FOREVER, false), - new HColumnDescriptor(HConstants.COLUMN_FAMILY_HISTORIAN, - HConstants.ALL_VERSIONS, HColumnDescriptor.CompressionType.NONE, - false, false, Integer.MAX_VALUE, HConstants.FOREVER, false) }); - - // Changes prior to version 3 were not recorded here. - // Version 3 adds metadata as a map where keys and values are byte[]. - public static final byte TABLE_DESCRIPTOR_VERSION = 3; - - private byte [] name = HConstants.EMPTY_BYTE_ARRAY; - private String nameAsString = ""; - - // Table metadata - protected Map values = - new HashMap(); - - public static final String FAMILIES = "FAMILIES"; - - public static final String MAX_FILESIZE = "MAX_FILESIZE"; - public static final String READONLY = "READONLY"; - public static final String MEMCACHE_FLUSHSIZE = "MEMCACHE_FLUSHSIZE"; - public static final String IS_ROOT = "IS_ROOT"; - public static final String IS_META = "IS_META"; - - public static final boolean DEFAULT_IN_MEMORY = false; - - public static final boolean DEFAULT_READONLY = false; - - public static final int DEFAULT_MEMCACHE_FLUSH_SIZE = 1024*1024*64; - - // Key is hash of the family name. - private final Map families = - new HashMap(); - - /** - * Private constructor used internally creating table descriptors for - * catalog tables: e.g. .META. and -ROOT-. - */ - protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families) { - this.name = name.clone(); - setMetaFlags(name); - for(HColumnDescriptor descriptor : families) { - this.families.put(Bytes.mapKey(descriptor.getName()), descriptor); - } - } - - /** - * Private constructor used internally creating table descriptors for - * catalog tables: e.g. .META. and -ROOT-. - */ - protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families, - Map values) { - this.name = name.clone(); - setMetaFlags(name); - for(HColumnDescriptor descriptor : families) { - this.families.put(Bytes.mapKey(descriptor.getName()), descriptor); - } - for (Map.Entry entry: - values.entrySet()) { - this.values.put(entry.getKey(), entry.getValue()); - } - } - - /** - * Constructs an empty object. - * For deserializing an HTableDescriptor instance only. - * @see #HTableDescriptor(byte[]) - */ - public HTableDescriptor() { - super(); - } - - /** - * Constructor. - * @param name Table name. - * @throws IllegalArgumentException if passed a table name - * that is made of other than 'word' characters, underscore or period: i.e. - * [a-zA-Z_0-9.]. - * @see HADOOP-1581 HBASE: Un-openable tablename bug - */ - public HTableDescriptor(final String name) { - this(Bytes.toBytes(name)); - } - - /** - * Constructor. - * @param name Table name. - * @throws IllegalArgumentException if passed a table name - * that is made of other than 'word' characters, underscore or period: i.e. - * [a-zA-Z_0-9-.]. - * @see HADOOP-1581 HBASE: Un-openable tablename bug - */ - public HTableDescriptor(final byte [] name) { - super(); - this.name = this.isMetaRegion() ? name: isLegalTableName(name); - this.nameAsString = Bytes.toString(this.name); - setMetaFlags(this.name); - } - - /** - * Constructor. - *

- * Makes a deep copy of the supplied descriptor. - * Can make a modifiable descriptor from an UnmodifyableHTableDescriptor. - * @param desc The descriptor. - */ - public HTableDescriptor(final HTableDescriptor desc) - { - super(); - this.name = desc.name.clone(); - this.nameAsString = Bytes.toString(this.name); - setMetaFlags(this.name); - for (HColumnDescriptor c: desc.families.values()) { - this.families.put(Bytes.mapKey(c.getName()), new HColumnDescriptor(c)); - } - for (Map.Entry e: - desc.values.entrySet()) { - this.values.put(e.getKey(), e.getValue()); - } - } - - /* - * Set meta flags on this table. - * Called by constructors. - * @param name - */ - private void setMetaFlags(final byte [] name) { - setRootRegion(Bytes.equals(name, HConstants.ROOT_TABLE_NAME)); - setMetaRegion(isRootRegion() || - Bytes.equals(name, HConstants.META_TABLE_NAME)); - } - - /** @return true if this is the root region */ - public boolean isRootRegion() { - String value = getValue(IS_ROOT); - if (value != null) - return Boolean.valueOf(value); - return false; - } - - /** @param isRoot true if this is the root region */ - protected void setRootRegion(boolean isRoot) { - values.put(new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT)), - new ImmutableBytesWritable(Bytes.toBytes(Boolean.toString(isRoot)))); - } - - /** @return true if this is a meta region (part of the root or meta tables) */ - public boolean isMetaRegion() { - String value = getValue(IS_META); - if (value != null) - return Boolean.valueOf(value); - return false; - } - - /** - * @param isMeta true if this is a meta region (part of the root or meta - * tables) */ - protected void setMetaRegion(boolean isMeta) { - values.put(new ImmutableBytesWritable(Bytes.toBytes(IS_META)), - new ImmutableBytesWritable(Bytes.toBytes(Boolean.toString(isMeta)))); - } - - /** @return true if table is the meta table */ - public boolean isMetaTable() { - return isMetaRegion() && !isRootRegion(); - } - - /** - * Check passed buffer is legal user-space table name. - * @param b Table name. - * @return Returns passed b param - * @throws NullPointerException If passed b is null - * @throws IllegalArgumentException if passed a table name - * that is made of other than 'word' characters or underscores: i.e. - * [a-zA-Z_0-9]. - */ - public static byte [] isLegalTableName(final byte [] b) { - if (b == null || b.length <= 0) { - throw new IllegalArgumentException("Name is null or empty"); - } - if (b[0] == '.' || b[0] == '-') { - throw new IllegalArgumentException("Illegal first character <" + b[0] + - ">. " + "User-space table names can only start with 'word " + - "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(b)); - } - for (int i = 0; i < b.length; i++) { - if (Character.isLetterOrDigit(b[i]) || b[i] == '_' || b[i] == '-' || - b[i] == '.') { - continue; - } - throw new IllegalArgumentException("Illegal character <" + b[i] + ">. " + - "User-space table names can only contain 'word characters':" + - "i.e. [a-zA-Z_0-9-.]: " + Bytes.toString(b)); - } - return b; - } - - /** - * @param key The key. - * @return The value. - */ - public byte[] getValue(byte[] key) { - ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key)); - if (ibw == null) - return null; - return ibw.get(); - } - - /** - * @param key The key. - * @return The value as a string. - */ - public String getValue(String key) { - byte[] value = getValue(Bytes.toBytes(key)); - if (value == null) - return null; - return Bytes.toString(value); - } - - /** - * @return All values. - */ - public Map getValues() { - return Collections.unmodifiableMap(values); - } - - /** - * @param key The key. - * @param value The value. - */ - public void setValue(byte[] key, byte[] value) { - values.put(new ImmutableBytesWritable(key), - new ImmutableBytesWritable(value)); - } - - /** - * @param key The key. - * @param value The value. - */ - public void setValue(String key, String value) { - setValue(Bytes.toBytes(key), Bytes.toBytes(value)); - } - - /** - * @return true if all columns in the table should be kept in the - * HRegionServer cache only - */ - public boolean isInMemory() { - String value = getValue(HConstants.IN_MEMORY); - if (value != null) - return Boolean.valueOf(value); - return DEFAULT_IN_MEMORY; - } - - /** - * @param inMemory True if all of the columns in the table should be kept in - * the HRegionServer cache only. - */ - public void setInMemory(boolean inMemory) { - setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory)); - } - - /** - * @return true if all columns in the table should be read only - */ - public boolean isReadOnly() { - String value = getValue(READONLY); - if (value != null) - return Boolean.valueOf(value); - return DEFAULT_READONLY; - } - - /** - * @param readOnly True if all of the columns in the table should be read - * only. - */ - public void setReadOnly(boolean readOnly) { - setValue(READONLY, Boolean.toString(readOnly)); - } - - /** @return name of table */ - public byte [] getName() { - return name; - } - - /** @return name of table */ - public String getNameAsString() { - return this.nameAsString; - } - - /** @return max hregion size for table */ - public long getMaxFileSize() { - String value = getValue(MAX_FILESIZE); - if (value != null) - return Long.valueOf(value); - return HConstants.DEFAULT_MAX_FILE_SIZE; - } - - /** - * @param maxFileSize The maximum file size that a store file can grow to - * before a split is triggered. - */ - public void setMaxFileSize(long maxFileSize) { - setValue(MAX_FILESIZE, Long.toString(maxFileSize)); - } - - /** - * @return memory cache flush size for each hregion - */ - public int getMemcacheFlushSize() { - String value = getValue(MEMCACHE_FLUSHSIZE); - if (value != null) - return Integer.valueOf(value); - return DEFAULT_MEMCACHE_FLUSH_SIZE; - } - - /** - * @param memcacheFlushSize memory cache flush size for each hregion - */ - public void setMemcacheFlushSize(int memcacheFlushSize) { - setValue(MEMCACHE_FLUSHSIZE, Integer.toString(memcacheFlushSize)); - } - - /** - * Adds a column family. - * @param family HColumnDescriptor of familyto add. - */ - public void addFamily(final HColumnDescriptor family) { - if (family.getName() == null || family.getName().length <= 0) { - throw new NullPointerException("Family name cannot be null or empty"); - } - this.families.put(Bytes.mapKey(family.getName()), family); - } - - /** - * Checks to see if this table contains the given column family - * @param c Family name or column name. - * @return true if the table contains the specified family name - */ - public boolean hasFamily(final byte [] c) { - return hasFamily(c, HStoreKey.getFamilyDelimiterIndex(c)); - } - - /** - * Checks to see if this table contains the given column family - * @param c Family name or column name. - * @param index Index to column family delimiter - * @return true if the table contains the specified family name - */ - public boolean hasFamily(final byte [] c, final int index) { - // If index is -1, then presume we were passed a column family name minus - // the colon delimiter. - return families.containsKey(Bytes.mapKey(c, index == -1? c.length: index)); - } - - /** - * @return Name of this table and then a map of all of the column family - * descriptors. - * @see #getNameAsString() - */ - @Override - public String toString() { - StringBuffer s = new StringBuffer(); - s.append('{'); - s.append(HConstants.NAME); - s.append(" => '"); - s.append(Bytes.toString(name)); - s.append("'"); - for (Map.Entry e: - values.entrySet()) { - s.append(", "); - s.append(Bytes.toString(e.getKey().get())); - s.append(" => '"); - s.append(Bytes.toString(e.getValue().get())); - s.append("'"); - } - s.append(", "); - s.append(FAMILIES); - s.append(" => "); - s.append(families.values()); - s.append('}'); - return s.toString(); - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object obj) { - return compareTo(obj) == 0; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - int result = Bytes.hashCode(this.name); - result ^= Byte.valueOf(TABLE_DESCRIPTOR_VERSION).hashCode(); - if (this.families != null && this.families.size() > 0) { - for (HColumnDescriptor e: this.families.values()) { - result ^= e.hashCode(); - } - } - result ^= values.hashCode(); - return result; - } - - // Writable - - /** {@inheritDoc} */ - public void readFields(DataInput in) throws IOException { - int version = in.readInt(); - if (version < 3) - throw new IOException("versions < 3 are not supported (and never existed!?)"); - // version 3+ - name = Bytes.readByteArray(in); - nameAsString = Bytes.toString(this.name); - setRootRegion(in.readBoolean()); - setMetaRegion(in.readBoolean()); - values.clear(); - int numVals = in.readInt(); - for (int i = 0; i < numVals; i++) { - ImmutableBytesWritable key = new ImmutableBytesWritable(); - ImmutableBytesWritable value = new ImmutableBytesWritable(); - key.readFields(in); - value.readFields(in); - values.put(key, value); - } - families.clear(); - int numFamilies = in.readInt(); - for (int i = 0; i < numFamilies; i++) { - HColumnDescriptor c = new HColumnDescriptor(); - c.readFields(in); - families.put(Bytes.mapKey(c.getName()), c); - } - } - - /** {@inheritDoc} */ - public void write(DataOutput out) throws IOException { - out.writeInt(TABLE_DESCRIPTOR_VERSION); - Bytes.writeByteArray(out, name); - out.writeBoolean(isRootRegion()); - out.writeBoolean(isMetaRegion()); - out.writeInt(values.size()); - for (Map.Entry e: - values.entrySet()) { - e.getKey().write(out); - e.getValue().write(out); - } - out.writeInt(families.size()); - for(Iterator it = families.values().iterator(); - it.hasNext(); ) { - HColumnDescriptor family = it.next(); - family.write(out); - } - } - - // Comparable - - /** {@inheritDoc} */ - public int compareTo(Object o) { - HTableDescriptor other = (HTableDescriptor) o; - int result = Bytes.compareTo(this.name, other.name); - if (result == 0) { - result = families.size() - other.families.size(); - } - if (result == 0 && families.size() != other.families.size()) { - result = Integer.valueOf(families.size()).compareTo( - Integer.valueOf(other.families.size())); - } - if (result == 0) { - for (Iterator it = families.values().iterator(), - it2 = other.families.values().iterator(); it.hasNext(); ) { - result = it.next().compareTo(it2.next()); - if (result != 0) { - break; - } - } - } - if (result == 0) { - // punt on comparison for ordering, just calculate difference - result = this.values.hashCode() - other.values.hashCode(); - if (result < 0) - result = -1; - else if (result > 0) - result = 1; - } - return result; - } - - /** - * @return Immutable sorted map of families. - */ - public Collection getFamilies() { - return Collections.unmodifiableCollection(this.families.values()); - } - - /** - * @param column - * @return Column descriptor for the passed family name or the family on - * passed in column. - */ - public HColumnDescriptor getFamily(final byte [] column) { - return this.families.get(HStoreKey.getFamilyMapKey(column)); - } - - /** - * @param column - * @return Column descriptor for the passed family name or the family on - * passed in column. - */ - public HColumnDescriptor removeFamily(final byte [] column) { - return this.families.remove(HStoreKey.getFamilyMapKey(column)); - } - - /** - * @param rootdir qualified path of HBase root directory - * @param tableName name of table - * @return path for table - */ - public static Path getTableDir(Path rootdir, final byte [] tableName) { - return new Path(rootdir, Bytes.toString(tableName)); - } -} +/** + * Copyright 2007 The Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.io.WritableComparable; + +/** + * HTableDescriptor contains the name of an HTable, and its + * column families. + */ +public class HTableDescriptor implements WritableComparable { + /** Table descriptor for -ROOT- catalog table */ + public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor( + HConstants.ROOT_TABLE_NAME, + new HColumnDescriptor[] { new HColumnDescriptor(HConstants.COLUMN_FAMILY, + 1, HColumnDescriptor.CompressionType.NONE, false, false, + Integer.MAX_VALUE, HConstants.FOREVER, false) }); + + /** Table descriptor for .META. catalog table */ + public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor( + HConstants.META_TABLE_NAME, new HColumnDescriptor[] { + new HColumnDescriptor(HConstants.COLUMN_FAMILY, 1, + HColumnDescriptor.CompressionType.NONE, false, false, + Integer.MAX_VALUE, HConstants.FOREVER, false), + new HColumnDescriptor(HConstants.COLUMN_FAMILY_HISTORIAN, + HConstants.ALL_VERSIONS, HColumnDescriptor.CompressionType.NONE, + false, false, Integer.MAX_VALUE, HConstants.FOREVER, false) }); + + // Changes prior to version 3 were not recorded here. + // Version 3 adds metadata as a map where keys and values are byte[]. + public static final byte TABLE_DESCRIPTOR_VERSION = 3; + + private byte [] name = HConstants.EMPTY_BYTE_ARRAY; + private String nameAsString = ""; + + // Table metadata + protected Map values = + new HashMap(); + + public static final String FAMILIES = "FAMILIES"; + + public static final String MAX_FILESIZE = "MAX_FILESIZE"; + public static final String READONLY = "READONLY"; + public static final String MEMCACHE_FLUSHSIZE = "MEMCACHE_FLUSHSIZE"; + public static final String IS_ROOT = "IS_ROOT"; + public static final String IS_META = "IS_META"; + + public static final boolean DEFAULT_IN_MEMORY = false; + + public static final boolean DEFAULT_READONLY = false; + + public static final int DEFAULT_MEMCACHE_FLUSH_SIZE = 1024*1024*64; + + // Key is hash of the family name. + private final Map families = + new HashMap(); + + /** + * Private constructor used internally creating table descriptors for + * catalog tables: e.g. .META. and -ROOT-. + */ + protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families) { + this.name = name.clone(); + setMetaFlags(name); + for(HColumnDescriptor descriptor : families) { + this.families.put(Bytes.mapKey(descriptor.getName()), descriptor); + } + } + + /** + * Private constructor used internally creating table descriptors for + * catalog tables: e.g. .META. and -ROOT-. + */ + protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families, + Map values) { + this.name = name.clone(); + setMetaFlags(name); + for(HColumnDescriptor descriptor : families) { + this.families.put(Bytes.mapKey(descriptor.getName()), descriptor); + } + for (Map.Entry entry: + values.entrySet()) { + this.values.put(entry.getKey(), entry.getValue()); + } + } + + /** + * Constructs an empty object. + * For deserializing an HTableDescriptor instance only. + * @see #HTableDescriptor(byte[]) + */ + public HTableDescriptor() { + super(); + } + + /** + * Constructor. + * @param name Table name. + * @throws IllegalArgumentException if passed a table name + * that is made of other than 'word' characters, underscore or period: i.e. + * [a-zA-Z_0-9.]. + * @see HADOOP-1581 HBASE: Un-openable tablename bug + */ + public HTableDescriptor(final String name) { + this(Bytes.toBytes(name)); + } + + /** + * Constructor. + * @param name Table name. + * @throws IllegalArgumentException if passed a table name + * that is made of other than 'word' characters, underscore or period: i.e. + * [a-zA-Z_0-9-.]. + * @see HADOOP-1581 HBASE: Un-openable tablename bug + */ + public HTableDescriptor(final byte [] name) { + super(); + this.name = this.isMetaRegion() ? name: isLegalTableName(name); + this.nameAsString = Bytes.toString(this.name); + setMetaFlags(this.name); + } + + /** + * Constructor. + *

+ * Makes a deep copy of the supplied descriptor. + * Can make a modifiable descriptor from an UnmodifyableHTableDescriptor. + * @param desc The descriptor. + */ + public HTableDescriptor(final HTableDescriptor desc) + { + super(); + this.name = desc.name.clone(); + this.nameAsString = Bytes.toString(this.name); + setMetaFlags(this.name); + for (HColumnDescriptor c: desc.families.values()) { + this.families.put(Bytes.mapKey(c.getName()), new HColumnDescriptor(c)); + } + for (Map.Entry e: + desc.values.entrySet()) { + this.values.put(e.getKey(), e.getValue()); + } + } + + /* + * Set meta flags on this table. + * Called by constructors. + * @param name + */ + private void setMetaFlags(final byte [] name) { + setRootRegion(Bytes.equals(name, HConstants.ROOT_TABLE_NAME)); + setMetaRegion(isRootRegion() || + Bytes.equals(name, HConstants.META_TABLE_NAME)); + } + + /** @return true if this is the root region */ + public boolean isRootRegion() { + String value = getValue(IS_ROOT); + if (value != null) + return Boolean.valueOf(value); + return false; + } + + /** @param isRoot true if this is the root region */ + protected void setRootRegion(boolean isRoot) { + values.put(new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT)), + new ImmutableBytesWritable(Bytes.toBytes(Boolean.toString(isRoot)))); + } + + /** @return true if this is a meta region (part of the root or meta tables) */ + public boolean isMetaRegion() { + String value = getValue(IS_META); + if (value != null) + return Boolean.valueOf(value); + return false; + } + + /** + * @param isMeta true if this is a meta region (part of the root or meta + * tables) */ + protected void setMetaRegion(boolean isMeta) { + values.put(new ImmutableBytesWritable(Bytes.toBytes(IS_META)), + new ImmutableBytesWritable(Bytes.toBytes(Boolean.toString(isMeta)))); + } + + /** @return true if table is the meta table */ + public boolean isMetaTable() { + return isMetaRegion() && !isRootRegion(); + } + + /** + * Check passed buffer is legal user-space table name. + * @param b Table name. + * @return Returns passed b param + * @throws NullPointerException If passed b is null + * @throws IllegalArgumentException if passed a table name + * that is made of other than 'word' characters or underscores: i.e. + * [a-zA-Z_0-9]. + */ + public static byte [] isLegalTableName(final byte [] b) { + if (b == null || b.length <= 0) { + throw new IllegalArgumentException("Name is null or empty"); + } + if (b[0] == '.' || b[0] == '-') { + throw new IllegalArgumentException("Illegal first character <" + b[0] + + ">. " + "User-space table names can only start with 'word " + + "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(b)); + } + for (int i = 0; i < b.length; i++) { + if (Character.isLetterOrDigit(b[i]) || b[i] == '_' || b[i] == '-' || + b[i] == '.') { + continue; + } + throw new IllegalArgumentException("Illegal character <" + b[i] + ">. " + + "User-space table names can only contain 'word characters':" + + "i.e. [a-zA-Z_0-9-.]: " + Bytes.toString(b)); + } + return b; + } + + /** + * @param key The key. + * @return The value. + */ + public byte[] getValue(byte[] key) { + ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key)); + if (ibw == null) + return null; + return ibw.get(); + } + + /** + * @param key The key. + * @return The value as a string. + */ + public String getValue(String key) { + byte[] value = getValue(Bytes.toBytes(key)); + if (value == null) + return null; + return Bytes.toString(value); + } + + /** + * @return All values. + */ + public Map getValues() { + return Collections.unmodifiableMap(values); + } + + /** + * @param key The key. + * @param value The value. + */ + public void setValue(byte[] key, byte[] value) { + values.put(new ImmutableBytesWritable(key), + new ImmutableBytesWritable(value)); + } + + /** + * @param key The key. + * @param value The value. + */ + public void setValue(String key, String value) { + setValue(Bytes.toBytes(key), Bytes.toBytes(value)); + } + + /** + * @return true if all columns in the table should be kept in the + * HRegionServer cache only + */ + public boolean isInMemory() { + String value = getValue(HConstants.IN_MEMORY); + if (value != null) + return Boolean.valueOf(value); + return DEFAULT_IN_MEMORY; + } + + /** + * @param inMemory True if all of the columns in the table should be kept in + * the HRegionServer cache only. + */ + public void setInMemory(boolean inMemory) { + setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory)); + } + + /** + * @return true if all columns in the table should be read only + */ + public boolean isReadOnly() { + String value = getValue(READONLY); + if (value != null) + return Boolean.valueOf(value); + return DEFAULT_READONLY; + } + + /** + * @param readOnly True if all of the columns in the table should be read + * only. + */ + public void setReadOnly(boolean readOnly) { + setValue(READONLY, Boolean.toString(readOnly)); + } + + /** @return name of table */ + public byte [] getName() { + return name; + } + + /** @return name of table */ + public String getNameAsString() { + return this.nameAsString; + } + + /** @return max hregion size for table */ + public long getMaxFileSize() { + String value = getValue(MAX_FILESIZE); + if (value != null) + return Long.valueOf(value); + return HConstants.DEFAULT_MAX_FILE_SIZE; + } + + /** + * @param maxFileSize The maximum file size that a store file can grow to + * before a split is triggered. + */ + public void setMaxFileSize(long maxFileSize) { + setValue(MAX_FILESIZE, Long.toString(maxFileSize)); + } + + /** + * @return memory cache flush size for each hregion + */ + public int getMemcacheFlushSize() { + String value = getValue(MEMCACHE_FLUSHSIZE); + if (value != null) + return Integer.valueOf(value); + return DEFAULT_MEMCACHE_FLUSH_SIZE; + } + + /** + * @param memcacheFlushSize memory cache flush size for each hregion + */ + public void setMemcacheFlushSize(int memcacheFlushSize) { + setValue(MEMCACHE_FLUSHSIZE, Integer.toString(memcacheFlushSize)); + } + + /** + * Adds a column family. + * @param family HColumnDescriptor of familyto add. + */ + public void addFamily(final HColumnDescriptor family) { + if (family.getName() == null || family.getName().length <= 0) { + throw new NullPointerException("Family name cannot be null or empty"); + } + this.families.put(Bytes.mapKey(family.getName()), family); + } + + /** + * Checks to see if this table contains the given column family + * @param c Family name or column name. + * @return true if the table contains the specified family name + */ + public boolean hasFamily(final byte [] c) { + return hasFamily(c, HStoreKey.getFamilyDelimiterIndex(c)); + } + + /** + * Checks to see if this table contains the given column family + * @param c Family name or column name. + * @param index Index to column family delimiter + * @return true if the table contains the specified family name + */ + public boolean hasFamily(final byte [] c, final int index) { + // If index is -1, then presume we were passed a column family name minus + // the colon delimiter. + return families.containsKey(Bytes.mapKey(c, index == -1? c.length: index)); + } + + /** + * @return Name of this table and then a map of all of the column family + * descriptors. + * @see #getNameAsString() + */ + @Override + public String toString() { + StringBuffer s = new StringBuffer(); + s.append('{'); + s.append(HConstants.NAME); + s.append(" => '"); + s.append(Bytes.toString(name)); + s.append("'"); + for (Map.Entry e: + values.entrySet()) { + s.append(", "); + s.append(Bytes.toString(e.getKey().get())); + s.append(" => '"); + s.append(Bytes.toString(e.getValue().get())); + s.append("'"); + } + s.append(", "); + s.append(FAMILIES); + s.append(" => "); + s.append(families.values()); + s.append('}'); + return s.toString(); + } + + /** {@inheritDoc} */ + @Override + public boolean equals(Object obj) { + return compareTo(obj) == 0; + } + + /** {@inheritDoc} */ + @Override + public int hashCode() { + int result = Bytes.hashCode(this.name); + result ^= Byte.valueOf(TABLE_DESCRIPTOR_VERSION).hashCode(); + if (this.families != null && this.families.size() > 0) { + for (HColumnDescriptor e: this.families.values()) { + result ^= e.hashCode(); + } + } + result ^= values.hashCode(); + return result; + } + + // Writable + + /** {@inheritDoc} */ + public void readFields(DataInput in) throws IOException { + int version = in.readInt(); + if (version < 3) + throw new IOException("versions < 3 are not supported (and never existed!?)"); + // version 3+ + name = Bytes.readByteArray(in); + nameAsString = Bytes.toString(this.name); + setRootRegion(in.readBoolean()); + setMetaRegion(in.readBoolean()); + values.clear(); + int numVals = in.readInt(); + for (int i = 0; i < numVals; i++) { + ImmutableBytesWritable key = new ImmutableBytesWritable(); + ImmutableBytesWritable value = new ImmutableBytesWritable(); + key.readFields(in); + value.readFields(in); + values.put(key, value); + } + families.clear(); + int numFamilies = in.readInt(); + for (int i = 0; i < numFamilies; i++) { + HColumnDescriptor c = new HColumnDescriptor(); + c.readFields(in); + families.put(Bytes.mapKey(c.getName()), c); + } + } + + /** {@inheritDoc} */ + public void write(DataOutput out) throws IOException { + out.writeInt(TABLE_DESCRIPTOR_VERSION); + Bytes.writeByteArray(out, name); + out.writeBoolean(isRootRegion()); + out.writeBoolean(isMetaRegion()); + out.writeInt(values.size()); + for (Map.Entry e: + values.entrySet()) { + e.getKey().write(out); + e.getValue().write(out); + } + out.writeInt(families.size()); + for(Iterator it = families.values().iterator(); + it.hasNext(); ) { + HColumnDescriptor family = it.next(); + family.write(out); + } + } + + // Comparable + + /** {@inheritDoc} */ + public int compareTo(Object o) { + HTableDescriptor other = (HTableDescriptor) o; + int result = Bytes.compareTo(this.name, other.name); + if (result == 0) { + result = families.size() - other.families.size(); + } + if (result == 0 && families.size() != other.families.size()) { + result = Integer.valueOf(families.size()).compareTo( + Integer.valueOf(other.families.size())); + } + if (result == 0) { + for (Iterator it = families.values().iterator(), + it2 = other.families.values().iterator(); it.hasNext(); ) { + result = it.next().compareTo(it2.next()); + if (result != 0) { + break; + } + } + } + if (result == 0) { + // punt on comparison for ordering, just calculate difference + result = this.values.hashCode() - other.values.hashCode(); + if (result < 0) + result = -1; + else if (result > 0) + result = 1; + } + return result; + } + + /** + * @return Immutable sorted map of families. + */ + public Collection getFamilies() { + return Collections.unmodifiableCollection(this.families.values()); + } + + /** + * @param column + * @return Column descriptor for the passed family name or the family on + * passed in column. + */ + public HColumnDescriptor getFamily(final byte [] column) { + return this.families.get(HStoreKey.getFamilyMapKey(column)); + } + + /** + * @param column + * @return Column descriptor for the passed family name or the family on + * passed in column. + */ + public HColumnDescriptor removeFamily(final byte [] column) { + return this.families.remove(HStoreKey.getFamilyMapKey(column)); + } + + /** + * @param rootdir qualified path of HBase root directory + * @param tableName name of table + * @return path for table + */ + public static Path getTableDir(Path rootdir, final byte [] tableName) { + return new Path(rootdir, Bytes.toString(tableName)); + } +} diff --git a/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java b/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java index 11ef311a746..ec7944ee16d 100644 --- a/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java +++ b/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java @@ -1,104 +1,104 @@ -/** - * Copyright 2008 The Apache Software Foundation - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.hadoop.hbase.client; - -import org.apache.hadoop.hbase.HColumnDescriptor; -import org.apache.hadoop.hbase.HTableDescriptor; - -/** - * Read-only table descriptor. - */ -public class UnmodifyableHTableDescriptor extends HTableDescriptor { - public UnmodifyableHTableDescriptor() { - super(); - } - - /* - * Create an unmodifyable copy of an HTableDescriptor - * @param desc - */ - UnmodifyableHTableDescriptor(final HTableDescriptor desc) { - super(desc.getName(), getUnmodifyableFamilies(desc), desc.getValues()); - } - - /* - * @param desc - * @return Families as unmodifiable array. - */ - private static HColumnDescriptor[] getUnmodifyableFamilies( - final HTableDescriptor desc) { - HColumnDescriptor [] f = new HColumnDescriptor[desc.getFamilies().size()]; - int i = 0; - for (HColumnDescriptor c: desc.getFamilies()) { - f[i++] = c; - } - return f; - } - - /** - * Does NOT add a column family. This object is immutable - * @param family HColumnDescriptor of familyto add. - */ - @Override - public void addFamily(final HColumnDescriptor family) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - /** - * @param column - * @return Column descriptor for the passed family name or the family on - * passed in column. - */ - @Override - public HColumnDescriptor removeFamily(final byte [] column) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setInMemory(boolean inMemory) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setReadOnly(boolean readOnly) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setValue(byte[] key, byte[] value) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setValue(String key, String value) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setMaxFileSize(long maxFileSize) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } - - @Override - public void setMemcacheFlushSize(int memcacheFlushSize) { - throw new UnsupportedOperationException("HTableDescriptor is read-only"); - } -} +/** + * Copyright 2008 The Apache Software Foundation + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hbase.client; + +import org.apache.hadoop.hbase.HColumnDescriptor; +import org.apache.hadoop.hbase.HTableDescriptor; + +/** + * Read-only table descriptor. + */ +public class UnmodifyableHTableDescriptor extends HTableDescriptor { + public UnmodifyableHTableDescriptor() { + super(); + } + + /* + * Create an unmodifyable copy of an HTableDescriptor + * @param desc + */ + UnmodifyableHTableDescriptor(final HTableDescriptor desc) { + super(desc.getName(), getUnmodifyableFamilies(desc), desc.getValues()); + } + + /* + * @param desc + * @return Families as unmodifiable array. + */ + private static HColumnDescriptor[] getUnmodifyableFamilies( + final HTableDescriptor desc) { + HColumnDescriptor [] f = new HColumnDescriptor[desc.getFamilies().size()]; + int i = 0; + for (HColumnDescriptor c: desc.getFamilies()) { + f[i++] = c; + } + return f; + } + + /** + * Does NOT add a column family. This object is immutable + * @param family HColumnDescriptor of familyto add. + */ + @Override + public void addFamily(final HColumnDescriptor family) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + /** + * @param column + * @return Column descriptor for the passed family name or the family on + * passed in column. + */ + @Override + public HColumnDescriptor removeFamily(final byte [] column) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setInMemory(boolean inMemory) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setReadOnly(boolean readOnly) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setValue(byte[] key, byte[] value) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setValue(String key, String value) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setMaxFileSize(long maxFileSize) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } + + @Override + public void setMemcacheFlushSize(int memcacheFlushSize) { + throw new UnsupportedOperationException("HTableDescriptor is read-only"); + } +}