CacheInvalidation: fixes for corner cases
 - call the `retriever` function at most once per component when a new generation is reached, not once for every out-of-date thread
 - call the `retriever` function after the new generation value is retrieved. In case there's a race, at least the next `get` will be able to call the `retriever` function again

diff --git a/trac/cache.py b/trac/cache.py
--- a/trac/cache.py
+++ b/trac/cache.py
@@ -131,6 +131,7 @@
             self._local.cache = local_cache = self._cache.copy()
         
         db_generation = local_meta.get(key, -1)
+        generation = -1
         
         # Try the thread-local copy first
         try:
@@ -150,15 +151,22 @@
             except KeyError:
                 pass
             
-            # Retrieve data from the database
+            if generation > db_generation: 
+                # component's cache is newer than per-thread cache
+                local_meta[key] = generation
+                return data
+
+            # Retrieve data using the retriever callback
             self.log.debug("***** Retrieving data for '%s'", key)
+            # retrieve current generation
             if db is None:
                 db = self.env.get_db_cnx()
-            data = retriever(db)
             cursor = db.cursor()
             cursor.execute("SELECT generation FROM cache WHERE key=%s", (key,))
             row = cursor.fetchone()
             generation = row and row[0] or -1
+            # retrieve data for at least this generation
+            data = retriever(db)
             local_cache[key] = self._cache[key] = (data, generation)
             local_meta[key] = generation
             return data

