aboutsummaryrefslogtreecommitdiff
path: root/build2/variable.txx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-02-13 09:48:12 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-02-13 12:42:42 +0200
commit737877e62467b924eea0a43eab68258b0c13db78 (patch)
tree3fe2f539a21ce0407cdaa908a9af56b4cf8087e0 /build2/variable.txx
parent38290dacd8faab166774d757a1e09807e57e9ba5 (diff)
Add MT-safe variable_cache, use for variable overrides
Diffstat (limited to 'build2/variable.txx')
-rw-r--r--build2/variable.txx69
1 files changed, 69 insertions, 0 deletions
diff --git a/build2/variable.txx b/build2/variable.txx
index b993200..5b212f0 100644
--- a/build2/variable.txx
+++ b/build2/variable.txx
@@ -552,4 +552,73 @@ namespace build2
&map_compare<K, V>,
&default_empty<map<K, V>>
};
+
+ // variable_cache
+ //
+ template <typename K>
+ pair<value&, ulock> variable_cache<K>::
+ insert (K k, const lookup& stem)
+ {
+ const variable_map* vars (stem.vars); // NULL if undefined.
+ size_t ver (
+ stem.defined ()
+ ? static_cast<const variable_map::value_data*> (stem.value)->version
+ : 0);
+
+ shared_mutex& m (
+ variable_cache_mutex_shard[
+ hash<variable_cache*> () (this) % variable_cache_mutex_shard_size]);
+
+ slock sl (m);
+ ulock ul (m, defer_lock);
+
+ auto i (m_.find (k));
+
+ // Cache hit.
+ //
+ if (i != m_.end () &&
+ i->second.stem_vars == vars &&
+ i->second.stem_version == ver)
+ return pair<value&, ulock> (i->second.value, move (ul));
+
+ // Relock for exclusive access. Note that it is entirely possible
+ // that between unlock and lock someone else has updated the entry.
+ //
+ sl.unlock ();
+ ul.lock ();
+
+ // Note that the cache entries are never removed so we can reuse the
+ // iterator.
+ //
+ pair<typename map_type::iterator, bool> p (i, i == m_.end ());
+
+ if (p.second)
+ p = m_.emplace (move (k), entry_type {value (nullptr), vars, ver});
+
+ entry_type& e (p.first->second);
+
+ // Cache miss.
+ //
+ if (p.second)
+ ;
+ //
+ // Cache invalidation.
+ //
+ else if (e.stem_vars != vars || e.stem_version != ver)
+ {
+ if (e.stem_vars != vars)
+ e.stem_vars = vars;
+ else
+ assert (e.stem_version <= ver);
+
+ e.stem_version = ver;
+ }
+ //
+ // Cache hit.
+ //
+ else
+ ul.unlock ();
+
+ return pair<value&, ulock> (e.value, move (ul));
+ }
}