mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
deprioiritize when fetch count exceeds threshold
Summary: check fetch count before `getPriority()` is used. If fetch count has exceeded `fetchThreshold_`, lower the priority by 1. Note: this diff only guarantees that the `getPriority()` function is returning the lowered priority. How the returned value is used for scheduling is handled by `HgQueuedBackingStore` Reviewed By: kmancini Differential Revision: D22550640 fbshipit-source-id: c032f8f72ca658618ac118dfb3ad3dcae61e9735
This commit is contained in:
parent
102d8586cc
commit
ce28ec8caa
@ -116,6 +116,16 @@ class RequestData : public folly::RequestData, public ObjectFetchContext {
|
||||
return priority_;
|
||||
}
|
||||
|
||||
// Override of `deprioritize`
|
||||
virtual void deprioritize(uint64_t delta) override {
|
||||
ImportPriority prev = priority_.load();
|
||||
priority_.compare_exchange_strong(prev, prev.getDeprioritized(delta));
|
||||
if (getClientPid().has_value()) {
|
||||
XLOG(DBG7) << "priority for " << getClientPid().value()
|
||||
<< " has changed to: " << priority_.load().value();
|
||||
}
|
||||
}
|
||||
|
||||
// Override of `ObjectFetchContext`
|
||||
Cause getCause() const override {
|
||||
return ObjectFetchContext::Cause::Fuse;
|
||||
|
@ -44,6 +44,16 @@ struct ImportPriority {
|
||||
offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprioritize ImportPriority by decreasing offset by delta.
|
||||
* Note: this function maintains ImportPriorityKind, as jobs
|
||||
* with higher priority kind are usually designed to be scheduled
|
||||
* ealier and should not lower their kind even when deprioritized.
|
||||
*/
|
||||
constexpr ImportPriority getDeprioritized(uint64_t delta) const noexcept {
|
||||
return ImportPriority{kind, offset > delta ? offset - delta : 0};
|
||||
}
|
||||
|
||||
friend bool operator<(
|
||||
const ImportPriority& lhs,
|
||||
const ImportPriority& rhs) noexcept {
|
||||
|
@ -66,6 +66,18 @@ class ObjectFetchContext {
|
||||
return ImportPriority::kNormal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Support deprioritizing in sub-classes.
|
||||
* Note: Normally, each ObjectFetchContext is designed to be used for only one
|
||||
* import (with NullObjectFetchContext being the only exception currenly).
|
||||
* Therefore, this method should only be called once on each
|
||||
* ObjectFetchContext object (when it is related to a process doing too much
|
||||
* fetches). However, implementations of this method should write the priority
|
||||
* change to log as debug information and watch out for unexpected uses of
|
||||
* ObjectFetchContext that cause it to be used for more than one import.
|
||||
*/
|
||||
virtual void deprioritize(uint64_t) {}
|
||||
|
||||
/**
|
||||
* Return a no-op fetch context suitable when no tracking is desired.
|
||||
*/
|
||||
|
@ -80,6 +80,17 @@ void ObjectStore::sendFetchHeavyEvent(pid_t pid, uint64_t fetch_count) const {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ObjectStore::deprioritizeWhenFetchHeavy(
|
||||
ObjectFetchContext& context) const {
|
||||
auto pid = context.getClientPid();
|
||||
if (pid.has_value()) {
|
||||
auto fetch_count = pidFetchCounts_->getCountByPid(pid.value());
|
||||
if (fetch_count >= fetchThreshold_) {
|
||||
context.deprioritize(importPriorityDeprioritizeAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<shared_ptr<const Tree>> ObjectStore::getTree(
|
||||
const Hash& id,
|
||||
ObjectFetchContext& fetchContext) const {
|
||||
@ -104,6 +115,8 @@ Future<shared_ptr<const Tree>> ObjectStore::getTree(
|
||||
return makeFuture(std::move(tree));
|
||||
}
|
||||
|
||||
self->deprioritizeWhenFetchHeavy(fetchContext);
|
||||
|
||||
// Note: We don't currently have logic here to avoid duplicate work if
|
||||
// multiple callers request the same tree at once. We could store a map
|
||||
// of pending lookups as (Hash --> std::list<Promise<unique_ptr<Tree>>),
|
||||
@ -231,6 +244,8 @@ Future<shared_ptr<const Blob>> ObjectStore::getBlob(
|
||||
return makeFuture(shared_ptr<const Blob>(std::move(blob)));
|
||||
}
|
||||
|
||||
self->deprioritizeWhenFetchHeavy(fetchContext);
|
||||
|
||||
// Look in the BackingStore
|
||||
return self->backingStore_
|
||||
->getBlob(id, fetchContext, fetchContext.getPriority())
|
||||
@ -319,6 +334,8 @@ Future<BlobMetadata> ObjectStore::getBlobMetadata(
|
||||
return makeFuture(*metadata);
|
||||
}
|
||||
|
||||
self->deprioritizeWhenFetchHeavy(context);
|
||||
|
||||
// Check backing store
|
||||
//
|
||||
// TODO: It would be nice to add a smarter API to the BackingStore so
|
||||
|
@ -47,8 +47,20 @@ struct PidFetchCounts {
|
||||
void clear() {
|
||||
map_.wlock()->clear();
|
||||
}
|
||||
|
||||
uint64_t getCountByPid(pid_t pid) {
|
||||
auto rl = map_.rlock();
|
||||
auto fetch_count = rl->find(pid);
|
||||
if (fetch_count != rl->end()) {
|
||||
return fetch_count->second;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constexpr uint64_t importPriorityDeprioritizeAmount{1};
|
||||
|
||||
/**
|
||||
* ObjectStore is a content-addressed store for eden object data.
|
||||
*
|
||||
@ -78,6 +90,18 @@ class ObjectStore : public IObjectStore,
|
||||
*/
|
||||
void sendFetchHeavyEvent(pid_t pid, uint64_t fetch_count) const;
|
||||
|
||||
/**
|
||||
* Check fetch count of the process using this fetchContext before using
|
||||
* the fetchContext in BackingStore. if fetchThreshold_ is exceeded,
|
||||
* deprioritize the fetchContext by 1.
|
||||
*
|
||||
* Note: Normally, one fetchContext is created for only one fetch request,
|
||||
* so deprioritize() should only be called once by one thread, but that is
|
||||
* not strictly guaranteed. See comments before deprioritize() for more
|
||||
* information
|
||||
*/
|
||||
void deprioritizeWhenFetchHeavy(ObjectFetchContext& context) const;
|
||||
|
||||
/**
|
||||
* Get a Tree by ID.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user