aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-08-13 08:09:04 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-08-13 08:09:04 +0200
commit61ac67105ef31e1ea31014e50e5b6deb74674594 (patch)
treee45e5be577d82b3c43a4cf94a833d17adb795a9e
parentb01aaa16e5adaa0cc064490535f8756b2ef8d421 (diff)
Cache git status results in version module
-rw-r--r--libbuild2/types.hxx34
-rw-r--r--libbuild2/utility.hxx33
-rw-r--r--libbuild2/version/snapshot-git.cxx46
-rw-r--r--libbuild2/version/snapshot.cxx4
4 files changed, 64 insertions, 53 deletions
diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx
index 0005e75..e3cacce 100644
--- a/libbuild2/types.hxx
+++ b/libbuild2/types.hxx
@@ -221,6 +221,40 @@ namespace build2
using std::thread;
namespace this_thread = std::this_thread;
+ // Global, MT-safe information cache. Normally used for caching information
+ // (versions, target triplets, search paths, etc) extracted from other
+ // programs (compilers, etc).
+ //
+ // The key is normally a hash of all the inputs that can affect the output.
+ //
+ // Note that insertion is racy and it's possible the cache entry already
+ // exists, in which case we ignore our value assuming it is the same.
+ //
+ template <typename T, typename K = string>
+ class global_cache
+ {
+ public:
+ const T*
+ find (const K& k) const
+ {
+ mlock l (mutex_);
+ auto i (cache_.find (k));
+ return i != cache_.end () ? &i->second : nullptr;
+ }
+
+ const T&
+ insert (K k, T v)
+ {
+ mlock l (mutex_);
+ return cache_.insert (std::make_pair (std::move (k),
+ std::move (v))).first->second;
+ }
+
+ private:
+ map<K, T> cache_;
+ mutable mutex mutex_;
+ };
+
// Exceptions.
//
// While <exception> is included, there is no using for std::exception --
diff --git a/libbuild2/utility.hxx b/libbuild2/utility.hxx
index c3e1921..c7ee2f4 100644
--- a/libbuild2/utility.hxx
+++ b/libbuild2/utility.hxx
@@ -535,39 +535,6 @@ namespace build2
verbosity, pe, args, forward<F> (f), error, ignore_exit, checksum);
}
- // Global, MT-safe information cache. Normally used for caching information
- // (versions, targets, search paths, etc) extracted from other programs
- // (compilers, etc).
- //
- // The key is normally a hash of all the inputs that can affect the output.
- //
- // Note that insertion is racy and it's possible the cache entry already
- // exists, in which case we ignore our value assuming it is the same.
- //
- template <typename T>
- class global_cache
- {
- public:
- const T*
- find (const string& k) const
- {
- mlock l (mutex_);
- auto i (cache_.find (k));
- return i != cache_.end () ? &i->second : nullptr;
- }
-
- const T&
- insert (string k, T v)
- {
- mlock l (mutex_);
- return cache_.insert (make_pair (move (k), move (v))).first->second;
- }
-
- private:
- map<string, T> cache_;
- mutable mutex mutex_;
- };
-
// File descriptor streams.
//
fdpipe
diff --git a/libbuild2/version/snapshot-git.cxx b/libbuild2/version/snapshot-git.cxx
index 28d96ac..e766bc9 100644
--- a/libbuild2/version/snapshot-git.cxx
+++ b/libbuild2/version/snapshot-git.cxx
@@ -14,11 +14,20 @@ namespace build2
{
namespace version
{
+ // We have to run git twice to extract the information we need and doing
+ // it repetitively is quite expensive, especially for larger repositories.
+ // So we cache it, which helps multi-package repositories.
+ //
+ static global_cache<snapshot, dir_path> cache;
+
snapshot
- extract_snapshot_git (const dir_path& src_root)
+ extract_snapshot_git (dir_path rep_root)
{
+ if (const snapshot* r = cache.find (rep_root))
+ return *r;
+
snapshot r;
- const char* d (src_root.string ().c_str ());
+ const char* d (rep_root.string ().c_str ());
// On startup git prepends the PATH environment variable value with the
// computed directory path where its sub-programs are supposedly located
@@ -192,30 +201,31 @@ namespace build2
// that.
}
- if (!run_finish_code (args, pr, l))
+ if (run_finish_code (args, pr, l))
+ {
+ if (r.sn == 0)
+ fail << "unable to extract git commit id/date for " << rep_root;
+
+ if (r.committed)
+ {
+ sha1 cs;
+ cs.append ("commit " + to_string (data.size ())); // Includes '\0'.
+ cs.append (data.c_str (), data.size ());
+ r.id.assign (cs.string (), 12); // 12-char abbreviated commit id.
+ }
+ else
+ r.sn++; // Add a second.
+ }
+ else
{
// Presumably new repository without HEAD. Return uncommitted snapshot
// with UNIX epoch as timestamp.
//
r.sn = 19700101000000ULL;
r.committed = false;
- return r;
- }
-
- if (r.sn == 0)
- fail << "unable to extract git commit id/date for " << src_root;
-
- if (r.committed)
- {
- sha1 cs;
- cs.append ("commit " + to_string (data.size ())); // Includes '\0'.
- cs.append (data.c_str (), data.size ());
- r.id.assign (cs.string (), 12); // 12-characters abbreviated commit id.
}
- else
- r.sn++; // Add a second.
- return r;
+ return cache.insert (move (rep_root), move (r));
}
}
}
diff --git a/libbuild2/version/snapshot.cxx b/libbuild2/version/snapshot.cxx
index 3a885b5..d20e633 100644
--- a/libbuild2/version/snapshot.cxx
+++ b/libbuild2/version/snapshot.cxx
@@ -12,7 +12,7 @@ namespace build2
namespace version
{
snapshot
- extract_snapshot_git (const dir_path&);
+ extract_snapshot_git (dir_path);
static const path git (".git");
@@ -46,7 +46,7 @@ namespace build2
if (butl::entry_exists (d / git,
true /* follow_symlinks */,
true /* ignore_errors */))
- return extract_snapshot_git (d);
+ return extract_snapshot_git (move (d));
}
return snapshot ();