Skip to content

Commit

Permalink
Improve code style and organization
Browse files Browse the repository at this point in the history
  • Loading branch information
gpang committed May 17, 2016
1 parent c4069e3 commit 19b1f64
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 60 deletions.
2 changes: 1 addition & 1 deletion core/common/src/main/java/alluxio/collections/Pair.java
Expand Up @@ -20,7 +20,7 @@
* @param <T2> the second element of the Pair * @param <T2> the second element of the Pair
*/ */
@NotThreadSafe @NotThreadSafe
public final class Pair<T1, T2> { public class Pair<T1, T2> {
private T1 mFirst; private T1 mFirst;
private T2 mSecond; private T2 mSecond;


Expand Down
Expand Up @@ -100,16 +100,16 @@ public enum ExceptionMessage {
HDFS_FILE_NOT_FOUND("File {0} with id {1} is not found"), HDFS_FILE_NOT_FOUND("File {0} with id {1} is not found"),


// file system master // file system master
PATH_MUST_HAVE_VALID_PARENT("{0} does not have a valid parent"),
FILEID_MUST_BE_FILE("File id {0} must be a file"), FILEID_MUST_BE_FILE("File id {0} must be a file"),
RENAME_CANNOT_BE_ONTO_MOUNT_POINT("{0} is a mount point and cannot be renamed onto"), NOT_MUTABLE_INODE_PATH("Not a MutableLockedInodePath: {0}"),
PATH_COMPONENTS_INVALID("parameter pathComponents is {0}"),
PATH_COMPONENTS_INVALID_START("Path starts with {0}"),
PATH_MUST_HAVE_VALID_PARENT("{0} does not have a valid parent"),
RENAME_CANNOT_BE_ACROSS_MOUNTS("Renaming {0} to {1} is a cross mount operation"), RENAME_CANNOT_BE_ACROSS_MOUNTS("Renaming {0} to {1} is a cross mount operation"),
RENAME_CANNOT_BE_ONTO_MOUNT_POINT("{0} is a mount point and cannot be renamed onto"),
RENAME_CANNOT_BE_TO_ROOT("Cannot rename a path to the root directory"), RENAME_CANNOT_BE_TO_ROOT("Cannot rename a path to the root directory"),
RENAME_CANNOT_BE_TO_SUBDIRECTORY("Cannot rename because {0} is a prefix of {1}"), RENAME_CANNOT_BE_TO_SUBDIRECTORY("Cannot rename because {0} is a prefix of {1}"),
ROOT_CANNOT_BE_RENAMED("The root directory cannot be renamed"), ROOT_CANNOT_BE_RENAMED("The root directory cannot be renamed"),
NOT_MUTABLE_INODE_PATH("Not a MutableLockedInodePath: {0}"),
PATH_COMPONENTS_INVALID("parameter pathComponents is {0}"),
PATH_COMPONENTS_INVALID_START("Path starts with {0}"),


// file system master ufs // file system master ufs
FAILED_UFS_CREATE("Failed to create {0} in the under file system"), FAILED_UFS_CREATE("Failed to create {0} in the under file system"),
Expand Down
Expand Up @@ -188,7 +188,7 @@ private List<String> getGroups(String user) throws AccessControlException {
/** /**
* Checks whether the client user is the owner of the path. * Checks whether the client user is the owner of the path.
* *
* @param inodePath to be checked on * @param inodePath path to be checked on
* @throws AccessControlException if permission checking fails * @throws AccessControlException if permission checking fails
* @throws InvalidPathException if the path is invalid * @throws InvalidPathException if the path is invalid
*/ */
Expand Down
22 changes: 18 additions & 4 deletions core/server/src/main/java/alluxio/master/file/meta/Inode.java
Expand Up @@ -271,33 +271,47 @@ public T setUserName(String userName) {
protected abstract T getThis(); protected abstract T getThis();


/** /**
* Lock this inode for reading. * Acquires the read lock for this inode.
*/ */
public void lockRead() { public void lockRead() {
mReadLock.lock(); mReadLock.lock();
} }


/** /**
* Read unlock this inode. * Releases the read lock for this inode.
*/ */
public void unlockRead() { public void unlockRead() {
mReadLock.unlock(); mReadLock.unlock();
} }


/** /**
* Lock this inode for writing/updating. * Acquires the write lock for this inode.
*/ */
public void lockWrite() { public void lockWrite() {
mWriteLock.lock(); mWriteLock.lock();
} }


/** /**
* Write unlock this inode. * Releases the write lock for this inode.
*/ */
public void unlockWrite() { public void unlockWrite() {
mWriteLock.unlock(); mWriteLock.unlock();
} }


/**
* @return returns true if the current thread holds a write lock on this inode, false otherwise
*/
public boolean isWriteLocked() {
return mLock.isWriteLockedByCurrentThread();
}

/**
* @return returns true if the current thread holds a read lock on this inode, false otherwise
*/
public boolean isReadLocked() {
return mLock.getReadHoldCount() > 0;
}

@Override @Override
public int hashCode() { public int hashCode() {
return ((Long) mId).hashCode(); return ((Long) mId).hashCode();
Expand Down
Expand Up @@ -11,6 +11,8 @@


package alluxio.master.file.meta; package alluxio.master.file.meta;


import com.sun.org.apache.regexp.internal.RE;

import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;


Expand All @@ -21,14 +23,12 @@
*/ */
@ThreadSafe @ThreadSafe
public final class InodeLockGroup implements AutoCloseable { public final class InodeLockGroup implements AutoCloseable {
private final List<Inode<?>> mReadLockedInodes;
private final List<Inode<?>> mWriteLockedInodes;
private final List<Inode<?>> mInodes; private final List<Inode<?>> mInodes;
private final List<InodeTree.LockMode> mLockModes;


InodeLockGroup() { InodeLockGroup() {
mReadLockedInodes = new ArrayList<>();
mWriteLockedInodes = new ArrayList<>();
mInodes = new ArrayList<>(); mInodes = new ArrayList<>();
mLockModes = new ArrayList<>();
} }


/** /**
Expand All @@ -38,8 +38,8 @@ public final class InodeLockGroup implements AutoCloseable {
*/ */
public synchronized void lockRead(Inode<?> inode) { public synchronized void lockRead(Inode<?> inode) {
inode.lockRead(); inode.lockRead();
mReadLockedInodes.add(inode);
mInodes.add(inode); mInodes.add(inode);
mLockModes.add(InodeTree.LockMode.READ);
} }


/** /**
Expand All @@ -50,17 +50,11 @@ public synchronized void unlockLast() {
return; return;
} }
Inode<?> inode = mInodes.remove(mInodes.size() - 1); Inode<?> inode = mInodes.remove(mInodes.size() - 1);
if (mReadLockedInodes.size() > 0 && mReadLockedInodes.get(mReadLockedInodes.size() - 1) InodeTree.LockMode lockMode = mLockModes.remove(mLockModes.size() - 1);
.equals(inode)) { if (lockMode == InodeTree.LockMode.READ) {
inode.unlockRead(); inode.unlockRead();
mReadLockedInodes.remove(mReadLockedInodes.size() - 1); } else {
return;
}
if (mWriteLockedInodes.size() > 0 && mWriteLockedInodes.get(mWriteLockedInodes.size() - 1)
.equals(inode)) {
inode.unlockWrite(); inode.unlockWrite();
mWriteLockedInodes.remove(mWriteLockedInodes.size() - 1);
return;
} }
} }


Expand All @@ -71,8 +65,8 @@ public synchronized void unlockLast() {
*/ */
public synchronized void lockWrite(Inode<?> inode) { public synchronized void lockWrite(Inode<?> inode) {
inode.lockWrite(); inode.lockWrite();
mWriteLockedInodes.add(inode);
mInodes.add(inode); mInodes.add(inode);
mLockModes.add(InodeTree.LockMode.WRITE);
} }


/** /**
Expand All @@ -84,14 +78,16 @@ public synchronized List<Inode<?>> getInodes() {


@Override @Override
public synchronized void close() { public synchronized void close() {
for (Inode<?> inode : mReadLockedInodes) { for (int i = mInodes.size() - 1; i >= 0; i--) {
inode.unlockRead(); Inode<?> inode = mInodes.get(i);
} InodeTree.LockMode lockMode = mLockModes.get(i);
for (Inode<?> inode : mWriteLockedInodes) { if (lockMode == InodeTree.LockMode.READ) {
inode.unlockWrite(); inode.unlockRead();
} else {
inode.unlockWrite();
}
} }
mReadLockedInodes.clear();
mWriteLockedInodes.clear();
mInodes.clear(); mInodes.clear();
mLockModes.clear();
} }
} }
Expand Up @@ -11,38 +11,35 @@


package alluxio.master.file.meta; package alluxio.master.file.meta;


import alluxio.collections.Pair;

import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;


/** /**
* This class represents a pair of {@link LockedInodePath}s. * This class represents a pair of {@link LockedInodePath}s. This is threadsafe, since the
* elements cannot set once the pair is constructed.
*/ */
@ThreadSafe @ThreadSafe
public final class InodePathPair implements AutoCloseable { public final class InodePathPair extends Pair<LockedInodePath, LockedInodePath>
private final LockedInodePath mInodePath1; implements AutoCloseable {
private final LockedInodePath mInodePath2;


InodePathPair(LockedInodePath inodePath1, LockedInodePath inodePath2) { InodePathPair(LockedInodePath inodePath1, LockedInodePath inodePath2) {
mInodePath1 = inodePath1; super(inodePath1, inodePath2);
mInodePath2 = inodePath2;
} }


/** @Override
* @return the first of two {@link LockedInodePath} public void setFirst(LockedInodePath first) {
*/ throw new UnsupportedOperationException();
public synchronized LockedInodePath getFirst() {
return mInodePath1;
} }


/** @Override
* @return the second of two {@link LockedInodePath} public void setSecond(LockedInodePath second) {
*/ throw new UnsupportedOperationException();
public synchronized LockedInodePath getSecond() {
return mInodePath2;
} }


@Override @Override
public synchronized void close() { public synchronized void close() {
mInodePath1.close(); getFirst().close();
mInodePath2.close(); getSecond().close();
} }
} }
25 changes: 23 additions & 2 deletions core/server/src/main/java/alluxio/master/file/meta/InodeTree.java
Expand Up @@ -355,14 +355,24 @@ public LockedInodePath lockFullInodePath(long id, LockMode lockMode)
computePathForInode(inode, builder); computePathForInode(inode, builder);
AlluxioURI uri = new AlluxioURI(builder.toString()); AlluxioURI uri = new AlluxioURI(builder.toString());


try (LockedInodePath inodePath = lockFullInodePath(uri, lockMode)) {
boolean valid = false;
LockedInodePath inodePath = null;
try {
inodePath = lockFullInodePath(uri, lockMode);
if (inodePath.getInode().getId() == id) { if (inodePath.getInode().getId() == id) {
// Set to true, so the path is not unlocked before returning.
valid = true;
return inodePath; return inodePath;
} }
// The path does not end up at the target inode id. Repeat the traversal. // The path does not end up at the target inode id. Repeat the traversal.
} catch (InvalidPathException e) { } catch (InvalidPathException e) {
// ignore and repeat the loop // ignore and repeat the loop
LOG.warn("Inode lookup id {} computed path {} mismatch id. Repeating.", id, uri); LOG.warn("Inode lookup id {} computed path {} mismatch id. Repeating.", id, uri);
} finally {
if (!valid && inodePath != null) {
inodePath.close();
}
} }
count++; count++;
if (count > PATH_TRAVERSAL_RETRIES) { if (count > PATH_TRAVERSAL_RETRIES) {
Expand All @@ -389,6 +399,13 @@ public void ensureFullInodePath(LockedInodePath inodePath, LockMode lockMode)
} }
} }


/**
* Appends components of the path from a given inode.
*
* @param inode the inode to compute the path for
* @param builder a {@link StringBuilder} that is updated with the path components
* @throws FileDoesNotExistException if an inode in the path does not exist
*/
private void computePathForInode(Inode<?> inode, StringBuilder builder) private void computePathForInode(Inode<?> inode, StringBuilder builder)
throws FileDoesNotExistException { throws FileDoesNotExistException {
inode.lockRead(); inode.lockRead();
Expand Down Expand Up @@ -423,6 +440,7 @@ private void computePathForInode(Inode<?> inode, StringBuilder builder)
* @throws FileDoesNotExistException if the path does not exist * @throws FileDoesNotExistException if the path does not exist
*/ */
public AlluxioURI getPath(Inode<?> inode) throws FileDoesNotExistException { public AlluxioURI getPath(Inode<?> inode) throws FileDoesNotExistException {
Preconditions.checkState(inode.isWriteLocked() || inode.isReadLocked());
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
computePathForInode(inode, builder); computePathForInode(inode, builder);
return new AlluxioURI(builder.toString()); return new AlluxioURI(builder.toString());
Expand Down Expand Up @@ -966,7 +984,10 @@ private TraversalResult traverseToInodeInternal(String[] pathComponents, List<In
if (lockMode != LockMode.READ if (lockMode != LockMode.READ
&& getLockModeForComponent(i - 1, pathComponents.length, lockMode, lockHints) && getLockModeForComponent(i - 1, pathComponents.length, lockMode, lockHints)
== LockMode.READ) { == LockMode.READ) {
// The lock mode is one of the WRITE modes, but the previous inode was READ locked. // The target lock mode is one of the WRITE modes, but READ lock is already held. The
// READ lock cannot be upgraded atomically, it needs be released first before WRITE
// lock can be acquired. As a consequence, we need to recheck if the child we are
// looking for has not been created in the meantime.
lockGroup.unlockLast(); lockGroup.unlockLast();
lockGroup.lockWrite(current); lockGroup.lockWrite(current);
Inode recheckNext = ((InodeDirectory) current).getChild(pathComponents[i]); Inode recheckNext = ((InodeDirectory) current).getChild(pathComponents[i]);
Expand Down
Expand Up @@ -26,6 +26,7 @@
*/ */
@ThreadSafe @ThreadSafe
public final class MutableLockedInodePath extends LockedInodePath { public final class MutableLockedInodePath extends LockedInodePath {
// TODO(gpang): restructure class hierarchy, rename class
MutableLockedInodePath(AlluxioURI uri, List<Inode<?>> inodes, InodeLockGroup lockGroup) MutableLockedInodePath(AlluxioURI uri, List<Inode<?>> inodes, InodeLockGroup lockGroup)
throws InvalidPathException { throws InvalidPathException {
super(uri, inodes, lockGroup); super(uri, inodes, lockGroup);
Expand Down
Expand Up @@ -29,6 +29,7 @@
* This allows methods to operate on descendants associated with an existing * This allows methods to operate on descendants associated with an existing
* {@link LockedInodePath}. * {@link LockedInodePath}.
*/ */
// TODO(gpang): can an iterator for a LockedInodePath handle functionality for this class?
@ThreadSafe @ThreadSafe
public final class TempInodePathForDescendant extends LockedInodePath { public final class TempInodePathForDescendant extends LockedInodePath {
private AlluxioURI mDescendantUri; private AlluxioURI mDescendantUri;
Expand Down
Expand Up @@ -25,6 +25,7 @@
import alluxio.heartbeat.ManuallyScheduleHeartbeat; import alluxio.heartbeat.ManuallyScheduleHeartbeat;
import alluxio.master.MasterContext; import alluxio.master.MasterContext;
import alluxio.master.block.BlockMaster; import alluxio.master.block.BlockMaster;
import alluxio.master.file.meta.LockedInodePath;
import alluxio.master.file.meta.PersistenceState; import alluxio.master.file.meta.PersistenceState;
import alluxio.master.file.meta.TtlBucket; import alluxio.master.file.meta.TtlBucket;
import alluxio.master.file.meta.TtlBucketPrivateAccess; import alluxio.master.file.meta.TtlBucketPrivateAccess;
Expand Down
Expand Up @@ -451,15 +451,16 @@ public void getPathTest() throws Exception {
} }


// test one level // test one level
InodeTree.CreatePathResult createResult = createPath(mTree, TEST_URI, sDirectoryOptions); createPath(mTree, TEST_URI, sDirectoryOptions);
List<Inode<?>> created = createResult.getCreated(); try (LockedInodePath inodePath = mTree.lockFullInodePath(TEST_URI, InodeTree.LockMode.READ)) {
Assert.assertEquals(new AlluxioURI("/test"), mTree.getPath(created.get(created.size() - 1))); Assert.assertEquals(new AlluxioURI("/test"), mTree.getPath(inodePath.getInode()));
}


// test nesting // test nesting
createResult = createPath(mTree, NESTED_URI, sNestedDirectoryOptions); createPath(mTree, NESTED_URI, sNestedDirectoryOptions);
created = createResult.getCreated(); try (LockedInodePath inodePath = mTree.lockFullInodePath(NESTED_URI, InodeTree.LockMode.READ)) {
Assert.assertEquals(new AlluxioURI("/nested/test"), Assert.assertEquals(new AlluxioURI("/nested/test"), mTree.getPath(inodePath.getInode()));
mTree.getPath(created.get(created.size() - 1))); }
} }


/** /**
Expand Down

0 comments on commit 19b1f64

Please sign in to comment.