From 61ac67105ef31e1ea31014e50e5b6deb74674594 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 13 Aug 2021 08:09:04 +0200 Subject: Cache git status results in version module --- libbuild2/types.hxx | 34 ++++++++++++++++++++++++++++ libbuild2/utility.hxx | 33 --------------------------- libbuild2/version/snapshot-git.cxx | 46 +++++++++++++++++++++++--------------- libbuild2/version/snapshot.cxx | 4 ++-- 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 + 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 cache_; + mutable mutex mutex_; + }; + // Exceptions. // // While 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), 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 - 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 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 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 (); -- cgit v1.1