sapling/eden/docs/InodeLocks.md
Adam Simpkins 0687431924 implement EdenMount::checkout()
Summary:
This is the initial code for implementing checkout.

This isn't quite 100% implemented yet, but I think it's worth checking in this
code as-is, and getting the remaining functionality done in separate diffs.
In particular, a few operations aren't implemented:
- Removing a directory that was deleted in the new revision
- Replacing a directory that was replaced with a file or symlink in the new
  revision
- When doing a forced update, replacing a file or directory that did not exist
  in the old revision, but that was created locally in the working directory,
  and also exists in the new revision.

Reviewed By: wez

Differential Revision: D4538516

fbshipit-source-id: 5bb4889b02f23ab2048fcae2c8b7614340181aa6
2017-02-15 20:33:31 -08:00

4.1 KiB

InodeBase's location_ lock:

No other locks should be acquired while holding this lock. Two location_ locks should never be held at the same time.

This field cannot be updated without holding both the EdenMount's rename lock and the location_ lock for the InodeBase in question.

Note that InodeBase::getLogPath() acquires location_ locks. This function is used in log statements in many places, including in places where other locks are held. It is therefore important to ensure that the location_ lock remains at the very bottom of our lock-ordering stack.

InodeMap data_ lock:

No other locks should be acquired while holding this lock, apart from InodeBase location_ locks. (InodeBase location_ locks are only held with the InodeMap lock already held for the purpose of calling inode->getLogPath() in VLOG statements.)

In general it should only be held very briefly while doing lookups/inserts on the map data structures. Once we need to load an Inode the InodeMap lock is released for the duration of the load operation itself. It is re-acquired when the load completes so we can insert the new Inode into the map.

FileInode lock:

The InodeBase location_ lock may be acquired while holding a FileInode's lock.

TreeInode contents_ lock:

  • The InodeMap lock may be acquired while holding a TreeInode's contents_ lock.

  • The InodeBase location_ lock may be acquired while holding a TreeInode's contents_ lock.

  • A FileInode's lock may be acquired while holding its parent TreeInode's contents_ lock.

In some situations the same thread acquires multiple contents_ locks together.

  • Some code paths hold a parent TreeInode's contents_ lock while accessing its children, and then acquire a child TreeInode's contents_ lock while still holding the parent TreeInode's lock.

  • The rename() code may hold up to 3 TreeInode locks. It always holds the contents_ lock on both the source TreeInode and the destination TreeInode. Additionally, if the destination name refers to an existing TreeInode, the rename() holds its contents_ lock as well, to ensure that it is empty, and to prevent new entries from being created inside this directory once the rename starts.

To prevent deadlocks, the lock ordering constraints for TreeInode contents_ are as follows:

  • If you are not holding the mountpoint rename lock, you can only acquire a TreeInode contents_ lock if the other contents_ locks you are holding are for this TreeInode's immediate parents. (e.g., if you are already holding another contents_ lock it must be for this TreeInode's parent. If you are holding two other contents_ locks it must be for this TreeInode's parent and grandparent.)

    Note however that acquiring multiple TreeInode contents locks discouraged. When possible it is preferred to release the lock on the parent TreeInode before locking the child. Acquiring locks on more than 2 levels of the tree hierarchy is technically safe from a lock ordering perspective, but is also strongly discouraged.

  • If you are holding the mountpoint rename lock, it is safe to acquire multiple TreeInode locks at a time. However, if there is an ancestor/child relationship between any of the TreeInode's, the ancestor lock must be acquired first. This avoids lock ordering issues with other threads that are not holding the rename lock. Among unrelated TreeInodes no particular ordering is required.

EdenMount's rename lock:

This lock is a very high level lock in our lock ordering stack--it is acquired before any other individual inode-specific locks.

This lock is held for the duration of a rename or unlink operation. No InodeBase location_ fields may be updated without holding this lock.

EdenMount's current snapshot lock:

This lock is also a very high level lock in our lock ordering stack. It is acquired for the duration of any operation that updates the current snapshot that is checked out.

Checkout operations acquire both the current snapshot lock and the rename lock. The snapshot lock is always acquired before the rename lock.