[amplab-tachyon] Update to latest but not yet functional due to glusterfs + hadoop update
tstclair
tstclair at fedoraproject.org
Tue May 6 20:42:03 UTC 2014
commit 8fdb4b990c5be8c469a1f384f24db29492918e39
Author: Timothy St. Clair <tstclair at redhat.com>
Date: Tue May 6 15:42:12 2014 -0500
Update to latest but not yet functional due to glusterfs + hadoop update
amplab-tachyon.spec | 27 +-
sources | 2 +-
tachyon-0.4.0-defaults.patch | 20 -
tachyon-0.4.1-permissions.patch | 39 -
tachyon-0.5.0-gluster.patch | 2513 +++++++++++++++++++++++++++++++++++++++
5 files changed, 2530 insertions(+), 71 deletions(-)
---
diff --git a/amplab-tachyon.spec b/amplab-tachyon.spec
index 72c6ba3..b23c096 100644
--- a/amplab-tachyon.spec
+++ b/amplab-tachyon.spec
@@ -1,12 +1,12 @@
-%global commit 4b9c806bbce73db39e010a8bafd031c9b9749882
+%global commit 71028e3478eac70b20d76ad75ae4fe771b2515da
%global shortcommit %(c=%{commit}; echo ${c:0:7})
%global shortname tachyon
Name: amplab-%{shortname}
# Given the naming conflicts with other packages, and eventually this will
# switch to apache-tachyon should
-Version: 0.4.1
-Release: 2.SNAPSHOT.%{shortcommit}%{?dist}
+Version: 0.5.0
+Release: 1.SNAPSHOT.%{shortcommit}%{?dist}
Summary: Reliable file sharing at memory speed across cluster frameworks
License: ASL 2.0
URL: http://tachyon-project.org/
@@ -19,9 +19,7 @@ Source5: %{shortname}-env.sh
Patch0: tachyon-0.4.0-SNAPSHOT-log4props.patch
Patch1: tachyon-0.4.0-defaults.patch
-
-# Will likely go away https://github.com/amplab/tachyon/pull/128
-Patch2: tachyon-0.4.1-permissions.patch
+Patch2: tachyon-0.5.0-gluster.patch
BuildRequires: java-devel
BuildRequires: mvn(commons-io:commons-io)
@@ -41,6 +39,10 @@ BuildRequires: mvn(org.eclipse.jetty:jetty-servlet)
BuildRequires: mvn(org.glassfish.web:javax.servlet.jsp)
BuildRequires: mvn(org.slf4j:slf4j-api)
BuildRequires: mvn(org.slf4j:slf4j-log4j12)
+BuildRequires: mvn(org.slf4j:slf4j-api)
+BuildRequires: mvn(org.powermock:powermock-module-junit4)
+BuildRequires: mvn(org.powermock:powermock-api-mockito)
+BuildRequires: mvn(org.apache.hadoop.fs.glusterfs:glusterfs)
# Test deps
BuildRequires: mvn(junit:junit)
@@ -81,8 +83,8 @@ This package contains javadoc for %{name}.
find -name '*.class' -print -delete
find -name '*.jar' -print -delete
-%patch0 -p1
-%patch1 -p1
+%patch0 -F2 -p1
+%patch1 -F2 -p1
%patch2 -p1
sed -i "s|<artifactId>hadoop-client|<artifactId>hadoop-mapreduce-client-core|" pom.xml
@@ -90,10 +92,10 @@ sed -i "s|<artifactId>hadoop-client|<artifactId>hadoop-mapreduce-client-core|" p
%pom_xpath_remove "pom:repositories"
# Remove unnecessary plugin
-%pom_remove_plugin :maven-assembly-plugin
+# %pom_remove_plugin :maven-assembly-plugin
# Fix unavailable jetty-jsp-2.1
-%pom_remove_dep org.eclipse.jetty:jetty-jsp
+#%pom_remove_dep org.eclipse.jetty:jetty-jsp
%pom_add_dep org.glassfish.web:javax.servlet.jsp::compile
#make additions for hadoop2
@@ -139,7 +141,7 @@ mkdir -p -m0755 %{buildroot}%{_var}/lib/%{shortname}/journal
#######################
mkdir -p -m0755 %{buildroot}/%{_datadir}/%{shortname}/web
-cp -rf src/main/java/tachyon/web/resources %{buildroot}/%{_datadir}/%{shortname}/web
+cp -rf main/src/main/webapp %{buildroot}/%{_datadir}/%{shortname}/web
#######################
# NOTE: The following is plugging into hadoop without
@@ -188,6 +190,9 @@ mkdir -p -m0755 %{buildroot}/%{_datadir}/hadoop/common/lib
%systemd_postun_with_restart %{shortname}-slave.service %{shortname}-master.service
%changelog
+* Mon May 5 2014 Timothy St. Clair <tstclair at redhat.com> - 0.5.0-1.SNAPSHOT.71028e3
+- Update to 0.5.0
+
* Mon Feb 24 2014 Timothy St. Clair <tstclair at redhat.com> - 0.4.1-2.SNAPSHOT.4b9c806
- Update due to cascading dependencies around java-headless
diff --git a/sources b/sources
index 0914e16..3a3febd 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-0e1c55d5a5bd5a768bcb1066e5f74120 tachyon-0.4.1-4b9c806.tar.gz
+e5c4849a38908e408a30073b2f67bbaf tachyon-0.5.0-71028e3.tar.gz
diff --git a/tachyon-0.4.0-defaults.patch b/tachyon-0.4.0-defaults.patch
index 1ed43d6..7a21177 100644
--- a/tachyon-0.4.0-defaults.patch
+++ b/tachyon-0.4.0-defaults.patch
@@ -54,23 +54,3 @@ index 9122bcd..66cb2a2 100755
done
exit 0
-diff --git a/src/main/java/tachyon/conf/CommonConf.java b/src/main/java/tachyon/conf/CommonConf.java
-index aad1b53..7359cbb 100644
---- a/src/main/java/tachyon/conf/CommonConf.java
-+++ b/src/main/java/tachyon/conf/CommonConf.java
-@@ -43,14 +43,7 @@ public class CommonConf extends Utils {
- public final boolean ASYNC_ENABLED;
-
- private CommonConf() {
-- if (System.getProperty("tachyon.home") == null) {
-- LOG.warn("tachyon.home is not set. Using /mnt/tachyon_default_home as the default value.");
-- File file = new File("/mnt/tachyon_default_home");
-- if (!file.exists()) {
-- file.mkdirs();
-- }
-- }
-- TACHYON_HOME = getProperty("tachyon.home", "/mnt/tachyon_default_home");
-+ TACHYON_HOME = getProperty("tachyon.home", "/var/lib/tachyon");
- WEB_RESOURCES = getProperty("tachyon.web.resources", TACHYON_HOME + "/src/main/java/tachyon/web/resources");
- UNDERFS_ADDRESS = getProperty("tachyon.underfs.address", TACHYON_HOME + "/underfs");
- UNDERFS_DATA_FOLDER = getProperty("tachyon.data.folder", UNDERFS_ADDRESS + "/tachyon/data");
diff --git a/tachyon-0.5.0-gluster.patch b/tachyon-0.5.0-gluster.patch
new file mode 100644
index 0000000..ac15684
--- /dev/null
+++ b/tachyon-0.5.0-gluster.patch
@@ -0,0 +1,2513 @@
+diff --git a/bin/tachyon b/bin/tachyon
+index d062f2b..9aea6c8 100755
+--- a/bin/tachyon
++++ b/bin/tachyon
+@@ -131,7 +131,7 @@ PARAMETER=""
+ if [ "$COMMAND" == "format" ]; then
+ if [ $# -eq 1 ]; then
+ if [ "$1" == "-s" ]; then
+- if [ -e $TACHYON_UNDERFS_ADDRESS ] || [[ $TACHYON_UNDERFS_ADDRESS == hdfs://* ]] || [[ $TACHYON_UNDERFS_ADDRESS == s3://* ]]; then
++ if [ -e $TACHYON_UNDERFS_ADDRESS ] || [[ $TACHYON_UNDERFS_ADDRESS == hdfs://* ]] || [[ $TACHYON_UNDERFS_ADDRESS == s3://* ]] || [[ $TACHYON_UNDERFS_ADDRESS == glusterfs://* ]]; then
+ # already exists, hdfs, or s3, don't format
+ exit 0
+ else
+diff --git a/conf/tachyon-glusterfs-env.sh.template b/conf/tachyon-glusterfs-env.sh.template
+new file mode 100755
+index 0000000..325246e
+--- /dev/null
++++ b/conf/tachyon-glusterfs-env.sh.template
+@@ -0,0 +1,57 @@
++#!/usr/bin/env bash
++
++# This file contains environment variables required to run Tachyon. Copy it as tachyon-env.sh and
++# edit that to configure Tachyon for your site. At a minimum,
++# the following variables should be set:
++#
++# - JAVA_HOME, to point to your JAVA installation
++# - TACHYON_MASTER_ADDRESS, to bind the master to a different IP address or hostname
++# - TACHYON_UNDERFS_ADDRESS, to set the under filesystem address.
++# - TACHYON_WORKER_MEMORY_SIZE, to set how much memory to use (e.g. 1000mb, 2gb) per worker
++# - TACHYON_RAM_FOLDER, to set where worker stores in memory data
++# - TACHYON_UNDERFS_HDFS_IMPL, to set which HDFS implementation to use (e.g. com.mapr.fs.MapRFileSystem,
++# org.apache.hadoop.hdfs.DistributedFileSystem)
++
++# The following gives an example:
++
++if [[ `uname -a` == Darwin* ]]; then
++ # Assuming Mac OS X
++ export JAVA_HOME=$(/usr/libexec/java_home)
++ export TACHYON_RAM_FOLDER=/Volumes/ramdisk
++ export TACHYON_JAVA_OPTS="-Djava.security.krb5.realm= -Djava.security.krb5.kdc="
++else
++ # Assuming Linux
++ if [ -z "$JAVA_HOME" ]; then
++ export JAVA_HOME=/usr/lib/jvm/java-1.6.0-sun-1.6.0.45.x86_64/
++ fi
++ export TACHYON_RAM_FOLDER=/mnt/ramdisk
++fi
++
++export TACHYON_MASTER_ADDRESS=localhost
++
++export TACHYON_UNDERFS_ADDRESS=glusterfs:///
++export TACHYON_UNDERFS_GLUSTER_VOLUMES=tachyon_vol
++export TACHYON_UNDERFS_GLUSTER_MOUNTS=/vol
++export TACHYON_UNDERFS_GLUSTER_MR_DIR=glusterfs:///mapred/system
++export TACHYON_WORKER_MEMORY_SIZE=1GB
++
++CONF_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
++
++export TACHYON_JAVA_OPTS+="
++ -Dlog4j.configuration=file:$CONF_DIR/log4j.properties
++ -Dtachyon.debug=true
++ -Dtachyon.underfs.address=$TACHYON_UNDERFS_ADDRESS
++ -Dtachyon.data.folder=$TACHYON_UNDERFS_ADDRESS/tmp/tachyon/data
++ -Dtachyon.workers.folder=$TACHYON_UNDERFS_ADDRESS/tmp/tachyon/workers
++ -Dtachyon.worker.memory.size=$TACHYON_WORKER_MEMORY_SIZE
++ -Dtachyon.worker.data.folder=$TACHYON_RAM_FOLDER/tachyonworker/
++ -Dtachyon.master.worker.timeout.ms=60000
++ -Dtachyon.master.hostname=$TACHYON_MASTER_ADDRESS
++ -Dtachyon.master.journal.folder=$TACHYON_HOME/journal/
++ -Dtachyon.master.pinlist=/pinfiles;/pindata
++ -Dtachyon.underfs.glusterfs.volumes=$TACHYON_UNDERFS_GLUSTER_VOLUMES
++ -Dtachyon.underfs.glusterfs.mounts=$TACHYON_UNDERFS_GLUSTER_MOUNTS
++ -Dtachyon.underfs.glusterfs.mapred.system.dir=$TACHYON_UNDERFS_GLUSTER_MR_DIR
++ -Dorg.apache.jasper.compiler.disablejsr199=true
++"
++export JAVA="$JAVA_HOME/bin/java $TACHYON_JAVA_OPTS"
+\ No newline at end of file
+diff --git a/docs/Startup-Tasks-for-New-Contributors.md b/docs/Startup-Tasks-for-New-Contributors.md
+index fb72ba5..2e65c10 100644
+--- a/docs/Startup-Tasks-for-New-Contributors.md
++++ b/docs/Startup-Tasks-for-New-Contributors.md
+@@ -46,13 +46,6 @@ You can generate Eclipse configure file by run:
+
+ Then import the folder into Eclipse.
+
+-### Testing
+-
+-If you want to run unit tests, you can use command: mvn test.
+-
+-If you want to run a single tests, you can use command: mvn -Dtest=TestCircle#mytest test ;
+-e.g. mvn -Dtest=TachyonFSTest#createFileTest test ;
+-
+ ### Coding Style
+
+ - Follow the style of the existing codebase. Specifically, we use
+@@ -71,10 +64,8 @@ e.g. mvn -Dtest=TachyonFSTest#createFileTest test ;
+ - Break your work into small, single-purpose patches if possible. It’s much harder to merge in
+ a large change with a lot of disjoint features.
+
+-- Make sure that any methods you add maintain the alphabetical ordering of method names in each file.
+-
+ - Submit the patch as a GitHub pull request. For a tutorial, see the GitHub guides on
+ [forking a repo](https://help.github.com/articles/fork-a-repo) and
+ [sending a pull request](https://help.github.com/articles/using-pull-requests).
+
+-- Make sure that your code passes the unit tests: mvn test.
++- Make sure that your code passes the unit tests.
+diff --git a/docs/Syncing-the-Underlying-Filesystem.md b/docs/Syncing-the-Underlying-Filesystem.md
+index 9fc449a..7ab9c8c 100644
+--- a/docs/Syncing-the-Underlying-Filesystem.md
++++ b/docs/Syncing-the-Underlying-Filesystem.md
+@@ -3,33 +3,15 @@ layout: global
+ title: Syncing the Underlayer Filesystem
+ ---
+
+-Often times, there is already data in the underlying store, but when Tachyon is started, it will
+-not have knowledge about the preexisting files.
++Often times, there is already data in the underlying store, but when Tachyon is started, it will not
++have knowledge about the preexisting files.
+
+ Use the tachyon shell command loadufs to sync the filesystems.
+
+- $ ./bin/tachyon loadufs [TACHYON_PATH] [UNDERLYING_FILESYSTEM_PATH] [Optional EXCLUDE_PATHS]
++ $ ./bin/tachyon loadufs [TACHYON_ADDRESS] [UNDERLYING_FILESYSTEM_ADDRESS] [ROOT_DIRECTORY] [-Optional EXCLUDE_PATHS]
+
+ For example:
+
+- $ ./bin/tachyon loadufs tachyon://127.0.0.1:19998 hdfs://localhost:9000 tachyon
++ $ ./bin/tachyon loadufs tachyon://127.0.0.1:19998 hdfs://localhost:9000 / /tachyon
+
+-Would load the meta-data for all the files in the local hdfs, except for the tachyon folder.
+-
+- $ ./bin/tachyon loadufs tachyon://127.0.0.1:19998/tomlogs file:///Users/tom/logs tachyon;spark
+-
+-Would load meta-data for all local files under the /Users/tom/logs directory (except for tachyon
+-and spark) to address tachyon://127.0.0.1:19998/tomlogs. If /Users/tom/logs itself is a file, only
+-that file is loaded as /tomlogs/logs in the TFS. The prefix "file://" can be safely omitted for
+-a local file system.
+-
+-Note that the optional EXCLUDE_PATHS are prefixes relative to the given local file path. Moreover,
+-only files matching the given prefixes relative to the path will be excluded. Hence, in the above
+-last example, logs/tachyon and logs/spark will be excluded, but not logs/shark/tachyon nor
+-logs/shark/spark. To exclude these two paths as well, the exclude list should be specified as
+-"tachyon;spark;shark/tachyon;shark/spark". It is important to note that when ";" is present to
+-concatenate multiple prefixes the quote marks must be used; otherwise it would be treated as
+-multiple commands to be executed in tandem.
+-
+-In a sense, loadufs is similar to the unix mount command. It's not called mount so as not to cause
+-confusions with the use of mount in the tachyon scripts.
++Would load the meta-data for all the files in the local hdfs, except for the Tachyon folder.
+diff --git a/main/pom.xml b/main/pom.xml
+index d5e0ea5..2db4297 100644
+--- a/main/pom.xml
++++ b/main/pom.xml
+@@ -49,6 +49,13 @@
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
++ <dependency>
++ <groupId>org.apache.hadoop.fs.glusterfs</groupId>
++ <artifactId>glusterfs-hadoop</artifactId>
++ <version>2.1.8</version>
++ <type>jar</type>
++ <scope>compile</scope>
++ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+diff --git a/main/src/main/java/tachyon/Constants.java b/main/src/main/java/tachyon/Constants.java
+index da558a8..e286d36 100644
+--- a/main/src/main/java/tachyon/Constants.java
++++ b/main/src/main/java/tachyon/Constants.java
+@@ -22,7 +22,6 @@ public class Constants {
+ public static final int MB = KB * 1024;
+ public static final int GB = MB * 1024;
+ public static final long TB = GB * 1024L;
+- public static final long PB = TB * 1024L;
+
+ public static final String ANSI_RESET = "\u001B[0m";
+ public static final String ANSI_BLACK = "\u001B[30m";
+diff --git a/main/src/main/java/tachyon/Format.java b/main/src/main/java/tachyon/Format.java
+index 51ba23b..7af0819 100644
+--- a/main/src/main/java/tachyon/Format.java
++++ b/main/src/main/java/tachyon/Format.java
+@@ -71,7 +71,7 @@ public class Format {
+ if (ufs.exists(localFolder)) {
+ String[] files = ufs.list(localFolder);
+ for (String file : files) {
+- ufs.delete(CommonUtils.concat(localFolder, file), true);
++ ufs.delete(localFolder + Constants.PATH_SEPARATOR + file, true);
+ }
+ }
+ } else {
+@@ -79,4 +79,4 @@ public class Format {
+ System.exit(-1);
+ }
+ }
+-}
++}
+\ No newline at end of file
+diff --git a/main/src/main/java/tachyon/LeaderInquireClient.java b/main/src/main/java/tachyon/LeaderInquireClient.java
+index defcd03..826fdc2 100644
+--- a/main/src/main/java/tachyon/LeaderInquireClient.java
++++ b/main/src/main/java/tachyon/LeaderInquireClient.java
+@@ -72,7 +72,8 @@ public class LeaderInquireClient {
+ long maxTime = 0;
+ String leader = "";
+ for (String master : masters) {
+- Stat stat = CLIENT.checkExists().forPath(CommonUtils.concat(LEADER_PATH, master));
++ Stat stat =
++ CLIENT.checkExists().forPath(LEADER_PATH + Constants.PATH_SEPARATOR + master);
+ if (stat != null && stat.getCtime() > maxTime) {
+ maxTime = stat.getCtime();
+ leader = master;
+diff --git a/main/src/main/java/tachyon/PrefixList.java b/main/src/main/java/tachyon/PrefixList.java
+index 5acdd15..9528319 100644
+--- a/main/src/main/java/tachyon/PrefixList.java
++++ b/main/src/main/java/tachyon/PrefixList.java
+@@ -67,18 +67,4 @@ public class PrefixList {
+ public boolean outList(String path) {
+ return !inList(path);
+ }
+-
+- /**
+- * Print out all prefixes separated by ";".
+- *
+- * @return the string representation like "a;b/c"
+- */
+- @Override
+- public String toString() {
+- StringBuilder s = new StringBuilder();
+- for (String prefix : LIST) {
+- s.append(prefix).append(";");
+- }
+- return s.toString();
+- }
+ }
+\ No newline at end of file
+diff --git a/main/src/main/java/tachyon/UnderFileSystem.java b/main/src/main/java/tachyon/UnderFileSystem.java
+index 6e27464..b8e8d40 100644
+--- a/main/src/main/java/tachyon/UnderFileSystem.java
++++ b/main/src/main/java/tachyon/UnderFileSystem.java
+@@ -44,49 +44,16 @@ public abstract class UnderFileSystem {
+ }
+
+ public static UnderFileSystem get(String path) {
+- if (path.startsWith("hdfs://") || path.startsWith("s3://") || path.startsWith("s3n://")) {
++ if (path.startsWith("hdfs://") || path.startsWith("file://") || path.startsWith("s3://")
++ || path.startsWith("s3n://") || path.startsWith("glusterfs:///")) {
+ return UnderFileSystemHdfs.getClient(path);
+- } else if (path.startsWith(Constants.PATH_SEPARATOR) || path.startsWith("file://")) {
++ } else if (path.startsWith(Constants.PATH_SEPARATOR)) {
+ return UnderFileSystemSingleLocal.getClient();
+ }
+ CommonUtils.illegalArgumentException("Unknown under file system scheme " + path);
+ return null;
+ }
+
+- /**
+- * Transform an input string like hdfs://host:port/dir, hdfs://host:port, file:///dir, /dir
+- * into a pair of address and path. The returned pairs are ("hdfs://host:port", "/dir"),
+- * ("hdfs://host:port", "/"), and ("/", "/dir"), respectively.
+- *
+- * @param path
+- * the input path string
+- * @return null if s does not start with tachyon://, tachyon-ft://, hdfs://, s3://, s3n://,
+- * file://, /. Or a pair of strings denoting the under FS address and the relative path
+- * relative to that address. For local FS (with prefixes file:// or /), the under FS
+- * address is "/" and the path starts with "/".
+- */
+- public static Pair<String, String> parse(String path) {
+- if (path == null) {
+- return null;
+- } else if (path.startsWith("tachyon://") || path.startsWith("tachyon-ft://")
+- || path.startsWith("hdfs://") || path.startsWith("s3://") || path.startsWith("s3n://")) {
+- String prefix = path.substring(0, path.indexOf("://") + 3);
+- String body = path.substring(prefix.length());
+- if (body.contains(Constants.PATH_SEPARATOR)) {
+- int ind = body.indexOf(Constants.PATH_SEPARATOR);
+- return new Pair<String, String>(prefix + body.substring(0, ind), body.substring(ind));
+- } else {
+- return new Pair<String, String>(path, Constants.PATH_SEPARATOR);
+- }
+- } else if (path.startsWith("file://") || path.startsWith(Constants.PATH_SEPARATOR)) {
+- String prefix = "file://";
+- String suffix = path.startsWith(prefix) ? path.substring(prefix.length()) : path;
+- return new Pair<String, String>(Constants.PATH_SEPARATOR, suffix);
+- }
+-
+- return null;
+- }
+-
+ public abstract void close() throws IOException;
+
+ public abstract OutputStream create(String path) throws IOException;
+@@ -115,25 +82,11 @@ public abstract class UnderFileSystem {
+ public abstract boolean isFile(String path) throws IOException;
+
+ /**
+- * Returns an array of strings naming the files and directories in the directory denoted by this
+- * abstract pathname.
+- *
+- * <p>
+- * If this abstract pathname does not denote a directory, then this method returns {@code null}.
+- * Otherwise an array of strings is returned, one for each file or directory in the directory.
+- * Names denoting the directory itself and the directory's parent directory are not included in
+- * the result. Each string is a file name rather than a complete path.
+- *
+- * <p>
+- * There is no guarantee that the name strings in the resulting array will appear in any specific
+- * order; they are not, in particular, guaranteed to appear in alphabetical order.
++ * List all the files in the folder.
+ *
+ * @param path
+ * the path to list.
+- * @return An array of strings naming the files and directories in the directory denoted by this
+- * abstract pathname. The array will be empty if the directory is empty. Returns
+- * {@code null} if this abstract pathname does not denote a directory, or if an I/O error
+- * occurs.
++ * @return all the file names under the path.
+ * @throws IOException
+ */
+ public abstract String[] list(String path) throws IOException;
+diff --git a/main/src/main/java/tachyon/UnderFileSystemHdfs.java b/main/src/main/java/tachyon/UnderFileSystemHdfs.java
+index 7766b2e..235fa2f 100644
+--- a/main/src/main/java/tachyon/UnderFileSystemHdfs.java
++++ b/main/src/main/java/tachyon/UnderFileSystemHdfs.java
+@@ -31,6 +31,8 @@ import org.apache.hadoop.fs.permission.FsPermission;
+ import org.apache.hadoop.hdfs.DistributedFileSystem;
+ import org.apache.log4j.Logger;
+
++import org.apache.hadoop.fs.glusterfs.*;
++
+ import tachyon.conf.CommonConf;
+ import tachyon.util.CommonUtils;
+
+@@ -56,19 +58,28 @@ public class UnderFileSystemHdfs extends UnderFileSystem {
+ mUfsPrefix = fsDefaultName;
+ Configuration tConf = new Configuration();
+ tConf.set("fs.defaultFS", fsDefaultName);
+- tConf.set("fs.hdfs.impl", CommonConf.get().UNDERFS_HDFS_IMPL);
++ String glusterfsPrefix = "glusterfs:///";
++ if (fsDefaultName.startsWith(glusterfsPrefix)) {
++ tConf.set("fs.glusterfs.impl", CommonConf.get().UNDERFS_GLUSTERFS_IMPL);
++ tConf.set("mapred.system.dir", CommonConf.get().UNDERFS_GLUSTERFS_MR_DIR);
++ tConf.set("fs.glusterfs.volumes", CommonConf.get().UNDERFS_GLUSTERFS_VOLUMES);
++ tConf.set("fs.glusterfs.volume.fuse." + CommonConf.get().UNDERFS_GLUSTERFS_VOLUMES,
++ CommonConf.get().UNDERFS_GLUSTERFS_MOUNTS);
++ }else{
++ tConf.set("fs.hdfs.impl", CommonConf.get().UNDERFS_HDFS_IMPL);
+
+- // To disable the instance cache for hdfs client, otherwise it causes the
+- // FileSystem closed exception. Being configurable for unit/integration
+- // test only, and not expose to the end-user currently.
+- tConf.set("fs.hdfs.impl.disable.cache",
+- System.getProperty("fs.hdfs.impl.disable.cache", "false"));
++ // To disable the instance cache for hdfs client, otherwise it causes the
++ // FileSystem closed exception. Being configurable for unit/integration
++ // test only, and not expose to the end-user currently.
++ tConf.set("fs.hdfs.impl.disable.cache",
++ System.getProperty("fs.hdfs.impl.disable.cache", "false"));
++ }
+
+ if (System.getProperty("fs.s3n.awsAccessKeyId") != null) {
+- tConf.set("fs.s3n.awsAccessKeyId", System.getProperty("fs.s3n.awsAccessKeyId"));
++ tConf.set("fs.s3n.awsAccessKeyId", System.getProperty("fs.s3n.awsAccessKeyId"));
+ }
+ if (System.getProperty("fs.s3n.awsSecretAccessKey") != null) {
+- tConf.set("fs.s3n.awsSecretAccessKey", System.getProperty("fs.s3n.awsSecretAccessKey"));
++ tConf.set("fs.s3n.awsSecretAccessKey", System.getProperty("fs.s3n.awsSecretAccessKey"));
+ }
+ Path path = new Path(fsDefaultName);
+ mFs = path.getFileSystem(tConf);
+@@ -256,8 +267,7 @@ public class UnderFileSystemHdfs extends UnderFileSystem {
+ String[] rtn = new String[files.length];
+ int i = 0;
+ for (FileStatus status : files) {
+- // only return the relative path, to keep consistent with java.io.File.list()
+- rtn[i ++] = status.getPath().toString().substring(path.length()); // mUfsPrefix
++ rtn[i ++] = status.getPath().toString().substring(mUfsPrefix.length());
+ }
+ return rtn;
+ } else {
+diff --git a/main/src/main/java/tachyon/UnderFileSystemSingleLocal.java b/main/src/main/java/tachyon/UnderFileSystemSingleLocal.java
+index 250a939..76e6b67 100644
+--- a/main/src/main/java/tachyon/UnderFileSystemSingleLocal.java
++++ b/main/src/main/java/tachyon/UnderFileSystemSingleLocal.java
+@@ -70,7 +70,7 @@ public class UnderFileSystemSingleLocal extends UnderFileSystem {
+ if (recursive && file.isDirectory()) {
+ String[] files = file.list();
+ for (String child : files) {
+- success = success && delete(CommonUtils.concat(path, child), true);
++ success = success && delete(path + Constants.PATH_SEPARATOR + child, true);
+ }
+ }
+
+diff --git a/main/src/main/java/tachyon/Users.java b/main/src/main/java/tachyon/Users.java
+index 5ab1426..0eab6b4 100644
+--- a/main/src/main/java/tachyon/Users.java
++++ b/main/src/main/java/tachyon/Users.java
+@@ -77,11 +77,11 @@ public class Users {
+ }
+
+ public String getUserTempFolder(long userId) {
+- return CommonUtils.concat(USER_FOLDER, userId);
++ return USER_FOLDER + Constants.PATH_SEPARATOR + userId;
+ }
+
+ public String getUserUnderfsTempFolder(long userId) {
+- return CommonUtils.concat(USER_UNDERFS_FOLDER, userId);
++ return USER_UNDERFS_FOLDER + Constants.PATH_SEPARATOR + userId;
+ }
+
+ /**
+diff --git a/main/src/main/java/tachyon/client/BlockOutStream.java b/main/src/main/java/tachyon/client/BlockOutStream.java
+index 355771e..c19ac2b 100644
+--- a/main/src/main/java/tachyon/client/BlockOutStream.java
++++ b/main/src/main/java/tachyon/client/BlockOutStream.java
+@@ -80,7 +80,7 @@ public class BlockOutStream extends OutStream {
+ throw new IOException(msg);
+ }
+
+- mLocalFilePath = CommonUtils.concat(localFolder.getPath(), BLOCK_ID);
++ mLocalFilePath = localFolder.getPath() + Constants.PATH_SEPARATOR + BLOCK_ID;
+ mLocalFile = new RandomAccessFile(mLocalFilePath, "rw");
+ mLocalFileChannel = mLocalFile.getChannel();
+ // change the permission of the temporary file in order that the worker can move it.
+diff --git a/main/src/main/java/tachyon/client/FileOutStream.java b/main/src/main/java/tachyon/client/FileOutStream.java
+index 7395d18..5f76584 100644
+--- a/main/src/main/java/tachyon/client/FileOutStream.java
++++ b/main/src/main/java/tachyon/client/FileOutStream.java
+@@ -24,7 +24,6 @@ import org.apache.log4j.Logger;
+
+ import tachyon.Constants;
+ import tachyon.UnderFileSystem;
+-import tachyon.util.CommonUtils;
+
+ /**
+ * <code>FileOutStream</code> implementation of TachyonFile. It can only be gotten by
+@@ -61,7 +60,7 @@ public class FileOutStream extends OutStream {
+ mCachedBytes = 0;
+
+ if (WRITE_TYPE.isThrough()) {
+- mUnderFsFile = CommonUtils.concat(TFS.createAndGetUserUnderfsTempFolder(), FILE.FID);
++ mUnderFsFile = TFS.createAndGetUserUnderfsTempFolder() + Constants.PATH_SEPARATOR + FILE.FID;
+ UnderFileSystem underfsClient = UnderFileSystem.get(mUnderFsFile);
+ if (BLOCK_CAPACITY > Integer.MAX_VALUE) {
+ throw new IOException("BLOCK_CAPCAITY (" + BLOCK_CAPACITY + ") can not bigger than "
+@@ -133,10 +132,9 @@ public class FileOutStream extends OutStream {
+
+ @Override
+ public void flush() throws IOException {
+- // TODO We only flush the checkpoint output stream. Flush for RAMFS block streams.
+- if (mCheckpointOutputStream != null) {
+- mCheckpointOutputStream.flush();
+- }
++ // We only flush the checkpoint output stream.
++ // TODO flushing for RAMFS block streams.
++ mCheckpointOutputStream.flush();
+ }
+
+ private void getNextBlock() throws IOException {
+diff --git a/main/src/main/java/tachyon/client/RemoteBlockInStream.java b/main/src/main/java/tachyon/client/RemoteBlockInStream.java
+index 3f8a5e5..11c85f9 100644
+--- a/main/src/main/java/tachyon/client/RemoteBlockInStream.java
++++ b/main/src/main/java/tachyon/client/RemoteBlockInStream.java
+@@ -30,7 +30,6 @@ import tachyon.conf.UserConf;
+ import tachyon.thrift.ClientBlockInfo;
+ import tachyon.thrift.NetAddress;
+ import tachyon.worker.DataServerMessage;
+-import tachyon.util.CommonUtils;
+
+ /**
+ * BlockInStream for remote block.
+@@ -200,7 +199,8 @@ public class RemoteBlockInStream extends BlockInStream {
+ }
+ if (host.equals(InetAddress.getLocalHost().getHostName())
+ || host.equals(InetAddress.getLocalHost().getHostAddress())) {
+- String localFileName = CommonUtils.concat(TFS.getRootFolder(), blockInfo.blockId);
++ String localFileName =
++ TFS.getRootFolder() + Constants.PATH_SEPARATOR + blockInfo.blockId;
+ LOG.warn("Master thinks the local machine has data " + localFileName + "! But not!");
+ }
+ LOG.info(host + ":" + (port + 1) + " current host is "
+diff --git a/main/src/main/java/tachyon/client/TachyonFS.java b/main/src/main/java/tachyon/client/TachyonFS.java
+index bc520b9..c89ed82 100644
+--- a/main/src/main/java/tachyon/client/TachyonFS.java
++++ b/main/src/main/java/tachyon/client/TachyonFS.java
+@@ -47,7 +47,6 @@ import tachyon.thrift.ClientFileInfo;
+ import tachyon.thrift.ClientRawTableInfo;
+ import tachyon.thrift.ClientWorkerInfo;
+ import tachyon.thrift.FileDoesNotExistException;
+-import tachyon.thrift.InvalidPathException;
+ import tachyon.thrift.NetAddress;
+ import tachyon.thrift.NoWorkerException;
+ import tachyon.thrift.TachyonException;
+@@ -131,16 +130,6 @@ public class TachyonFS {
+ mAvailableSpaceBytes = 0L;
+ }
+
+- /**
+- * Print out the string representation of this Tachyon server address.
+- *
+- * @return the string representation like tachyon://host:port or tachyon-ft://host:port
+- */
+- @Override
+- public String toString() {
+- return (mZookeeperMode ? Constants.HEADER_FT : Constants.HEADER) + mMasterAddress.toString();
+- }
+-
+ public synchronized void accessLocalBlock(long blockId) {
+ connect();
+ if (mWorkerClient != null && mIsWorkerLocal) {
+@@ -201,21 +190,6 @@ public class TachyonFS {
+ }
+ }
+
+- /**
+- * Cleans the given path, throwing an IOException rather than an InvalidPathException.
+- *
+- * @param path
+- * The path to clean
+- * @return the cleaned path
+- */
+- private synchronized String cleanPathIOException(String path) throws IOException {
+- try {
+- return CommonUtils.cleanPath(path);
+- } catch (InvalidPathException e) {
+- throw new IOException(e.getMessage());
+- }
+- }
+-
+ public synchronized void close() throws TException {
+ if (mMasterClient != null) {
+ mMasterClient.cleanConnect();
+@@ -384,7 +358,7 @@ public class TachyonFS {
+ if (!mConnected) {
+ return -1;
+ }
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ int fid = -1;
+ try {
+ fid = mMasterClient.user_createFile(path, blockSizeByte);
+@@ -400,7 +374,7 @@ public class TachyonFS {
+ if (!mConnected) {
+ return -1;
+ }
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ int fid = -1;
+ try {
+ fid = mMasterClient.user_createFileOnCheckpoint(path, checkpointPath);
+@@ -421,7 +395,8 @@ public class TachyonFS {
+ if (!mConnected) {
+ return -1;
+ }
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
++
+ if (columns < 1 || columns > CommonConf.get().MAX_COLUMNS) {
+ throw new IOException("Column count " + columns + " is smaller than 1 or " + "bigger than "
+ + CommonConf.get().MAX_COLUMNS);
+@@ -599,7 +574,7 @@ public class TachyonFS {
+ return null;
+ }
+ ClientFileInfo ret;
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ if (useCachedMetadata && mCachedClientFileInfos.containsKey(path)) {
+ return mCachedClientFileInfos.get(path);
+ }
+@@ -660,7 +635,7 @@ public class TachyonFS {
+
+ public synchronized TachyonFile getFile(String path, boolean useCachedMetadata)
+ throws IOException {
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ ClientFileInfo clientFileInfo = getClientFileInfo(path, useCachedMetadata);
+ if (clientFileInfo == null) {
+ return null;
+@@ -724,7 +699,7 @@ public class TachyonFS {
+ return -1;
+ }
+ int fid = -1;
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ try {
+ fid = mMasterClient.user_getFileId(path);
+ } catch (TException e) {
+@@ -796,7 +771,7 @@ public class TachyonFS {
+ String getLocalFilename(long blockId) {
+ String rootFolder = getRootFolder();
+ if (rootFolder != null) {
+- String localFileName = CommonUtils.concat(rootFolder, blockId);
++ String localFileName = rootFolder + Constants.PATH_SEPARATOR + blockId;
+ File file = new File(localFileName);
+ if (file.exists()) {
+ return localFileName;
+@@ -855,7 +830,7 @@ public class TachyonFS {
+
+ public synchronized RawTable getRawTable(String path) throws IOException {
+ connect();
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ ClientRawTableInfo clientRawTableInfo;
+ try {
+ clientRawTableInfo = mMasterClient.user_getClientRawTableInfoByPath(path);
+@@ -1007,7 +982,7 @@ public class TachyonFS {
+ if (!mConnected) {
+ return false;
+ }
+- path = cleanPathIOException(path);
++ path = CommonUtils.cleanPath(path);
+ try {
+ return mMasterClient.user_mkdir(path);
+ } catch (TException e) {
+diff --git a/main/src/main/java/tachyon/client/TachyonFile.java b/main/src/main/java/tachyon/client/TachyonFile.java
+index eb09173..aab2f1f 100644
+--- a/main/src/main/java/tachyon/client/TachyonFile.java
++++ b/main/src/main/java/tachyon/client/TachyonFile.java
+@@ -31,7 +31,6 @@ import tachyon.conf.UserConf;
+ import tachyon.thrift.ClientBlockInfo;
+ import tachyon.thrift.NetAddress;
+ import tachyon.worker.DataServerMessage;
+-import tachyon.util.CommonUtils;
+
+ /**
+ * Tachyon File.
+@@ -108,8 +107,8 @@ public class TachyonFile implements Comparable<TachyonFile> {
+ * is no guarantee that the file still exists after this call returns, as Tachyon may evict blocks
+ * from memory at any time.
+ *
+- * @param blockIndex
+- * The index of the block in the file.
++ * @param blockId
++ * The id of the block.
+ * @return filename on local file system or null if file not present on local file system.
+ * @throws IOException
+ */
+@@ -121,9 +120,8 @@ public class TachyonFile implements Comparable<TachyonFile> {
+
+ public List<String> getLocationHosts() throws IOException {
+ List<NetAddress> locations = TFS.getClientBlockInfo(FID, 0).getLocations();
+- List<String> ret = null;
++ List<String> ret = new ArrayList<String>(locations.size());
+ if (locations != null) {
+- ret = new ArrayList<String>(locations.size());
+ for (int k = 0; k < locations.size(); k ++) {
+ ret.add(locations.get(k).mHost);
+ }
+@@ -235,7 +233,7 @@ public class TachyonFile implements Comparable<TachyonFile> {
+ }
+ if (host.equals(InetAddress.getLocalHost().getHostName())
+ || host.equals(InetAddress.getLocalHost().getHostAddress())) {
+- String localFileName = CommonUtils.concat(TFS.getRootFolder(), FID);
++ String localFileName = TFS.getRootFolder() + Constants.PATH_SEPARATOR + FID;
+ LOG.warn("Master thinks the local machine has data " + localFileName + "! But not!");
+ } else {
+ LOG.info(host + ":" + (port + 1) + " current host is "
+diff --git a/main/src/main/java/tachyon/client/table/RawColumn.java b/main/src/main/java/tachyon/client/table/RawColumn.java
+index f336888..9ad11ce 100644
+--- a/main/src/main/java/tachyon/client/table/RawColumn.java
++++ b/main/src/main/java/tachyon/client/table/RawColumn.java
+@@ -20,7 +20,6 @@ import tachyon.Constants;
+ import tachyon.client.TachyonFS;
+ import tachyon.client.TachyonFile;
+ import tachyon.master.MasterInfo;
+-import tachyon.util.CommonUtils;
+
+ /**
+ * The column of a <code>RawTable</code>.
+@@ -38,8 +37,8 @@ public class RawColumn {
+
+ // TODO creating file here should be based on id.
+ public boolean createPartition(int pId) throws IOException {
+- return TFS.createFile(CommonUtils.concat(RAW_TABLE.getPath(), MasterInfo.COL + COLUMN_INDEX,
+- pId)) > 0;
++ return TFS.createFile(RAW_TABLE.getPath() + Constants.PATH_SEPARATOR + MasterInfo.COL
++ + COLUMN_INDEX + Constants.PATH_SEPARATOR + pId) > 0;
+ }
+
+ // TODO creating file here should be based on id.
+@@ -49,14 +48,13 @@ public class RawColumn {
+
+ // TODO creating file here should be based on id.
+ public TachyonFile getPartition(int pId, boolean cachedMetadata) throws IOException {
+- return TFS.getFile(
+- CommonUtils.concat(RAW_TABLE.getPath(), MasterInfo.COL + COLUMN_INDEX, pId),
+- cachedMetadata);
++ return TFS.getFile(RAW_TABLE.getPath() + Constants.PATH_SEPARATOR + MasterInfo.COL
++ + COLUMN_INDEX + Constants.PATH_SEPARATOR + pId, cachedMetadata);
+ }
+
+ // TODO creating file here should be based on id.
+ public int partitions() throws IOException {
+- return TFS.getNumberOfFiles(CommonUtils.concat(RAW_TABLE.getPath(), MasterInfo.COL
+- + COLUMN_INDEX));
++ return TFS.getNumberOfFiles(RAW_TABLE.getPath() + Constants.PATH_SEPARATOR + MasterInfo.COL
++ + COLUMN_INDEX);
+ }
+-}
++}
+\ No newline at end of file
+diff --git a/main/src/main/java/tachyon/conf/CommonConf.java b/main/src/main/java/tachyon/conf/CommonConf.java
+index 9215d99..5e8edfc 100644
+--- a/main/src/main/java/tachyon/conf/CommonConf.java
++++ b/main/src/main/java/tachyon/conf/CommonConf.java
+@@ -49,6 +49,10 @@ public class CommonConf extends Utils {
+ public final String UNDERFS_WORKERS_FOLDER;
+
+ public final String UNDERFS_HDFS_IMPL;
++ public final String UNDERFS_GLUSTERFS_IMPL;
++ public final String UNDERFS_GLUSTERFS_VOLUMES;
++ public final String UNDERFS_GLUSTERFS_MOUNTS;
++ public final String UNDERFS_GLUSTERFS_MR_DIR;
+ public final String WEB_RESOURCES;
+ public final boolean USE_ZOOKEEPER;
+ public final String ZOOKEEPER_ADDRESS;
+@@ -79,7 +83,14 @@ public class CommonConf extends Utils {
+ getProperty("tachyon.workers.folder", UNDERFS_ADDRESS + "/tachyon/workers");
+ UNDERFS_HDFS_IMPL =
+ getProperty("tachyon.underfs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
+-
++ UNDERFS_GLUSTERFS_IMPL =
++ getProperty("tachyon.underfs.glusterfs.impl", "org.apache.hadoop.fs.glusterfs.GlusterFileSystem");
++ UNDERFS_GLUSTERFS_VOLUMES =
++ getProperty("tachyon.underfs.glusterfs.volumes", null);
++ UNDERFS_GLUSTERFS_MOUNTS =
++ getProperty("tachyon.underfs.glusterfs.mounts", null);
++ UNDERFS_GLUSTERFS_MR_DIR =
++ getProperty("tachyon.underfs.glusterfs.mapred.system.dir", "glusterfs:///mapred/system");
+ USE_ZOOKEEPER = getBooleanProperty("tachyon.usezookeeper", false);
+ if (USE_ZOOKEEPER) {
+ ZOOKEEPER_ADDRESS = getProperty("tachyon.zookeeper.address");
+diff --git a/main/src/main/java/tachyon/conf/MasterConf.java b/main/src/main/java/tachyon/conf/MasterConf.java
+index d045199..e0dc7d9 100644
+--- a/main/src/main/java/tachyon/conf/MasterConf.java
++++ b/main/src/main/java/tachyon/conf/MasterConf.java
+@@ -44,7 +44,6 @@ public class MasterConf extends Utils {
+ public final String FORMAT_FILE_PREFIX;
+ public final String HOSTNAME;
+ public final int PORT;
+- public final String MASTER_ADDRESS;
+
+ public final int WEB_PORT;
+ public final String TEMPORARY_FOLDER;
+@@ -70,9 +69,6 @@ public class MasterConf extends Utils {
+
+ HOSTNAME = getProperty("tachyon.master.hostname", "localhost");
+ PORT = getIntProperty("tachyon.master.port", Constants.DEFAULT_MASTER_PORT);
+- MASTER_ADDRESS =
+- (CommonConf.get().USE_ZOOKEEPER ? Constants.HEADER_FT : Constants.HEADER) + HOSTNAME + ":"
+- + PORT;
+ WEB_PORT = getIntProperty("tachyon.master.web.port", Constants.DEFAULT_MASTER_WEB_PORT);
+ TEMPORARY_FOLDER = getProperty("tachyon.master.temporary.folder", "/tmp");
+
+diff --git a/main/src/main/java/tachyon/hadoop/TFS.java b/main/src/main/java/tachyon/hadoop/TFS.java
+index 2058fb6..87661e7 100644
+--- a/main/src/main/java/tachyon/hadoop/TFS.java
++++ b/main/src/main/java/tachyon/hadoop/TFS.java
+@@ -177,8 +177,7 @@ public class TFS extends FileSystem {
+ Path hdfsPath = Utils.getHDFSPath(path);
+ FileSystem fs = hdfsPath.getFileSystem(getConf());
+ if (fs.exists(hdfsPath)) {
+- String ufsAddrPath = CommonUtils.concat(UNDERFS_ADDRESS, path);
+- UnderfsUtil.loadUnderFs(mTFS, Constants.PATH_SEPARATOR, ufsAddrPath, new PrefixList(null));
++ UnderfsUtil.getInfo(mTFS, UNDERFS_ADDRESS, path, new PrefixList(null));
+ }
+ }
+ }
+diff --git a/main/src/main/java/tachyon/hadoop/Utils.java b/main/src/main/java/tachyon/hadoop/Utils.java
+index 9108117..2328a51 100644
+--- a/main/src/main/java/tachyon/hadoop/Utils.java
++++ b/main/src/main/java/tachyon/hadoop/Utils.java
+@@ -23,7 +23,6 @@ import org.apache.hadoop.mapred.InputSplit;
+ import org.apache.log4j.Logger;
+
+ import tachyon.Constants;
+-import tachyon.util.CommonUtils;
+
+ public final class Utils {
+ private static final Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE);
+@@ -47,7 +46,7 @@ public final class Utils {
+ if (ret.equals("")) {
+ ret = path.getName();
+ } else {
+- ret = CommonUtils.concat(path.getName(), ret);
++ ret = path.getName() + Constants.PATH_SEPARATOR + ret;
+ }
+ path = path.getParent();
+ }
+diff --git a/main/src/main/java/tachyon/master/Dependency.java b/main/src/main/java/tachyon/master/Dependency.java
+index 97abc8c..6a4f7e0 100644
+--- a/main/src/main/java/tachyon/master/Dependency.java
++++ b/main/src/main/java/tachyon/master/Dependency.java
+@@ -13,7 +13,6 @@ import java.util.Set;
+ import org.apache.log4j.Logger;
+
+ import tachyon.Constants;
+-import tachyon.conf.MasterConf;
+ import tachyon.io.Utils;
+ import tachyon.thrift.ClientDependencyInfo;
+ import tachyon.util.CommonUtils;
+@@ -125,7 +124,6 @@ public class Dependency implements ImageWriter {
+ // TODO We should support different types of command in the future.
+ // For now, assume there is only one command model.
+ StringBuilder sb = new StringBuilder(parseCommandPrefix());
+- sb.append(" ").append(MasterConf.get().MASTER_ADDRESS);
+ sb.append(" ").append(ID);
+ for (int k = 0; k < CHILDREN_FILES.size(); k ++) {
+ int id = CHILDREN_FILES.get(k);
+diff --git a/main/src/main/java/tachyon/master/EditLog.java b/main/src/main/java/tachyon/master/EditLog.java
+index a13a30e..102ae8d 100644
+--- a/main/src/main/java/tachyon/master/EditLog.java
++++ b/main/src/main/java/tachyon/master/EditLog.java
+@@ -58,11 +58,10 @@ public class EditLog {
+
+ public static void deleteCompletedLogs(String path, int upTo) {
+ UnderFileSystem ufs = UnderFileSystem.get(path);
+- String folder =
+- path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR) + 1) + "completed";
++ String folder = path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR)) + "/completed";
+ try {
+ for (int i = 0; i < upTo; i ++) {
+- String toDelete = CommonUtils.concat(folder, i + ".editLog");
++ String toDelete = folder + Constants.PATH_SEPARATOR + i + ".editLog";
+ LOG.info("Deleting editlog " + toDelete);
+ ufs.delete(toDelete, true);
+ }
+@@ -102,18 +101,20 @@ public class EditLog {
+ mBackUpLogStartNum = currentLogFileNum;
+ int numFiles = 1;
+ String completedPath =
+- path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR) + 1) + "completed";
++ path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR)) + "/completed";
+ if (!ufs.exists(completedPath)) {
+ LOG.info("No completed edit logs to be parsed");
+ } else {
+- while (ufs.exists(CommonUtils.concat(completedPath, (completedLogs ++) + ".editLog"))) {
++ while (ufs
++ .exists(completedPath + Constants.PATH_SEPARATOR + (completedLogs ++) + ".editLog")) {
+ numFiles ++;
+ }
+ }
+ String editLogs[] = new String[numFiles];
+ for (int i = 0; i < numFiles; i ++) {
+ if (i != numFiles - 1) {
+- editLogs[i] = CommonUtils.concat(completedPath, (i + currentLogFileNum) + ".editLog");
++ editLogs[i] =
++ completedPath + Constants.PATH_SEPARATOR + (i + currentLogFileNum) + ".editLog";
+ } else {
+ editLogs[i] = path;
+ }
+@@ -214,16 +215,15 @@ public class EditLog {
+
+ public static void markUpToDate(String path) {
+ UnderFileSystem ufs = UnderFileSystem.get(path);
+- String folder =
+- path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR) + 1) + "completed";
++ String folder = path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR)) + "/completed";
+ try {
+ // delete all loaded editlogs since mBackupLogStartNum.
+- String toDelete = CommonUtils.concat(folder, mBackUpLogStartNum + ".editLog");
++ String toDelete = folder + Constants.PATH_SEPARATOR + mBackUpLogStartNum + ".editLog";
+ while (ufs.exists(toDelete)) {
+ LOG.info("Deleting editlog " + toDelete);
+ ufs.delete(toDelete, true);
+ mBackUpLogStartNum ++;
+- toDelete = CommonUtils.concat(folder, mBackUpLogStartNum + ".editLog");
++ toDelete = folder + Constants.PATH_SEPARATOR + mBackUpLogStartNum + ".editLog";
+ }
+ } catch (IOException e) {
+ CommonUtils.runtimeException(e);
+@@ -253,24 +253,24 @@ public class EditLog {
+ UFS = UnderFileSystem.get(path);
+ if (mBackUpLogStartNum != -1) {
+ String folder =
+- path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR) + 1) + "/completed";
++ path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR)) + "/completed";
+ LOG.info("Deleting completed editlogs that are part of the image.");
+ deleteCompletedLogs(path, mBackUpLogStartNum);
+ LOG.info("Backing up logs from " + mBackUpLogStartNum + " since image is not updated.");
+ UFS.mkdirs(folder, true);
+- String toRename = CommonUtils.concat(folder, mBackUpLogStartNum + ".editLog");
++ String toRename = folder + Constants.PATH_SEPARATOR + mBackUpLogStartNum + ".editLog";
+ int currentLogFileNum = 0;
+ while (UFS.exists(toRename)) {
+- LOG.info("Rename " + toRename + " to "
+- + CommonUtils.concat(folder, currentLogFileNum + ".editLog"));
++ LOG.info("Rename " + toRename + " to " + folder + Constants.PATH_SEPARATOR
++ + currentLogFileNum + ".editLog");
+ currentLogFileNum ++;
+ mBackUpLogStartNum ++;
+- toRename = CommonUtils.concat(folder, mBackUpLogStartNum + ".editLog");
++ toRename = folder + Constants.PATH_SEPARATOR + mBackUpLogStartNum + ".editLog";
+ }
+ if (UFS.exists(path)) {
+- UFS.rename(path, CommonUtils.concat(folder, currentLogFileNum + ".editLog"));
+- LOG.info("Rename " + path + " to "
+- + CommonUtils.concat(folder, currentLogFileNum + ".editLog"));
++ UFS.rename(path, folder + Constants.PATH_SEPARATOR + currentLogFileNum + ".editLog");
++ LOG.info("Rename " + path + " to " + folder + Constants.PATH_SEPARATOR
++ + currentLogFileNum + ".editLog");
+ currentLogFileNum ++;
+ }
+ mBackUpLogStartNum = -1;
+@@ -500,13 +500,14 @@ public class EditLog {
+ _close();
+ LOG.info("Edit log max size reached, rotating edit log");
+ String pathPrefix =
+- path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR) + 1) + "completed";
++ path.substring(0, path.lastIndexOf(Constants.PATH_SEPARATOR)) + "/completed";
+ LOG.info("path: " + path + " prefix: " + pathPrefix);
+ try {
+ if (!UFS.exists(pathPrefix)) {
+ UFS.mkdirs(pathPrefix, true);
+ }
+- String newPath = CommonUtils.concat(pathPrefix, (mCurrentLogFileNum ++) + ".editLog");
++ String newPath =
++ pathPrefix + Constants.PATH_SEPARATOR + (mCurrentLogFileNum ++) + ".editLog";
+ UFS.rename(path, newPath);
+ LOG.info("Renamed " + path + " to " + newPath);
+ OS = UFS.create(path);
+diff --git a/main/src/main/java/tachyon/master/Inode.java b/main/src/main/java/tachyon/master/Inode.java
+index e144f33..1e04cf4 100644
+--- a/main/src/main/java/tachyon/master/Inode.java
++++ b/main/src/main/java/tachyon/master/Inode.java
+@@ -108,10 +108,10 @@ public abstract class Inode implements Comparable<Inode>, ImageWriter {
+
+ @Override
+ public synchronized String toString() {
+- StringBuilder sb = new StringBuilder("Inode(");
++ StringBuilder sb = new StringBuilder("INode(");
+ sb.append("ID:").append(mId).append(", NAME:").append(mName);
+ sb.append(", PARENT_ID:").append(mParentId);
+ sb.append(", CREATION_TIME_MS:").append(CREATION_TIME_MS).append(")");
+ return sb.toString();
+ }
+-}
++}
+\ No newline at end of file
+diff --git a/main/src/main/java/tachyon/master/InodeFolder.java b/main/src/main/java/tachyon/master/InodeFolder.java
+index 16fc58f..db3d853 100644
+--- a/main/src/main/java/tachyon/master/InodeFolder.java
++++ b/main/src/main/java/tachyon/master/InodeFolder.java
+@@ -20,8 +20,8 @@ import java.io.IOException;
+ import java.util.ArrayList;
+ import java.util.HashSet;
+ import java.util.List;
++import java.util.Map;
+ import java.util.Set;
+-import java.util.Collections;
+
+ import tachyon.io.Utils;
+ import tachyon.thrift.ClientFileInfo;
+@@ -45,14 +45,9 @@ public class InodeFolder extends Inode {
+ int parentId = is.readInt();
+
+ int numberOfChildren = is.readInt();
+- Inode[] children = new Inode[numberOfChildren];
++ int[] children = new int[numberOfChildren];
+ for (int k = 0; k < numberOfChildren; k ++) {
+- byte type = is.readByte();
+- if (type == Image.T_INODE_FILE) {
+- children[k] = InodeFile.loadImage(is);
+- } else {
+- children[k] = InodeFolder.loadImage(is);
+- }
++ children[k] = is.readInt();
+ }
+
+ InodeFolder folder = new InodeFolder(fileName, fileId, parentId, creationTimeMs);
+@@ -60,41 +55,22 @@ public class InodeFolder extends Inode {
+ return folder;
+ }
+
+- private Set<Inode> mChildren = new HashSet<Inode>();
++ private Set<Integer> mChildren = new HashSet<Integer>();
+
+ public InodeFolder(String name, int id, int parentId, long creationTimeMs) {
+ super(name, id, parentId, true, creationTimeMs);
+ }
+
+- /**
+- * Adds the given inode to the set of children.
+- *
+- * @param child
+- * The inode to add
+- */
+- public synchronized void addChild(Inode child) {
+- mChildren.add(child);
++ public synchronized void addChild(int childId) {
++ mChildren.add(childId);
+ }
+
+- /**
+- * Adds the given inodes to the set of children.
+- *
+- * @param children
+- * The inodes to add
+- */
+- public synchronized void addChildren(Inode[] children) {
+- for (Inode child : children) {
+- addChild(child);
++ public synchronized void addChildren(int[] childrenIds) {
++ for (int k = 0; k < childrenIds.length; k ++) {
++ addChild(childrenIds[k]);
+ }
+ }
+
+- /**
+- * Generates client file info for the folder.
+- *
+- * @param path
+- * The path of the folder in the filesystem
+- * @return the generated ClientFileInfo
+- */
+ @Override
+ public ClientFileInfo generateClientFileInfo(String path) {
+ ClientFileInfo ret = new ClientFileInfo();
+@@ -117,91 +93,37 @@ public class InodeFolder extends Inode {
+ return ret;
+ }
+
+- /**
+- * Returns the child with the given id.
+- *
+- * @param fid
+- * The id of the child
+- * @return the inode with the given id, or null if there is no child with that id
+- */
+- public synchronized Inode getChild(int fid) {
+- for (Inode child : mChildren) {
+- if (child.getId() == fid) {
+- return child;
+- }
+- }
+- return null;
+- }
+-
+- /**
+- * Returns the child with the given name.
+- *
+- * @param name
+- * The name of the child
+- * @return the inode with the given name, or null if there is no child with that name
+- */
+- public synchronized Inode getChild(String name) {
+- for (Inode child : mChildren) {
+- if (child.getName().equals(name)) {
+- return child;
++ public synchronized Inode getChild(String name, Map<Integer, Inode> allInodes) {
++ Inode tInode = null;
++ for (int childId : mChildren) {
++ tInode = allInodes.get(childId);
++ if (tInode != null && tInode.getName().equals(name)) {
++ return tInode;
+ }
+ }
+ return null;
+ }
+
+- /**
+- * Returns the folder's children.
+- *
+- * @return an unmodifiable set of the children inodes.
+- */
+- public synchronized Set<Inode> getChildren() {
+- return Collections.unmodifiableSet(mChildren);
+- }
+-
+- /**
+- * Returns the ids of the children.
+- *
+- * @return the ids of the children
+- */
+ public synchronized List<Integer> getChildrenIds() {
+ List<Integer> ret = new ArrayList<Integer>(mChildren.size());
+- for (Inode child : mChildren) {
+- ret.add(child.getId());
+- }
++ ret.addAll(mChildren);
+ return ret;
+ }
+
+- /**
+- * Returns the number of children the folder has.
+- *
+- * @return the number of children in the folder.
+- */
+ public synchronized int getNumberOfChildren() {
+ return mChildren.size();
+ }
+
+- /**
+- * Removes the given inode from the folder.
+- *
+- * @param child
+- * The Inode to remove
+- * @return true if the inode was removed, false otherwise.
+- */
+- public synchronized boolean removeChild(Inode child) {
+- return mChildren.remove(child);
++ public synchronized void removeChild(int id) {
++ mChildren.remove(id);
+ }
+
+- /**
+- * Removes the given child from the folder.
+- *
+- * @param name
+- * The name of the Inode to remove.
+- * @return true if the inode was removed, false otherwise.
+- */
+- public synchronized boolean removeChild(String name) {
+- for (Inode child : mChildren) {
+- if (child.getName().equals(name)) {
+- mChildren.remove(child);
++ public synchronized boolean removeChild(String name, Map<Integer, Inode> allInodes) {
++ Inode tInode = null;
++ for (int childId : mChildren) {
++ tInode = allInodes.get(childId);
++ if (tInode != null && tInode.getName().equals(name)) {
++ mChildren.remove(childId);
+ return true;
+ }
+ }
+@@ -215,12 +137,6 @@ public class InodeFolder extends Inode {
+ return sb.toString();
+ }
+
+- /**
+- * Write an image of the folder.
+- *
+- * @param os
+- * The output stream to write the folder to
+- */
+ @Override
+ public void writeImage(DataOutputStream os) throws IOException {
+ os.writeByte(Image.T_INODE_FOLDER);
+@@ -232,8 +148,8 @@ public class InodeFolder extends Inode {
+
+ List<Integer> children = getChildrenIds();
+ os.writeInt(children.size());
+- for (Inode inode : getChildren()) {
+- inode.writeImage(os);
++ for (int k = 0; k < children.size(); k ++) {
++ os.writeInt(children.get(k));
+ }
+ }
+-}
++}
+\ No newline at end of file
+diff --git a/main/src/main/java/tachyon/master/MasterInfo.java b/main/src/main/java/tachyon/master/MasterInfo.java
+index af885e6..44675ad 100644
+--- a/main/src/main/java/tachyon/master/MasterInfo.java
++++ b/main/src/main/java/tachyon/master/MasterInfo.java
+@@ -122,8 +122,7 @@ public class MasterInfo implements ImageWriter {
+ dep.addLostFile(tFile.getId());
+ LOG.info("File " + tFile.getId() + " got lost from worker " + worker.getId()
+ + " . Trying to recompute it using dependency " + dep.ID);
+- String path = getPath(tFile);
+- if (path != null && !path.startsWith(MASTER_CONF.TEMPORARY_FOLDER)) {
++ if (!getPath(tFile).startsWith(MASTER_CONF.TEMPORARY_FOLDER)) {
+ mMustRecomputeDependencies.add(depId);
+ }
+ }
+@@ -239,8 +238,8 @@ public class MasterInfo implements ImageWriter {
+ private Map<Integer, Dependency> mDependencies = new HashMap<Integer, Dependency>();
+ private RawTables mRawTables = new RawTables();
+
+- // TODO add initialization part for master failover or restart. All operations on these members
+- // are synchronized on mDependencies.
++ // TODO add initialization part for master failover or restart.
++ // All operations on these members are synchronized on mDependencies.
+ private Set<Integer> mUncheckpointedDependencies = new HashSet<Integer>();
+ private Set<Integer> mPriorityDependencies = new HashSet<Integer>();
+ private Set<Integer> mLostFiles = new HashSet<Integer>();
+@@ -344,21 +343,11 @@ public class MasterInfo implements ImageWriter {
+ * Internal API.
+ *
+ * @param recursive
+- * If recursive is true and the filesystem tree is not filled in all the way to path yet,
+- * it fills in the missing components.
+ * @param path
+- * The path to create
+ * @param directory
+- * If true, creates an InodeFolder instead of an Inode
+ * @param blockSizeByte
+- * If it's a file, the block size for the Inode
+ * @param creationTimeMs
+- * The time the file was created
+- * @param id
+- * If not -1, use this id as the id to the inode we create at the given path.
+- * Any intermediate directories created will use mInodeCounter, so using this parameter
+- * assumes no intermediate directories will be created.
+- * @return the id of the inode created at the given path
++ * @return
+ * @throws FileAlreadyExistException
+ * @throws InvalidPathException
+ * @throws BlockInfoException
+@@ -378,9 +367,6 @@ public class MasterInfo implements ImageWriter {
+ synchronized (mRoot) {
+ Inode inode = getInode(pathNames);
+ if (inode != null) {
+- if (inode.isDirectory() && directory) {
+- return inode.getId();
+- }
+ LOG.info("FileAlreadyExistException: File " + path + " already exist.");
+ throw new FileAlreadyExistException("Path " + path + " already exist.");
+ }
+@@ -435,7 +421,7 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ mInodes.put(ret.getId(), ret);
+- ((InodeFolder) inode).addChild(ret);
++ ((InodeFolder) inode).addChild(ret.getId());
+
+ LOG.debug("createFile: File Created: " + ret + " parent: " + inode);
+ return ret.getId();
+@@ -473,7 +459,7 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ InodeFolder parent = (InodeFolder) mInodes.get(inode.getParentId());
+- parent.removeChild(inode);
++ parent.removeChild(inode.getId());
+ mInodes.remove(inode.getId());
+ if (inode.isFile()) {
+ String checkpointPath = ((InodeFile) inode).getCheckpointPath();
+@@ -614,43 +600,6 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ /**
+- * Adds the given inode to mFileIdPinList, traversing folders recursively. Used while loading an
+- * image.
+- *
+- * @param inode
+- * The inode to add
+- */
+- private void addToFileIdPinList(Inode inode) throws IOException {
+- if (inode.isFile() && ((InodeFile) inode).isPin()) {
+- synchronized (mFileIdPinList) {
+- mFileIdPinList.add(inode.getId());
+- }
+- } else if (inode.isDirectory()) {
+- for (Inode child : ((InodeFolder) inode).getChildren()) {
+- addToFileIdPinList(child);
+- }
+- }
+- }
+-
+- /**
+- * While loading an image, addToInodeMap will map the various ids to their inodes.
+- *
+- * @param inode
+- * The inode to add
+- * @param map
+- * The map to add the inodes to
+- */
+- private void addToInodeMap(Inode inode, Map<Integer, Inode> map) {
+- map.put(inode.getId(), inode);
+- if (inode.isDirectory()) {
+- InodeFolder inodeFolder = (InodeFolder) inode;
+- for (Inode child : inodeFolder.getChildren()) {
+- addToInodeMap(child, map);
+- }
+- }
+- }
+-
+- /**
+ * A worker cache a block in its memory.
+ *
+ * @param workerId
+@@ -827,7 +776,7 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ for (int k = 0; k < columns; k ++) {
+- mkdir(CommonUtils.concat(path, COL + k));
++ mkdir(path + Constants.PATH_SEPARATOR + COL + k);
+ }
+
+ return id;
+@@ -1116,6 +1065,23 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ /**
++ * Get the path of a file with the given id
++ *
++ * @param fileId
++ * The id of the file to look up
++ * @return the path of the file
++ */
++ public String getFileNameById(int fileId) throws FileDoesNotExistException {
++ synchronized (mRoot) {
++ Inode inode = mInodes.get(fileId);
++ if (inode == null) {
++ throw new FileDoesNotExistException("FileId " + fileId + " does not exist");
++ }
++ return getPath(inode);
++ }
++ }
++
++ /**
+ * Get the file id's of the given paths. It recursively scans directories for the file id's inside
+ * of them.
+ *
+@@ -1153,11 +1119,14 @@ public class MasterInfo implements ImageWriter {
+ }
+
+ if (inode.isDirectory()) {
+- Set<Inode> children = ((InodeFolder) inode).getChildren();
++ List<Integer> childernIds = ((InodeFolder) inode).getChildrenIds();
+
++ if (!path.endsWith(Constants.PATH_SEPARATOR)) {
++ path += Constants.PATH_SEPARATOR;
++ }
+ synchronized (mRoot) {
+- for (Inode child : children) {
+- ret.add(getClientFileInfo(child.getId()));
++ for (int k : childernIds) {
++ ret.add(getClientFileInfo(k));
+ }
+ }
+ } else {
+@@ -1183,9 +1152,10 @@ public class MasterInfo implements ImageWriter {
+ InodeFolder tFolder = tPair.getFirst();
+ String curPath = tPair.getSecond();
+
+- Set<Inode> children = tFolder.getChildren();
+- for (Inode tInode : children) {
+- String newPath = CommonUtils.concat(curPath, tInode.getName());
++ List<Integer> childrenIds = tFolder.getChildrenIds();
++ for (int id : childrenIds) {
++ Inode tInode = mInodes.get(id);
++ String newPath = curPath + Constants.PATH_SEPARATOR + tInode.getName();
+ if (tInode.isDirectory()) {
+ nodesQueue.add(new Pair<InodeFolder, String>((InodeFolder) tInode, newPath));
+ } else if (((InodeFile) tInode).isFullyInMemory()) {
+@@ -1236,7 +1206,7 @@ public class MasterInfo implements ImageWriter {
+ if (cur.isFile()) {
+ return null;
+ }
+- cur = ((InodeFolder) cur).getChild(name);
++ cur = ((InodeFolder) cur).getChild(name, mInodes);
+ }
+
+ return cur;
+@@ -1304,24 +1274,8 @@ public class MasterInfo implements ImageWriter {
+ if (inode.getParentId() == 1) {
+ return Constants.PATH_SEPARATOR + inode.getName();
+ }
+- return CommonUtils.concat(getPath(mInodes.get(inode.getParentId())), inode.getName());
+- }
+- }
+-
+- /**
+- * Get the path of a file with the given id
+- *
+- * @param fileId
+- * The id of the file to look up
+- * @return the path of the file
+- */
+- public String getPath(int fileId) throws FileDoesNotExistException {
+- synchronized (mRoot) {
+- Inode inode = mInodes.get(fileId);
+- if (inode == null) {
+- throw new FileDoesNotExistException("FileId " + fileId + " does not exist");
+- }
+- return getPath(inode);
++ return getPath(mInodes.get(inode.getParentId())) + Constants.PATH_SEPARATOR
++ + inode.getName();
+ }
+ }
+
+@@ -1475,7 +1429,7 @@ public class MasterInfo implements ImageWriter {
+ * If true, select a random worker
+ * @param host
+ * If <code>random</code> is false, select a worker on this host
+- * @return the address of the selected worker, or null if no address could be found
++ * @return the address of the selected worker
+ */
+ public NetAddress getWorker(boolean random, String host) {
+ synchronized (mWorkers) {
+@@ -1593,15 +1547,17 @@ public class MasterInfo implements ImageWriter {
+ if (inode.isFile()) {
+ ret.add(inode.getId());
+ } else if (recursive) {
+- Queue<Inode> queue = new LinkedList<Inode>();
+- queue.addAll(((InodeFolder) inode).getChildren());
++ Queue<Integer> queue = new LinkedList<Integer>();
++ queue.addAll(((InodeFolder) inode).getChildrenIds());
+
+ while (!queue.isEmpty()) {
+- Inode qinode = queue.poll();
+- if (qinode.isDirectory()) {
+- queue.addAll(((InodeFolder) inode).getChildren());
++ int id = queue.poll();
++ inode = mInodes.get(id);
++
++ if (inode.isDirectory()) {
++ queue.addAll(((InodeFolder) inode).getChildrenIds());
+ } else {
+- ret.add(qinode.getId());
++ ret.add(id);
+ }
+ }
+ }
+@@ -1649,16 +1605,15 @@ public class MasterInfo implements ImageWriter {
+ inode = InodeFolder.loadImage(is);
+ }
+
++ LOG.info("Putting " + inode);
+ if (inode.getId() > mInodeCounter.get()) {
+ mInodeCounter.set(inode.getId());
+ }
+
+- addToInodeMap(inode, mInodes);
+- addToFileIdPinList(inode);
+-
+ if (inode.getId() == 1) {
+ mRoot = (InodeFolder) inode;
+ }
++ mInodes.put(inode.getId(), inode);
+ } else if (Image.T_RAW_TABLE == type) {
+ mRawTables.loadImage(is);
+ } else {
+@@ -1689,15 +1644,22 @@ public class MasterInfo implements ImageWriter {
+ if (inode.isFile()) {
+ ret.add(path);
+ } else {
+- Set<Inode> children = ((InodeFolder) inode).getChildren();
++ List<Integer> childrenIds = ((InodeFolder) inode).getChildrenIds();
++
++ if (!path.endsWith(Constants.PATH_SEPARATOR)) {
++ path += Constants.PATH_SEPARATOR;
++ }
+ ret.add(path);
+
+ synchronized (mRoot) {
+- for (Inode child : children) {
+- if (recursive) {
+- ret.addAll(ls(CommonUtils.concat(path, child.getName()), true));
+- } else {
+- ret.add(CommonUtils.concat(path, child.getName()));
++ for (int k : childrenIds) {
++ inode = mInodes.get(k);
++ if (inode != null) {
++ if (recursive) {
++ ret.addAll(ls(path + inode.getName(), true));
++ } else {
++ ret.add(path + inode.getName());
++ }
+ }
+ }
+ }
+@@ -1711,7 +1673,7 @@ public class MasterInfo implements ImageWriter {
+ *
+ * @param path
+ * The path to create a directory at
+- * @return true if and only if the directory was created; false otherwise
++ * @return true if the creation was successful and false if it wasn't
+ */
+ public boolean mkdir(String path) throws FileAlreadyExistException, InvalidPathException,
+ TachyonException {
+@@ -1836,9 +1798,9 @@ public class MasterInfo implements ImageWriter {
+
+ srcInode.setName(dstName);
+ InodeFolder parent = (InodeFolder) mInodes.get(srcInode.getParentId());
+- parent.removeChild(srcInode);
++ parent.removeChild(srcInode.getId());
+ srcInode.setParentId(dstFolderInode.getId());
+- ((InodeFolder) dstFolderInode).addChild(srcInode);
++ ((InodeFolder) dstFolderInode).addChild(srcInode.getId());
+
+ mJournal.getEditLog().rename(srcInode.getId(), dstPath);
+ mJournal.getEditLog().flush();
+@@ -2055,13 +2017,30 @@ public class MasterInfo implements ImageWriter {
+ * The output stream to write the image to
+ */
+ public void writeImage(DataOutputStream os) throws IOException {
++ Queue<InodeFolder> folderQueue = new LinkedList<InodeFolder>();
++
+ synchronized (mRoot) {
+- synchronized (mDependencies) {
+- for (Dependency dep : mDependencies.values()) {
+- dep.writeImage(os);
+- }
++ for (Dependency dep : mDependencies.values()) {
++ dep.writeImage(os);
+ }
++
+ mRoot.writeImage(os);
++ folderQueue.add(mRoot);
++ while (!folderQueue.isEmpty()) {
++ List<Integer> childrenIds = folderQueue.poll().getChildrenIds();
++ for (int id : childrenIds) {
++ Inode tInode = mInodes.get(id);
++ tInode.writeImage(os);
++ if (tInode.isDirectory()) {
++ folderQueue.add((InodeFolder) tInode);
++ } else if (((InodeFile) tInode).isPin()) {
++ synchronized (mFileIdPinList) {
++ mFileIdPinList.add(tInode.getId());
++ }
++ }
++ }
++ }
++
+ mRawTables.writeImage(os);
+
+ os.writeByte(Image.T_CHECKPOINT);
+diff --git a/main/src/main/java/tachyon/util/CommonUtils.java b/main/src/main/java/tachyon/util/CommonUtils.java
+index cd43ccf..4b326c6 100644
+--- a/main/src/main/java/tachyon/util/CommonUtils.java
++++ b/main/src/main/java/tachyon/util/CommonUtils.java
+@@ -19,7 +19,6 @@ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.OutputStream;
+ import java.io.PrintStream;
+-import java.math.BigDecimal;
+ import java.net.InetSocketAddress;
+ import java.nio.ByteBuffer;
+ import java.text.DateFormat;
+@@ -29,7 +28,6 @@ import java.util.Date;
+ import java.util.List;
+ import java.util.Scanner;
+
+-import org.apache.commons.io.FilenameUtils;
+ import org.apache.log4j.Logger;
+
+ import tachyon.Constants;
+@@ -81,17 +79,14 @@ public final class CommonUtils {
+ changeLocalFilePermission(filePath, "777");
+ }
+
+- /**
+- * Checks and normalizes the given path
+- *
+- * @param path
+- * The path to clean up
+- * @return a normalized version of the path, with single separators between path components and
+- * dot components resolved
+- */
+- public static String cleanPath(String path) throws InvalidPathException {
+- validatePath(path);
+- return FilenameUtils.separatorsToUnix(FilenameUtils.normalizeNoEndSeparator(path));
++ public static String cleanPath(String path) throws IOException {
++ if (path == null || path.isEmpty()) {
++ throw new IOException("Path (" + path + ") is invalid.");
++ }
++ while (path.endsWith(Constants.PATH_SEPARATOR) && path.length() > 1) {
++ path = path.substring(0, path.length() - 1);
++ }
++ return path;
+ }
+
+ public static ByteBuffer cloneByteBuffer(ByteBuffer buf) {
+@@ -109,31 +104,6 @@ public final class CommonUtils {
+ return ret;
+ }
+
+- /**
+- * Add the path component to the base path
+- *
+- * @param args
+- * The components to concatenate
+- * @return the concatenated path
+- */
+- public static String concat(Object... args) {
+- if (args.length == 0) {
+- return "";
+- }
+- String retPath = args[0].toString();
+- for (int k = 1; k < args.length; k ++) {
+- while (retPath.endsWith(Constants.PATH_SEPARATOR)) {
+- retPath = retPath.substring(0, retPath.length() - 1);
+- }
+- if (args[k].toString().startsWith(Constants.PATH_SEPARATOR)) {
+- retPath += args[k].toString();
+- } else {
+- retPath += Constants.PATH_SEPARATOR + args[k].toString();
+- }
+- }
+- return retPath;
+- }
+-
+ public static String convertByteArrayToStringWithoutEscape(byte[] data) {
+ StringBuilder sb = new StringBuilder(data.length);
+ for (int i = 0; i < data.length; i ++) {
+@@ -214,7 +184,8 @@ public final class CommonUtils {
+ * @return the name of the file
+ */
+ public static String getName(String path) throws InvalidPathException {
+- return FilenameUtils.getName(cleanPath(path));
++ String[] pathNames = getPathComponents(path);
++ return pathNames[pathNames.length - 1];
+ }
+
+ /**
+@@ -225,8 +196,8 @@ public final class CommonUtils {
+ * @return the path split into components
+ */
+ public static String[] getPathComponents(String path) throws InvalidPathException {
+- path = cleanPath(path);
+- if (isRoot(path)) {
++ validatePath(path);
++ if (path.length() == 1 && path.equals(Constants.PATH_SEPARATOR)) {
+ String[] ret = new String[1];
+ ret[0] = "";
+ return ret;
+@@ -260,17 +231,6 @@ public final class CommonUtils {
+ throw new IllegalArgumentException(msg);
+ }
+
+- /**
+- * Check if the given path is the root.
+- *
+- * @param path
+- * The path to check
+- * @return true if the path is the root
+- */
+- public static boolean isRoot(String path) throws InvalidPathException {
+- return Constants.PATH_SEPARATOR.equals(cleanPath(path));
+- }
+-
+ public static <T> String listToString(List<T> list) {
+ StringBuilder sb = new StringBuilder();
+ for (int k = 0; k < list.size(); k ++) {
+@@ -340,11 +300,6 @@ public final class CommonUtils {
+ return (long) (ret * Constants.GB + alpha);
+ } else if (end.equals("tb")) {
+ return (long) (ret * Constants.TB + alpha);
+- } else if (end.equals("pb")) {
+- // When parsing petabyte values, we can't multiply with doubles and longs, since that will
+- // lose presicion with such high numbers. Therefore we use a BigDecimal.
+- BigDecimal PBDecimal = new BigDecimal(Constants.PB);
+- return PBDecimal.multiply(BigDecimal.valueOf(ret)).longValue();
+ } else {
+ runtimeException("Fail to parse " + ori + " as memory size");
+ return -1;
+@@ -437,8 +392,8 @@ public final class CommonUtils {
+ }
+
+ public static void validatePath(String path) throws InvalidPathException {
+- if (path == null || path.isEmpty() || !path.startsWith(Constants.PATH_SEPARATOR)
+- || path.contains(" ")) {
++ if (path == null || !path.startsWith(Constants.PATH_SEPARATOR)
++ || (path.length() > 1 && path.endsWith(Constants.PATH_SEPARATOR)) || path.contains(" ")) {
+ throw new InvalidPathException("Path " + path + " is invalid.");
+ }
+ }
+diff --git a/main/src/main/java/tachyon/util/UnderfsUtil.java b/main/src/main/java/tachyon/util/UnderfsUtil.java
+index bd8bfdd..75b25fc 100644
+--- a/main/src/main/java/tachyon/util/UnderfsUtil.java
++++ b/main/src/main/java/tachyon/util/UnderfsUtil.java
+@@ -18,14 +18,19 @@ import java.io.IOException;
+ import java.util.LinkedList;
+ import java.util.Queue;
+
++import org.apache.hadoop.conf.Configuration;
+ import org.apache.log4j.Logger;
++import org.apache.thrift.TException;
+
+ import tachyon.Constants;
+-import tachyon.Pair;
+ import tachyon.PrefixList;
+ import tachyon.UnderFileSystem;
+ import tachyon.Version;
+ import tachyon.client.TachyonFS;
++import tachyon.thrift.FileAlreadyExistException;
++import tachyon.thrift.FileDoesNotExistException;
++import tachyon.thrift.InvalidPathException;
++import tachyon.thrift.SuspectedFileSizeException;
+
+ /**
+ * Utilities related to under filesystem
+@@ -33,167 +38,73 @@ import tachyon.client.TachyonFS;
+ public class UnderfsUtil {
+ private static Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE);
+
+- /**
+- * Create a new path relative to a given TFS root.
+- *
+- * @param tfsRootPath
+- * the destination point in TFS to load the under FS path onto
+- * @param ufsRootPath
+- * the source path in the under FS to be loaded
+- * @param path
+- * the path relative to ufsRootPath of a file to be loaded
+- * @return the new path relative to tfsRootPath.
+- */
+- private static String createTFSPath(String tfsRootPath, String ufsRootPath, String path) {
+- String filePath = path.substring(ufsRootPath.length());
+- if (filePath.isEmpty()) {
+- // retrieve the basename in ufsRootPath
+- filePath = path.substring(ufsRootPath.lastIndexOf(Constants.PATH_SEPARATOR) + 1);
+- }
+- return CommonUtils.concat(tfsRootPath, filePath);
+- }
+-
+- /**
+- * Load files under path "ufsAddrRootPath" (excluding excludePathPrefix relative to the path)
+- * to the given tfs under a given destination path.
+- *
+- * @param tfsAddrRootPath
+- * the TFS address and path to load the src files, like "tachyon://host:port/dest".
+- * @param ufsAddrRootPath
+- * the address and root path of the under FS, like "hdfs://host:port/src".
+- * @param excludePaths
+- * paths to exclude from ufsRootPath, which will not be loaded in TFS.
+- * @throws IOException
+- */
+- public static void loadUnderFs(String tfsAddrRootPath, String ufsAddrRootPath,
+- String excludePaths) throws IOException {
+- Pair<String, String> tfsPair = UnderFileSystem.parse(tfsAddrRootPath);
+- String tfsAddress = tfsPair.getFirst();
+- String tfsRootPath = tfsPair.getSecond();
+- TachyonFS tfs = TachyonFS.get(tfsAddress);
+-
+- PrefixList excludePathPrefix = new PrefixList(excludePaths, ";");
+-
+- loadUnderFs(tfs, tfsRootPath, ufsAddrRootPath, excludePathPrefix);
+- }
+-
+- /**
+- * Load files under path "ufsAddress/ufsRootPath" (excluding excludePathPrefix)
+- * to the given tfs under the given tfsRootPath directory.
+- *
+- * @param tfs
+- * the TFS handler created out of address like "tachyon://host:port"
+- * @param tfsRootPath
+- * the destination point in TFS to load the under FS path onto
+- * @param ufsAddrRootPath
+- * the address and root path of the under FS, like "hdfs://host:port/dir".
+- * @param excludePathPrefix
+- * paths to exclude from ufsRootPath, which will not be registered in TFS.
+- * @throws IOException
+- */
+- public static void loadUnderFs(TachyonFS tfs, String tfsRootPath, String ufsAddrRootPath,
++ public static void getInfo(TachyonFS tfs, String underfsAddress, String rootPath,
+ PrefixList excludePathPrefix) throws IOException {
+- LOG.info(tfs + tfsRootPath + " " + ufsAddrRootPath + " " + excludePathPrefix);
+-
+- Pair<String, String> tfsPair = UnderFileSystem.parse(ufsAddrRootPath);
+- String ufsAddress = tfsPair.getFirst();
+- String ufsRootPath = tfsPair.getSecond();
++ LOG.info(tfs + " " + underfsAddress + " " + rootPath + " " + excludePathPrefix);
+
+- if (!tfs.exist(tfsRootPath)) {
+- tfs.mkdir(tfsRootPath);
+- // TODO Add the following.
+- // if (tfs.mkdir(tfsRootPath)) {
+- // LOG.info("directory " + tfsRootPath + " does not exist in Tachyon: created");
+- // } else {
+- // throw new IOException("Failed to create folder in Tachyon: " + tfsRootPath);
+- // }
+- }
+-
+- // create the under FS handler (e.g. hdfs, local FS, s3 etc.)
+- UnderFileSystem ufs = UnderFileSystem.get(ufsAddress);
++ Configuration tConf = new Configuration();
++ tConf.set("fs.default.name", underfsAddress + rootPath);
++ // TODO Use underfs to make this generic.
++ UnderFileSystem fs = UnderFileSystem.get(underfsAddress);
+
+- Queue<String> ufsPathQueue = new LinkedList<String>();
+- if (excludePathPrefix.outList(ufsRootPath)) {
+- ufsPathQueue.add(ufsAddrRootPath);
++ Queue<String> pathQueue = new LinkedList<String>();
++ if (excludePathPrefix.outList(rootPath)) {
++ pathQueue.add(underfsAddress + rootPath);
+ }
+-
+- while (!ufsPathQueue.isEmpty()) {
+- String ufsPath = ufsPathQueue.poll(); // the absolute path
+- if (ufs.isFile(ufsPath)) {
+- String tfsPath = createTFSPath(tfsRootPath, ufsAddrRootPath, ufsPath);
+- if (tfs.exist(tfsPath)) {
+- LOG.info("File " + tfsPath + " already exists in Tachyon.");
++ while (!pathQueue.isEmpty()) {
++ String path = pathQueue.poll();
++ if (fs.isFile(path)) {
++ String filePath = path.substring(underfsAddress.length());
++ if (tfs.exist(filePath)) {
++ LOG.info("File " + filePath + " already exists in Tachyon.");
+ continue;
+ }
+- int fileId = tfs.createFile(tfsPath, ufsPath);
++ int fileId = tfs.createFile(filePath, path);
+ if (fileId == -1) {
+- LOG.info("Failed to create tachyon file: " + tfsPath);
++ LOG.info("Failed to create tachyon file: " + filePath);
+ } else {
+- LOG.info("Create tachyon file " + tfsPath + " with file id " + fileId + " and "
+- + "checkpoint location " + ufsPath);
++ LOG.info("Create tachyon file " + filePath + " with file id " + fileId + " and "
++ + "checkpoint location " + path);
+ }
+- } else { // ufsPath is a directory
+- String[] files = ufs.list(ufsPath); // ufs.list() returns relative path
++ } else {
++ String[] files = fs.list(path);
+ if (files != null) {
+ for (String filePath : files) {
+ LOG.info("Get: " + filePath);
+- String aPath = CommonUtils.concat(ufsPath, filePath);
+- String checkPath = aPath.substring(ufsAddrRootPath.length());
+- if (checkPath.startsWith(Constants.PATH_SEPARATOR)) {
+- checkPath = checkPath.substring(Constants.PATH_SEPARATOR.length());
+- }
+- if (excludePathPrefix.inList(checkPath)) {
+- LOG.info("excluded: " + checkPath);
+- } else {
+- ufsPathQueue.add(aPath);
++ if (excludePathPrefix.outList(filePath)) {
++ pathQueue.add(underfsAddress + filePath);
+ }
+ }
+ }
+- String tfsPath = createTFSPath(tfsRootPath, ufsAddrRootPath, ufsPath);
+- if (!tfs.exist(tfsPath)) {
+- tfs.mkdir(tfsPath);
+- // TODO Add the following.
+- // if (tfs.mkdir(tfsPath)) {
+- // LOG.info("Created tachyon folder " + tfsPath + " with checkpoint location " + ufsPath);
+- // } else {
+- // LOG.info("Failed to create tachyon folder: " + tfsPath);
+- // }
++ String filePath = path.substring(underfsAddress.length());
++ if (!tfs.exist(filePath)) {
++ tfs.mkdir(filePath);
+ }
+ }
+ }
+ }
+
+- public static void main(String[] args) {
+- if (!(args.length == 2 || args.length == 3)) {
+- printUsage();
++ public static void main(String[] args) throws SuspectedFileSizeException, InvalidPathException,
++ IOException, FileDoesNotExistException, FileAlreadyExistException, TException {
++ if (!(args.length == 3 || args.length == 4)) {
++ String prefix =
++ "java -cp target/tachyon-" + Version.VERSION + "-jar-with-dependencies.jar "
++ + "tachyon.util.UnderfsUtil ";
++ System.out.println("Usage: " + prefix + "<TachyonAddress> <UnderfsAddress> <Path> "
++ + "[<ExcludePathPrefix, separated by ;>]");
++ System.out.println("Example: " + prefix
++ + "tachyon://127.0.0.1:19998 hdfs://localhost:9000 / /tachyon");
+ System.exit(-1);
+ }
+
+- String exList = (args.length == 3) ? args[2] : "";
+-
+- try {
+- loadUnderFs(args[0], args[1], exList);
+- } catch (Exception e) {
+- e.printStackTrace();
+- printUsage();
+- System.exit(-2);
++ PrefixList tExcludePathPrefix = null;
++ if (args.length == 4) {
++ tExcludePathPrefix = new PrefixList(args[3], ";");
++ } else {
++ tExcludePathPrefix = new PrefixList(null);
+ }
+
++ getInfo(TachyonFS.get(args[0]), args[1], args[2], tExcludePathPrefix);
+ System.exit(0);
+ }
+-
+- public static void printUsage() {
+- String cmd =
+- "java -cp target/tachyon-" + Version.VERSION + "-jar-with-dependencies.jar "
+- + "tachyon.util.UnderfsUtil ";
+-
+- System.out.println("Usage: " + cmd + "<TachyonPath> <UnderfsPath> "
+- + "[<Optional ExcludePathPrefix, separated by ;>]");
+- System.out
+- .println("Example: " + cmd + "tachyon://127.0.0.1:19998/a hdfs://localhost:9000/b c");
+- System.out.println("Example: " + cmd + "tachyon://127.0.0.1:19998/a file:///b c");
+- System.out.println("Example: " + cmd + "tachyon://127.0.0.1:19998/a /b c");
+- System.out.print("In the TFS, all files under local FS /b will be registered under /a, ");
+- System.out.println("except for those with prefix c");
+- }
+ }
+diff --git a/main/src/main/java/tachyon/web/WebInterfaceBrowseServlet.java b/main/src/main/java/tachyon/web/WebInterfaceBrowseServlet.java
+index 6b1917a..c0d0ebf 100644
+--- a/main/src/main/java/tachyon/web/WebInterfaceBrowseServlet.java
++++ b/main/src/main/java/tachyon/web/WebInterfaceBrowseServlet.java
+@@ -363,8 +363,9 @@ public class WebInterfaceBrowseServlet extends HttpServlet {
+ String currentPath = Constants.PATH_SEPARATOR;
+ pathInfos[0] = new UiFileInfo(mMasterInfo.getClientFileInfo(currentPath));
+ for (int i = 1; i < splitPath.length - 1; i ++) {
+- currentPath = CommonUtils.concat(currentPath, splitPath[i]);
++ currentPath = currentPath + splitPath[i];
+ pathInfos[i] = new UiFileInfo(mMasterInfo.getClientFileInfo(currentPath));
++ currentPath = currentPath + Constants.PATH_SEPARATOR;
+ }
+ request.setAttribute("pathInfos", pathInfos);
+ return;
+diff --git a/main/src/main/java/tachyon/web/WebInterfaceDependencyServlet.java b/main/src/main/java/tachyon/web/WebInterfaceDependencyServlet.java
+index d7474bb..787e981 100644
+--- a/main/src/main/java/tachyon/web/WebInterfaceDependencyServlet.java
++++ b/main/src/main/java/tachyon/web/WebInterfaceDependencyServlet.java
+@@ -35,10 +35,10 @@ public class WebInterfaceDependencyServlet extends HttpServlet {
+ try {
+ ClientDependencyInfo dependencyInfo = mMasterInfo.getClientDependencyInfo(dependencyId);
+ for (int pId : dependencyInfo.parents) {
+- parentFileNames.add(mMasterInfo.getPath(pId));
++ parentFileNames.add(mMasterInfo.getFileNameById(pId));
+ }
+ for (int cId : dependencyInfo.children) {
+- childrenFileNames.add(mMasterInfo.getPath(cId));
++ childrenFileNames.add(mMasterInfo.getFileNameById(cId));
+ }
+ } catch (DependencyDoesNotExistException ddnee) {
+ request.setAttribute("error", ddnee.getMessage());
+diff --git a/main/src/main/java/tachyon/worker/DataServerMessage.java b/main/src/main/java/tachyon/worker/DataServerMessage.java
+index de01bb3..04b6a06 100644
+--- a/main/src/main/java/tachyon/worker/DataServerMessage.java
++++ b/main/src/main/java/tachyon/worker/DataServerMessage.java
+@@ -77,7 +77,7 @@ public class DataServerMessage {
+ throw new IOException("Length can not be negative except -1: " + len);
+ }
+
+- String filePath = CommonUtils.concat(WorkerConf.get().DATA_FOLDER, blockId);
++ String filePath = WorkerConf.get().DATA_FOLDER + Constants.PATH_SEPARATOR + blockId;
+ ret.LOG.info("Try to response remote requst by reading from " + filePath);
+ RandomAccessFile file = new RandomAccessFile(filePath, "r");
+
+diff --git a/main/src/main/java/tachyon/worker/WorkerStorage.java b/main/src/main/java/tachyon/worker/WorkerStorage.java
+index d0e089f..a02fdf3 100644
+--- a/main/src/main/java/tachyon/worker/WorkerStorage.java
++++ b/main/src/main/java/tachyon/worker/WorkerStorage.java
+@@ -174,8 +174,9 @@ public class WorkerStorage {
+
+ // TODO checkpoint process. In future, move from midPath to dstPath should be done by
+ // master
+- String midPath = CommonUtils.concat(mUnderfsWorkerDataFolder, fileId);
+- String dstPath = CommonUtils.concat(CommonConf.get().UNDERFS_DATA_FOLDER, fileId);
++ String midPath = mUnderfsWorkerDataFolder + Constants.PATH_SEPARATOR + fileId;
++ String dstPath =
++ CommonConf.get().UNDERFS_DATA_FOLDER + Constants.PATH_SEPARATOR + fileId;
+ LOG.info("Thread " + ID + " is checkpointing file " + fileId + " from "
+ + mLocalDataFolder.toString() + " to " + midPath + " to " + dstPath);
+
+@@ -196,7 +197,8 @@ public class WorkerStorage {
+ long fileSizeByte = 0;
+ for (int k = 0; k < fileInfo.blockIds.size(); k ++) {
+ File tempFile =
+- new File(CommonUtils.concat(mLocalDataFolder.toString(), fileInfo.blockIds.get(k)));
++ new File(mLocalDataFolder.toString() + Constants.PATH_SEPARATOR
++ + fileInfo.blockIds.get(k));
+ fileSizeByte += tempFile.length();
+ InputStream is = new FileInputStream(tempFile);
+ byte[] buf = new byte[16 * Constants.KB];
+@@ -313,7 +315,8 @@ public class WorkerStorage {
+ mLocalDataFolder = new File(dataFolder);
+ mLocalUserFolder =
+ new File(mLocalDataFolder.toString(), WorkerConf.get().USER_TEMP_RELATIVE_FOLDER);
+- mUnderfsWorkerFolder = CommonUtils.concat(COMMON_CONF.UNDERFS_WORKERS_FOLDER, mWorkerId);
++ mUnderfsWorkerFolder =
++ COMMON_CONF.UNDERFS_WORKERS_FOLDER + Constants.PATH_SEPARATOR + mWorkerId;
+ mUnderfsWorkerDataFolder = mUnderfsWorkerFolder + "/data";
+ mUnderFs = UnderFileSystem.get(COMMON_CONF.UNDERFS_ADDRESS);
+ mUsers = new Users(mLocalUserFolder.toString(), mUnderfsWorkerFolder);
+@@ -359,8 +362,8 @@ public class WorkerStorage {
+ public void addCheckpoint(long userId, int fileId) throws FileDoesNotExistException,
+ SuspectedFileSizeException, FailedToCheckpointException, BlockInfoException, TException {
+ // TODO This part need to be changed.
+- String srcPath = CommonUtils.concat(getUserUnderfsTempFolder(userId), fileId);
+- String dstPath = CommonUtils.concat(COMMON_CONF.UNDERFS_DATA_FOLDER, fileId);
++ String srcPath = getUserUnderfsTempFolder(userId) + Constants.PATH_SEPARATOR + fileId;
++ String dstPath = COMMON_CONF.UNDERFS_DATA_FOLDER + Constants.PATH_SEPARATOR + fileId;
+ try {
+ if (!mUnderFs.rename(srcPath, dstPath)) {
+ throw new FailedToCheckpointException("Failed to rename " + srcPath + " to " + dstPath);
+@@ -403,8 +406,8 @@ public class WorkerStorage {
+
+ public void cacheBlock(long userId, long blockId) throws FileDoesNotExistException,
+ SuspectedFileSizeException, BlockInfoException, TException {
+- File srcFile = new File(CommonUtils.concat(getUserTempFolder(userId), blockId));
+- File dstFile = new File(CommonUtils.concat(mLocalDataFolder, blockId));
++ File srcFile = new File(getUserTempFolder(userId) + Constants.PATH_SEPARATOR + blockId);
++ File dstFile = new File(mLocalDataFolder + Constants.PATH_SEPARATOR + blockId);
+ long fileSizeBytes = srcFile.length();
+ if (!srcFile.exists()) {
+ throw new FileDoesNotExistException("File " + srcFile + " does not exist.");
+@@ -453,21 +456,21 @@ public class WorkerStorage {
+ * The block to be removed.
+ * @return Removed file size in bytes.
+ */
+- private long freeBlock(long blockId) {
++ private synchronized long freeBlock(long blockId) {
+ Long freedFileBytes = null;
+- synchronized (mLatestBlockAccessTimeMs) {
+- if (mBlockSizes.containsKey(blockId)) {
+- mWorkerSpaceCounter.returnUsedBytes(mBlockSizes.get(blockId));
+- File srcFile = new File(CommonUtils.concat(mLocalDataFolder, blockId));
+- srcFile.delete();
++ if (mBlockSizes.containsKey(blockId)) {
++ mWorkerSpaceCounter.returnUsedBytes(mBlockSizes.get(blockId));
++ File srcFile = new File(mLocalDataFolder + Constants.PATH_SEPARATOR + blockId);
++ srcFile.delete();
++ synchronized (mLatestBlockAccessTimeMs) {
+ mLatestBlockAccessTimeMs.remove(blockId);
+ freedFileBytes = mBlockSizes.remove(blockId);
+ mRemovedBlockList.add(blockId);
+ mMemoryData.remove(blockId);
+- LOG.info("Removed Data " + blockId);
+- } else {
+- LOG.warn("File " + blockId + " does not exist in memory.");
+ }
++ LOG.info("Removed Data " + blockId);
++ } else {
++ LOG.warn("File " + blockId + " does not exist in memory.");
+ }
+
+ return freedFileBytes == null ? 0 : freedFileBytes;
+@@ -705,7 +708,7 @@ public class WorkerStorage {
+ RandomAccessFile localFile = new RandomAccessFile(file, "r");
+ ByteBuffer buf = localFile.getChannel().map(MapMode.READ_ONLY, 0, file.length());
+
+- String ufsOrphanBlock = CommonUtils.concat(mUnderfsOrphansFolder, blockId);
++ String ufsOrphanBlock = mUnderfsOrphansFolder + Constants.PATH_SEPARATOR + blockId;
+ OutputStream os = mUnderFs.create(ufsOrphanBlock);
+ int BULKSIZE = 1024 * 64;
+ byte[] bulk = new byte[BULKSIZE];
+diff --git a/main/src/main/webapp/browse.jsp b/main/src/main/webapp/browse.jsp
+index d73a10e..5281511 100644
+--- a/main/src/main/webapp/browse.jsp
++++ b/main/src/main/webapp/browse.jsp
+@@ -1,7 +1,5 @@
+ <%@ page import="java.util.*" %>
+ <%@ page import="tachyon.web.*" %>
+-<%@ page import="static org.apache.commons.lang.StringEscapeUtils.escapeHtml" %>
+-<%@ page import="static java.net.URLEncoder.encode" %>
+
+ <html>
+ <head>
+@@ -35,11 +33,11 @@
+ <ul class="nav nav-pills">
+ <% if (request.getAttribute("pathInfos") != null) { %>
+ <% for (WebInterfaceBrowseServlet.UiFileInfo pathInfo : ((WebInterfaceBrowseServlet.UiFileInfo[]) request.getAttribute("pathInfos"))) { %>
+- <li><a href="./browse?path=<%= encode(pathInfo.getAbsolutePath(), "UTF-8") %>"><%= escapeHtml(pathInfo.getName()) %> </a></li>
++ <li><a href="./browse?path=<%= pathInfo.getAbsolutePath() %>"><%= pathInfo.getName() %> </a></li>
+ <% } %>
+ <% } %>
+ <% if (request.getAttribute("currentDirectory") != null) { %>
+- <li class="active"><a href="./browse?path=<%= encode(request.getAttribute("currentPath").toString(), "UTF-8") %>"><%= escapeHtml(((WebInterfaceBrowseServlet.UiFileInfo) request.getAttribute("currentDirectory")).getName()) %></a></li>
++ <li class="active"><a href="./browse?path=<%= request.getAttribute("currentPath") %>"><%= ((WebInterfaceBrowseServlet.UiFileInfo) request.getAttribute("currentDirectory")).getName() %></a></li>
+ <% } %>
+ </ul>
+ </div>
+@@ -115,7 +113,7 @@
+ <% if (!fileInfo.getIsDirectory()) { %>
+ <i class="icon-file"></i>
+ <% } %>
+- <a href="./browse?path=<%=encode(fileInfo.getAbsolutePath(), "UTF-8")%>"><%= escapeHtml(fileInfo.getName()) %></a>
++ <a href="./browse?path=<%=fileInfo.getAbsolutePath()%>"><%= fileInfo.getName() %></a>
+ </th>
+ <th><%= fileInfo.getSize() %></th>
+ <th><%= fileInfo.getBlockSizeBytes() %></th>
+diff --git a/main/src/main/webapp/viewFile.jsp b/main/src/main/webapp/viewFile.jsp
+index 2eb564e..31ce58b 100644
+--- a/main/src/main/webapp/viewFile.jsp
++++ b/main/src/main/webapp/viewFile.jsp
+@@ -1,7 +1,5 @@
+ <%@ page import="java.util.*" %>
+ <%@ page import="tachyon.web.*" %>
+-<%@ page import="static org.apache.commons.lang.StringEscapeUtils.escapeHtml" %>
+-<%@ page import="static java.net.URLEncoder.encode" %>
+
+ <html>
+ <head>
+@@ -17,7 +15,7 @@
+ function displayContent()
+ {
+ var tmp = document.getElementById("offset").value;
+- window.location.href = "./browse?path=<%= encode(request.getAttribute("currentPath").toString(), "UTF-8") %>&offset=" + tmp;
++ window.location.href = "./browse?path=<%= request.getAttribute("currentPath") %>&offset=" + tmp;
+ }
+ </script>
+ <div class="container-fluid">
+@@ -38,7 +36,7 @@
+ <h1 class="text-error">
+ <%= request.getAttribute("invalidPathError") %>
+ </h1>
+- <h4><%= escapeHtml(request.getAttribute("currentPath").toString()) %>: First 5KB from <%= request.getAttribute("viewingOffset") %> in ASCII</h4>
++ <h4><%= request.getAttribute("currentPath") %>: First 5KB from <%= request.getAttribute("viewingOffset") %> in ASCII</h4>
+ <textarea class="file-content"><%= request.getAttribute("fileData") %></textarea>
+ </div>
+ </div>
+diff --git a/main/src/test/java/tachyon/PrefixListTest.java b/main/src/test/java/tachyon/PrefixListTest.java
+index 3b31644..8d06b0d 100644
+--- a/main/src/test/java/tachyon/PrefixListTest.java
++++ b/main/src/test/java/tachyon/PrefixListTest.java
+@@ -83,19 +83,4 @@ public final class PrefixListTest {
+ Assert.assertTrue(prefixList.outList(""));
+ Assert.assertTrue(prefixList.outList(null));
+ }
+-
+- @Test
+- public void toStringTest() {
+- PrefixList prefixList = new PrefixList("", ";");
+- Assert.assertEquals(prefixList.toString(), ";");
+-
+- prefixList = new PrefixList(";", ";");
+- Assert.assertEquals(prefixList.toString(), "");
+-
+- prefixList = new PrefixList("a/b;c", ";");
+- Assert.assertEquals(prefixList.toString(), "a/b;c;");
+-
+- prefixList = new PrefixList("a/b;c;", ";");
+- Assert.assertEquals(prefixList.toString(), "a/b;c;");
+- }
+ }
+diff --git a/main/src/test/java/tachyon/UnderFileSystemCluster.java b/main/src/test/java/tachyon/UnderFileSystemCluster.java
+index 2ca049e..387283e 100644
+--- a/main/src/test/java/tachyon/UnderFileSystemCluster.java
++++ b/main/src/test/java/tachyon/UnderFileSystemCluster.java
+@@ -109,7 +109,7 @@ public abstract class UnderFileSystemCluster {
+ String path = getUnderFilesystemAddress() + Constants.PATH_SEPARATOR;
+ UnderFileSystem ufs = UnderFileSystem.get(path);
+ for (String p : ufs.list(path)) {
+- ufs.delete(CommonUtils.concat(path, p), true);
++ ufs.delete(path + p, true);
+ }
+ }
+ }
+diff --git a/main/src/test/java/tachyon/UnderFileSystemTest.java b/main/src/test/java/tachyon/UnderFileSystemTest.java
+deleted file mode 100644
+index 087694e..0000000
+--- a/main/src/test/java/tachyon/UnderFileSystemTest.java
++++ /dev/null
+@@ -1,67 +0,0 @@
+-/*
+- * 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 tachyon;
+-
+-import org.junit.Assert;
+-import org.junit.Test;
+-
+-/**
+- * Unit tests for {@link UnderFileSystem}
+- */
+-public final class UnderFileSystemTest {
+-
+- @Test
+- public void parseTest() {
+- Pair<String, String> result = UnderFileSystem.parse("/path");
+- Assert.assertEquals(result.getFirst(), "/");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("file:///path");
+- Assert.assertEquals(result.getFirst(), "/");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("tachyon://localhost:19998");
+- Assert.assertEquals(result.getFirst(), "tachyon://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/");
+-
+- result = UnderFileSystem.parse("tachyon://localhost:19998/");
+- Assert.assertEquals(result.getFirst(), "tachyon://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/");
+-
+- result = UnderFileSystem.parse("tachyon://localhost:19998/path");
+- Assert.assertEquals(result.getFirst(), "tachyon://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("tachyon-ft://localhost:19998/path");
+- Assert.assertEquals(result.getFirst(), "tachyon-ft://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("hdfs://localhost:19998/path");
+- Assert.assertEquals(result.getFirst(), "hdfs://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("s3://localhost:19998/path");
+- Assert.assertEquals(result.getFirst(), "s3://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- result = UnderFileSystem.parse("s3n://localhost:19998/path");
+- Assert.assertEquals(result.getFirst(), "s3n://localhost:19998");
+- Assert.assertEquals(result.getSecond(), "/path");
+-
+- Assert.assertEquals(UnderFileSystem.parse(null), null);
+- Assert.assertEquals(UnderFileSystem.parse(""), null);
+- Assert.assertEquals(UnderFileSystem.parse("anythingElse"), null);
+- }
+-}
+diff --git a/main/src/test/java/tachyon/client/TachyonFSTest.java b/main/src/test/java/tachyon/client/TachyonFSTest.java
+index ab54ff8..f99afb5 100644
+--- a/main/src/test/java/tachyon/client/TachyonFSTest.java
++++ b/main/src/test/java/tachyon/client/TachyonFSTest.java
+@@ -338,13 +338,6 @@ public class TachyonFSTest {
+ }
+
+ @Test
+- public void toStringTest() throws Exception {
+- String tfsAddress = "tachyon://localhost:19998";
+- TachyonFS tfs = TachyonFS.get(tfsAddress);
+- Assert.assertEquals(tfs.toString(), "tachyon://localhost/127.0.0.1:19998");
+- }
+-
+- @Test
+ public void unlockBlockTest1() throws IOException {
+ TachyonFile tFile = null;
+ int numOfFiles = 5;
+diff --git a/main/src/test/java/tachyon/command/TFsShellTest.java b/main/src/test/java/tachyon/command/TFsShellTest.java
+index cb3a05a..a3b887e 100644
+--- a/main/src/test/java/tachyon/command/TFsShellTest.java
++++ b/main/src/test/java/tachyon/command/TFsShellTest.java
+@@ -363,10 +363,10 @@ public class TFsShellTest {
+ Assert.assertTrue(tFile.isDirectory());
+ }
+
+- @Test
++ @Test(expected = IOException.class)
+ public void mkdirExistingTest() throws IOException {
+- Assert.assertEquals(0, mFsShell.mkdir(new String[] { "mkdir", "/testFile1" }));
+- Assert.assertEquals(0, mFsShell.mkdir(new String[] { "mkdir", "/testFile1" }));
++ mFsShell.mkdir(new String[] { "mkdir", "/testFile1" });
++ mFsShell.mkdir(new String[] { "mkdir", "/testFile1" });
+ }
+
+ @Test(expected = IOException.class)
+diff --git a/main/src/test/java/tachyon/hadoop/GlusterFSTest.java b/main/src/test/java/tachyon/hadoop/GlusterFSTest.java
+new file mode 100644
+index 0000000..2ef6a74
+--- /dev/null
++++ b/main/src/test/java/tachyon/hadoop/GlusterFSTest.java
+@@ -0,0 +1,55 @@
++/*
++ * 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 tachyon.hadoop;
++
++import java.io.IOException;
++
++import org.apache.hadoop.fs.glusterfs.*;
++import org.junit.After;
++import org.junit.Before;
++import org.junit.Assert;
++import org.junit.Test;
++
++import tachyon.UnderFileSystem;
++
++/**
++ * Unit tests for <code>tachyon.hadoop.GlusterFS</code>.
++ */
++public class GlusterFSTest {
++ private UnderFileSystem mHcfs = null;
++
++ @After
++ public final void after() throws Exception {
++ System.clearProperty("fs.default.name");
++ System.clearProperty("tachyon.underfs.glusterfs.mapred.system.dir");
++ System.clearProperty("tachyon.underfs.glusterfs.mounts");
++ System.clearProperty("tachyon.underfs.glusterfs.volumes");
++ }
++
++ @Before
++ public final void before() throws IOException {
++ System.setProperty("fs.default.name", "glusterfs:///");
++ System.setProperty("tachyon.underfs.glusterfs.mapred.system.dir", "glusterfs:///mapred/system");
++ System.setProperty("tachyon.underfs.glusterfs.mounts", "/vol");
++ System.setProperty("tachyon.underfs.glusterfs.volumes", "tachyon_vol");
++ }
++ @Test
++ public void createGlusterFS() throws Exception {
++ mHcfs = UnderFileSystem.get("glusterfs:///");
++
++ Assert.assertTrue(mHcfs.create("tachyon_test") != null);
++ Assert.assertTrue(mHcfs.delete("tachyon_test", false));
++ }
++}
+diff --git a/main/src/test/java/tachyon/hadoop/HadoopCompatibleFSTest.java b/main/src/test/java/tachyon/hadoop/HadoopCompatibleFSTest.java
+new file mode 100644
+index 0000000..359ee97
+--- /dev/null
++++ b/main/src/test/java/tachyon/hadoop/HadoopCompatibleFSTest.java
+@@ -0,0 +1,59 @@
++/*
++ * 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 tachyon.hadoop;
++
++import java.io.IOException;
++
++// import org.apache.hadoop.conf.Configuration;
++// import org.apache.hadoop.fs.FileSystem;
++// import org.apache.hadoop.hdfs.DistributedFileSystem;
++// import org.apache.hadoop.hdfs.MiniDFSCluster;
++// import org.apache.hadoop.hdfs.server.common.HdfsConstants.StartupOption;
++import org.junit.After;
++import org.junit.Before;
++import tachyon.client.TachyonFS;
++import tachyon.master.LocalTachyonCluster;
++
++/**
++ * Unit tests for <code>tachyon.hadoop.HadoopCompatibleFS</code>.
++ */
++public class HadoopCompatibleFSTest {
++ private LocalTachyonCluster mLocalTachyonCluster = null;
++ private TachyonFS mTfs = null;
++
++ // private MiniDFSCluster mDfsCluster = null;
++ // private DistributedFileSystem mDfs = null;
++
++ @After
++ public final void after() throws Exception {
++ mLocalTachyonCluster.stop();
++ System.clearProperty("tachyon.user.quota.unit.bytes");
++ }
++
++ @Before
++ public final void before() throws IOException {
++ System.setProperty("tachyon.user.quota.unit.bytes", "1000");
++ mLocalTachyonCluster = new LocalTachyonCluster(10000);
++ mLocalTachyonCluster.start();
++ mTfs = mLocalTachyonCluster.getClient();
++
++ // Configuration conf = new Configuration();
++ // System.setProperty("fs.default.name", "hdfs://localhost:54310");
++ // mDfsCluster = new MiniDFSCluster();
++ // FileSystem fs = mDfsCluster.getFileSystem();
++ // Assert.assertTrue("Not a HDFS: "+fs.getUri(), fs instanceof DistributedFileSystem);
++ // mDfs = (DistributedFileSystem) fs;
++ }
++}
+diff --git a/main/src/test/java/tachyon/master/InodeFolderTest.java b/main/src/test/java/tachyon/master/InodeFolderTest.java
+index 3009032..4b5ea94 100644
+--- a/main/src/test/java/tachyon/master/InodeFolderTest.java
++++ b/main/src/test/java/tachyon/master/InodeFolderTest.java
+@@ -31,10 +31,8 @@ public class InodeFolderTest {
+ @Test
+ public void addChildrenTest() {
+ InodeFolder inodeFolder = new InodeFolder("testFolder1", 1, 0, System.currentTimeMillis());
+- InodeFile inodeFile1 = new InodeFile("testFile1", 2, 1, 1000, System.currentTimeMillis());
+- InodeFile inodeFile2 = new InodeFile("testFile2", 3, 1, 1000, System.currentTimeMillis());
+- inodeFolder.addChild(inodeFile1);
+- inodeFolder.addChild(inodeFile2);
++ inodeFolder.addChild(2);
++ inodeFolder.addChild(3);
+ Assert.assertEquals(2, (int) inodeFolder.getChildrenIds().get(0));
+ Assert.assertEquals(3, (int) inodeFolder.getChildrenIds().get(1));
+ }
+@@ -44,12 +42,14 @@ public class InodeFolderTest {
+ InodeFolder inodeFolder = new InodeFolder("testFolder1", 1, 0, System.currentTimeMillis());
+ InodeFile inodeFile1 = new InodeFile("testFile1", 2, 1, 1000, System.currentTimeMillis());
+ InodeFile inodeFile2 = new InodeFile("testFile2", 3, 1, 1000, System.currentTimeMillis());
+- InodeFile inodeFile3 = new InodeFile("testFile3", 4, 1, 1000, System.currentTimeMillis());
+- inodeFolder.addChild(inodeFile1);
+- inodeFolder.addChild(inodeFile2);
+- inodeFolder.addChild(inodeFile3);
++ inodeFolder.addChild(2);
++ inodeFolder.addChild(3);
++ inodeFolder.addChild(4);
++ Map<Integer, Inode> testMap = new HashMap<Integer, Inode>(2);
++ testMap.put(2, inodeFile1);
++ testMap.put(3, inodeFile2);
+ Assert.assertEquals(3, inodeFolder.getNumberOfChildren());
+- inodeFolder.removeChild("testFile1");
++ inodeFolder.removeChild("testFile1", testMap);
+ Assert.assertEquals(2, inodeFolder.getNumberOfChildren());
+ Assert.assertFalse(inodeFolder.getChildrenIds().contains(2));
+ }
+@@ -90,21 +90,18 @@ public class InodeFolderTest {
+ @Test
+ public void removeChildTest() {
+ InodeFolder inodeFolder = new InodeFolder("testFolder1", 1, 0, System.currentTimeMillis());
+- InodeFile inodeFile1 = new InodeFile("testFile1", 2, 1, 1000, System.currentTimeMillis());
+- inodeFolder.addChild(inodeFile1);
++ inodeFolder.addChild(2);
+ Assert.assertEquals(1, inodeFolder.getNumberOfChildren());
+- inodeFolder.removeChild(inodeFile1);
++ inodeFolder.removeChild(2);
+ Assert.assertEquals(0, inodeFolder.getNumberOfChildren());
+ }
+
+ @Test
+ public void removeNonExistentChildTest() {
+ InodeFolder inodeFolder = new InodeFolder("testFolder1", 1, 0, System.currentTimeMillis());
+- InodeFile inodeFile1 = new InodeFile("testFile1", 2, 1, 1000, System.currentTimeMillis());
+- InodeFile inodeFile2 = new InodeFile("testFile2", 3, 1, 1000, System.currentTimeMillis());
+- inodeFolder.addChild(inodeFile1);
++ inodeFolder.addChild(2);
+ Assert.assertEquals(1, inodeFolder.getNumberOfChildren());
+- inodeFolder.removeChild(inodeFile2);
++ inodeFolder.removeChild(3);
+ Assert.assertEquals(1, inodeFolder.getNumberOfChildren());
+ }
+
+@@ -118,9 +115,8 @@ public class InodeFolderTest {
+ @Test
+ public void sameIdChildrenTest() {
+ InodeFolder inodeFolder = new InodeFolder("testFolder1", 1, 0, System.currentTimeMillis());
+- InodeFile inodeFile1 = new InodeFile("testFile1", 2, 1, 1000, System.currentTimeMillis());
+- inodeFolder.addChild(inodeFile1);
+- inodeFolder.addChild(inodeFile1);
++ inodeFolder.addChild(2);
++ inodeFolder.addChild(2);
+ Assert.assertTrue(inodeFolder.getChildrenIds().get(0) == 2);
+ Assert.assertEquals(1, inodeFolder.getNumberOfChildren());
+ }
+diff --git a/main/src/test/java/tachyon/util/CommonUtilsTest.java b/main/src/test/java/tachyon/util/CommonUtilsTest.java
+index b8bb69b..b4154b2 100644
+--- a/main/src/test/java/tachyon/util/CommonUtilsTest.java
++++ b/main/src/test/java/tachyon/util/CommonUtilsTest.java
+@@ -52,12 +52,5 @@ public class CommonUtilsTest {
+ Assert.assertEquals(k * Constants.TB / 10, CommonUtils.parseMemorySize(k / 10.0 + "TB"));
+ Assert.assertEquals(k * Constants.TB / 10, CommonUtils.parseMemorySize(k / 10.0 + "tB"));
+ }
+- // We stop the pb test before 8192, since 8192 petabytes is beyond the scope of a java long.
+- for (long k = 0; k < 8192; k ++) {
+- Assert.assertEquals(k * Constants.PB / 10, CommonUtils.parseMemorySize(k / 10.0 + "pb"));
+- Assert.assertEquals(k * Constants.PB / 10, CommonUtils.parseMemorySize(k / 10.0 + "Pb"));
+- Assert.assertEquals(k * Constants.PB / 10, CommonUtils.parseMemorySize(k / 10.0 + "PB"));
+- Assert.assertEquals(k * Constants.PB / 10, CommonUtils.parseMemorySize(k / 10.0 + "pB"));
+- }
+ }
+ }
+diff --git a/main/src/test/java/tachyon/util/UnderfsUtilTest.java b/main/src/test/java/tachyon/util/UnderfsUtilTest.java
+index 7a71f3a..860a598 100644
+--- a/main/src/test/java/tachyon/util/UnderfsUtilTest.java
++++ b/main/src/test/java/tachyon/util/UnderfsUtilTest.java
+@@ -31,6 +31,8 @@ import tachyon.UnderFileSystem;
+ import tachyon.UnderFileSystemCluster;
+ import tachyon.client.TachyonFS;
+ import tachyon.master.LocalTachyonCluster;
++import tachyon.util.UnderfsUtil;
++import tachyon.util.CommonUtils;
+
+ /**
+ * To test the utilities related to under filesystem, including loadufs and etc.
+@@ -62,7 +64,7 @@ public class UnderfsUtilTest {
+ }
+
+ @Test
+- public void loadUnderFsTest() throws IOException {
++ public void getInfoTest() throws IOException {
+ if (!UnderFileSystemCluster.isUFSHDFS()) {
+ return;
+ }
+@@ -82,8 +84,8 @@ public class UnderfsUtilTest {
+ CommonUtils.touch(mUnderfsAddress + inclusion + "/1");
+ }
+
+- UnderfsUtil.loadUnderFs(mTfs, Constants.PATH_SEPARATOR, mUnderfsAddress
+- + Constants.PATH_SEPARATOR, new PrefixList(Arrays.asList(exclusions)));
++ UnderfsUtil.getInfo(mTfs, mUnderfsAddress, Constants.PATH_SEPARATOR,
++ new PrefixList(Arrays.asList(exclusions)));
+
+ List<String> paths = null;
+ for (String exclusion : exclusions) {
+diff --git a/pom.xml b/pom.xml
+index c74d6bb..767fbaf 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -70,6 +70,16 @@
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
++ <repository>
++ <id>glusterfs-hadoop-repo</id>
++ <url>http://rhbd.s3.amazonaws.com/maven/repositories/internal/</url>
++ <releases>
++ <enabled>true</enabled>
++ </releases>
++ <snapshots>
++ <enabled>false</enabled>
++ </snapshots>
++ </repository>
+ </repositories>
+
+ <pluginRepositories>
More information about the scm-commits
mailing list