blob: 4d6840449864ea7045ab9f50e8d5e681320533d5 [file] [log] [blame]
/**
* Copyright 2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.dfs;
import org.apache.hadoop.io.*;
import java.io.*;
import java.util.*;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
/*************************************************
* FSDirectory stores the filesystem directory state.
* It handles writing/loading values to disk, and logging
* changes as we go.
*
* It keeps the filename->blockset mapping always-current
* and logged to disk.
*
* @author Mike Cafarella
*************************************************/
class FSDirectory implements FSConstants {
private static final String FS_IMAGE = "fsimage";
private static final String NEW_FS_IMAGE = "fsimage.new";
private static final String OLD_FS_IMAGE = "fsimage.old";
private static final byte OP_ADD = 0;
private static final byte OP_RENAME = 1;
private static final byte OP_DELETE = 2;
private static final byte OP_MKDIR = 3;
private static final byte OP_SET_REPLICATION = 4;
/******************************************************
* We keep an in-memory representation of the file/block
* hierarchy.
******************************************************/
class INode {
private String name;
private INode parent;
private TreeMap children = new TreeMap();
private Block blocks[];
private short blockReplication;
/**
*/
INode(String name, Block blocks[], short replication) {
this.name = name;
this.parent = null;
this.blocks = blocks;
this.blockReplication = replication;
}
/**
*/
INode(String name) {
this.name = name;
this.parent = null;
this.blocks = null;
this.blockReplication = 0;
}
/**
* Check whether it's a directory
*/
synchronized public boolean isDir() {
return (blocks == null);
}
/**
* Get block replication for the file
* @return block replication
*/
public short getReplication() {
return this.blockReplication;
}
/**
* This is the external interface
*/
INode getNode(String target) {
if ( target == null ||
! target.startsWith("/") || target.length() == 0) {
return null;
} else if (parent == null && "/".equals(target)) {
return this;
} else {
Vector components = new Vector();
int start = 0;
int slashid = 0;
while (start < target.length() && (slashid = target.indexOf('/', start)) >= 0) {
components.add(target.substring(start, slashid));
start = slashid + 1;
}
if (start < target.length()) {
components.add(target.substring(start));
}
return getNode(components, 0);
}
}
/**
*/
INode getNode(Vector components, int index) {
if (! name.equals((String) components.elementAt(index))) {
return null;
}
if (index == components.size()-1) {
return this;
}
// Check with children
INode child = this.getChild((String)components.elementAt(index+1));
if (child == null) {
return null;
} else {
return child.getNode(components, index+1);
}
}
INode getChild( String name) {
return (INode) children.get( name );
}
/**
* Add new INode to the file tree.
* Find the parent and insert
*
* @param path file path
* @param newNode INode to be added
* @return null if the node already exists; inserted INode, otherwise
* @throws FileNotFoundException
* @author shv
*/
INode addNode(String path, INode newNode) throws FileNotFoundException {
File target = new File( path );
// find parent
Path parent = new Path(path).getParent();
if (parent == null) { // add root
return null;
}
INode parentNode = getNode(parent.toString());
if (parentNode == null) {
throw new FileNotFoundException(
"Parent path does not exist: "+path);
}
// check whether the parent already has a node with that name
String name = newNode.name = target.getName();
if( parentNode.getChild( name ) != null )
return null;
// insert into the parent children list
parentNode.children.put(name, newNode);
newNode.parent = parentNode;
return newNode;
}
/**
*/
boolean removeNode() {
if (parent == null) {
return false;
} else {
parent.children.remove(name);
return true;
}
}
/**
* Collect all the blocks at this INode and all its children.
* This operation is performed after a node is removed from the tree,
* and we want to GC all the blocks at this node and below.
*/
void collectSubtreeBlocks(Vector v) {
if (blocks != null) {
for (int i = 0; i < blocks.length; i++) {
v.add(blocks[i]);
}
}
for (Iterator it = children.values().iterator(); it.hasNext(); ) {
INode child = (INode) it.next();
child.collectSubtreeBlocks(v);
}
}
/**
*/
int numItemsInTree() {
int total = 0;
for (Iterator it = children.values().iterator(); it.hasNext(); ) {
INode child = (INode) it.next();
total += child.numItemsInTree();
}
return total + 1;
}
/**
*/
String computeName() {
if (parent != null) {
return parent.computeName() + "/" + name;
} else {
return name;
}
}
/**
*/
long computeFileLength() {
long total = 0;
if (blocks != null) {
for (int i = 0; i < blocks.length; i++) {
total += blocks[i].getNumBytes();
}
}
return total;
}
/**
*/
long computeContentsLength() {
long total = computeFileLength();
for (Iterator it = children.values().iterator(); it.hasNext(); ) {
INode child = (INode) it.next();
total += child.computeContentsLength();
}
return total;
}
/**
* Get the block size of the first block
* @return the number of bytes
*/
public long getBlockSize() {
if (blocks == null || blocks.length == 0) {
return 0;
} else {
return blocks[0].getNumBytes();
}
}
/**
*/
void listContents(Vector v) {
if (parent != null && blocks != null) {
v.add(this);
}
for (Iterator it = children.values().iterator(); it.hasNext(); ) {
INode child = (INode) it.next();
v.add(child);
}
}
/**
*/
void saveImage(String parentPrefix, DataOutputStream out) throws IOException {
String fullName = "";
if (parent != null) {
fullName = parentPrefix + "/" + name;
new UTF8(fullName).write(out);
out.writeShort(blockReplication);
if (blocks == null) {
out.writeInt(0);
} else {
out.writeInt(blocks.length);
for (int i = 0; i < blocks.length; i++) {
blocks[i].write(out);
}
}
}
for (Iterator it = children.values().iterator(); it.hasNext(); ) {
INode child = (INode) it.next();
child.saveImage(fullName, out);
}
}
}
INode rootDir = new INode("");
TreeMap activeBlocks = new TreeMap();
TreeMap activeLocks = new TreeMap();
DataOutputStream editlog = null;
boolean ready = false;
int namespaceID = 0; /// a persistent attribute of the namespace
/** Access an existing dfs name directory. */
public FSDirectory(File dir, Configuration conf) throws IOException {
File fullimage = new File(dir, "image");
if (! fullimage.exists()) {
throw new IOException("NameNode not formatted: " + dir);
}
File edits = new File(dir, "edits");
if (loadFSImage(fullimage, edits, conf)) {
saveFSImage(fullimage, edits);
}
synchronized (this) {
this.ready = true;
this.notifyAll();
this.editlog = new DataOutputStream(new FileOutputStream(edits));
editlog.writeInt( DFS_CURRENT_VERSION );
}
}
/** Create a new dfs name directory. Caution: this destroys all files
* in this filesystem. */
public static void format(File dir, Configuration conf)
throws IOException {
File image = new File(dir, "image");
File edits = new File(dir, "edits");
if (!((!image.exists() || FileUtil.fullyDelete(image)) &&
(!edits.exists() || edits.delete()) &&
image.mkdirs())) {
throw new IOException("Unable to format: "+dir);
}
}
/**
* Generate new namespaceID.
*
* namespaceID is a persistent attribute of the namespace.
* It is generated when the namenode is formatted and remains the same
* during the life cycle of the namenode.
* When a datanodes register they receive it as the registrationID,
* which is checked every time the datanode is communicating with the
* namenode. Datanodes that do not 'know' the namespaceID are rejected.
*
* @return new namespaceID
*/
private int newNamespaceID() {
Random r = new Random();
r.setSeed( System.currentTimeMillis() );
int newID = 0;
while( newID == 0)
newID = r.nextInt();
return newID;
}
/**
* Shutdown the filestore
*/
public void close() throws IOException {
editlog.close();
}
/**
* Block until the object is ready to be used.
*/
void waitForReady() {
if (! ready) {
synchronized (this) {
while (!ready) {
try {
this.wait(5000);
} catch (InterruptedException ie) {
}
}
}
}
}
/**
* Load in the filesystem image. It's a big list of
* filenames and blocks. Return whether we should
* "re-save" and consolidate the edit-logs
*/
boolean loadFSImage( File fsdir,
File edits,
Configuration conf
) throws IOException {
//
// Atomic move sequence, to recover from interrupted save
//
File curFile = new File(fsdir, FS_IMAGE);
File newFile = new File(fsdir, NEW_FS_IMAGE);
File oldFile = new File(fsdir, OLD_FS_IMAGE);
// Maybe we were interrupted between 2 and 4
if (oldFile.exists() && curFile.exists()) {
oldFile.delete();
if (edits.exists()) {
edits.delete();
}
} else if (oldFile.exists() && newFile.exists()) {
// Or maybe between 1 and 2
newFile.renameTo(curFile);
oldFile.delete();
} else if (curFile.exists() && newFile.exists()) {
// Or else before stage 1, in which case we lose the edits
newFile.delete();
}
//
// Load in bits
//
boolean needToSave = true;
int imgVersion = DFS_CURRENT_VERSION;
if (curFile.exists()) {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(curFile)));
try {
// read image version: first appeared in version -1
imgVersion = in.readInt();
// read namespaceID: first appeared in version -2
if( imgVersion <= -2 )
namespaceID = in.readInt();
// read number of files
int numFiles = 0;
// version 0 does not store version #
// starts directly with the number of files
if( imgVersion >= 0 ) {
numFiles = imgVersion;
imgVersion = 0;
} else
numFiles = in.readInt();
needToSave = ( imgVersion != DFS_CURRENT_VERSION );
if( imgVersion < DFS_CURRENT_VERSION ) // future version
throw new IOException(
"Unsupported version of the file system image: "
+ imgVersion
+ ". Current version = "
+ DFS_CURRENT_VERSION + "." );
// read file info
short replication = (short)conf.getInt("dfs.replication", 3);
for (int i = 0; i < numFiles; i++) {
UTF8 name = new UTF8();
name.readFields(in);
// version 0 does not support per file replication
if( !(imgVersion >= 0) ) {
replication = in.readShort(); // other versions do
replication = adjustReplication( replication, conf );
}
int numBlocks = in.readInt();
Block blocks[] = null;
if (numBlocks > 0) {
blocks = new Block[numBlocks];
for (int j = 0; j < numBlocks; j++) {
blocks[j] = new Block();
blocks[j].readFields(in);
}
}
unprotectedAddFile(name,
new INode( name.toString(), blocks, replication ));
}
} finally {
in.close();
}
}
if( namespaceID == 0 )
namespaceID = newNamespaceID();
return needToSave || ( edits.exists() && loadFSEdits(edits, conf) > 0 );
}
/**
* Load an edit log, and apply the changes to the in-memory structure
*
* This is where we apply edits that we've been writing to disk all
* along.
*/
int loadFSEdits(File edits, Configuration conf) throws IOException {
int numEdits = 0;
int logVersion = 0;
if (edits.exists()) {
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream(edits)));
// Read log file version. Could be missing.
in.mark( 4 );
if( in.available() > 0 ) {
logVersion = in.readByte();
in.reset();
if( logVersion >= 0 )
logVersion = 0;
else
logVersion = in.readInt();
if( logVersion < DFS_CURRENT_VERSION ) // future version
throw new IOException(
"Unexpected version of the file system log file: "
+ logVersion
+ ". Current version = "
+ DFS_CURRENT_VERSION + "." );
}
short replication = (short)conf.getInt("dfs.replication", 3);
try {
while (in.available() > 0) {
byte opcode = in.readByte();
numEdits++;
switch (opcode) {
case OP_ADD: {
UTF8 name = new UTF8();
ArrayWritable aw = null;
Writable writables[];
// version 0 does not support per file replication
if( logVersion >= 0 )
name.readFields(in); // read name only
else { // other versions do
// get name and replication
aw = new ArrayWritable(UTF8.class);
aw.readFields(in);
writables = aw.get();
if( writables.length != 2 )
throw new IOException("Incorrect data fortmat. "
+ "Name & replication pair expected");
name = (UTF8) writables[0];
replication = Short.parseShort(
((UTF8)writables[1]).toString());
replication = adjustReplication( replication, conf );
}
// get blocks
aw = new ArrayWritable(Block.class);
aw.readFields(in);
writables = aw.get();
Block blocks[] = new Block[writables.length];
System.arraycopy(writables, 0, blocks, 0, blocks.length);
// add to the file tree
unprotectedAddFile(name,
new INode( name.toString(), blocks, replication ));
break;
}
case OP_SET_REPLICATION: {
UTF8 src = new UTF8();
UTF8 repl = new UTF8();
src.readFields(in);
repl.readFields(in);
replication=adjustReplication(
fromLogReplication(repl),
conf);
unprotectedSetReplication(src.toString(),
replication,
null);
break;
}
case OP_RENAME: {
UTF8 src = new UTF8();
UTF8 dst = new UTF8();
src.readFields(in);
dst.readFields(in);
unprotectedRenameTo(src, dst);
break;
}
case OP_DELETE: {
UTF8 src = new UTF8();
src.readFields(in);
unprotectedDelete(src);
break;
}
case OP_MKDIR: {
UTF8 src = new UTF8();
src.readFields(in);
unprotectedMkdir(src.toString());
break;
}
default: {
throw new IOException("Never seen opcode " + opcode);
}
}
}
} finally {
in.close();
}
}
if( logVersion != DFS_CURRENT_VERSION ) // other version
numEdits++; // save this image asap
return numEdits;
}
private static short adjustReplication( short replication, Configuration conf) {
short minReplication = (short)conf.getInt("dfs.replication.min", 1);
if( replication<minReplication ) {
replication = minReplication;
}
short maxReplication = (short)conf.getInt("dfs.replication.max", 512);
if( replication>maxReplication ) {
replication = maxReplication;
}
return replication;
}
/**
* Save the contents of the FS image
*/
void saveFSImage(File fullimage, File edits) throws IOException {
File curFile = new File(fullimage, FS_IMAGE);
File newFile = new File(fullimage, NEW_FS_IMAGE);
File oldFile = new File(fullimage, OLD_FS_IMAGE);
//
// Write out data
//
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(newFile)));
try {
out.writeInt(DFS_CURRENT_VERSION);
out.writeInt(this.namespaceID);
out.writeInt(rootDir.numItemsInTree() - 1);
rootDir.saveImage("", out);
} finally {
out.close();
}
//
// Atomic move sequence
//
// 1. Move cur to old
curFile.renameTo(oldFile);
// 2. Move new to cur
newFile.renameTo(curFile);
// 3. Remove pending-edits file (it's been integrated with newFile)
edits.delete();
// 4. Delete old
oldFile.delete();
}
/**
* Write an operation to the edit log
*/
void logEdit(byte op, Writable w1, Writable w2) {
synchronized (editlog) {
try {
editlog.write(op);
if (w1 != null) {
w1.write(editlog);
}
if (w2 != null) {
w2.write(editlog);
}
} catch (IOException ie) {
}
}
}
/**
* Add the given filename to the fs.
*/
public boolean addFile(UTF8 path, Block[] blocks, short replication) {
waitForReady();
// Always do an implicit mkdirs for parent directory tree
String pathString = path.toString();
mkdirs(new Path(pathString).getParent().toString());
INode newNode = new INode( new File(pathString).getName(), blocks, replication);
if( ! unprotectedAddFile(path, newNode) ) {
NameNode.stateChangeLog.info("DIR* FSDirectory.addFile: "
+"failed to add "+path+" with "
+blocks.length+" blocks to the file system" );
return false;
}
// add create file record to log
UTF8 nameReplicationPair[] = new UTF8[] {
path,
toLogReplication( replication )};
logEdit(OP_ADD,
new ArrayWritable( UTF8.class, nameReplicationPair ),
new ArrayWritable( Block.class, newNode.blocks ));
NameNode.stateChangeLog.debug("DIR* FSDirectory.addFile: "
+path+" with "+blocks.length+" blocks is added to the file system" );
return true;
}
private static UTF8 toLogReplication( short replication ) {
return new UTF8( Short.toString(replication));
}
private static short fromLogReplication( UTF8 replication ) {
return Short.parseShort(replication.toString());
}
/**
*/
boolean unprotectedAddFile(UTF8 path, INode newNode) {
synchronized (rootDir) {
try {
if( rootDir.addNode(path.toString(), newNode ) != null ) {
int nrBlocks = (newNode.blocks == null) ? 0 : newNode.blocks.length;
// Add file->block mapping
for (int i = 0; i < nrBlocks; i++)
activeBlocks.put(newNode.blocks[i], newNode);
return true;
} else {
return false;
}
} catch (FileNotFoundException e ) {
return false;
}
}
}
/**
* Change the filename
*/
public boolean renameTo(UTF8 src, UTF8 dst) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.renameTo: "
+src+" to "+dst );
waitForReady();
if (unprotectedRenameTo(src, dst)) {
logEdit(OP_RENAME, src, dst);
return true;
} else {
return false;
}
}
/**
*/
boolean unprotectedRenameTo(UTF8 src, UTF8 dst) {
synchronized(rootDir) {
String srcStr = src.toString();
String dstStr = dst.toString();
INode renamedNode = rootDir.getNode(srcStr);
if (renamedNode == null) {
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: "
+"failed to rename "+src+" to "+dst+ " because source does not exist" );
return false;
}
if (isDir(dst)) {
dstStr += "/" + new File(srcStr).getName();
}
if( rootDir.getNode(dstStr.toString()) != null ) {
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: "
+"failed to rename "+src+" to "+dstStr+ " because destination exists" );
return false;
}
renamedNode.removeNode();
// the renamed node can be reused now
try {
if( rootDir.addNode(dstStr, renamedNode ) != null ) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedRenameTo: "
+src+" is renamed to "+dst );
return true;
}
} catch (FileNotFoundException e ) {
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedRenameTo: "
+"failed to rename "+src+" to "+dst );
try {
rootDir.addNode(srcStr, renamedNode); // put it back
}catch(FileNotFoundException e2) {
}
}
return false;
}
}
/**
* Set file replication
*
* @param src file name
* @param replication new replication
* @param oldReplication old replication - output parameter
* @return array of file blocks
* @throws IOException
*/
public Block[] setReplication(String src,
short replication,
Vector oldReplication
) throws IOException {
waitForReady();
Block[] fileBlocks = unprotectedSetReplication(src, replication, oldReplication );
if( fileBlocks != null ) //
logEdit(OP_SET_REPLICATION,
new UTF8(src),
toLogReplication( replication ));
return fileBlocks;
}
private Block[] unprotectedSetReplication( String src,
short replication,
Vector oldReplication
) throws IOException {
if( oldReplication == null )
oldReplication = new Vector();
oldReplication.setSize(1);
oldReplication.set( 0, new Integer(-1) );
Block[] fileBlocks = null;
synchronized(rootDir) {
INode fileNode = rootDir.getNode(src);
if (fileNode == null)
return null;
if( fileNode.isDir() )
return null;
oldReplication.set( 0, new Integer( fileNode.blockReplication ));
fileNode.blockReplication = replication;
fileBlocks = fileNode.blocks;
}
return fileBlocks;
}
/**
* Get the blocksize of a file
* @param filename the filename
* @return the number of bytes in the first block
* @throws IOException if it is a directory or does not exist.
*/
public long getBlockSize(String filename) throws IOException {
synchronized (rootDir) {
INode fileNode = rootDir.getNode(filename);
if (fileNode == null) {
throw new IOException("Unknown file: " + filename);
}
if (fileNode.isDir()) {
throw new IOException("Getting block size of a directory: " +
filename);
}
return fileNode.getBlockSize();
}
}
/**
* Remove the file from management, return blocks
*/
public Block[] delete(UTF8 src) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.delete: "
+src );
waitForReady();
Block[] blocks = unprotectedDelete(src);
if( blocks != null )
logEdit(OP_DELETE, src, null);
return blocks;
}
/**
*/
Block[] unprotectedDelete(UTF8 src) {
synchronized (rootDir) {
INode targetNode = rootDir.getNode(src.toString());
if (targetNode == null) {
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedDelete: "
+"failed to remove "+src+" because it does not exist" );
return null;
} else {
//
// Remove the node from the namespace and GC all
// the blocks underneath the node.
//
if (! targetNode.removeNode()) {
NameNode.stateChangeLog.warn("DIR* FSDirectory.unprotectedDelete: "
+"failed to remove "+src+" because it does not have a parent" );
return null;
} else {
NameNode.stateChangeLog.debug("DIR* FSDirectory.unprotectedDelete: "
+src+" is removed" );
Vector v = new Vector();
targetNode.collectSubtreeBlocks(v);
for (Iterator it = v.iterator(); it.hasNext(); ) {
Block b = (Block) it.next();
activeBlocks.remove(b);
}
return (Block[]) v.toArray(new Block[v.size()]);
}
}
}
}
/**
*/
public int obtainLock(UTF8 src, UTF8 holder, boolean exclusive) {
TreeSet holders = (TreeSet) activeLocks.get(src);
if (holders == null) {
holders = new TreeSet();
activeLocks.put(src, holders);
}
if (exclusive && holders.size() > 0) {
return STILL_WAITING;
} else {
holders.add(holder);
return COMPLETE_SUCCESS;
}
}
/**
*/
public int releaseLock(UTF8 src, UTF8 holder) {
TreeSet holders = (TreeSet) activeLocks.get(src);
if (holders != null && holders.contains(holder)) {
holders.remove(holder);
if (holders.size() == 0) {
activeLocks.remove(src);
}
return COMPLETE_SUCCESS;
} else {
return OPERATION_FAILED;
}
}
/**
* Get a listing of files given path 'src'
*
* This function is admittedly very inefficient right now. We'll
* make it better later.
*/
public DFSFileInfo[] getListing(UTF8 src) {
String srcs = normalizePath(src);
synchronized (rootDir) {
INode targetNode = rootDir.getNode(srcs);
if (targetNode == null) {
return null;
} else {
Vector contents = new Vector();
targetNode.listContents(contents);
DFSFileInfo listing[] = new DFSFileInfo[contents.size()];
int i = 0;
for (Iterator it = contents.iterator(); it.hasNext(); i++) {
listing[i] = new DFSFileInfo( (INode) it.next() );
}
return listing;
}
}
}
/**
* Get the blocks associated with the file
*/
public Block[] getFile(UTF8 src) {
waitForReady();
synchronized (rootDir) {
INode targetNode = rootDir.getNode(src.toString());
if (targetNode == null) {
return null;
} else {
return targetNode.blocks;
}
}
}
/**
* Check whether the filepath could be created
*/
public boolean isValidToCreate(UTF8 src) {
String srcs = normalizePath(src);
synchronized (rootDir) {
if (srcs.startsWith("/") &&
! srcs.endsWith("/") &&
rootDir.getNode(srcs) == null) {
return true;
} else {
return false;
}
}
}
/**
* Check whether the path specifies a directory
*/
public boolean isDir(UTF8 src) {
synchronized (rootDir) {
INode node = rootDir.getNode(normalizePath(src));
return node != null && node.isDir();
}
}
/**
* Create the given directory and all its parent dirs.
*/
public boolean mkdirs(UTF8 src) {
return mkdirs(src.toString());
}
/**
* Create directory entries for every item
*/
boolean mkdirs(String src) {
src = normalizePath(new UTF8(src));
// Use this to collect all the dirs we need to construct
Vector v = new Vector();
// The dir itself
v.add(src);
// All its parents
Path parent = new Path(src).getParent();
while (parent != null) {
v.add(parent.toString());
parent = parent.getParent();
}
// Now go backwards through list of dirs, creating along
// the way
int numElts = v.size();
for (int i = numElts - 1; i >= 0; i--) {
String cur = (String) v.elementAt(i);
try {
INode inserted = unprotectedMkdir(cur);
if (inserted != null) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.mkdirs: "
+"created directory "+cur );
logEdit(OP_MKDIR, new UTF8(inserted.computeName()), null);
} // otherwise cur exists, continue
} catch (FileNotFoundException e ) {
NameNode.stateChangeLog.debug("DIR* FSDirectory.mkdirs: "
+"failed to create directory "+src);
return false;
}
}
return true;
}
/**
*/
INode unprotectedMkdir(String src) throws FileNotFoundException {
synchronized (rootDir) {
return rootDir.addNode(src, new INode(new File(src).getName()));
}
}
/**
*/
String normalizePath(UTF8 src) {
String srcs = src.toString();
if (srcs.length() > 1 && srcs.endsWith("/")) {
srcs = srcs.substring(0, srcs.length() - 1);
}
return srcs;
}
/**
* Returns whether the given block is one pointed-to by a file.
*/
public boolean isValidBlock(Block b) {
synchronized (rootDir) {
if (activeBlocks.containsKey(b)) {
return true;
} else {
return false;
}
}
}
/**
* Returns whether the given block is one pointed-to by a file.
*/
public INode getFileByBlock(Block b) {
synchronized (rootDir) {
return (INode)activeBlocks.get(b);
}
}
}