mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 08:47:12 +03:00
086fc9ac30
Summary: Update FuseChannel to send all invalidation requests in a separate thread. This eliminates a deadlock that could previously occur during checkout operations. The invalidation requests would block until they could acquire the kernel's inode lock on the inode in question. However, the inode lock may already be held by another thread attempting to perform an unlink() or rename() call. These FUSE unlink or rename operations would be blocked waiting on Eden's mount point rename lock, which was acquired by the checkout operation. Checkout operations now let the invalidations complete asynchronously, but we wait for all invalidation operations to complete before indicating to our caller that the checkout has succeeded. Reviewed By: chadaustin, wez Differential Revision: D7404971 fbshipit-source-id: 6fa20c00d054e210eb0258d247d083010557f210
115 lines
3.2 KiB
C++
115 lines
3.2 KiB
C++
/*
|
|
* Copyright (c) 2004-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
#include <folly/Synchronized.h>
|
|
#include <vector>
|
|
#include "eden/fs/inodes/EdenMount.h"
|
|
#include "eden/fs/inodes/InodePtrFwd.h"
|
|
#include "eden/fs/service/gen-cpp2/eden_types.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
namespace folly {
|
|
class exception_wrapper;
|
|
template <typename T>
|
|
class Future;
|
|
class Unit;
|
|
} // namespace folly
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
class CheckoutConflict;
|
|
class TreeInode;
|
|
class Tree;
|
|
|
|
/**
|
|
* CheckoutContext maintains state during a checkout operation.
|
|
*/
|
|
class CheckoutContext {
|
|
public:
|
|
CheckoutContext(
|
|
EdenMount* mount,
|
|
folly::Synchronized<EdenMount::ParentInfo>::LockedPtr&& parentsLock,
|
|
CheckoutMode checkoutMode);
|
|
~CheckoutContext();
|
|
|
|
/**
|
|
* Returns true if the checkout operation should do a dry run, looking for
|
|
* conflicts without actually updating the inode contents. If it returns
|
|
* false, it should actually update the inodes as part of the checkout.
|
|
*/
|
|
bool isDryRun() const {
|
|
// TODO: make this configurable on checkout start
|
|
return checkoutMode_ == CheckoutMode::DRY_RUN;
|
|
}
|
|
|
|
/**
|
|
* Returns true if this checkout operation should force the new inode
|
|
* contents to look like the data in the Tree being checked out, even if
|
|
* there are conflicts.
|
|
*
|
|
* This will cause the checkout to always update files with conflicts to the
|
|
* new contents, rather than just reporting and skipping files with
|
|
* conflicts.
|
|
*
|
|
* forceUpdate() can only return true when isDryRun() is false.
|
|
*/
|
|
bool forceUpdate() const {
|
|
return checkoutMode_ == CheckoutMode::FORCE;
|
|
}
|
|
|
|
/**
|
|
* Start the checkout operation.
|
|
*/
|
|
void start(RenameLock&& renameLock);
|
|
|
|
/**
|
|
* Complete the checkout operation
|
|
*
|
|
* Returns the list of conflicts and errors that were encountered during the
|
|
* operation.
|
|
*/
|
|
folly::Future<std::vector<CheckoutConflict>> finish(Hash newSnapshot);
|
|
|
|
void addConflict(ConflictType type, RelativePathPiece path);
|
|
void
|
|
addConflict(ConflictType type, TreeInode* parent, PathComponentPiece name);
|
|
void addConflict(ConflictType type, InodeBase* inode);
|
|
|
|
void addError(
|
|
TreeInode* parent,
|
|
PathComponentPiece name,
|
|
const folly::exception_wrapper& ew);
|
|
|
|
/**
|
|
* Get a reference to the rename lock.
|
|
*
|
|
* This is mostly used for APIs that require proof that we are currently
|
|
* holding the lock.
|
|
*/
|
|
const RenameLock& renameLock() const {
|
|
return renameLock_;
|
|
}
|
|
|
|
private:
|
|
CheckoutMode checkoutMode_;
|
|
EdenMount* const mount_;
|
|
folly::Synchronized<EdenMount::ParentInfo>::LockedPtr parentsLock_;
|
|
RenameLock renameLock_;
|
|
|
|
// The checkout processing may occur across many threads,
|
|
// if some data load operations complete asynchronously on other threads.
|
|
// Therefore access to the conflicts list must be synchronized.
|
|
folly::Synchronized<std::vector<CheckoutConflict>> conflicts_;
|
|
};
|
|
} // namespace eden
|
|
} // namespace facebook
|