nix copy: Revive progress bar

This commit is contained in:
Eelco Dolstra 2017-08-14 15:28:16 +02:00
parent dffc3fe43b
commit c5e4404580
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
6 changed files with 99 additions and 2 deletions

View file

@ -135,7 +135,6 @@ struct LegacySSHStore : public Store
if (readInt(conn->from) != 1) if (readInt(conn->from) != 1)
throw Error("failed to add path '%s' to remote host '%s', info.path, host"); throw Error("failed to add path '%s' to remote host '%s', info.path, host");
} }
void narFromPath(const Path & path, Sink & sink) override void narFromPath(const Path & path, Sink & sink) override

View file

@ -565,8 +565,12 @@ 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(actCopyPath, fmt("copying path '%s'", storePath));
auto info = srcStore->queryPathInfo(storePath); auto info = srcStore->queryPathInfo(storePath);
//act->progress(0, info->size());
StringSink sink; StringSink sink;
srcStore->narFromPath({storePath}, sink); srcStore->narFromPath({storePath}, sink);
@ -600,13 +604,28 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
for (auto & path : storePaths) for (auto & path : storePaths)
if (!valid.count(path)) missing.insert(path); if (!valid.count(path)) missing.insert(path);
Activity act;
logger->event(evCopyStarted, act);
std::atomic<size_t> nrCopied{0};
std::atomic<size_t> nrDone{storePaths.size() - missing.size()};
auto showProgress = [&]() {
logger->event(evCopyProgress, act, storePaths.size(), nrCopied, nrDone);
};
ThreadPool pool; ThreadPool pool;
processGraph<Path>(pool, processGraph<Path>(pool,
PathSet(missing.begin(), missing.end()), PathSet(missing.begin(), missing.end()),
[&](const Path & storePath) { [&](const Path & storePath) {
if (dstStore->isValidPath(storePath)) return PathSet(); if (dstStore->isValidPath(storePath)) {
nrDone++;
showProgress();
return PathSet();
}
return srcStore->queryPathInfo(storePath)->references; return srcStore->queryPathInfo(storePath)->references;
}, },
@ -616,7 +635,12 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
if (!dstStore->isValidPath(storePath)) { if (!dstStore->isValidPath(storePath)) {
printInfo("copying '%s'...", storePath); printInfo("copying '%s'...", storePath);
copyStorePath(srcStore, dstStore, storePath, repair, checkSigs); copyStorePath(srcStore, dstStore, storePath, repair, checkSigs);
nrCopied++;
} }
nrDone++;
showProgress();
}); });
} }

View file

@ -56,6 +56,8 @@ static void dumpContents(const Path & path, size_t size,
static void dump(const Path & path, Sink & sink, PathFilter & filter) static void dump(const Path & path, Sink & sink, PathFilter & filter)
{ {
checkInterrupt();
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
throw SysError(format("getting attributes of path '%1%'") % path); throw SysError(format("getting attributes of path '%1%'") % path);

View file

@ -80,4 +80,15 @@ std::atomic<uint64_t> nextId{(uint64_t) getpid() << 32};
Activity::Activity() : id(nextId++) { }; Activity::Activity() : id(nextId++) { };
Activity::Activity(ActivityType type, std::string msg)
: Activity()
{
logger->event(evStartActivity, id, msg);
}
Activity::~Activity()
{
logger->event(evStopActivity, id);
}
} }

View file

@ -13,6 +13,10 @@ typedef enum {
lvlVomit lvlVomit
} Verbosity; } Verbosity;
typedef enum {
actCopyPath = 100,
} ActivityType;
class Activity class Activity
{ {
public: public:
@ -21,6 +25,10 @@ public:
Activity(); Activity();
Activity(const Activity & act) : id(act.id) { }; Activity(const Activity & act) : id(act.id) { };
Activity(uint64_t id) : id(id) { }; Activity(uint64_t id) : id(id) { };
Activity(ActivityType type, std::string msg = "");
~Activity();
//void progress(...);
}; };
typedef enum { typedef enum {
@ -35,6 +43,13 @@ typedef enum {
evSubstitutionCreated = 8, evSubstitutionCreated = 8,
evSubstitutionStarted = 9, evSubstitutionStarted = 9,
evSubstitutionFinished = 10, evSubstitutionFinished = 10,
evCopyStarted = 100,
evCopyProgress = 101,
evStartActivity = 1000,
evStopActivity = 1001,
} EventType; } EventType;
struct Event struct Event

View file

@ -27,17 +27,29 @@ private:
DownloadInfo(const std::string & uri) : uri(uri) { } DownloadInfo(const std::string & uri) : uri(uri) { }
}; };
struct CopyInfo
{
uint64_t expected = 0;
uint64_t copied = 0;
uint64_t done = 0;
};
struct State struct State
{ {
std::map<Activity::t, Path> builds; std::map<Activity::t, Path> builds;
std::set<Activity::t> runningBuilds; std::set<Activity::t> runningBuilds;
uint64_t succeededBuilds = 0; uint64_t succeededBuilds = 0;
uint64_t failedBuilds = 0; uint64_t failedBuilds = 0;
std::map<Activity::t, Path> substitutions; std::map<Activity::t, Path> substitutions;
std::set<Activity::t> runningSubstitutions; std::set<Activity::t> runningSubstitutions;
uint64_t succeededSubstitutions = 0; uint64_t succeededSubstitutions = 0;
uint64_t downloadedBytes = 0; // finished downloads uint64_t downloadedBytes = 0; // finished downloads
std::map<Activity::t, DownloadInfo> downloads; std::map<Activity::t, DownloadInfo> downloads;
std::map<Activity::t, CopyInfo> runningCopies;
std::list<ActInfo> activities; std::list<ActInfo> activities;
std::map<Activity::t, std::list<ActInfo>::iterator> its; std::map<Activity::t, std::list<ActInfo>::iterator> its;
}; };
@ -167,11 +179,35 @@ public:
res += fmt("%1$.0f/%2$.0f KiB", current / 1024.0, expected / 1024.0); res += fmt("%1$.0f/%2$.0f KiB", current / 1024.0, expected / 1024.0);
} }
if (!state.runningCopies.empty()) {
if (!res.empty()) res += ", ";
uint64_t copied = 0, expected = 0;
for (auto & i : state.runningCopies) {
copied += i.second.copied;
expected += i.second.expected - (i.second.done - i.second.copied);
}
res += fmt("%d/%d copied", copied, expected);
}
return res; return res;
} }
void event(const Event & ev) override void event(const Event & ev) override
{ {
if (ev.type == evStartActivity) {
auto state(state_.lock());
Activity::t act = ev.getI(0);
createActivity(*state, act, ev.getS(1));
update(*state);
}
if (ev.type == evStopActivity) {
auto state(state_.lock());
Activity::t act = ev.getI(0);
deleteActivity(*state, act);
update(*state);
}
if (ev.type == evBuildCreated) { if (ev.type == evBuildCreated) {
auto state(state_.lock()); auto state(state_.lock());
state->builds[ev.getI(0)] = ev.getS(1); state->builds[ev.getI(0)] = ev.getS(1);
@ -280,6 +316,16 @@ public:
update(*state); update(*state);
} }
} }
if (ev.type == evCopyProgress) {
auto state(state_.lock());
Activity::t act = ev.getI(0);
auto & i = state->runningCopies[act];
i.expected = ev.getI(1);
i.copied = ev.getI(2);
i.done = ev.getI(3);
update(*state);
}
} }
}; };