You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by sz...@apache.org on 2009/05/05 01:56:47 UTC

svn commit: r771505 - in /hadoop/core/trunk: CHANGES.txt src/core/org/apache/hadoop/io/EnumSetWritable.java src/core/org/apache/hadoop/io/ObjectWritable.java src/test/org/apache/hadoop/io/TestEnumSetWritable.java

Author: szetszwo
Date: Mon May  4 23:56:46 2009
New Revision: 771505

URL: http://svn.apache.org/viewvc?rev=771505&view=rev
Log:
HADOOP-5596. Add EnumSetWritable. Contributed by He Yongqiang

Added:
    hadoop/core/trunk/src/core/org/apache/hadoop/io/EnumSetWritable.java
    hadoop/core/trunk/src/test/org/apache/hadoop/io/TestEnumSetWritable.java
Modified:
    hadoop/core/trunk/CHANGES.txt
    hadoop/core/trunk/src/core/org/apache/hadoop/io/ObjectWritable.java

Modified: hadoop/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/CHANGES.txt?rev=771505&r1=771504&r2=771505&view=diff
==============================================================================
--- hadoop/core/trunk/CHANGES.txt (original)
+++ hadoop/core/trunk/CHANGES.txt Mon May  4 23:56:46 2009
@@ -298,6 +298,8 @@
     HADOOP-5733. Add map/reduce slot capacity and blacklisted capacity to
     JobTracker metrics. (Sreekanth Ramakrishnan via cdouglas)
 
+    HADOOP-5596. Add EnumSetWritable. (He Yongqiang via szetszwo)
+
   OPTIMIZATIONS
 
     HADOOP-5595. NameNode does not need to run a replicator to choose a

Added: hadoop/core/trunk/src/core/org/apache/hadoop/io/EnumSetWritable.java
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/src/core/org/apache/hadoop/io/EnumSetWritable.java?rev=771505&view=auto
==============================================================================
--- hadoop/core/trunk/src/core/org/apache/hadoop/io/EnumSetWritable.java (added)
+++ hadoop/core/trunk/src/core/org/apache/hadoop/io/EnumSetWritable.java Mon May  4 23:56:46 2009
@@ -0,0 +1,202 @@
+/**
+ * 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.io;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.Iterator;
+
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+
+/** A Writable wrapper for EnumSet. */
+public class EnumSetWritable<E extends Enum<E>> implements Writable,
+    Configurable {
+
+  private EnumSet<E> value;
+
+  private Class<E> elementType;
+
+  private Configuration conf;
+
+  EnumSetWritable() {
+  }
+
+  /**
+   * Construct a new EnumSetWritable. If the <tt>value</tt> argument is null or
+   * its size is zero, the <tt>elementType</tt> argument must not be null. If
+   * the argument <tt>value</tt>'s size is bigger than zero, the argument
+   * <tt>elementType</tt> is not be used.
+   * 
+   * @param value
+   * @param elementType
+   */
+  public EnumSetWritable(EnumSet<E> value, Class<E> elementType) {
+    set(value, elementType);
+  }
+
+  /**
+   * Construct a new EnumSetWritable. Argument <tt>value</tt> should not be null
+   * or empty.
+   * 
+   * @param value
+   */
+  public EnumSetWritable(EnumSet<E> value) {
+    this(value, null);
+  }
+
+  /**
+   * reset the EnumSetWritable with specified
+   * <tt>value</value> and <tt>elementType</tt>. If the <tt>value</tt> argument
+   * is null or its size is zero, the <tt>elementType</tt> argument must not be
+   * null. If the argument <tt>value</tt>'s size is bigger than zero, the
+   * argument <tt>elementType</tt> is not be used.
+   * 
+   * @param value
+   * @param elementType
+   */
+  public void set(EnumSet<E> value, Class<E> elementType) {
+    if ((value == null || value.size() == 0)
+        && (this.elementType == null && elementType == null)) {
+      throw new IllegalArgumentException(
+          "The EnumSet argument is null, or is an empty set but with no elementType provided.");
+    }
+    this.value = value;
+    if (value != null && value.size() > 0) {
+      Iterator<E> iterator = value.iterator();
+      this.elementType = iterator.next().getDeclaringClass();
+    } else if (elementType != null) {
+      this.elementType = elementType;
+    }
+  }
+
+  /** Return the value of this EnumSetWritable. */
+  public EnumSet<E> get() {
+    return value;
+  }
+
+  /** {@inheritDoc} */
+  @SuppressWarnings("unchecked")
+  public void readFields(DataInput in) throws IOException {
+    int length = in.readInt();
+    if (length == -1)
+      this.value = null;
+    else if (length == 0) {
+      this.elementType = (Class<E>) ObjectWritable.loadClass(conf,
+          WritableUtils.readString(in));
+      this.value = EnumSet.noneOf(this.elementType);
+    } else {
+      E first = (E) ObjectWritable.readObject(in, conf);
+      this.value = (EnumSet<E>) EnumSet.of(first);
+      for (int i = 1; i < length; i++)
+        this.value.add((E) ObjectWritable.readObject(in, conf));
+    }
+  }
+
+  /** {@inheritDoc} */
+  public void write(DataOutput out) throws IOException {
+    if (this.value == null) {
+      out.writeInt(-1);
+      WritableUtils.writeString(out, this.elementType.getName());
+    } else {
+      Object[] array = this.value.toArray();
+      int length = array.length;
+      out.writeInt(length);
+      if (length == 0) {
+        if (this.elementType == null)
+          throw new UnsupportedOperationException(
+              "Unable to serialize empty EnumSet with no element type provided.");
+        WritableUtils.writeString(out, this.elementType.getName());
+      }
+      for (int i = 0; i < length; i++) {
+        ObjectWritable.writeObject(out, array[i], array[i].getClass(), conf);
+      }
+    }
+  }
+
+  /**
+   * Returns true if <code>o</code> is an EnumSetWritable with the same value,
+   * or both are null.
+   */
+  public boolean equals(Object o) {
+    if (o == null) {
+      throw new IllegalArgumentException("null argument passed in equal().");
+    }
+
+    if (!(o instanceof EnumSetWritable))
+      return false;
+
+    EnumSetWritable<?> other = (EnumSetWritable<?>) o;
+
+    if (this == o || (this.value == other.value))
+      return true;
+    if (this.value == null) // other.value must not be null if we reach here
+      return false;
+
+    return this.value.equals(other.value);
+  }
+
+  /**
+   * Returns the class of all the elements of the underlying EnumSetWriable. It
+   * may return null.
+   * 
+   * @return the element class
+   */
+  public Class<E> getElementType() {
+    return elementType;
+  }
+
+  /** {@inheritDoc} */
+  public int hashCode() {
+    if (value == null)
+      return 0;
+    return (int) value.hashCode();
+  }
+
+  /** {@inheritDoc} */
+  public String toString() {
+    if (value == null)
+      return "(null)";
+    return value.toString();
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Configuration getConf() {
+    return this.conf;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public void setConf(Configuration conf) {
+    this.conf = conf;
+  }
+
+  static {
+    WritableFactories.setFactory(EnumSetWritable.class, new WritableFactory() {
+      @SuppressWarnings("unchecked")
+      @Override
+      public Writable newInstance() {
+        return new EnumSetWritable();
+      }
+    });
+  }
+}

Modified: hadoop/core/trunk/src/core/org/apache/hadoop/io/ObjectWritable.java
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/src/core/org/apache/hadoop/io/ObjectWritable.java?rev=771505&r1=771504&r2=771505&view=diff
==============================================================================
--- hadoop/core/trunk/src/core/org/apache/hadoop/io/ObjectWritable.java (original)
+++ hadoop/core/trunk/src/core/org/apache/hadoop/io/ObjectWritable.java Mon May  4 23:56:46 2009
@@ -179,13 +179,9 @@
     String className = UTF8.readString(in);
     Class<?> declaredClass = PRIMITIVE_NAMES.get(className);
     if (declaredClass == null) {
-      try {
-        declaredClass = conf.getClassByName(className);
-      } catch (ClassNotFoundException e) {
-        throw new RuntimeException("readObject can't find class " + className, e);
-      }
-    }    
-
+      declaredClass = loadClass(conf, className);
+    }
+    
     Object instance;
     
     if (declaredClass.isPrimitive()) {            // primitive types
@@ -225,13 +221,8 @@
       instance = Enum.valueOf((Class<? extends Enum>) declaredClass, UTF8.readString(in));
     } else {                                      // Writable
       Class instanceClass = null;
-      String str = "";
-      try {
-        str = UTF8.readString(in);
-        instanceClass = conf.getClassByName(str);
-      } catch (ClassNotFoundException e) {
-        throw new RuntimeException("readObject can't find class " + str, e);
-      }
+      String str = UTF8.readString(in);
+      instanceClass = loadClass(conf, str);
       
       Writable writable = WritableFactories.newInstance(instanceClass, conf);
       writable.readFields(in);
@@ -252,6 +243,25 @@
       
   }
 
+  /**
+   * Find and load the class with given name <tt>className</tt> by first finding
+   * it in the specified <tt>conf</tt>. If the specified <tt>conf</tt> is null,
+   * try load it directly.
+   */
+  public static Class<?> loadClass(Configuration conf, String className) {
+    Class<?> declaredClass = null;
+    try {
+      if (conf != null)
+        declaredClass = conf.getClassByName(className);
+      else
+        declaredClass = Class.forName(className);
+    } catch (ClassNotFoundException e) {
+      throw new RuntimeException("readObject can't find class " + className,
+          e);
+    }
+    return declaredClass;
+  }
+
   public void setConf(Configuration conf) {
     this.conf = conf;
   }

Added: hadoop/core/trunk/src/test/org/apache/hadoop/io/TestEnumSetWritable.java
URL: http://svn.apache.org/viewvc/hadoop/core/trunk/src/test/org/apache/hadoop/io/TestEnumSetWritable.java?rev=771505&view=auto
==============================================================================
--- hadoop/core/trunk/src/test/org/apache/hadoop/io/TestEnumSetWritable.java (added)
+++ hadoop/core/trunk/src/test/org/apache/hadoop/io/TestEnumSetWritable.java Mon May  4 23:56:46 2009
@@ -0,0 +1,103 @@
+/**
+ * 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.io;
+
+import java.io.IOException;
+import java.util.EnumSet;
+
+import junit.framework.TestCase;
+
+/** Unit test for EnumSetWritable */
+public class TestEnumSetWritable extends TestCase {
+
+  enum TestEnumSet {
+    CREATE, OVERWRITE, APPEND;
+  }
+
+  EnumSet<TestEnumSet> nonEmptyFlag = EnumSet.of(TestEnumSet.APPEND);
+  EnumSetWritable<TestEnumSet> nonEmptyFlagWritable = new EnumSetWritable<TestEnumSet>(
+      nonEmptyFlag);
+
+  @SuppressWarnings("unchecked")
+  public void testSerializeAndDeserializeNonEmpty() throws IOException {
+    DataOutputBuffer out = new DataOutputBuffer();
+    ObjectWritable.writeObject(out, nonEmptyFlagWritable, nonEmptyFlagWritable
+        .getClass(), null);
+    DataInputBuffer in = new DataInputBuffer();
+    in.reset(out.getData(), out.getLength());
+    EnumSet<TestEnumSet> read = ((EnumSetWritable<TestEnumSet>) ObjectWritable
+        .readObject(in, null)).get();
+    assertEquals(read, nonEmptyFlag);
+  }
+
+  EnumSet<TestEnumSet> emptyFlag = EnumSet.noneOf(TestEnumSet.class);
+
+  @SuppressWarnings("unchecked")
+  public void testSerializeAndDeserializeEmpty() throws IOException {
+
+    boolean gotException = false;
+    try {
+      new EnumSetWritable<TestEnumSet>(emptyFlag);
+    } catch (RuntimeException e) {
+      gotException = true;
+    }
+
+    assertTrue(
+        "Instantiate empty EnumSetWritable with no element type class providesd should throw exception.",
+        gotException);
+
+    EnumSetWritable<TestEnumSet> emptyFlagWritable = new EnumSetWritable<TestEnumSet>(
+        emptyFlag, TestEnumSet.class);
+    DataOutputBuffer out = new DataOutputBuffer();
+    ObjectWritable.writeObject(out, emptyFlagWritable, emptyFlagWritable
+        .getClass(), null);
+    DataInputBuffer in = new DataInputBuffer();
+    in.reset(out.getData(), out.getLength());
+    EnumSet<TestEnumSet> read = ((EnumSetWritable<TestEnumSet>) ObjectWritable
+        .readObject(in, null)).get();
+    assertEquals(read, emptyFlag);
+  }
+
+  @SuppressWarnings("unchecked")
+  public void testSerializeAndDeserializeNull() throws IOException {
+
+    boolean gotException = false;
+    try {
+      new EnumSetWritable<TestEnumSet>(null);
+    } catch (RuntimeException e) {
+      gotException = true;
+    }
+
+    assertTrue(
+        "Instantiate empty EnumSetWritable with no element type class providesd should throw exception.",
+        gotException);
+
+    EnumSetWritable<TestEnumSet> nullFlagWritable = new EnumSetWritable<TestEnumSet>(
+        null, TestEnumSet.class);
+
+    DataOutputBuffer out = new DataOutputBuffer();
+    ObjectWritable.writeObject(out, nullFlagWritable, nullFlagWritable
+        .getClass(), null);
+    DataInputBuffer in = new DataInputBuffer();
+    in.reset(out.getData(), out.getLength());
+    EnumSet<TestEnumSet> read = ((EnumSetWritable<TestEnumSet>) ObjectWritable
+        .readObject(in, null)).get();
+    assertEquals(read, null);
+  }
+}