From 3aee641aab491a3da53364aafb9074ae69dd2212 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 25 Jan 2011 17:13:22 -0800 Subject: [PATCH] Use a field rather than a superclass for ContentCache's cache. This makes it easier for cache experiments to swap out the LinkedHashMap for another cache. http://b/3184897 Change-Id: Iacdb266e41f5a98efd9bb30bc09ff8fff5a0a5a9 --- .../android/email/provider/ContentCache.java | 70 ++++++++++--------- .../data/MailboxAccountLoaderTestCase.java | 3 +- .../email/provider/ContentCacheTests.java | 10 +-- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/com/android/email/provider/ContentCache.java b/src/com/android/email/provider/ContentCache.java index 662fa2f42..a0aaa4340 100644 --- a/src/com/android/email/provider/ContentCache.java +++ b/src/com/android/email/provider/ContentCache.java @@ -70,9 +70,7 @@ import java.util.Set; * All references to ContentCache that are external to the ContentCache class MUST synchronize on * the ContentCache instance (e.g. CachedCursor.close()) */ -public final class ContentCache extends LinkedHashMap { - private static final long serialVersionUID = 1L; - +public final class ContentCache { private static final boolean DEBUG_CACHE = false; // DO NOT CHECK IN TRUE private static final boolean DEBUG_TOKENS = false; // DO NOT CHECK IN TRUE private static final boolean DEBUG_NOT_CACHEABLE = false; // DO NOT CHECK IN TRUE @@ -86,6 +84,24 @@ public final class ContentCache extends LinkedHashMap { // A map of queries that aren't cacheable (debug only) private static final CounterMap sNotCacheableMap = new CounterMap(); + private final Map mMap = new LinkedHashMap() { + @Override + public boolean removeEldestEntry(Map.Entry entry) { + synchronized (ContentCache.this) { + // If we're above the maximum size for this cache, remove the LRU cache entry + if (size() > mMaxSize) { + Cursor cursor = entry.getValue(); + // Close this cursor if it's no longer being used + if (!sActiveCursors.contains(cursor)) { + cursor.close(); + } + return true; + } + return false; + } + } + }; + // All defined caches private static final ArrayList sContentCaches = new ArrayList(); // A set of all unclosed, cached cursors; this will typically be a very small set, as cursors @@ -113,7 +129,6 @@ public final class ContentCache extends LinkedHashMap { * A synchronized reference counter for arbitrary objects */ /*package*/ static class CounterMap { - private static final long serialVersionUID = 1L; private HashMap mMap; /*package*/ CounterMap(int maxSize) { @@ -238,7 +253,6 @@ public final class ContentCache extends LinkedHashMap { * record. */ public static final class CacheToken { - private static final long serialVersionUID = 1L; private final String mId; private boolean mIsValid = READ_CACHE_ENABLED; @@ -304,7 +318,7 @@ public final class ContentCache extends LinkedHashMap { public void close() { synchronized(mCache) { int count = sActiveCursors.subtract(mCursor); - if ((count == 0) && !mCache.containsValue(mCursor)) { + if ((count == 0) && !mCache.mMap.containsValue(mCursor)) { super.close(); } } @@ -390,8 +404,6 @@ public final class ContentCache extends LinkedHashMap { * @param maxSize the maximum number of content cursors to cache */ public ContentCache(String name, String[] baseProjection, int maxSize) { - // Third argument true makes this LRU, rather than LRI - super(maxSize, .75F, true); mName = name; mMaxSize = maxSize; mBaseProjection = baseProjection; @@ -426,21 +438,12 @@ public final class ContentCache extends LinkedHashMap { return token; } - /* (non-Javadoc) - * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) - */ - @Override - public synchronized boolean removeEldestEntry(Map.Entry entry) { - // If we're above the maximum size for this cache, remove the LRU cache entry - if (size() > mMaxSize) { - Cursor cursor = entry.getValue(); - // Close this cursor if it's no longer being used - if (!sActiveCursors.contains(cursor)) { - cursor.close(); - } - return true; - } - return false; + public int size() { + return mMap.size(); + } + + private Cursor get(String id) { + return mMap.get(id); } /** @@ -479,7 +482,7 @@ public final class ContentCache extends LinkedHashMap { if (existingCursor != null) { unlockImpl(id, null, false); } - put(id, c); + mMap.put(id, c); return new CachedCursor(c, this, id); } return c; @@ -623,12 +626,12 @@ public final class ContentCache extends LinkedHashMap { Log.d(mLogTag, "=========== Recaching with new values: " + id); } cursor.moveToFirst(); - put(id, cursor); + mMap.put(id, cursor); } else { - remove(id); + mMap.remove(id); } } else { - remove(id); + mMap.remove(id); } // If there are no cursors using the old cached cursor, close it if (!sActiveCursors.contains(c)) { @@ -662,12 +665,12 @@ public final class ContentCache extends LinkedHashMap { } mStats.mInvalidateCount++; // Close all cached cursors that are no longer in use - for (Cursor c: values()) { + for (Cursor c: mMap.values()) { if (!sActiveCursors.contains(c)) { c.close(); } } - clear(); + mMap.clear(); // Invalidate all current tokens mTokenList.invalidate(); } @@ -701,7 +704,7 @@ public final class ContentCache extends LinkedHashMap { } } - private static class CacheCounter implements Comparable { + private static class CacheCounter implements Comparable { String uri; Integer count; @@ -711,9 +714,8 @@ public final class ContentCache extends LinkedHashMap { } @Override - public int compareTo(Object another) { - CacheCounter x = (CacheCounter)another; - return x.count > count ? 1 : x.count == count ? 0 : -1; + public int compareTo(CacheCounter another) { + return another.count > count ? 1 : another.count == count ? 0 : -1; } } @@ -722,7 +724,7 @@ public final class ContentCache extends LinkedHashMap { CacheCounter[] array = new CacheCounter[size]; int i = 0; - for (Entry entry: sNotCacheableMap.entrySet()) { + for (Map.Entry entry: sNotCacheableMap.entrySet()) { array[i++] = new CacheCounter(entry.getKey(), entry.getValue()); } Arrays.sort(array); diff --git a/tests/src/com/android/email/data/MailboxAccountLoaderTestCase.java b/tests/src/com/android/email/data/MailboxAccountLoaderTestCase.java index 294296cce..6798c8e1e 100644 --- a/tests/src/com/android/email/data/MailboxAccountLoaderTestCase.java +++ b/tests/src/com/android/email/data/MailboxAccountLoaderTestCase.java @@ -17,7 +17,6 @@ package com.android.email.data; import com.android.email.DBTestHelper; -import com.android.email.provider.ContentCache; import com.android.email.provider.EmailContent.Account; import com.android.email.provider.EmailContent.Mailbox; import com.android.email.provider.ProviderTestUtils; @@ -26,7 +25,7 @@ import android.content.Context; import android.test.LoaderTestCase; public class MailboxAccountLoaderTestCase extends LoaderTestCase { - // Isolted Context for providers. + // Isolated Context for providers. private Context mProviderContext; @Override diff --git a/tests/src/com/android/email/provider/ContentCacheTests.java b/tests/src/com/android/email/provider/ContentCacheTests.java index e7175ca5d..e774d4942 100644 --- a/tests/src/com/android/email/provider/ContentCacheTests.java +++ b/tests/src/com/android/email/provider/ContentCacheTests.java @@ -256,7 +256,7 @@ public class ContentCacheTests extends ProviderTestCase2 { assertFalse(cursor2.isClosed()); assertFalse(cursor3.isClosed()); } - + public void testCloseCachedCursor() { // Create a cache of size 2 ContentCache cache = new ContentCache("Name", SIMPLE_PROJECTION, 2); @@ -274,10 +274,10 @@ public class ContentCacheTests extends ProviderTestCase2 { assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor)); // Underlying cursor should be closed (no cached cursors open) assertTrue(underlyingCursor.isClosed()); - + underlyingCursor = getOneRowCursor(); - cache.put("2", underlyingCursor); - cachedCursor1 = new CachedCursor(underlyingCursor, cache, "2"); + cachedCursor1 = cache.putCursor( + underlyingCursor, "2", SIMPLE_PROJECTION, cache.getCacheToken("2")); cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2"); assertEquals(2, ContentCache.sActiveCursors.getCount(underlyingCursor)); cachedCursor1.close(); @@ -289,7 +289,7 @@ public class ContentCacheTests extends ProviderTestCase2 { cachedCursor2 = new CachedCursor(underlyingCursor, cache, "2"); assertEquals(1, ContentCache.sActiveCursors.getCount(underlyingCursor)); // Remove "2" from the cache and close the cursor - cache.remove("2"); + cache.invalidate(); cachedCursor2.close(); // The underlying cursor should now be closed (not in the cache and no cached cursors) assertEquals(0, ContentCache.sActiveCursors.getCount(underlyingCursor));