Allow activities to be nested

In particular, this allows more relevant activities ("substituting X")
to supersede inferior ones ("downloading X").
This commit is contained in:
Eelco Dolstra 2017-08-25 17:49:40 +02:00
parent f194629f96
commit c137c0a5eb
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
7 changed files with 55 additions and 12 deletions

View file

@ -2407,14 +2407,14 @@ struct BuilderLogger : Logger
} }
void startActivity(ActivityId act, ActivityType type, void startActivity(ActivityId act, ActivityType type,
const std::string & s, const Fields & fields) override const std::string & s, const Fields & fields, ActivityId parent) override
{ {
nlohmann::json json; nlohmann::json json;
json["action"] = "start"; json["action"] = "start";
json["id"] = act; json["id"] = act;
json["type"] = type; json["type"] = type;
json["text"] = s; json["text"] = s;
// FIXME: handle fields // FIXME: handle fields, parent
log(lvlError, "@nix " + json.dump()); log(lvlError, "@nix " + json.dump());
} }
@ -3313,7 +3313,7 @@ void DerivationGoal::flushLine()
if (type == actDownload) if (type == actDownload)
builderActivities.emplace(std::piecewise_construct, builderActivities.emplace(std::piecewise_construct,
std::forward_as_tuple(json["id"]), std::forward_as_tuple(json["id"]),
std::forward_as_tuple(*logger, type, json["text"])); std::forward_as_tuple(*logger, type, json["text"], Logger::Fields{}, act->id));
} }
else if (action == "stop") else if (action == "stop")
@ -3655,6 +3655,9 @@ void SubstitutionGoal::tryToRun()
/* Wake up the worker loop when we're done. */ /* Wake up the worker loop when we're done. */
Finally updateStats([this]() { outPipe.writeSide = -1; }); Finally updateStats([this]() { outPipe.writeSide = -1; });
Activity act(*logger, actSubstitute, "", Logger::Fields{storePath, sub->getUri()});
PushActivity pact(act.id);
copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()), copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
storePath, repair); storePath, repair);

View file

@ -85,7 +85,7 @@ struct CurlDownloader : public Downloader
DownloadItem(CurlDownloader & downloader, const DownloadRequest & request) DownloadItem(CurlDownloader & downloader, const DownloadRequest & request)
: downloader(downloader) : downloader(downloader)
, request(request) , request(request)
, act(*logger, actDownload, fmt("downloading '%s'", request.uri)) , act(*logger, actDownload, fmt("downloading '%s'", request.uri), {}, request.parentAct)
{ {
if (!request.expectedETag.empty()) if (!request.expectedETag.empty())
requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str()); requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str());

View file

@ -16,8 +16,10 @@ struct DownloadRequest
bool head = false; bool head = false;
size_t tries = 5; size_t tries = 5;
unsigned int baseRetryTimeMs = 250; unsigned int baseRetryTimeMs = 250;
ActivityId parentAct;
DownloadRequest(const std::string & uri) : uri(uri) { } DownloadRequest(const std::string & uri)
: uri(uri), parentAct(curActivity) { }
}; };
struct DownloadResult struct DownloadResult

View file

@ -565,7 +565,9 @@ void Store::buildPaths(const PathSet & paths, BuildMode buildMode)
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore, void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs) const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
{ {
Activity act(*logger, actCopyPath, fmt("copying path '%s'", storePath)); Activity act(*logger, actCopyPath, fmt("copying path '%s'", storePath),
{storePath, srcStore->getUri(), dstStore->getUri()});
PushActivity pact(act.id);
auto info = srcStore->queryPathInfo(storePath); auto info = srcStore->queryPathInfo(storePath);

View file

@ -5,6 +5,8 @@
namespace nix { namespace nix {
thread_local ActivityId curActivity = 0;
Logger * logger = makeDefaultLogger(); Logger * logger = makeDefaultLogger();
void Logger::warn(const std::string & msg) void Logger::warn(const std::string & msg)
@ -75,10 +77,10 @@ Logger * makeDefaultLogger()
std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32}; std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32};
Activity::Activity(Logger & logger, ActivityType type, Activity::Activity(Logger & logger, ActivityType type,
const std::string & s, const Logger::Fields & fields) const std::string & s, const Logger::Fields & fields, ActivityId parent)
: logger(logger), id(nextId++) : logger(logger), id(nextId++)
{ {
logger.startActivity(id, type, s, fields); logger.startActivity(id, type, s, fields, parent);
} }
} }

View file

@ -23,6 +23,7 @@ typedef enum {
actBuild = 105, actBuild = 105,
actOptimiseStore = 106, actOptimiseStore = 106,
actVerifyPaths = 107, actVerifyPaths = 107,
actSubstitute = 108,
} ActivityType; } ActivityType;
typedef enum { typedef enum {
@ -65,7 +66,7 @@ public:
virtual void warn(const std::string & msg); virtual void warn(const std::string & msg);
virtual void startActivity(ActivityId act, ActivityType type, virtual void startActivity(ActivityId act, ActivityType type,
const std::string & s, const Fields & fields) { }; const std::string & s, const Fields & fields, ActivityId parent) { };
virtual void stopActivity(ActivityId act) { }; virtual void stopActivity(ActivityId act) { };
@ -76,6 +77,8 @@ public:
virtual void result(ActivityId act, ResultType type, const Fields & fields) { }; virtual void result(ActivityId act, ResultType type, const Fields & fields) { };
}; };
extern thread_local ActivityId curActivity;
struct Activity struct Activity
{ {
Logger & logger; Logger & logger;
@ -83,7 +86,7 @@ struct Activity
const ActivityId id; const ActivityId id;
Activity(Logger & logger, ActivityType type, const std::string & s = "", Activity(Logger & logger, ActivityType type, const std::string & s = "",
const Logger::Fields & fields = {}); const Logger::Fields & fields = {}, ActivityId parent = curActivity);
Activity(const Activity & act) = delete; Activity(const Activity & act) = delete;
@ -107,6 +110,13 @@ struct Activity
friend class Logger; friend class Logger;
}; };
struct PushActivity
{
const ActivityId prevAct;
PushActivity(ActivityId act) : prevAct(curActivity) { curActivity = act; }
~PushActivity() { curActivity = prevAct; }
};
extern Logger * logger; extern Logger * logger;
Logger * makeDefaultLogger(); Logger * makeDefaultLogger();

View file

@ -73,6 +73,8 @@ private:
uint64_t running = 0; uint64_t running = 0;
uint64_t failed = 0; uint64_t failed = 0;
std::map<ActivityType, uint64_t> expectedByType; std::map<ActivityType, uint64_t> expectedByType;
bool visible = true;
ActivityId parent;
}; };
struct ActivitiesByType struct ActivitiesByType
@ -125,7 +127,7 @@ public:
} }
void startActivity(ActivityId act, ActivityType type, const std::string & s, void startActivity(ActivityId act, ActivityType type, const std::string & s,
const Fields & fields) override const Fields & fields, ActivityId parent) override
{ {
auto state(state_.lock()); auto state(state_.lock());
@ -133,6 +135,7 @@ public:
auto i = std::prev(state->activities.end()); auto i = std::prev(state->activities.end());
i->s = s; i->s = s;
i->type = type; i->type = type;
i->parent = parent;
state->its.emplace(act, i); state->its.emplace(act, i);
state->activitiesByType[type].its.emplace(act, i); state->activitiesByType[type].its.emplace(act, i);
@ -143,9 +146,30 @@ public:
i->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name); i->s = fmt("building " ANSI_BOLD "%s" ANSI_NORMAL, name);
} }
if (type == actSubstitute) {
auto name = storePathToName(getS(fields, 0));
i->s = fmt("fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", name, getS(fields, 1));
}
if ((type == actDownload && hasAncestor(*state, actCopyPath, parent))
|| (type == actCopyPath && hasAncestor(*state, actSubstitute, parent)))
i->visible = false;
update(*state); update(*state);
} }
/* Check whether an activity has an ancestore with the specified
type. */
bool hasAncestor(State & state, ActivityType type, ActivityId act)
{
while (act != 0) {
auto i = state.its.find(act);
if (i == state.its.end()) break;
if (i->second->type == type) return true;
}
return false;
}
void stopActivity(ActivityId act) override void stopActivity(ActivityId act) override
{ {
auto state(state_.lock()); auto state(state_.lock());
@ -253,7 +277,7 @@ public:
if (!status.empty()) line += " "; if (!status.empty()) line += " ";
auto i = state.activities.rbegin(); auto i = state.activities.rbegin();
while (i != state.activities.rend() && i->s.empty() && i->s2.empty()) while (i != state.activities.rend() && (!i->visible || (i->s.empty() && i->s2.empty())))
++i; ++i;
if (i != state.activities.rend()) { if (i != state.activities.rend()) {