mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
5d738193e5
Summary: This is a major change to how we manage the dirstate in Eden's Hg extension. Previously, the dirstate information was stored under `$EDEN_CONFIG_DIR`, which is Eden's private storage. Any time the Mercurial extension wanted to read or write the dirstate, it had to make a Thrift request to Eden to do so on its behalf. The upside is that Eden could answer dirstate-related questions independently of the Python code. This was sufficiently different than how Mercurial's default dirstate worked that our subclass, `eden_dirstate`, had to override quite a bit of behavior. Failing to manage the `.hg/dirstate` file in a way similar to the way Mercurial does has exposed some "unofficial contracts" that Mercurial has. For example, tools like Nuclide rely on changes to the `.hg/dirstate` file as a heuristic to determine when to invalidate its internal caches for Mercurial data. Today, Mercurial has a well-factored `dirstatemap` abstraction that is primarily responsible for the transactions with the dirstate's data. With this split, we can focus on putting most of our customizations in our `eden_dirstate_map` subclass while our `eden_dirstate` class has to override fewer methods. Because the data is managed through the `.hg/dirstate` file, transaction logic in Mercurial that relies on renaming/copying that file will work out-of-the-box. This change also reduces the number of Thrift calls the Mercurial extension has to make for operations like `hg status` or `hg add`. In this revision, we introduce our own binary format for the `.hg/dirstate` file. The logic to read and write this file is in `eden/py/dirstate.py`. After the first 40 bytes, which are used for the parent hashes, the next four bytes are reserved for a version number for the file format so we can manage file format changes going forward. Admittedly one downside of this change is that it is a breaking change. Ideally, users should commit all of their local changes in their existing mounts, shutdown Eden, delete the old mounts, restart Eden, and re-clone. In the end, this change deletes a number of Mercurial-specific code and Thrift APIs from Eden. This is a better separation of concerns that makes Eden more SCM-agnostic. For example, this change removes `Dirstate.cpp` and `DirstatePersistance.cpp`, replacing them with the much simpler and more general `Differ.cpp`. The Mercurial-specific logic from `Dirstate.cpp` that turned a diff into an `hg status` now lives in the Mercurial extension in `EdenThriftClient.getStatus()`, which is much more appropriate. Note that this reverts the changes that were recently introduced in D6116105: we now need to intercept `localrepo.localrepository.dirstate` once again. Reviewed By: simpkins Differential Revision: D6179950 fbshipit-source-id: 5b78904909b669c9cc606e2fe1fd118ef6eaab95
178 lines
5.2 KiB
C++
178 lines
5.2 KiB
C++
/*
|
|
* Copyright (c) 2016-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 "common/fb303/cpp/FacebookBase2.h"
|
|
#include "eden/fs/service/gen-cpp2/StreamingEdenService.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
namespace folly {
|
|
template <typename T>
|
|
class Future;
|
|
}
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
class Hash;
|
|
class EdenMount;
|
|
class EdenServer;
|
|
class TreeInode;
|
|
|
|
/*
|
|
* Handler for the EdenService thrift interface
|
|
*/
|
|
class EdenServiceHandler : virtual public StreamingEdenServiceSvIf,
|
|
public facebook::fb303::FacebookBase2 {
|
|
public:
|
|
explicit EdenServiceHandler(EdenServer* server);
|
|
|
|
facebook::fb303::cpp2::fb_status getStatus() override;
|
|
|
|
void mount(std::unique_ptr<MountInfo> info) override;
|
|
|
|
void unmount(std::unique_ptr<std::string> mountPoint) override;
|
|
|
|
void listMounts(std::vector<MountInfo>& results) override;
|
|
|
|
void getParentCommits(
|
|
WorkingDirectoryParents& result,
|
|
std::unique_ptr<std::string> mountPoint) override;
|
|
|
|
void checkOutRevision(
|
|
std::vector<CheckoutConflict>& results,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> hash,
|
|
bool force) override;
|
|
|
|
void resetParentCommits(
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<WorkingDirectoryParents> parents) override;
|
|
|
|
void getBindMounts(
|
|
std::vector<std::string>& out,
|
|
std::unique_ptr<std::string> mountPoint) override;
|
|
|
|
void getSHA1(
|
|
std::vector<SHA1Result>& out,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::vector<std::string>> paths) override;
|
|
|
|
void getCurrentJournalPosition(
|
|
JournalPosition& out,
|
|
std::unique_ptr<std::string> mountPoint) override;
|
|
|
|
void getFilesChangedSince(
|
|
FileDelta& out,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<JournalPosition> fromPosition) override;
|
|
|
|
void getFileInformation(
|
|
std::vector<FileInformationOrError>& out,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::vector<std::string>> paths) override;
|
|
|
|
void glob(
|
|
std::vector<std::string>& out,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::vector<std::string>> globs) override;
|
|
|
|
void async_tm_subscribe(
|
|
std::unique_ptr<apache::thrift::StreamingHandlerCallback<
|
|
std::unique_ptr<JournalPosition>>> callback,
|
|
std::unique_ptr<std::string> mountPoint) override;
|
|
|
|
void getManifestEntry(
|
|
ManifestEntry& out,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> relativePath) override;
|
|
|
|
folly::Future<std::unique_ptr<ScmStatus>> future_getScmStatus(
|
|
std::unique_ptr<std::string> mountPoint,
|
|
bool listIgnored) override;
|
|
|
|
void debugGetScmTree(
|
|
std::vector<ScmTreeEntry>& entries,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> id,
|
|
bool localStoreOnly) override;
|
|
|
|
void debugGetScmBlob(
|
|
std::string& data,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> id,
|
|
bool localStoreOnly) override;
|
|
|
|
void debugGetScmBlobMetadata(
|
|
ScmBlobMetadata& metadata,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> id,
|
|
bool localStoreOnly) override;
|
|
|
|
void debugInodeStatus(
|
|
std::vector<TreeInodeDebugInfo>& inodeInfo,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> path) override;
|
|
|
|
void debugGetInodePath(
|
|
InodePathDebugInfo& inodePath,
|
|
std::unique_ptr<std::string> mountPoint,
|
|
int64_t inodeNumber) override;
|
|
|
|
void debugSetLogLevel(
|
|
SetLogLevelResult& result,
|
|
std::unique_ptr<std::string> category,
|
|
std::unique_ptr<std::string> level) override;
|
|
|
|
int64_t unloadInodeForPath(
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> path,
|
|
std::unique_ptr<TimeSpec> age) override;
|
|
|
|
void flushStatsNow() override;
|
|
|
|
void invalidateKernelInodeCache(
|
|
std::unique_ptr<std::string> mountPoint,
|
|
std::unique_ptr<std::string> path) override;
|
|
|
|
void getStatInfo(InternalStats& result) override;
|
|
|
|
/**
|
|
* When this Thrift handler is notified to shutdown, it notifies the
|
|
* EdenServer to shut down, as well.
|
|
*/
|
|
void shutdown() override;
|
|
|
|
private:
|
|
// Forbidden copy constructor and assignment operator
|
|
EdenServiceHandler(EdenServiceHandler const&) = delete;
|
|
EdenServiceHandler& operator=(EdenServiceHandler const&) = delete;
|
|
|
|
folly::Future<Hash> getSHA1ForPath(
|
|
folly::StringPiece mountPoint,
|
|
folly::StringPiece path);
|
|
|
|
folly::Future<Hash> getSHA1ForPathDefensively(
|
|
folly::StringPiece mountPoint,
|
|
folly::StringPiece path) noexcept;
|
|
|
|
/**
|
|
* If `filename` exists in the manifest as a file (not a directory), returns
|
|
* the mode of the file as recorded in the manifest.
|
|
*/
|
|
folly::Optional<mode_t> isInManifestAsFile(
|
|
const EdenMount* mount,
|
|
const RelativePathPiece filename);
|
|
|
|
EdenServer* const server_;
|
|
};
|
|
} // namespace eden
|
|
} // namespace facebook
|