Merge "Refactor PropertyInvalidatedCache locks" into tm-qpr-dev
This commit is contained in:
@@ -391,7 +391,12 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean VERIFY = false;
|
||||
|
||||
// Per-Cache performance counters. As some cache instances are declared static,
|
||||
/**
|
||||
* The object-private lock.
|
||||
*/
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// Per-Cache performance counters.
|
||||
@GuardedBy("mLock")
|
||||
private long mHits = 0;
|
||||
|
||||
@@ -410,26 +415,20 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
@GuardedBy("mLock")
|
||||
private long mClears = 0;
|
||||
|
||||
// Most invalidation is done in a static context, so the counters need to be accessible.
|
||||
@GuardedBy("sCorkLock")
|
||||
private static final HashMap<String, Long> sInvalidates = new HashMap<>();
|
||||
/**
|
||||
* Protect objects that support corking. mLock and sGlobalLock must never be taken while this
|
||||
* is held.
|
||||
*/
|
||||
private static final Object sCorkLock = new Object();
|
||||
|
||||
/**
|
||||
* Record the number of invalidate or cork calls that were nops because
|
||||
* the cache was already corked. This is static because invalidation is
|
||||
* done in a static context.
|
||||
* Record the number of invalidate or cork calls that were nops because the cache was already
|
||||
* corked. This is static because invalidation is done in a static context. Entries are
|
||||
* indexed by the cache property.
|
||||
*/
|
||||
@GuardedBy("sCorkLock")
|
||||
private static final HashMap<String, Long> sCorkedInvalidates = new HashMap<>();
|
||||
|
||||
/**
|
||||
* If sEnabled is false then all cache operations are stubbed out. Set
|
||||
* it to false inside test processes.
|
||||
*/
|
||||
private static boolean sEnabled = true;
|
||||
|
||||
private static final Object sCorkLock = new Object();
|
||||
|
||||
/**
|
||||
* A map of cache keys that we've "corked". (The values are counts.) When a cache key is
|
||||
* corked, we skip the cache invalidate when the cache key is in the unset state --- that
|
||||
@@ -439,22 +438,40 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
@GuardedBy("sCorkLock")
|
||||
private static final HashMap<String, Integer> sCorks = new HashMap<>();
|
||||
|
||||
/**
|
||||
* A lock for the global list of caches and cache keys. This must never be taken inside mLock
|
||||
* or sCorkLock.
|
||||
*/
|
||||
private static final Object sGlobalLock = new Object();
|
||||
|
||||
/**
|
||||
* A map of cache keys that have been disabled in the local process. When a key is
|
||||
* disabled locally, existing caches are disabled and the key is saved in this map.
|
||||
* Future cache instances that use the same key will be disabled in their constructor.
|
||||
*/
|
||||
@GuardedBy("sCorkLock")
|
||||
@GuardedBy("sGlobalLock")
|
||||
private static final HashSet<String> sDisabledKeys = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Weakly references all cache objects in the current process, allowing us to iterate over
|
||||
* them all for purposes like issuing debug dumps and reacting to memory pressure.
|
||||
*/
|
||||
@GuardedBy("sCorkLock")
|
||||
@GuardedBy("sGlobalLock")
|
||||
private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = new WeakHashMap<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
/**
|
||||
* Counts of the number of times a cache key was invalidated. Invalidation occurs in a static
|
||||
* context with no cache object available, so this is a static map. Entries are indexed by
|
||||
* the cache property.
|
||||
*/
|
||||
@GuardedBy("sGlobalLock")
|
||||
private static final HashMap<String, Long> sInvalidates = new HashMap<>();
|
||||
|
||||
/**
|
||||
* If sEnabled is false then all cache operations are stubbed out. Set
|
||||
* it to false inside test processes.
|
||||
*/
|
||||
private static boolean sEnabled = true;
|
||||
|
||||
/**
|
||||
* Name of the property that holds the unique value that we use to invalidate the cache.
|
||||
@@ -595,14 +612,17 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
};
|
||||
}
|
||||
|
||||
// Register the map in the global list. If the cache is disabled globally, disable it
|
||||
// now.
|
||||
/**
|
||||
* Register the map in the global list. If the cache is disabled globally, disable it
|
||||
* now. This method is only ever called from the constructor, which means no other thread has
|
||||
* access to the object yet. It can safely be modified outside any lock.
|
||||
*/
|
||||
private void registerCache() {
|
||||
synchronized (sCorkLock) {
|
||||
sCaches.put(this, null);
|
||||
synchronized (sGlobalLock) {
|
||||
if (sDisabledKeys.contains(mCacheName)) {
|
||||
disableInstance();
|
||||
}
|
||||
sCaches.put(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,8 +817,9 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the use of this cache in this process. This method is using during
|
||||
* testing. To disable a cache in normal code, use disableLocal().
|
||||
* Disable the use of this cache in this process. This method is using internally and during
|
||||
* testing. To disable a cache in normal code, use disableLocal(). A disabled cache cannot
|
||||
* be re-enabled.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@@ -811,17 +832,23 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
|
||||
/**
|
||||
* Disable the local use of all caches with the same name. All currently registered caches
|
||||
* using the key will be disabled now, and all future cache instances that use the key will be
|
||||
* disabled in their constructor.
|
||||
* with the name will be disabled now, and all future cache instances that use the name will
|
||||
* be disabled in their constructor.
|
||||
*/
|
||||
private static final void disableLocal(@NonNull String name) {
|
||||
synchronized (sCorkLock) {
|
||||
sDisabledKeys.add(name);
|
||||
synchronized (sGlobalLock) {
|
||||
if (sDisabledKeys.contains(name)) {
|
||||
// The key is already in recorded so there is no further work to be done.
|
||||
return;
|
||||
}
|
||||
for (PropertyInvalidatedCache cache : sCaches.keySet()) {
|
||||
if (name.equals(cache.mCacheName)) {
|
||||
cache.disableInstance();
|
||||
}
|
||||
}
|
||||
// Record the disabled key after the iteration. If an exception occurs during the
|
||||
// iteration above, and the code is retried, the function should not exit early.
|
||||
sDisabledKeys.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -834,7 +861,7 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
*/
|
||||
@TestApi
|
||||
public final void forgetDisableLocal() {
|
||||
synchronized (sCorkLock) {
|
||||
synchronized (sGlobalLock) {
|
||||
sDisabledKeys.remove(mCacheName);
|
||||
}
|
||||
}
|
||||
@@ -851,9 +878,9 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable this cache in the current process, and all other caches that use the same
|
||||
* name. This does not affect caches that have a different name but use the same
|
||||
* property.
|
||||
* Disable this cache in the current process, and all other present and future caches that use
|
||||
* the same name. This does not affect caches that have a different name but use the same
|
||||
* property. Once disabled, a cache cannot be reenabled.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
@@ -1381,10 +1408,9 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
/**
|
||||
* Returns a list of caches alive at the current time.
|
||||
*/
|
||||
@GuardedBy("sGlobalLock")
|
||||
private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
|
||||
synchronized (sCorkLock) {
|
||||
return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
|
||||
}
|
||||
return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1540,7 +1566,7 @@ public class PropertyInvalidatedCache<Query, Result> {
|
||||
boolean detail = anyDetailed(args);
|
||||
|
||||
ArrayList<PropertyInvalidatedCache> activeCaches;
|
||||
synchronized (sCorkLock) {
|
||||
synchronized (sGlobalLock) {
|
||||
activeCaches = getActiveCaches();
|
||||
if (!detail) {
|
||||
dumpCorkInfo(pw);
|
||||
|
||||
Reference in New Issue
Block a user