瀏覽代碼

HADOOP-1759. Change file name in INode from String to byte[], saving memory on the namenode. Contributed by Konstantin.

git-svn-id: https://svn.apache.org/repos/asf/lucene/hadoop/trunk@569015 13f79535-47bb-0310-9956-ffa450edef68
Doug Cutting 17 年之前
父節點
當前提交
3e38672dab
共有 2 個文件被更改,包括 94 次插入23 次删除
  1. 3 0
      CHANGES.txt
  2. 91 23
      src/java/org/apache/hadoop/dfs/INode.java

+ 3 - 0
CHANGES.txt

@@ -41,6 +41,9 @@ Trunk (unreleased changes)
     class, with specialized subclasses for directories and files, to
     class, with specialized subclasses for directories and files, to
     save memory on the namenode.  (Konstantin Shvachko via cutting)
     save memory on the namenode.  (Konstantin Shvachko via cutting)
 
 
+    HADOOP-1759.  Change file name in INode from String to byte[],
+    saving memory on the namenode. (Konstantin Shvachko via cutting)
+
   BUG FIXES
   BUG FIXES
 
 
     HADOOP-1463.  HDFS report correct usage statistics for disk space
     HADOOP-1463.  HDFS report correct usage statistics for disk space

+ 91 - 23
src/java/org/apache/hadoop/dfs/INode.java

@@ -18,8 +18,10 @@
 package org.apache.hadoop.dfs;
 package org.apache.hadoop.dfs;
 
 
 import java.io.FileNotFoundException;
 import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Collections;
+import java.util.Arrays;
 import java.util.List;
 import java.util.List;
 
 
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.Path;
@@ -29,17 +31,19 @@ import org.apache.hadoop.fs.Path;
  * This is a base INode class containing common fields for file and 
  * This is a base INode class containing common fields for file and 
  * directory inodes.
  * directory inodes.
  */
  */
-abstract class INode implements Comparable<String> {
-  protected String name;
+abstract class INode implements Comparable<byte[]> {
+  protected byte[] name;
   protected INodeDirectory parent;
   protected INodeDirectory parent;
   protected long modificationTime;
   protected long modificationTime;
 
 
   protected INode(String name) {
   protected INode(String name) {
     this(0L);
     this(0L);
-    this.name = name;
+    setLocalName(name);
   }
   }
 
 
   INode(long mTime) {
   INode(long mTime) {
+    this.name = null;
+    this.parent = null;
     this.modificationTime = mTime;
     this.modificationTime = mTime;
   }
   }
 
 
@@ -55,14 +59,14 @@ abstract class INode implements Comparable<String> {
    * @return local file name
    * @return local file name
    */
    */
   String getLocalName() {
   String getLocalName() {
-    return name;
+    return bytes2String(name);
   }
   }
 
 
   /**
   /**
    * Set local file name
    * Set local file name
    */
    */
   void setLocalName(String name) {
   void setLocalName(String name) {
-    this.name = name;
+    this.name = string2Bytes(name);
   }
   }
 
 
   /**
   /**
@@ -78,9 +82,9 @@ abstract class INode implements Comparable<String> {
       return Path.SEPARATOR;       // root directory is "/"
       return Path.SEPARATOR;       // root directory is "/"
     }
     }
     if (this.parent.parent == null) {
     if (this.parent.parent == null) {
-      return Path.SEPARATOR + name;
+      return Path.SEPARATOR + getLocalName();
     }
     }
-    return parent.getAbsoluteName() + Path.SEPARATOR + name;
+    return parent.getAbsoluteName() + Path.SEPARATOR + getLocalName();
   }
   }
 
 
   /**
   /**
@@ -109,13 +113,24 @@ abstract class INode implements Comparable<String> {
     }
     }
   }
   }
 
 
-  static String[] getPathComponents(String path) {
+  /**
+   * Breaks file path into components.
+   * @param path
+   * @return array of byte arrays each of which represents 
+   * a single path component.
+   */
+  static byte[][] getPathComponents(String path) {
     if (path == null || !path.startsWith(Path.SEPARATOR)) {
     if (path == null || !path.startsWith(Path.SEPARATOR)) {
       return null;
       return null;
     }
     }
     if (Path.SEPARATOR.equals(path))  // root
     if (Path.SEPARATOR.equals(path))  // root
-      return new String[]{""};
-    return path.split(Path.SEPARATOR, -1);
+      return new byte[][]{null};
+    String[] strings = path.split(Path.SEPARATOR, -1);
+    int size = strings.length;
+    byte[][] bytes = new byte[size][];
+    for (int i = 0; i < size; i++)
+      bytes[i] = string2Bytes(strings[i]);
+    return bytes;
   }
   }
 
 
   /**
   /**
@@ -133,19 +148,68 @@ abstract class INode implements Comparable<String> {
   //
   //
   // Comparable interface
   // Comparable interface
   //
   //
-  public int compareTo(String o) {
-    return getLocalName().compareTo(o);
+  public int compareTo(byte[] o) {
+    return compareBytes(name, o);
   }
   }
 
 
   public boolean equals(Object o) {
   public boolean equals(Object o) {
     if (!(o instanceof INode)) {
     if (!(o instanceof INode)) {
       return false;
       return false;
     }
     }
-    return getLocalName().equals(((INode)o).getLocalName());
+    return Arrays.equals(this.name, ((INode)o).name);
   }
   }
-    
+
   public int hashCode() {
   public int hashCode() {
-    return getLocalName().hashCode();
+    return Arrays.hashCode(this.name);
+  }
+
+  //
+  // static methods
+  //
+  /**
+   * Compare two byte arrays.
+   * 
+   * @return a negative integer, zero, or a positive integer 
+   * as defined by {@link #compareTo(byte[])}.
+   */
+  static int compareBytes(byte[] a1, byte[] a2) {
+    if (a1==a2)
+        return 0;
+    int len1 = (a1==null ? 0 : a1.length);
+    int len2 = (a2==null ? 0 : a2.length);
+    int n = Math.min(len1, len2);
+    byte b1, b2;
+    for (int i=0; i<n; i++) {
+      b1 = a1[i];
+      b2 = a2[i];
+      if (b1 != b2)
+        return b1 - b2;
+    }
+    return len1 - len2;
+  }
+
+  /**
+   * Converts a byte array to a string using UTF8 encoding.
+   */
+  static String bytes2String(byte[] bytes) {
+    try {
+      return new String(bytes, "UTF8");
+    } catch(UnsupportedEncodingException e) {
+      assert false : "UTF8 encoding is not supported ";
+    }
+    return null;
+  }
+
+  /**
+   * Converts a string to a byte array using UTF8 encoding.
+   */
+  static byte[] string2Bytes(String str) {
+    try {
+      return str.getBytes("UTF8");
+    } catch(UnsupportedEncodingException e) {
+      assert false : "UTF8 encoding is not supported ";
+    }
+    return null;
   }
   }
 }
 }
 
 
@@ -177,13 +241,17 @@ class INodeDirectory extends INode {
 
 
   void removeChild(INode node) {
   void removeChild(INode node) {
     assert children != null;
     assert children != null;
-    int low = Collections.binarySearch(children, node.getLocalName());
+    int low = Collections.binarySearch(children, node.name);
     if (low >= 0) {
     if (low >= 0) {
       children.remove(low);
       children.remove(low);
     }
     }
   }
   }
 
 
   INode getChild(String name) {
   INode getChild(String name) {
+    return getChildINode(string2Bytes(name));
+  }
+
+  private INode getChildINode(byte[] name) {
     if (children == null) {
     if (children == null) {
       return null;
       return null;
     }
     }
@@ -196,7 +264,7 @@ class INodeDirectory extends INode {
 
 
   /**
   /**
    */
    */
-  private INode getNode(String[] components) {
+  private INode getNode(byte[][] components) {
     return getINode(components, components.length-1);
     return getINode(components, components.length-1);
   }
   }
 
 
@@ -207,8 +275,8 @@ class INodeDirectory extends INode {
    * @param end the end component of the path
    * @param end the end component of the path
    * @return found INode or null otherwise 
    * @return found INode or null otherwise 
    */
    */
-  private INode getINode(String[] components, int end) {
-    assert getLocalName().equals(components[0]) :
+  private INode getINode(byte[][] components, int end) {
+    assert compareBytes(this.name, components[0]) == 0 :
       "Incorrect name " + getLocalName() + " expected " + components[0];
       "Incorrect name " + getLocalName() + " expected " + components[0];
     if (end >= components.length)
     if (end >= components.length)
       end = components.length-1;
       end = components.length-1;
@@ -219,7 +287,7 @@ class INodeDirectory extends INode {
       if(!curNode.isDirectory())  // file is not expected here
       if(!curNode.isDirectory())  // file is not expected here
         return null;        // because there is more components in the path
         return null;        // because there is more components in the path
       INodeDirectory parentDir = (INodeDirectory)curNode;
       INodeDirectory parentDir = (INodeDirectory)curNode;
-      curNode = parentDir.getChild(components[start+1]);
+      curNode = parentDir.getChildINode(components[start+1]);
       if(curNode == null)  // not found
       if(curNode == null)  // not found
         return null;
         return null;
     }
     }
@@ -244,7 +312,7 @@ class INodeDirectory extends INode {
     if (children == null) {
     if (children == null) {
       children = new ArrayList<INode>(DEFAULT_FILES_PER_DIRECTORY);
       children = new ArrayList<INode>(DEFAULT_FILES_PER_DIRECTORY);
     }
     }
-    int low = Collections.binarySearch(children, node.getLocalName());
+    int low = Collections.binarySearch(children, node.name);
     if(low >= 0)
     if(low >= 0)
       return null;
       return null;
     node.parent = this;
     node.parent = this;
@@ -264,7 +332,7 @@ class INodeDirectory extends INode {
    * @throws FileNotFoundException 
    * @throws FileNotFoundException 
    */
    */
   <T extends INode> T addNode(String path, T newNode) throws FileNotFoundException {
   <T extends INode> T addNode(String path, T newNode) throws FileNotFoundException {
-    String[] pathComponents = getPathComponents(path);
+    byte[][] pathComponents = getPathComponents(path);
     assert pathComponents != null : "Incorrect path " + path;
     assert pathComponents != null : "Incorrect path " + path;
     int pathLen = pathComponents.length;
     int pathLen = pathComponents.length;
     if (pathLen < 2)  // add root
     if (pathLen < 2)  // add root
@@ -278,7 +346,7 @@ class INodeDirectory extends INode {
     }
     }
     INodeDirectory parentNode = (INodeDirectory)node;
     INodeDirectory parentNode = (INodeDirectory)node;
     // insert into the parent children list
     // insert into the parent children list
-    newNode.setLocalName(pathComponents[pathLen-1]);
+    newNode.name = pathComponents[pathLen-1];
     return parentNode.addChild(newNode);
     return parentNode.addChild(newNode);
   }
   }