Manages the locks for a list of inodes, based off an existing lock list. This does not
modify the base lock list, and when this lock list is closed, the base lock list is not closed.
The purpose of this class is to allow lock lists to be temporarily extended and then restored.
The base lock list can end with either an inode or edge, and can be read locked or write locked.
Modification is only supported for the non-base part of the lock list.
Locks the given inode and adds it to the lock list. This method does *not* check that the inode
is still a child of the previous inode, or that the inode still exists. This method should only
be called when the edge leading to the inode is locked.
Starting from [a, a->b]
lockInode(b, LockMode.READ) results in [a, a->b, b]
lockInode(b, LockMode.WRITE) results in [a, a->b, b*]
Locks an edge leading out of the last inode in the list.
Starting from [a, a->b, b]
lockEdge(b, c, LockMode.READ) results in [a, a->b, b, b->c]
lockEdge(b, c, LockMode.WRITE) results in [a, a->b, b, b->c*]
Leapfrogs the final edge write lock forward, reducing the lock list's write-locked scope.
Starting from [a, a->b*]
pushWriteLockedEdge(b, c) results in [a, a->b, b, b->c*]
The read lock on a->b is acquired before releasing the write lock. This ensures that no other
thread can take the write lock before the read lock is acquired.
If this is a composite lock list and the final write lock is part of the base lock list, the
new locks will be acquired but no downgrade will occur.