inodes: unload inodes before checkout on Windows

Summary:
On Windows, we never unload any inodes until EdenFS is restarted, thus,
checkout times go up over time as more and more inodes are being loaded. While
on Windows we don't keep track of what is referenced by the kernel, the
checkout code will use the "precise inodes" code path when deciding what to
update. This means that every inode that is in the overlay will get updated
properly, and since the overlay is a superset of what is hydrated, we are
guaranteed to always invalidate what we need to.

Due to the above, this shouldn't result in any changes as we never gc the
overlay, but that will come later, at which point checkout times will stop
being more and more expensive as time goes.

Reviewed By: chadaustin

Differential Revision: D24634253

fbshipit-source-id: c7b838edc20589bbf92ff4e2b3abd079b9a4443d
This commit is contained in:
Xavier Deguillard 2020-11-02 21:02:30 -08:00 committed by Facebook GitHub Bot
parent e3c3133fd3
commit 1ed7eeef95
3 changed files with 23 additions and 22 deletions

View File

@ -895,29 +895,30 @@ folly::Future<CheckoutResult> EdenMount::checkout(
ctx->start(this->acquireRenameLock());
checkoutTimes->didAcquireRenameLock = stopWatch.elapsed();
#ifndef _WIN32
/**
* If a significant number of tree inodes are loaded or referenced
* by FUSE, then checkout is slow, because Eden must precisely
* manage changes to each one, as if the checkout was actually
* creating and removing files in each directory. If a tree is
* unloaded and unmodified, Eden can pretend the checkout
* operation blew away the entire subtree and assigned new inode
* numbers to everything under it, which is much cheaper.
*
* To make checkout faster, enumerate all loaded, unreferenced
* inodes and unload them, allowing checkout to use the fast path.
*
* Note that this will not unload any inodes currently referenced
* by FUSE, including the kernel's cache, so rapidly switching
* between commits while working should not be materially
* affected.
*/
// If a significant number of tree inodes are loaded or referenced
// by FUSE, then checkout is slow, because Eden must precisely
// manage changes to each one, as if the checkout was actually
// creating and removing files in each directory. If a tree is
// unloaded and unmodified, Eden can pretend the checkout
// operation blew away the entire subtree and assigned new inode
// numbers to everything under it, which is much cheaper.
//
// To make checkout faster, enumerate all loaded, unreferenced
// inodes and unload them, allowing checkout to use the fast path.
//
// Note that this will not unload any inodes currently referenced
// by FUSE, including the kernel's cache, so rapidly switching
// between commits while working should not be materially
// affected.
//
// On Windows, most of the above is also true, but instead of files
// being referenced by the kernel, the files are actually on disk. All
// the files on disk must also be present in the overlay, and thus the
// checkout code will take care of doing the right invalidation for
// these.
this->getRootInode()->unloadChildrenUnreferencedByFuse();
#endif // !1
auto rootInode = getRootInode();
return serverState_->getFaultInjector()
.checkAsync("inodeCheckout", getPath().stringPiece())

View File

@ -3343,7 +3343,6 @@ size_t TreeInode::unloadChildrenNow() {
[](InodeBase*) { return true; });
}
#ifndef _WIN32
size_t TreeInode::unloadChildrenUnreferencedByFuse() {
auto treeChildren = getTreeChildren(this);
return unloadChildrenIf(
@ -3354,6 +3353,7 @@ size_t TreeInode::unloadChildrenUnreferencedByFuse() {
[](InodeBase* child) { return child->getFuseRefcount() == 0; });
}
#ifndef _WIN32
size_t TreeInode::unloadChildrenLastAccessedBefore(const timespec& cutoff) {
// Unloading children by criteria is a bit of an intricate operation. The
// InodeMap and tree's contents lock must be held simultaneously when

View File

@ -333,7 +333,6 @@ class TreeInode final : public InodeBaseMetadata<DirContents> {
*/
size_t unloadChildrenNow();
#ifndef _WIN32
/**
* Unload all children, recursively, neither referenced internally by Eden nor
* by FUSE.
@ -342,6 +341,7 @@ class TreeInode final : public InodeBaseMetadata<DirContents> {
*/
size_t unloadChildrenUnreferencedByFuse();
#ifndef _WIN32
/**
* Unload all unreferenced inodes under this tree whose last access time is
* older than the specified cutoff.