sapling/eden/fs/store/hg/HgBackingStore.h

208 lines
6.6 KiB
C
Raw Normal View History

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#pragma once
Track the duration of outstanding imports Summary: Here we are tracking the duration of each of the current imports in `HgBackingStore`. This changes is setup to display the duration of the longest outstanding import in `eden top`. Displaying the duration of the longest import in eden top will help debug where the problem is when eden hangs. These specifically help determine if eden is hanging because of a queueing issue or not being able to fetch an object from the server. This is a stronger signal to the user that there is an issue in importing over just a count of imports (the previous addition) because many pending imports is not always abnormal. For example a program may prefetch a big batch of files to read, and this could cause a large number of pending imports. A single import should not hang due to a big prefetch and other normal uses. Thus we want to display this in addition to the number of imports and use this as our warning indicator. (i.e. a high duration of import will mark the metrics as yellow or red in `eden top` to give a warning to the user) *code changes*: - adding lists to store watches to time the duration of each of the imports in `HgBackingStore` - removing the counters previously used to count the number of imports in `HgBackingStore` in favor of using the size of these lists as this is constant time, so there is no benefit to tracking this value ourselves Reviewed By: chadaustin Differential Revision: D20611704 fbshipit-source-id: 8bbe0aed8d10688f7bfb7ecfa2fa5ac181945a76
2020-04-01 19:52:05 +03:00
#include <memory>
#include <optional>
#include <folly/Executor.h>
#include <folly/Range.h>
#include <folly/String.h>
Track the duration of outstanding imports Summary: Here we are tracking the duration of each of the current imports in `HgBackingStore`. This changes is setup to display the duration of the longest outstanding import in `eden top`. Displaying the duration of the longest import in eden top will help debug where the problem is when eden hangs. These specifically help determine if eden is hanging because of a queueing issue or not being able to fetch an object from the server. This is a stronger signal to the user that there is an issue in importing over just a count of imports (the previous addition) because many pending imports is not always abnormal. For example a program may prefetch a big batch of files to read, and this could cause a large number of pending imports. A single import should not hang due to a big prefetch and other normal uses. Thus we want to display this in addition to the number of imports and use this as our warning indicator. (i.e. a high duration of import will mark the metrics as yellow or red in `eden top` to give a warning to the user) *code changes*: - adding lists to store watches to time the duration of each of the imports in `HgBackingStore` - removing the counters previously used to count the number of imports in `HgBackingStore` in favor of using the size of these lists as this is constant time, so there is no benefit to tracking this value ourselves Reviewed By: chadaustin Differential Revision: D20611704 fbshipit-source-id: 8bbe0aed8d10688f7bfb7ecfa2fa5ac181945a76
2020-04-01 19:52:05 +03:00
#include <folly/Synchronized.h>
#include "eden/fs/eden-config.h"
#include "eden/fs/store/BackingStore.h"
#include "eden/fs/store/LocalStore.h"
#include "eden/fs/store/ObjectFetchContext.h"
#include "eden/fs/store/hg/HgDatapackStore.h"
#include "eden/fs/telemetry/RequestMetricsScope.h"
#include "eden/fs/utils/PathFuncs.h"
/* forward declare support classes from mercurial */
class ConstantStringRef;
class DatapackStore;
class UnionDatapackStore;
namespace facebook {
namespace eden {
class HgImporter;
struct ImporterOptions;
class EdenStats;
class LocalStore;
class UnboundedQueueExecutor;
class ReloadableConfig;
class ServiceAddress;
class HgProxyHash;
/**
* A BackingStore implementation that loads data out of a mercurial repository.
*/
class HgBackingStore : public BackingStore {
public:
/**
* Create a new HgBackingStore.
*
* The LocalStore object is owned by the EdenServer (which also owns this
* HgBackingStore object). It is guaranteed to be valid for the lifetime of
* the HgBackingStore object.
*/
HgBackingStore(
AbsolutePathPiece repository,
LocalStore* localStore,
UnboundedQueueExecutor* serverThreadPool,
std::shared_ptr<ReloadableConfig> config,
std::shared_ptr<EdenStats>);
/**
* Create an HgBackingStore suitable for use in unit tests. It uses an inline
* executor to process loaded objects rather than the thread pools used in
* production Eden.
*/
HgBackingStore(
AbsolutePathPiece repository,
HgImporter* importer,
LocalStore* localStore,
std::shared_ptr<EdenStats>);
~HgBackingStore() override;
folly::SemiFuture<std::unique_ptr<Tree>> getTree(
const Hash& id,
ObjectFetchContext& context,
ImportPriority priority = ImportPriority::kNormal()) override;
folly::SemiFuture<std::unique_ptr<Blob>> getBlob(
const Hash& id,
ObjectFetchContext& context,
ImportPriority priority = ImportPriority::kNormal()) override;
folly::SemiFuture<std::unique_ptr<Tree>> getTreeForCommit(
const Hash& commitID) override;
folly::SemiFuture<std::unique_ptr<Tree>> getTreeForManifest(
const Hash& commitID,
const Hash& manifestID) override;
FOLLY_NODISCARD folly::SemiFuture<folly::Unit> prefetchBlobs(
const std::vector<Hash>& ids) override;
void periodicManagementTask() override;
/**
* Import the manifest for the specified revision using mercurial
* treemanifest data.
*/
folly::Future<std::unique_ptr<Tree>> importTreeManifest(const Hash& commitId);
/**
* Objects that can be imported from Hg
*/
enum HgImportObject { BLOB, TREE, PREFETCH };
constexpr static std::array<HgImportObject, 3> hgImportObjects{
HgImportObject::BLOB,
HgImportObject::TREE,
HgImportObject::PREFETCH};
static folly::StringPiece stringOfHgImportObject(HgImportObject object);
/**
* Gets the watches timing live `object` imports
* ex. HgBackingStore::getLiveImportWatches(
* RequestMetricsScope::HgImportObject::BLOB,
* )
* gets the watches timing live blob imports
*/
RequestMetricsScope::LockedRequestWatchList& getLiveImportWatches(
HgImportObject object) const;
// Get blob step functions
/**
* Retrieve a blob from hgcache. This function may return `nullptr` when it
* couldn't fetch the blob.
*/
std::unique_ptr<Blob> getBlobFromHgCache(
const Hash& id,
const HgProxyHash& hgInfo);
folly::SemiFuture<std::unique_ptr<Blob>> fetchBlobFromHgImporter(
HgProxyHash hgInfo);
HgDatapackStore& getDatapackStore() {
return datapackStore_;
}
private:
// Forbidden copy constructor and assignment operator
HgBackingStore(HgBackingStore const&) = delete;
HgBackingStore& operator=(HgBackingStore const&) = delete;
/**
* Initialize the unionStore_ needed for treemanifest import support.
*/
void initializeTreeManifestImport(
const ImporterOptions& options,
AbsolutePathPiece repoPath);
folly::Future<std::unique_ptr<Tree>> getTreeForCommitImpl(Hash commitID);
folly::Future<std::unique_ptr<Tree>> getTreeForRootTreeImpl(
const Hash& commitID,
const Hash& rootTreeHash);
// Import the Tree from Hg and cache it in the LocalStore before returning it.
folly::SemiFuture<std::unique_ptr<Tree>> importTreeForCommit(Hash commitID);
void initializeDatapackImport(AbsolutePathPiece repository);
folly::Future<std::unique_ptr<Tree>> importTreeImpl(
const Hash& manifestNode,
const Hash& edenTreeID,
RelativePathPiece path);
folly::Future<std::unique_ptr<Tree>> fetchTreeFromHgCacheOrImporter(
Hash manifestNode,
Hash edenTreeID,
RelativePath path);
folly::Future<std::unique_ptr<Tree>> fetchTreeFromImporter(
Hash manifestNode,
Hash edenTreeID,
RelativePath path,
std::shared_ptr<LocalStore::WriteBatch> writeBatch);
std::unique_ptr<Tree> processTree(
ConstantStringRef& content,
const Hash& manifestNode,
const Hash& edenTreeID,
RelativePathPiece path,
LocalStore::WriteBatch* writeBatch);
LocalStore* localStore_{nullptr};
std::shared_ptr<EdenStats> stats_;
// A set of threads owning HgImporter instances
std::unique_ptr<folly::Executor> importThreadPool_;
std::shared_ptr<ReloadableConfig> config_;
// The main server thread pool; we push the Futures back into
// this pool to run their completion code to avoid clogging
// the importer pool. Queuing in this pool can never block (which would risk
// deadlock) or throw an exception when full (which would incorrectly fail the
// load).
folly::Executor* serverThreadPool_;
// These DatapackStore objects are never referenced once UnionDatapackStore
// is allocated. They are here solely so their lifetime persists while the
// UnionDatapackStore is alive.
std::vector<std::unique_ptr<DatapackStore>> dataPackStores_;
std::unique_ptr<folly::Synchronized<UnionDatapackStore>> unionStore_;
std::string repoName_;
HgDatapackStore datapackStore_;
// Track metrics for imports currently fetching data from hg
mutable RequestMetricsScope::LockedRequestWatchList liveImportBlobWatches_;
mutable RequestMetricsScope::LockedRequestWatchList liveImportTreeWatches_;
mutable RequestMetricsScope::LockedRequestWatchList
liveImportPrefetchWatches_;
};
} // namespace eden
} // namespace facebook