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)
throw Error("failed to add path '%s' to remote host '%s', info.path, host");
}
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,
const Path & storePath, RepairFlag repair, CheckSigsFlag checkSigs)
{
Activity act(actCopyPath, fmt("copying path '%s'", storePath));
auto info = srcStore->queryPathInfo(storePath);
//act->progress(0, info->size());
StringSink sink;
srcStore->narFromPath({storePath}, sink);
@ -600,13 +604,28 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
for (auto & path : storePaths)
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;
processGraph<Path>(pool,
PathSet(missing.begin(), missing.end()),
[&](const Path & storePath) {
if (dstStore->isValidPath(storePath)) return PathSet();
if (dstStore->isValidPath(storePath)) {
nrDone++;
showProgress();
return PathSet();
}
return srcStore->queryPathInfo(storePath)->references;
},
@ -616,7 +635,12 @@ void copyPaths(ref<Store> srcStore, ref<Store> dstStore, const PathSet & storePa
if (!dstStore->isValidPath(storePath)) {
printInfo("copying '%s'...", storePath);
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)
{
checkInterrupt();
struct stat st;
if (lstat(path.c_str(), &st))
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(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
} Verbosity;
typedef enum {
actCopyPath = 100,
} ActivityType;
class Activity
{
public:
@ -21,6 +25,10 @@ public:
Activity();
Activity(const Activity & act) : id(act.id) { };
Activity(uint64_t id) : id(id) { };
Activity(ActivityType type, std::string msg = "");
~Activity();
//void progress(...);
};
typedef enum {
@ -35,6 +43,13 @@ typedef enum {
evSubstitutionCreated = 8,
evSubstitutionStarted = 9,
evSubstitutionFinished = 10,
evCopyStarted = 100,
evCopyProgress = 101,
evStartActivity = 1000,
evStopActivity = 1001,
} EventType;
struct Event

View file

@ -27,17 +27,29 @@ private:
DownloadInfo(const std::string & uri) : uri(uri) { }
};
struct CopyInfo
{
uint64_t expected = 0;
uint64_t copied = 0;
uint64_t done = 0;
};
struct State
{
std::map<Activity::t, Path> builds;
std::set<Activity::t> runningBuilds;
uint64_t succeededBuilds = 0;
uint64_t failedBuilds = 0;
std::map<Activity::t, Path> substitutions;
std::set<Activity::t> runningSubstitutions;
uint64_t succeededSubstitutions = 0;
uint64_t downloadedBytes = 0; // finished downloads
std::map<Activity::t, DownloadInfo> downloads;
std::map<Activity::t, CopyInfo> runningCopies;
std::list<ActInfo> activities;
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);
}
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;
}
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) {
auto state(state_.lock());
state->builds[ev.getI(0)] = ev.getS(1);
@ -280,6 +316,16 @@ public:
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);
}
}
};