public void traverse ( ) throws InvalidPathException { if ( mLockList . getLockMode ( ) == LockMode . WRITE ) { traverseWithoutLocking ( ) ; return ; } // This locks the root edge and inode if necessary. bootstrapTraversal ( ) ; // Each iteration either locks a new inode/edge or hits a missing inode and returns. while ( ! fullPathExists ( ) ) { int lastInodeIndex = mLockList . getLockedInodes ( ) . size ( ) - 1 ; String nextComponent = mPathComponents [ lastInodeIndex + 1 ] ; boolean isFinalComponent = lastInodeIndex == mPathComponents . length - 2 ; if ( mLockList . endsInInode ( ) ) { // Lock an edge next. if ( mLockPattern == LockPattern . WRITE_EDGE && isFinalComponent ) { mLockList . lockEdge ( nextComponent , LockMode . WRITE ) ; } else { mLockList . lockEdge ( nextComponent , LockMode . READ ) ; } } else { // Lock an inode next. Inode lastInode = mLockList . getLockedInodes ( ) . get ( lastInodeIndex ) ; if ( ! lastInode . isDirectory ( ) ) { throw new InvalidPathException ( String . format ( "Traversal failed for path %s. Component %s(%s) is a file, not a directory." , mUri , lastInodeIndex , lastInode . getName ( ) ) ) ; } Optional < Inode > nextInodeOpt = mInodeStore . getChild ( lastInode . asDirectory ( ) , nextComponent ) ; if ( ! nextInodeOpt . isPresent ( ) && mLockPattern == LockPattern . WRITE_EDGE && ! isFinalComponent ) { // This pattern requires that we obtain a write lock on the final edge, so we must // upgrade to a write lock. mLockList . unlockLastEdge ( ) ; mLockList . lockEdge ( nextComponent , LockMode . WRITE ) ; nextInodeOpt = mInodeStore . getChild ( lastInode . asDirectory ( ) , nextComponent ) ; if ( nextInodeOpt . isPresent ( ) ) { // The component must have been created between releasing the read lock and acquiring // the write lock. Downgrade and continue as normal. mLockList . downgradeLastEdge ( ) ; } } if ( ! nextInodeOpt . isPresent ( ) ) { if ( mLockPattern != LockPattern . WRITE_EDGE ) { // Other lock patterns only lock up to the last existing inode. mLockList . unlockLastEdge ( ) ; } return ; } Inode nextInode = nextInodeOpt . get ( ) ; if ( isFinalComponent ) { if ( mLockPattern == LockPattern . READ ) { mLockList . lockInode ( nextInode , LockMode . READ ) ; } else if ( mLockPattern == LockPattern . WRITE_INODE ) { mLockList . lockInode ( nextInode , LockMode . WRITE ) ; } else if ( mLockPattern == LockPattern . WRITE_EDGE ) { if ( mLockList . numLockedInodes ( ) == mExistingInodes . size ( ) ) { // Add the final inode, which is not locked but does exist. mExistingInodes . add ( nextInode ) ; } } } else { mLockList . lockInode ( nextInode , LockMode . READ ) ; } // Avoid adding the inode if it is already in mExistingInodes. if ( mLockList . numLockedInodes ( ) > mExistingInodes . size ( ) ) { mExistingInodes . add ( nextInode ) ; } } } }
Traverses the inode path according to its lock pattern . If the inode path is already partially traversed this method will pick up where the previous traversal left off . If the path already ends in a write lock traverse will populate the inodes list without taking any additional locks .