diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2017-02-13 09:48:12 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2017-02-13 12:42:42 +0200 |
commit | 737877e62467b924eea0a43eab68258b0c13db78 (patch) | |
tree | 3fe2f539a21ce0407cdaa908a9af56b4cf8087e0 /build2/variable.txx | |
parent | 38290dacd8faab166774d757a1e09807e57e9ba5 (diff) |
Add MT-safe variable_cache, use for variable overrides
Diffstat (limited to 'build2/variable.txx')
-rw-r--r-- | build2/variable.txx | 69 |
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)); + } } |