You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ji...@apache.org on 2008/08/11 23:24:05 UTC

svn commit: r684937 - in /hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase: HColumnDescriptor.java HTableDescriptor.java client/UnmodifyableHTableDescriptor.java

Author: jimk
Date: Mon Aug 11 14:24:04 2008
New Revision: 684937

URL: http://svn.apache.org/viewvc?rev=684937&view=rev
Log:
HBASE-811 fix whitespaace

Modified:
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HTableDescriptor.java
    hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java?rev=684937&r1=684936&r2=684937&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HColumnDescriptor.java Mon Aug 11 14:24:04 2008
@@ -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<ImmutableBytesWritable,ImmutableBytesWritable> values =
-    new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
-
-
-  /**
-   * 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<ImmutableBytesWritable, ImmutableBytesWritable> 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 &lt;= 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. <code>[a-zA-Z_0-9]</code> and does not
-   * end in a <code>:</code>
-   * @throws IllegalArgumentException if the number of versions is &lt;= 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 <code>b</code>
-   * @throws IllegalArgumentException If not null and not a legitimate family
-   * name: i.e. 'printable' and ends in a ':' (Null passes are allowed because
-   * <code>b</code> 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<ImmutableBytesWritable,ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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<ImmutableBytesWritable,ImmutableBytesWritable> values =
+    new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
+
+
+  /**
+   * 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<ImmutableBytesWritable, ImmutableBytesWritable> 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 &lt;= 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. <code>[a-zA-Z_0-9]</code> and does not
+   * end in a <code>:</code>
+   * @throws IllegalArgumentException if the number of versions is &lt;= 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 <code>b</code>
+   * @throws IllegalArgumentException If not null and not a legitimate family
+   * name: i.e. 'printable' and ends in a ':' (Null passes are allowed because
+   * <code>b</code> 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<ImmutableBytesWritable,ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HTableDescriptor.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HTableDescriptor.java?rev=684937&r1=684936&r2=684937&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HTableDescriptor.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/HTableDescriptor.java Mon Aug 11 14:24:04 2008
@@ -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 <core>-ROOT-</code> 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 <code>.META.</code> 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<ImmutableBytesWritable,ImmutableBytesWritable> values =
-    new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
-  
-  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<Integer, HColumnDescriptor> families =
-    new HashMap<Integer, HColumnDescriptor>();
-
-  /**
-   * 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<ImmutableBytesWritable,ImmutableBytesWritable> values) {
-    this.name = name.clone();
-    setMetaFlags(name);
-    for(HColumnDescriptor descriptor : families) {
-      this.families.put(Bytes.mapKey(descriptor.getName()), descriptor);
-    }
-    for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> 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.
-   * <code>[a-zA-Z_0-9.].
-   * @see <a href="HADOOP-1581">HADOOP-1581 HBASE: Un-openable tablename bug</a>
-   */
-  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.
-   * <code>[a-zA-Z_0-9-.].
-   * @see <a href="HADOOP-1581">HADOOP-1581 HBASE: Un-openable tablename bug</a>
-   */
-  public HTableDescriptor(final byte [] name) {
-    super();
-    this.name = this.isMetaRegion() ? name: isLegalTableName(name);
-    this.nameAsString = Bytes.toString(this.name);
-    setMetaFlags(this.name);
-  }
-
-  /**
-   * Constructor.
-   * <p>
-   * 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<ImmutableBytesWritable, ImmutableBytesWritable> 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 <code>b</code> param
-   * @throws NullPointerException If passed <code>b</code> is null
-   * @throws IllegalArgumentException if passed a table name
-   * that is made of other than 'word' characters or underscores: i.e.
-   * <code>[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<ImmutableBytesWritable,ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> e:
-        values.entrySet()) {
-      e.getKey().write(out);
-      e.getValue().write(out);
-    }
-    out.writeInt(families.size());
-    for(Iterator<HColumnDescriptor> 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<HColumnDescriptor> 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<HColumnDescriptor> 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 <core>-ROOT-</code> 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 <code>.META.</code> 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<ImmutableBytesWritable,ImmutableBytesWritable> values =
+    new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
+  
+  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<Integer, HColumnDescriptor> families =
+    new HashMap<Integer, HColumnDescriptor>();
+
+  /**
+   * 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<ImmutableBytesWritable,ImmutableBytesWritable> values) {
+    this.name = name.clone();
+    setMetaFlags(name);
+    for(HColumnDescriptor descriptor : families) {
+      this.families.put(Bytes.mapKey(descriptor.getName()), descriptor);
+    }
+    for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> 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.
+   * <code>[a-zA-Z_0-9.].
+   * @see <a href="HADOOP-1581">HADOOP-1581 HBASE: Un-openable tablename bug</a>
+   */
+  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.
+   * <code>[a-zA-Z_0-9-.].
+   * @see <a href="HADOOP-1581">HADOOP-1581 HBASE: Un-openable tablename bug</a>
+   */
+  public HTableDescriptor(final byte [] name) {
+    super();
+    this.name = this.isMetaRegion() ? name: isLegalTableName(name);
+    this.nameAsString = Bytes.toString(this.name);
+    setMetaFlags(this.name);
+  }
+
+  /**
+   * Constructor.
+   * <p>
+   * 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<ImmutableBytesWritable, ImmutableBytesWritable> 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 <code>b</code> param
+   * @throws NullPointerException If passed <code>b</code> is null
+   * @throws IllegalArgumentException if passed a table name
+   * that is made of other than 'word' characters or underscores: i.e.
+   * <code>[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<ImmutableBytesWritable,ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> 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<ImmutableBytesWritable, ImmutableBytesWritable> e:
+        values.entrySet()) {
+      e.getKey().write(out);
+      e.getValue().write(out);
+    }
+    out.writeInt(families.size());
+    for(Iterator<HColumnDescriptor> 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<HColumnDescriptor> 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<HColumnDescriptor> 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));
+  }
+}

Modified: hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java
URL: http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java?rev=684937&r1=684936&r2=684937&view=diff
==============================================================================
--- hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java (original)
+++ hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/client/UnmodifyableHTableDescriptor.java Mon Aug 11 14:24:04 2008
@@ -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");
+  }
+}