Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 40 additions & 15 deletions src/libfetchers/git-utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
#include <git2/sys/mempack.h>
#include <git2/tree.h>

#include <boost/unordered/concurrent_flat_set.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/unordered/unordered_flat_set.hpp>
#include <iostream>
#include <queue>
#include <regex>
#include <span>
#include <ranges>

namespace std {

Expand Down Expand Up @@ -330,32 +332,57 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
checkInterrupt();
}

/**
* Return a connection pool for this repo. Useful for
* multithreaded access.
*/
Pool<GitRepoImpl> getPool()
{
// TODO: as an optimization, it would be nice to include `this` in the pool.
return Pool<GitRepoImpl>(
std::numeric_limits<size_t>::max(), [this, useMempack(useMempack)]() -> ref<GitRepoImpl> {
return make_ref<GitRepoImpl>(path, false, bare, useMempack);
});
}

uint64_t getRevCount(const Hash & rev) override
{
boost::unordered_flat_set<git_oid, std::hash<git_oid>> done;
std::queue<Commit> todo;
boost::concurrent_flat_set<git_oid, std::hash<git_oid>> done;

todo.push(peelObject<Commit>(lookupObject(*this, hashToOID(rev)).get(), GIT_OBJECT_COMMIT));
auto startCommit = peelObject<Commit>(lookupObject(*this, hashToOID(rev)).get(), GIT_OBJECT_COMMIT);
auto startOid = *git_commit_id(startCommit.get());
done.insert(startOid);

while (auto commit = pop(todo)) {
if (!done.insert(*git_commit_id(commit->get())).second)
continue;
auto repoPool(getPool());

ThreadPool pool;

for (size_t n = 0; n < git_commit_parentcount(commit->get()); ++n) {
git_commit * parent;
if (git_commit_parent(&parent, commit->get(), n)) {
auto process = [&done, &pool, &repoPool](this const auto & process, const git_oid & oid) -> void {
auto repo(repoPool.get());

auto _commit = lookupObject(*repo, oid, GIT_OBJECT_COMMIT);
auto commit = (const git_commit *) &*_commit;

for (auto n : std::views::iota(0U, git_commit_parentcount(commit))) {
auto parentOid = git_commit_parent_id(commit, n);
if (!parentOid) {
throw Error(
"Failed to retrieve the parent of Git commit '%s': %s. "
"This may be due to an incomplete repository history. "
"To resolve this, either enable the shallow parameter in your flake URL (?shallow=1) "
"or add set the shallow parameter to true in builtins.fetchGit, "
"or fetch the complete history for this branch.",
*git_commit_id(commit->get()),
*git_commit_id(commit),
git_error_last()->message);
}
todo.push(Commit(parent));
if (done.insert(*parentOid))
pool.enqueue(std::bind(process, *parentOid));
}
}
};

pool.enqueue(std::bind(process, startOid));

pool.process();

return done.size();
}
Expand Down Expand Up @@ -1070,9 +1097,7 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink

GitFileSystemObjectSinkImpl(ref<GitRepoImpl> repo)
: repo(repo)
, repoPool(std::numeric_limits<size_t>::max(), [repo, useMempack(useMempack)]() -> ref<GitRepoImpl> {
return make_ref<GitRepoImpl>(repo->path, false, repo->bare, useMempack);
})
, repoPool(repo->getPool())
{
}

Expand Down